/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
- /*
- * Assorted helper functions for doing I/O.
- *
- * Copyright: This file may be distributed under version 2 of the GPL licence.
- *
- * $Id: util_io.c 2851 2010-03-06 18:16:56Z kuhlmann $
- */
- #include "climm.h"
- #include <errno.h>
- #if HAVE_SYS_TYPES_H
- #include <sys/types.h>
- #endif
- #if HAVE_SYS_SOCKET_H
- #include <sys/socket.h>
- #endif
- #if HAVE_SYS_STAT_H
- #include <sys/stat.h>
- #endif
- #if HAVE_SYS_UN_H
- #include <sys/un.h>
- #endif
- #include <fcntl.h>
- #if HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include <assert.h>
- #if HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #ifdef HAVE_SYS_SELECT_H
- #include <sys/select.h>
- #endif
- #include <signal.h>
- #include <stdarg.h>
- #include "preferences.h"
- #include "util_ui.h"
- #include "connection.h"
- #include "util_io.h"
- #include "io/io_private.h"
- #include "io/io_tcp.h"
- #include "io/io_socks5.h"
- #include "conv.h"
- #include "util.h"
- #include "contact.h"
- void UtilIOConnectTCP (Connection *conn)
- {
- if (ServerPrefVal (conn->serv, CO_S5USE))
- return IOConnectSocks5 (conn);
- return IOConnectTCP (conn);
- }
- void UtilIOListenTCP (Connection *conn)
- {
- if (ServerPrefVal (conn->serv, CO_S5USE))
- return IOListenSocks5 (conn);
- return IOListenTCP (conn);
- }
- io_err_t io_util_accept (Connection *conn, Dispatcher *d, Connection *newc)
- {
- if (!d)
- return IO_NO_CONN;
- if (d->flags != FLAG_OPEN)
- return d->funcs->f_cting (conn, d);
- if (d->funcs->f_accept)
- return d->funcs->f_accept (conn, d, newc);
- return io_util_accept (conn, d->next, newc);
- }
- int UtilIOAccept (Connection *conn, Connection *newc)
- {
- return io_util_accept (conn, conn->dispatcher, newc);
- }
- io_err_t io_util_read (Connection *conn, Dispatcher *d, char *buf, size_t count)
- {
- if (!d)
- return IO_NO_CONN;
- if (d->flags != FLAG_OPEN)
- return d->funcs->f_cting (conn, d);
- if (d->funcs->f_read)
- return d->funcs->f_read (conn, d, buf, count);
- return io_util_read (conn, d->next, buf, count);
- }
- int UtilIORead (Connection *conn, char *buf, size_t count)
- {
- return io_util_read (conn, conn->dispatcher, buf, count);
- }
- io_err_t io_util_write (Connection *conn, Dispatcher *d, const char *buf, size_t count)
- {
- if (!d)
- return IO_NO_CONN;
- if (d->flags != FLAG_OPEN)
- return io_any_appendbuf (conn, d, buf, count);
- if (d->funcs->f_write)
- return d->funcs->f_write (conn, d, buf, count);
- return io_util_write (conn, d->next, buf, count);
- }
- io_err_t UtilIOWrite (Connection *conn, const char *buf, size_t count)
- {
- return io_util_write (conn, conn->dispatcher, buf, count);
- }
- io_err_t io_any_appendbuf (Connection *conn, Dispatcher *d, const char *buf, size_t count)
- {
- char *newbuf;
- conn->connect |= CONNECT_SELECT_W;
- DebugH (DEB_TCP, "conn %p append %ld to %ld", conn, (long int)count, (long int)d->outlen);
- if (!count)
- return IO_OK;
- if (d->outlen)
- newbuf = realloc (d->outbuf, d->outlen + count);
- else
- newbuf = malloc (count);
- if (!newbuf)
- {
- s_repl (&d->lasterr, "");
- return IO_NO_MEM;
- }
- memcpy (newbuf + d->outlen, buf, count);
- d->outlen += count;
- d->outbuf = newbuf;
- return IO_OK;
- }
- void UtilIOClose (Connection *conn)
- {
- if (conn && conn->dispatcher && conn->dispatcher->funcs && conn->dispatcher->funcs->f_close)
- conn->dispatcher->funcs->f_close (conn, conn->dispatcher);
- conn->connect &= ~CONNECT_SELECT_A;
- assert (!conn || conn->sok < 0);
- assert (!conn || !conn->dispatcher);
- }
- const char *UtilIOErr (Connection *conn)
- {
- return conn->dispatcher->funcs->f_err (conn, conn->dispatcher);
- }
- io_ssl_err_t UtilIOSSLSupported (void)
- {
- io_ssl_err_t rcgnutls = IOGnuTLSSupported ();
- io_ssl_err_t rcopenssl = rcgnutls == IO_SSL_OK ? IO_SSL_NOLIB : IOOpenSSLSupported ();
- if (rcgnutls == IO_SSL_OK || rcopenssl == IO_SSL_OK)
- return IO_SSL_OK;
- if (rcgnutls != IO_SSL_NOLIB)
- {
- rl_printf (i18n (2374, "SSL error: %s [%d]\n"), IOGnuTLSInitError (), 0);
- rl_printf (i18n (2371, "SSL init failed.\n"));
- }
- if (rcopenssl == IO_SSL_INIT)
- {
- rl_printf (i18n (2374, "SSL error: %s [%d]\n"), IOOpenSSLInitError (), 0);
- rl_printf (i18n (2371, "SSL init failed.\n"));
- }
- else
- rl_printf (i18n (2581, "Install the GnuTLS library and enjoy encrypted connections to peers!\n"));
- return IO_SSL_NOLIB;
- }
- io_ssl_err_t UtilIOSSLOpen (Connection *conn, char is_client)
- {
- if (IOGnuTLSSupported () == IO_SSL_OK)
- return IOGnuTLSOpen (conn, is_client);
- else if (IOOpenSSLSupported () == IO_SSL_OK)
- return IOOpenSSLOpen (conn, is_client);
- else
- return IO_SSL_NOLIB;
- }
- io_err_t UtilIOShowError (Connection *conn, io_err_t rc)
- {
- int e = errno;
- const char *t = NULL;
- switch (rc) {
-
- case IO_CONNECTED:
- rl_print ("");
- if (prG->verbose || (conn->serv && conn == conn->serv->conn))
- if (rl_pos () > 0)
- rl_print (i18n (1634, "ok.\n"));
- return IO_CONNECTED;
- case IO_OK:
- return IO_OK;
- case IO_NO_MEM:
- case IO_NO_PARAM:
- assert (0);
- case IO_NO_SOCKET:
- if (1) t = i18n (1638, "Couldn't create socket"); else
- case IO_NO_NONBLOCK:
- if (1) t = i18n (1950, "Couldn't set socket nonblocking"); else
- case IO_NO_HOSTNAME:
- if (1) t = i18n (2743, "Can't find hostname"); else
- case IO_CONN_TO:
- if (1) t = i18n (2744, "Connection timed out"); else
- case IO_NO_CONN:
- t = i18n (1952, "Couldn't open connection");
- if (prG->verbose || (conn->serv && conn == conn->serv->conn))
- {
- Contact *cont = conn->cont;
- char *semi = strchr (conn->server, ';');
- if (semi)
- *semi = 0;
- rl_log_for (cont->nick, COLCONTACT);
- rl_printf (i18n (2745, "Opening connection to %s:%s%ld%s "),
- s_wordquote (conn->server), COLQUOTE, UD2UL (conn->port), COLNONE);
- if (semi)
- *semi = ';';
- rl_print (i18n (1949, "failed:\n"));
- rl_printf ("%s [%d]\n",
- s_sprintf ("%s: %s (%d).", t, conn->dispatcher->funcs->f_err (conn, conn->dispatcher), e),
- __LINE__);
- }
- UtilIOClose (conn);
- return IO_RW;
- case IO_CLOSED:
- #ifdef ECONNRESET
- if (!errno)
- errno = ECONNRESET;
- #endif
- case IO_RW:
- if (prG->verbose || (conn->serv && conn == conn->serv->conn))
- {
- Contact *cont;
- if ((cont = conn->cont))
- {
- rl_log_for (cont->nick, COLCONTACT);
- rl_printf (i18n (1878, "Error while reading from socket: %s (%d, %d)\n"), conn->dispatcher->funcs->f_err (conn, conn->dispatcher), rc, errno);
- }
- }
- UtilIOClose (conn);
- return IO_RW;
- default:
- assert (0);
- }
- }
- /*
- * Read a complete line from a fd.
- *
- * Returned string may not be free()d.
- */
- strc_t UtilIOReadline (FILE *fd)
- {
- static str_s str;
- char *p;
-
- s_init (&str, "", 256);
- while (1)
- {
- str.txt[str.max - 2] = 0;
- if (!fgets (str.txt + str.len, str.max - str.len, fd))
- {
- str.txt[str.len] = '\0';
- if (!str.len)
- return NULL;
- break;
- }
- str.txt[str.max - 1] = '\0';
- str.len = strlen (str.txt);
- if (!str.txt[str.max - 2])
- break;
- s_blow (&str, 128);
- }
- if ((p = strpbrk (str.txt, "\r\n")))
- {
- *p = 0;
- str.len = strlen (str.txt);
- }
- return &str;
- }
- static struct timeval tv;
- static fd_set fds[3];
- static int maxfd;
- void UtilIOSelectInit (int sec, int usec)
- {
- FD_ZERO (&fds[0]);
- FD_ZERO (&fds[1]);
- FD_ZERO (&fds[2]);
- tv.tv_sec = sec;
- tv.tv_usec = usec;
- maxfd = 0;
- }
- void UtilIOSelectAdd (FD_T sok, int nr)
- {
- FD_SET (sok, &fds[nr & 3]);
- if (sok > maxfd)
- maxfd = sok;
- }
- BOOL UtilIOSelectIs (FD_T sok, int nr)
- {
- return ((nr & READFDS) && FD_ISSET (sok, &fds[READFDS & 3]))
- || ((nr & WRITEFDS) && FD_ISSET (sok, &fds[WRITEFDS & 3]))
- || ((nr & EXCEPTFDS) && FD_ISSET (sok, &fds[EXCEPTFDS & 3]));
- }
- void UtilIOSelect (void)
- {
- int res, rc;
- errno = 0;
- res = select (maxfd + 1, &fds[READFDS & 3], &fds[WRITEFDS & 3], &fds[EXCEPTFDS & 3], &tv);
- rc = errno;
- if (res == -1)
- {
- FD_ZERO (&fds[READFDS & 3]);
- FD_ZERO (&fds[WRITEFDS & 3]);
- FD_ZERO (&fds[EXCEPTFDS & 3]);
- if (rc != EINTR && rc != EAGAIN)
- {
- printf (i18n (1849, "Error on select: %s (%d)\n"), strerror (rc), rc);
- assert (0);
- }
- }
- }