PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/climm-0.7.1/src/util_io.c

#
C | 330 lines | 288 code | 30 blank | 12 comment | 76 complexity | f24fb3d6305c65792b453a12aad4c323 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0, LGPL-2.1
  1. /*
  2. * Assorted helper functions for doing I/O.
  3. *
  4. * Copyright: This file may be distributed under version 2 of the GPL licence.
  5. *
  6. * $Id: util_io.c 2851 2010-03-06 18:16:56Z kuhlmann $
  7. */
  8. #include "climm.h"
  9. #include <errno.h>
  10. #if HAVE_SYS_TYPES_H
  11. #include <sys/types.h>
  12. #endif
  13. #if HAVE_SYS_SOCKET_H
  14. #include <sys/socket.h>
  15. #endif
  16. #if HAVE_SYS_STAT_H
  17. #include <sys/stat.h>
  18. #endif
  19. #if HAVE_SYS_UN_H
  20. #include <sys/un.h>
  21. #endif
  22. #include <fcntl.h>
  23. #if HAVE_UNISTD_H
  24. #include <unistd.h>
  25. #endif
  26. #include <assert.h>
  27. #if HAVE_UNISTD_H
  28. #include <unistd.h>
  29. #endif
  30. #ifdef HAVE_SYS_SELECT_H
  31. #include <sys/select.h>
  32. #endif
  33. #include <signal.h>
  34. #include <stdarg.h>
  35. #include "preferences.h"
  36. #include "util_ui.h"
  37. #include "connection.h"
  38. #include "util_io.h"
  39. #include "io/io_private.h"
  40. #include "io/io_tcp.h"
  41. #include "io/io_socks5.h"
  42. #include "conv.h"
  43. #include "util.h"
  44. #include "contact.h"
  45. void UtilIOConnectTCP (Connection *conn)
  46. {
  47. if (ServerPrefVal (conn->serv, CO_S5USE))
  48. return IOConnectSocks5 (conn);
  49. return IOConnectTCP (conn);
  50. }
  51. void UtilIOListenTCP (Connection *conn)
  52. {
  53. if (ServerPrefVal (conn->serv, CO_S5USE))
  54. return IOListenSocks5 (conn);
  55. return IOListenTCP (conn);
  56. }
  57. io_err_t io_util_accept (Connection *conn, Dispatcher *d, Connection *newc)
  58. {
  59. if (!d)
  60. return IO_NO_CONN;
  61. if (d->flags != FLAG_OPEN)
  62. return d->funcs->f_cting (conn, d);
  63. if (d->funcs->f_accept)
  64. return d->funcs->f_accept (conn, d, newc);
  65. return io_util_accept (conn, d->next, newc);
  66. }
  67. int UtilIOAccept (Connection *conn, Connection *newc)
  68. {
  69. return io_util_accept (conn, conn->dispatcher, newc);
  70. }
  71. io_err_t io_util_read (Connection *conn, Dispatcher *d, char *buf, size_t count)
  72. {
  73. if (!d)
  74. return IO_NO_CONN;
  75. if (d->flags != FLAG_OPEN)
  76. return d->funcs->f_cting (conn, d);
  77. if (d->funcs->f_read)
  78. return d->funcs->f_read (conn, d, buf, count);
  79. return io_util_read (conn, d->next, buf, count);
  80. }
  81. int UtilIORead (Connection *conn, char *buf, size_t count)
  82. {
  83. return io_util_read (conn, conn->dispatcher, buf, count);
  84. }
  85. io_err_t io_util_write (Connection *conn, Dispatcher *d, const char *buf, size_t count)
  86. {
  87. if (!d)
  88. return IO_NO_CONN;
  89. if (d->flags != FLAG_OPEN)
  90. return io_any_appendbuf (conn, d, buf, count);
  91. if (d->funcs->f_write)
  92. return d->funcs->f_write (conn, d, buf, count);
  93. return io_util_write (conn, d->next, buf, count);
  94. }
  95. io_err_t UtilIOWrite (Connection *conn, const char *buf, size_t count)
  96. {
  97. return io_util_write (conn, conn->dispatcher, buf, count);
  98. }
  99. io_err_t io_any_appendbuf (Connection *conn, Dispatcher *d, const char *buf, size_t count)
  100. {
  101. char *newbuf;
  102. conn->connect |= CONNECT_SELECT_W;
  103. DebugH (DEB_TCP, "conn %p append %ld to %ld", conn, (long int)count, (long int)d->outlen);
  104. if (!count)
  105. return IO_OK;
  106. if (d->outlen)
  107. newbuf = realloc (d->outbuf, d->outlen + count);
  108. else
  109. newbuf = malloc (count);
  110. if (!newbuf)
  111. {
  112. s_repl (&d->lasterr, "");
  113. return IO_NO_MEM;
  114. }
  115. memcpy (newbuf + d->outlen, buf, count);
  116. d->outlen += count;
  117. d->outbuf = newbuf;
  118. return IO_OK;
  119. }
  120. void UtilIOClose (Connection *conn)
  121. {
  122. if (conn && conn->dispatcher && conn->dispatcher->funcs && conn->dispatcher->funcs->f_close)
  123. conn->dispatcher->funcs->f_close (conn, conn->dispatcher);
  124. conn->connect &= ~CONNECT_SELECT_A;
  125. assert (!conn || conn->sok < 0);
  126. assert (!conn || !conn->dispatcher);
  127. }
  128. const char *UtilIOErr (Connection *conn)
  129. {
  130. return conn->dispatcher->funcs->f_err (conn, conn->dispatcher);
  131. }
  132. io_ssl_err_t UtilIOSSLSupported (void)
  133. {
  134. io_ssl_err_t rcgnutls = IOGnuTLSSupported ();
  135. io_ssl_err_t rcopenssl = rcgnutls == IO_SSL_OK ? IO_SSL_NOLIB : IOOpenSSLSupported ();
  136. if (rcgnutls == IO_SSL_OK || rcopenssl == IO_SSL_OK)
  137. return IO_SSL_OK;
  138. if (rcgnutls != IO_SSL_NOLIB)
  139. {
  140. rl_printf (i18n (2374, "SSL error: %s [%d]\n"), IOGnuTLSInitError (), 0);
  141. rl_printf (i18n (2371, "SSL init failed.\n"));
  142. }
  143. if (rcopenssl == IO_SSL_INIT)
  144. {
  145. rl_printf (i18n (2374, "SSL error: %s [%d]\n"), IOOpenSSLInitError (), 0);
  146. rl_printf (i18n (2371, "SSL init failed.\n"));
  147. }
  148. else
  149. rl_printf (i18n (2581, "Install the GnuTLS library and enjoy encrypted connections to peers!\n"));
  150. return IO_SSL_NOLIB;
  151. }
  152. io_ssl_err_t UtilIOSSLOpen (Connection *conn, char is_client)
  153. {
  154. if (IOGnuTLSSupported () == IO_SSL_OK)
  155. return IOGnuTLSOpen (conn, is_client);
  156. else if (IOOpenSSLSupported () == IO_SSL_OK)
  157. return IOOpenSSLOpen (conn, is_client);
  158. else
  159. return IO_SSL_NOLIB;
  160. }
  161. io_err_t UtilIOShowError (Connection *conn, io_err_t rc)
  162. {
  163. int e = errno;
  164. const char *t = NULL;
  165. switch (rc) {
  166. case IO_CONNECTED:
  167. rl_print ("");
  168. if (prG->verbose || (conn->serv && conn == conn->serv->conn))
  169. if (rl_pos () > 0)
  170. rl_print (i18n (1634, "ok.\n"));
  171. return IO_CONNECTED;
  172. case IO_OK:
  173. return IO_OK;
  174. case IO_NO_MEM:
  175. case IO_NO_PARAM:
  176. assert (0);
  177. case IO_NO_SOCKET:
  178. if (1) t = i18n (1638, "Couldn't create socket"); else
  179. case IO_NO_NONBLOCK:
  180. if (1) t = i18n (1950, "Couldn't set socket nonblocking"); else
  181. case IO_NO_HOSTNAME:
  182. if (1) t = i18n (2743, "Can't find hostname"); else
  183. case IO_CONN_TO:
  184. if (1) t = i18n (2744, "Connection timed out"); else
  185. case IO_NO_CONN:
  186. t = i18n (1952, "Couldn't open connection");
  187. if (prG->verbose || (conn->serv && conn == conn->serv->conn))
  188. {
  189. Contact *cont = conn->cont;
  190. char *semi = strchr (conn->server, ';');
  191. if (semi)
  192. *semi = 0;
  193. rl_log_for (cont->nick, COLCONTACT);
  194. rl_printf (i18n (2745, "Opening connection to %s:%s%ld%s "),
  195. s_wordquote (conn->server), COLQUOTE, UD2UL (conn->port), COLNONE);
  196. if (semi)
  197. *semi = ';';
  198. rl_print (i18n (1949, "failed:\n"));
  199. rl_printf ("%s [%d]\n",
  200. s_sprintf ("%s: %s (%d).", t, conn->dispatcher->funcs->f_err (conn, conn->dispatcher), e),
  201. __LINE__);
  202. }
  203. UtilIOClose (conn);
  204. return IO_RW;
  205. case IO_CLOSED:
  206. #ifdef ECONNRESET
  207. if (!errno)
  208. errno = ECONNRESET;
  209. #endif
  210. case IO_RW:
  211. if (prG->verbose || (conn->serv && conn == conn->serv->conn))
  212. {
  213. Contact *cont;
  214. if ((cont = conn->cont))
  215. {
  216. rl_log_for (cont->nick, COLCONTACT);
  217. rl_printf (i18n (1878, "Error while reading from socket: %s (%d, %d)\n"), conn->dispatcher->funcs->f_err (conn, conn->dispatcher), rc, errno);
  218. }
  219. }
  220. UtilIOClose (conn);
  221. return IO_RW;
  222. default:
  223. assert (0);
  224. }
  225. }
  226. /*
  227. * Read a complete line from a fd.
  228. *
  229. * Returned string may not be free()d.
  230. */
  231. strc_t UtilIOReadline (FILE *fd)
  232. {
  233. static str_s str;
  234. char *p;
  235. s_init (&str, "", 256);
  236. while (1)
  237. {
  238. str.txt[str.max - 2] = 0;
  239. if (!fgets (str.txt + str.len, str.max - str.len, fd))
  240. {
  241. str.txt[str.len] = '\0';
  242. if (!str.len)
  243. return NULL;
  244. break;
  245. }
  246. str.txt[str.max - 1] = '\0';
  247. str.len = strlen (str.txt);
  248. if (!str.txt[str.max - 2])
  249. break;
  250. s_blow (&str, 128);
  251. }
  252. if ((p = strpbrk (str.txt, "\r\n")))
  253. {
  254. *p = 0;
  255. str.len = strlen (str.txt);
  256. }
  257. return &str;
  258. }
  259. static struct timeval tv;
  260. static fd_set fds[3];
  261. static int maxfd;
  262. void UtilIOSelectInit (int sec, int usec)
  263. {
  264. FD_ZERO (&fds[0]);
  265. FD_ZERO (&fds[1]);
  266. FD_ZERO (&fds[2]);
  267. tv.tv_sec = sec;
  268. tv.tv_usec = usec;
  269. maxfd = 0;
  270. }
  271. void UtilIOSelectAdd (FD_T sok, int nr)
  272. {
  273. FD_SET (sok, &fds[nr & 3]);
  274. if (sok > maxfd)
  275. maxfd = sok;
  276. }
  277. BOOL UtilIOSelectIs (FD_T sok, int nr)
  278. {
  279. return ((nr & READFDS) && FD_ISSET (sok, &fds[READFDS & 3]))
  280. || ((nr & WRITEFDS) && FD_ISSET (sok, &fds[WRITEFDS & 3]))
  281. || ((nr & EXCEPTFDS) && FD_ISSET (sok, &fds[EXCEPTFDS & 3]));
  282. }
  283. void UtilIOSelect (void)
  284. {
  285. int res, rc;
  286. errno = 0;
  287. res = select (maxfd + 1, &fds[READFDS & 3], &fds[WRITEFDS & 3], &fds[EXCEPTFDS & 3], &tv);
  288. rc = errno;
  289. if (res == -1)
  290. {
  291. FD_ZERO (&fds[READFDS & 3]);
  292. FD_ZERO (&fds[WRITEFDS & 3]);
  293. FD_ZERO (&fds[EXCEPTFDS & 3]);
  294. if (rc != EINTR && rc != EAGAIN)
  295. {
  296. printf (i18n (1849, "Error on select: %s (%d)\n"), strerror (rc), rc);
  297. assert (0);
  298. }
  299. }
  300. }