talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

socket.c (27232B)


      1 /*
      2  * Claws Mail -- a GTK based, lightweight, and fast e-mail client
      3  * Copyright (C) 1999-2022 the Claws Mail team and Hiroyuki Yamamoto
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 3 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
     17  */
     18 
     19 #include <glib.h>
     20 #include <glib/gi18n.h>
     21 
     22 #include <sys/time.h>
     23 #include <sys/types.h>
     24 #include <sys/wait.h>
     25 #include <sys/socket.h>
     26 #include <sys/stat.h>
     27 #include <sys/un.h>
     28 #include <netinet/in.h>
     29 #include <arpa/inet.h>
     30 #include <netdb.h>
     31 #include <unistd.h>
     32 #include <stdio.h>
     33 #include <string.h>
     34 #include <stdarg.h>
     35 #include <fcntl.h>
     36 #include <errno.h>
     37 #include <signal.h>
     38 #include <setjmp.h>
     39 #if HAVE_SYS_SELECT_H
     40 #  include <sys/select.h>
     41 #endif
     42 
     43 #include "socket.h"
     44 #include "utils.h"
     45 #include "log.h"
     46 #include "ssl.h"
     47 
     48 #if USE_GIO
     49 #error USE_GIO is currently not supported
     50 #endif
     51 
     52 #define BUFFSIZE	8192
     53 
     54 typedef gint (*SockAddrFunc)	(GList		*addr_list,
     55 				 gpointer	 data);
     56 
     57 typedef struct _SockConnectData	SockConnectData;
     58 typedef struct _SockLookupData	SockLookupData;
     59 typedef struct _SockAddrData	SockAddrData;
     60 typedef struct _SockSource	SockSource;
     61 
     62 struct _SockConnectData {
     63 	gint id;
     64 	gchar *hostname;
     65 	gushort port;
     66 	GList *addr_list;
     67 	GList *cur_addr;
     68 	SockLookupData *lookup_data;
     69 	GIOChannel *channel;
     70 	guint io_tag;
     71 	SockConnectFunc func;
     72 	gpointer data;
     73 	gchar *canonical_name;
     74 };
     75 
     76 struct _SockLookupData {
     77 	gchar *hostname;
     78 	pid_t child_pid;
     79 	GIOChannel *channel;
     80 	guint io_tag;
     81 	SockAddrFunc func;
     82 	gpointer data;
     83 	gushort port;
     84         gint pipe_fds[2];
     85 	gchar *canonical_name;
     86 };
     87 
     88 struct _SockAddrData {
     89 	gint family;
     90 	gint socktype;
     91 	gint protocol;
     92 	gint addr_len;
     93 	struct sockaddr *addr;
     94 };
     95 
     96 struct _SockSource {
     97 	GSource parent;
     98 	SockInfo *sock;
     99 };
    100 
    101 static guint io_timeout = 60;
    102 
    103 static GList *sock_connect_data_list = NULL;
    104 
    105 static gboolean ssl_sock_prepare	(GSource	*source,
    106 					 gint		*timeout);
    107 static gboolean ssl_sock_check		(GSource	*source);
    108 static gboolean ssl_sock_dispatch	(GSource	*source,
    109 					 GSourceFunc	 callback,
    110 					 gpointer	 user_data);
    111 GSourceFuncs ssl_watch_funcs = {
    112 	ssl_sock_prepare,
    113 	ssl_sock_check,
    114 	ssl_sock_dispatch,
    115 	NULL,
    116 	NULL,
    117 	NULL
    118 };
    119 
    120 static gint sock_connect_with_timeout	(gint			 sock,
    121 					 const struct sockaddr	*serv_addr,
    122 					 gint			 addrlen,
    123 					 guint			 timeout_secs);
    124 
    125 static gint sock_connect_by_getaddrinfo	(const gchar	*hostname,
    126 					 gushort	 port);
    127 
    128 static SockInfo *sockinfo_from_fd(const gchar *hostname,
    129 				  gushort port,
    130 				  gint sock);
    131 static void sock_address_list_free		(GList		*addr_list);
    132 
    133 static gboolean sock_connect_async_cb		(GIOChannel	*source,
    134 						 GIOCondition	 condition,
    135 						 gpointer	 data);
    136 static gint sock_connect_async_get_address_info_cb
    137 						(GList		*addr_list,
    138 						 gpointer	 data);
    139 
    140 static gint sock_connect_address_list_async	(SockConnectData *conn_data);
    141 
    142 static gboolean sock_get_address_info_async_cb	(GIOChannel	*source,
    143 						 GIOCondition	 condition,
    144 						 gpointer	 data);
    145 static SockLookupData *sock_get_address_info_async
    146 						(const gchar	*hostname,
    147 						 gushort	 port,
    148 						 SockAddrFunc	 func,
    149 						 gpointer	 data);
    150 static gint sock_get_address_info_async_cancel	(SockLookupData	*lookup_data);
    151 
    152 gint sock_set_io_timeout(guint sec)
    153 {
    154 	io_timeout = sec;
    155 	return 0;
    156 }
    157 
    158 #define SOCKET_IS_VALID(s) 	(s != -1)
    159 
    160 gint fd_connect_unix(const gchar *path)
    161 {
    162 #ifdef G_OS_UNIX
    163 	gint sock;
    164 	struct sockaddr_un addr;
    165 
    166 	sock = socket(PF_UNIX, SOCK_STREAM, 0);
    167 	if (sock < 0) {
    168 		perror("sock_connect_unix(): socket");
    169 		return -1;
    170 	}
    171 
    172 	memset(&addr, 0, sizeof(addr));
    173 	addr.sun_family = AF_UNIX;
    174 	strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
    175 
    176 	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
    177 		close(sock);
    178 		return -1;
    179 	}
    180 
    181 	return sock;
    182 #else
    183 	return -1;
    184 #endif
    185 }
    186 
    187 gint fd_open_unix(const gchar *path)
    188 {
    189 #ifdef G_OS_UNIX
    190 	gint sock;
    191 	struct sockaddr_un addr;
    192 
    193 	sock = socket(PF_UNIX, SOCK_STREAM, 0);
    194 
    195 	if (sock < 0) {
    196 		perror("sock_open_unix(): socket");
    197 		return -1;
    198 	}
    199 
    200 	memset(&addr, 0, sizeof(addr));
    201 	addr.sun_family = AF_UNIX;
    202 	strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
    203 
    204 	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
    205 		gchar *buf = g_strdup_printf("can't bind to %s", path);
    206 		perror(buf);
    207 		g_free(buf);
    208 		close(sock);
    209 		return -1;
    210 	}
    211 
    212 	if (listen(sock, 1) < 0) {
    213 		gchar *buf = g_strdup_printf("can't listen on %s", path);
    214 		perror(buf);
    215 		g_free(buf);
    216 		close(sock);
    217 		return -1;
    218 	}
    219 
    220 	return sock;
    221 #else
    222 	return -1;
    223 #endif
    224 }
    225 
    226 gint fd_accept(gint sock)
    227 {
    228 	struct sockaddr_in caddr;
    229 	guint caddr_len;
    230 
    231 	caddr_len = sizeof(caddr);
    232 	return accept(sock, (struct sockaddr *)&caddr, &caddr_len);
    233 }
    234 
    235 
    236 static gint set_nonblocking_mode(gint fd, gboolean nonblock)
    237 {
    238 #ifdef G_OS_UNIX
    239 	gint flags;
    240 
    241 	flags = fcntl(fd, F_GETFL, 0);
    242 	if (flags < 0) {
    243 		perror("fcntl");
    244 		return -1;
    245 	}
    246 
    247 	if (nonblock)
    248 		flags |= O_NONBLOCK;
    249 	else
    250 		flags &= ~O_NONBLOCK;
    251 
    252 	return fcntl(fd, F_SETFL, flags);
    253 #else
    254 	return -1;
    255 #endif
    256 }
    257 
    258 gint sock_set_nonblocking_mode(SockInfo *sock, gboolean nonblock)
    259 {
    260 	cm_return_val_if_fail(sock != NULL, -1);
    261 
    262 	return set_nonblocking_mode(sock->sock, nonblock);
    263 }
    264 
    265 static gboolean is_nonblocking_mode(gint fd)
    266 {
    267 #ifdef G_OS_UNIX
    268 	gint flags;
    269 
    270 	flags = fcntl(fd, F_GETFL, 0);
    271 	if (flags < 0) {
    272 		perror("fcntl");
    273 		return FALSE;
    274 	}
    275 
    276 	return ((flags & O_NONBLOCK) != 0);
    277 #else
    278 	return FALSE;
    279 #endif
    280 }
    281 
    282 gboolean sock_is_nonblocking_mode(SockInfo *sock)
    283 {
    284 	cm_return_val_if_fail(sock != NULL, FALSE);
    285 
    286 	return is_nonblocking_mode(sock->sock);
    287 }
    288 
    289 
    290 static gboolean ssl_sock_prepare(GSource *source, gint *timeout)
    291 {
    292 	*timeout = 1;
    293 	return FALSE;
    294 }
    295 
    296 static gboolean ssl_sock_check(GSource *source)
    297 {
    298 	SockInfo *sock = ((SockSource *)source)->sock;
    299 	struct timeval timeout = {0, 0};
    300 	fd_set fds;
    301 	GIOCondition condition = 0;
    302 
    303 	if (!sock || !sock->sock)
    304 		return FALSE;
    305 
    306 	condition = sock->condition;
    307 
    308 	if ((condition & G_IO_IN) == G_IO_IN &&
    309 	    gnutls_record_check_pending(sock->ssl) != 0)
    310 		return TRUE;
    311 
    312 	FD_ZERO(&fds);
    313 	FD_SET(sock->sock, &fds);
    314 
    315 	select(sock->sock + 1,
    316 	       (condition & G_IO_IN)  ? &fds : NULL,
    317 	       (condition & G_IO_OUT) ? &fds : NULL,
    318 	       NULL, &timeout);
    319 
    320 	return FD_ISSET(sock->sock, &fds) != 0;
    321 }
    322 
    323 static gboolean ssl_sock_dispatch(GSource *source, GSourceFunc callback,
    324 			      gpointer user_data)
    325 {
    326 	SockInfo *sock = ((SockSource *)source)->sock;
    327 
    328 	if (!sock || !sock->callback || !sock->data)
    329 		return FALSE;
    330 
    331 	return sock->callback(sock, sock->condition, sock->data);
    332 }
    333 
    334 static gboolean sock_watch_cb(GIOChannel *source, GIOCondition condition,
    335 			      gpointer data)
    336 {
    337 	SockInfo *sock = (SockInfo *)data;
    338 
    339 	if ((condition & sock->condition) == 0)
    340 		return TRUE;
    341 
    342 	return sock->callback(sock, sock->condition, sock->data);
    343 }
    344 
    345 guint sock_add_watch(SockInfo *sock, GIOCondition condition, SockFunc func,
    346 		     gpointer data)
    347 {
    348 	if (!sock)
    349 		return FALSE;
    350 
    351 	sock->callback = func;
    352 	sock->condition = condition;
    353 	sock->data = data;
    354 
    355 	if (sock->ssl) {
    356 		GSource *source = g_source_new(&ssl_watch_funcs,
    357 					       sizeof(SockSource));
    358 		((SockSource *) source)->sock = sock;
    359 		g_source_set_priority(source, G_PRIORITY_DEFAULT);
    360 		g_source_set_can_recurse(source, FALSE);
    361 		sock->g_source = g_source_attach(source, NULL);
    362 		g_source_unref (source); /* Refcount back down to 1 */
    363 		return sock->g_source;
    364 	}
    365 
    366 	return g_io_add_watch(sock->sock_ch, condition, sock_watch_cb, sock);
    367 }
    368 
    369 static gint fd_check_io(gint fd, GIOCondition cond)
    370 {
    371 	struct timeval timeout;
    372 	fd_set fds;
    373 
    374 	if (is_nonblocking_mode(fd))
    375 		return 0;
    376 
    377 	timeout.tv_sec  = io_timeout;
    378 	timeout.tv_usec = 0;
    379 
    380 	FD_ZERO(&fds);
    381 	FD_SET(fd, &fds);
    382 
    383 	if (cond == G_IO_IN) {
    384 		select(fd + 1, &fds, NULL, NULL,
    385 		       io_timeout > 0 ? &timeout : NULL);
    386 	} else {
    387 		select(fd + 1, NULL, &fds, NULL,
    388 		       io_timeout > 0 ? &timeout : NULL);
    389 	}
    390 
    391 	if (FD_ISSET(fd, &fds)) {
    392 		return 0;
    393 	} else {
    394 		g_warning("socket IO timeout");
    395 		log_error(LOG_PROTOCOL, "Socket IO timeout.\n");
    396 		return -1;
    397 	}
    398 }
    399 
    400 #ifdef G_OS_UNIX
    401 static sigjmp_buf jmpenv;
    402 
    403 static void timeout_handler(gint sig)
    404 {
    405 	siglongjmp(jmpenv, 1);
    406 }
    407 #endif /*G_OS_UNIX*/
    408 
    409 static gint sock_connect_with_timeout(gint sock,
    410 				      const struct sockaddr *serv_addr,
    411 				      gint addrlen,
    412 				      guint timeout_secs)
    413 {
    414 	gint ret, saved_errno;
    415 #ifdef G_OS_UNIX
    416 	void (*prev_handler)(gint);
    417 
    418 	alarm(0);
    419 	prev_handler = signal(SIGALRM, timeout_handler);
    420 	if (sigsetjmp(jmpenv, 1)) {
    421 		alarm(0);
    422 		signal(SIGALRM, prev_handler);
    423 		errno = ETIMEDOUT;
    424 		log_error(LOG_PROTOCOL, "Connection timed out.\n");
    425 		return -1;
    426 	}
    427 	alarm(timeout_secs);
    428 #endif
    429 
    430 	ret = connect(sock, serv_addr, addrlen);
    431 	saved_errno = errno;
    432 
    433 	if (ret == -1) {
    434 		debug_print("connect() failed: %d (%s)\n",
    435 				saved_errno, g_strerror(saved_errno));
    436 	}
    437 
    438 #ifdef G_OS_UNIX
    439 	alarm(0);
    440 	signal(SIGALRM, prev_handler);
    441 #endif
    442 
    443 	return ret;
    444 }
    445 
    446 static gint sock_connect_by_getaddrinfo(const gchar *hostname, gushort	port)
    447 {
    448 	gint sock = -1, gai_error;
    449 	struct addrinfo hints, *res, *ai;
    450 	gchar port_str[6];
    451 
    452 	memset(&hints, 0, sizeof(hints));
    453 	hints.ai_flags = AI_ADDRCONFIG;
    454 	hints.ai_family = AF_UNSPEC;
    455 	hints.ai_socktype = SOCK_STREAM;
    456 	hints.ai_protocol = IPPROTO_TCP;
    457 
    458 	/* convert port from integer to string. */
    459 	g_snprintf(port_str, sizeof(port_str), "%d", port);
    460 
    461 	if ((gai_error = getaddrinfo(hostname, port_str, &hints, &res)) != 0) {
    462 		g_printerr("getaddrinfo for %s:%s failed: %s\n",
    463 			hostname, port_str, gai_strerror(gai_error));
    464 		return -1;
    465 	}
    466 
    467 	for (ai = res; ai != NULL; ai = ai->ai_next) {
    468 		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    469 		if (sock < 0 )
    470 			continue;
    471 		if (sock_connect_with_timeout
    472 			(sock, ai->ai_addr, ai->ai_addrlen, io_timeout) == 0)
    473 			break;
    474 
    475 		close(sock);
    476 	}
    477 
    478 	if (res != NULL)
    479 		freeaddrinfo(res);
    480 
    481 	if (ai == NULL)
    482 		return -1;
    483 
    484 	return sock;
    485 }
    486 
    487 SockInfo *sock_connect(const gchar *hostname, gushort port)
    488 {
    489 	gint sock;
    490 
    491 	if ((sock = sock_connect_by_getaddrinfo(hostname, port)) < 0) {
    492 		return NULL;
    493 	}
    494 
    495 	return sockinfo_from_fd(hostname, port, sock);
    496 }
    497 
    498 
    499 static void sock_address_list_free(GList *addr_list)
    500 {
    501 	GList *cur;
    502 
    503 	for (cur = addr_list; cur != NULL; cur = cur->next) {
    504 		SockAddrData *addr_data = (SockAddrData *)cur->data;
    505 		g_free(addr_data->addr);
    506 		g_free(addr_data);
    507 	}
    508 
    509 	g_list_free(addr_list);
    510 }
    511 
    512 /* asynchronous TCP connection */
    513 
    514 static gboolean sock_connect_async_cb(GIOChannel *source,
    515 				      GIOCondition condition, gpointer data)
    516 {
    517 	SockConnectData *conn_data = (SockConnectData *)data;
    518 	gint fd;
    519 	gint val;
    520 	socklen_t len;
    521 	SockInfo *sockinfo;
    522 
    523 	if (conn_data->io_tag == 0 && conn_data->channel == NULL)
    524 		return FALSE;
    525 
    526 	fd = g_io_channel_unix_get_fd(source);
    527 
    528 	conn_data->io_tag = 0;
    529 	conn_data->channel = NULL;
    530 	g_io_channel_unref(source);
    531 
    532 	len = sizeof(val);
    533 	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&val, &len) < 0) {
    534 		perror("getsockopt");
    535 		close(fd);
    536 		sock_connect_address_list_async(conn_data);
    537 		return FALSE;
    538 	}
    539 
    540 	if (val != 0) {
    541 		close(fd);
    542 		log_error(LOG_PROTOCOL, "%s:%d: connection failed (%s).\n",
    543 			  conn_data->hostname, conn_data->port,
    544 			  g_strerror(val));
    545 		sock_connect_address_list_async(conn_data);
    546 		return FALSE;
    547 	}
    548 
    549 	sockinfo = g_new0(SockInfo, 1);
    550 	sockinfo->sock = fd;
    551 	sockinfo->sock_ch = g_io_channel_unix_new(fd);
    552 	sockinfo->hostname = g_strdup(conn_data->hostname);
    553 	sockinfo->port = conn_data->port;
    554 	sockinfo->state = CONN_ESTABLISHED;
    555 	sockinfo->canonical_name = g_strdup(conn_data->canonical_name);
    556 
    557 	conn_data->func(sockinfo, conn_data->data);
    558 
    559 	sock_connect_async_cancel(conn_data->id);
    560 
    561 	return FALSE;
    562 }
    563 
    564 static gint sock_connect_async_get_address_info_cb(GList *addr_list,
    565 						   gpointer data)
    566 {
    567 	SockConnectData *conn_data = (SockConnectData *)data;
    568 
    569 	conn_data->addr_list = addr_list;
    570 	conn_data->cur_addr = addr_list;
    571 	if (conn_data->lookup_data) {
    572 		conn_data->canonical_name = conn_data->lookup_data->canonical_name;
    573 		conn_data->lookup_data->canonical_name = NULL;
    574 		conn_data->lookup_data = NULL;
    575 	}
    576 	return sock_connect_address_list_async(conn_data);
    577 }
    578 
    579 gint sock_connect_async(const gchar *hostname, gushort port,
    580 			SockConnectFunc func, gpointer data)
    581 {
    582 	static gint id = 1;
    583 	SockConnectData *conn_data;
    584 
    585 	conn_data = g_new0(SockConnectData, 1);
    586 	conn_data->id = id++;
    587 	conn_data->hostname = g_strdup(hostname);
    588 	conn_data->port = port;
    589 	conn_data->addr_list = NULL;
    590 	conn_data->cur_addr = NULL;
    591 	conn_data->io_tag = 0;
    592 	conn_data->func = func;
    593 	conn_data->data = data;
    594 
    595 	conn_data->lookup_data = sock_get_address_info_async
    596 		(hostname, port, sock_connect_async_get_address_info_cb,
    597 		 conn_data);
    598 
    599 	if (conn_data->lookup_data == NULL) {
    600 		g_free(conn_data->hostname);
    601 		g_free(conn_data);
    602 		return -1;
    603 	}
    604 
    605 	sock_connect_data_list = g_list_append(sock_connect_data_list,
    606 					       conn_data);
    607 
    608 	return conn_data->id;
    609 }
    610 
    611 gint sock_connect_async_cancel(gint id)
    612 {
    613 	SockConnectData *conn_data = NULL;
    614 	GList *cur;
    615 
    616 	for (cur = sock_connect_data_list; cur != NULL; cur = cur->next) {
    617 		if (((SockConnectData *)cur->data)->id == id) {
    618 			conn_data = (SockConnectData *)cur->data;
    619 			break;
    620 		}
    621 	}
    622 
    623 	if (conn_data) {
    624 		sock_connect_data_list = g_list_remove(sock_connect_data_list,
    625 						       conn_data);
    626 
    627 		if (conn_data->lookup_data)
    628 			sock_get_address_info_async_cancel
    629 				(conn_data->lookup_data);
    630 
    631 		if (conn_data->io_tag > 0)
    632 			g_source_remove(conn_data->io_tag);
    633 		if (conn_data->channel) {
    634 			GError *err = NULL;
    635 			g_io_channel_shutdown(conn_data->channel, TRUE, &err);
    636 			if (err)
    637 				g_error_free(err);
    638 			g_io_channel_unref(conn_data->channel);
    639 		}
    640 
    641 		sock_address_list_free(conn_data->addr_list);
    642 		g_free(conn_data->canonical_name);
    643 		g_free(conn_data->hostname);
    644 		g_free(conn_data);
    645 	} else {
    646 		g_warning("sock_connect_async_cancel: id %d not found", id);
    647 		return -1;
    648 	}
    649 
    650 	return 0;
    651 }
    652 
    653 static gint sock_connect_address_list_async(SockConnectData *conn_data)
    654 {
    655 	SockAddrData *addr_data;
    656 	gint sock = -1;
    657 
    658 	for (; conn_data->cur_addr != NULL;
    659 	     conn_data->cur_addr = conn_data->cur_addr->next) {
    660 		addr_data = (SockAddrData *)conn_data->cur_addr->data;
    661 
    662 		if ((sock = socket(addr_data->family, addr_data->socktype,
    663 				   addr_data->protocol)) < 0) {
    664 			perror("socket");
    665 
    666 			continue;
    667 		}
    668 
    669 		set_nonblocking_mode(sock, TRUE);
    670 
    671 		if (connect(sock, addr_data->addr, addr_data->addr_len) < 0) {
    672 			if (EINPROGRESS == errno) {
    673 				break;
    674 			} else {
    675 				perror("connect");
    676 				close(sock);
    677 			}
    678 		} else {
    679 			break;
    680 		}
    681 	}
    682 
    683 	if (conn_data->cur_addr == NULL) {
    684 		conn_data->func(NULL, conn_data->data);
    685 		sock_connect_async_cancel(conn_data->id);
    686 		return -1;
    687 	}
    688 
    689 	conn_data->cur_addr = conn_data->cur_addr->next;
    690 	conn_data->channel = g_io_channel_unix_new(sock);
    691 	conn_data->io_tag = g_io_add_watch(conn_data->channel, G_IO_IN|G_IO_OUT,
    692 					   sock_connect_async_cb, conn_data);
    693 
    694 	return 0;
    695 }
    696 
    697 /* asynchronous DNS lookup */
    698 
    699 static gboolean sock_get_address_info_async_cb(GIOChannel *source,
    700 					       GIOCondition condition,
    701 					       gpointer data)
    702 {
    703 	SockLookupData *lookup_data = (SockLookupData *)data;
    704 	GList *addr_list = NULL;
    705 	SockAddrData *addr_data;
    706 	gsize bytes_read;
    707 	gint ai_member[4];
    708 	struct sockaddr *addr;
    709 	gchar *canonical_name = NULL;
    710 	gchar len = 0;
    711 	GError *err = NULL;
    712 
    713 	g_io_channel_set_encoding(source, NULL, &err);
    714 	if (err) {
    715 		g_warning("can't unset encoding: %s", err->message);
    716 		g_error_free(err);
    717 		return FALSE;
    718 	}
    719 	g_io_channel_set_buffered(source, FALSE);
    720 	if (g_io_channel_read_chars(source, &len, sizeof(len),
    721 			      &bytes_read, &err) == G_IO_STATUS_NORMAL) {
    722 		if (err != NULL) {
    723 			g_warning("g_io_channel_read_chars: %s", err->message);
    724 			g_error_free(err);
    725 			return FALSE;
    726 		}
    727 		if (bytes_read == sizeof(len) && len > 0) {
    728 			gchar *cur = NULL;
    729 			gint todo = len;
    730 			canonical_name = g_malloc0(len + 1);
    731 			cur = canonical_name;
    732 			while (todo > 0) {
    733 				if (g_io_channel_read_chars(source, cur, todo,
    734 				      &bytes_read, &err) != G_IO_STATUS_NORMAL) {
    735 					if (err) {
    736 					      g_warning("canonical name not read %s", err->message);
    737 					      g_free(canonical_name);
    738 					      canonical_name = NULL;
    739 					      g_error_free(err);
    740 					      err = NULL;
    741 					      break;
    742 					}
    743 				} else {
    744 					cur += bytes_read;
    745 					todo -= bytes_read;
    746 				}
    747 				if (bytes_read == 0) {
    748 				      g_warning("canonical name not read");
    749 				      g_free(canonical_name);
    750 				      canonical_name = NULL;
    751 				      break;
    752 				}
    753 			}
    754 		}
    755 	}
    756 	for (;;) {
    757 		if (g_io_channel_read_chars(source, (gchar *)ai_member,
    758 				      sizeof(ai_member), &bytes_read, &err)
    759 		    != G_IO_STATUS_NORMAL) {
    760 			if (err != NULL) {
    761 				g_warning("g_io_channel_read_chars: addr len %s", err->message);
    762 				g_error_free(err);
    763 				err = NULL;
    764 				break;
    765 			}
    766 		}
    767 
    768 		if (bytes_read == 0 || bytes_read != sizeof(ai_member))
    769 			break;
    770 
    771 		if (ai_member[0] == AF_UNSPEC) {
    772 			g_warning("DNS lookup failed");
    773 			log_error(LOG_PROTOCOL, "%s:%d: unknown host.\n",
    774 				lookup_data->hostname, lookup_data->port);
    775 			break;
    776 		}
    777 
    778 		addr = g_malloc(ai_member[3]);
    779 		if (g_io_channel_read_chars(source, (gchar *)addr, ai_member[3],
    780 				      &bytes_read, &err)
    781 		    != G_IO_STATUS_NORMAL) {
    782 			if (err != NULL) {
    783 				g_warning("g_io_channel_read_chars: addr data read %s", err->message);
    784 				g_error_free(err);
    785 				err = NULL;
    786 				g_free(addr);
    787 				break;
    788 			}
    789 		}
    790 
    791 		if (bytes_read != ai_member[3]) {
    792 			g_warning("sock_get_address_info_async_cb: "
    793 				  "incomplete address data");
    794 			g_free(addr);
    795 			break;
    796 		}
    797 
    798 		addr_data = g_new0(SockAddrData, 1);
    799 		addr_data->family = ai_member[0];
    800 		addr_data->socktype = ai_member[1];
    801 		addr_data->protocol = ai_member[2];
    802 		addr_data->addr_len = ai_member[3];
    803 		addr_data->addr = addr;
    804 
    805 		addr_list = g_list_append(addr_list, addr_data);
    806 	}
    807 
    808 	g_io_channel_shutdown(source, TRUE, &err);
    809 	if (err)
    810 		g_error_free(err);
    811 	g_io_channel_unref(source);
    812 
    813 	kill(lookup_data->child_pid, SIGKILL);
    814 	waitpid(lookup_data->child_pid, NULL, 0);
    815 
    816 	lookup_data->canonical_name = canonical_name;
    817 
    818 	lookup_data->func(addr_list, lookup_data->data);
    819 
    820 	g_free(lookup_data->canonical_name);
    821 	g_free(lookup_data->hostname);
    822 	g_free(lookup_data);
    823 
    824 	return FALSE;
    825 }
    826 
    827 
    828 /* For better readability we use a separate function to implement the
    829    child code of sock_get_address_info_async.  Note, that under W32
    830    this is actually not a child but a thread and this is the reason
    831    why we pass only a void pointer. */
    832 static void address_info_async_child(void *opaque)
    833 {
    834         SockLookupData *parm = opaque;
    835         gint gai_err;
    836         struct addrinfo hints, *res, *ai;
    837         gchar port_str[6];
    838         gint ai_member[4] = {AF_UNSPEC, 0, 0, 0};
    839 
    840         close(parm->pipe_fds[0]);
    841         parm->pipe_fds[0] = -1;
    842 
    843         memset(&hints, 0, sizeof(hints));
    844         hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
    845         hints.ai_family = AF_UNSPEC;
    846         hints.ai_socktype = SOCK_STREAM;
    847         hints.ai_protocol = IPPROTO_TCP;
    848 
    849         g_snprintf(port_str, sizeof(port_str), "%d", parm->port);
    850 
    851         gai_err = getaddrinfo(parm->hostname, port_str, &hints, &res);
    852         if (gai_err != 0) {
    853 		gchar len = 0;
    854                 g_warning("getaddrinfo for %s:%s failed: %s",
    855                           parm->hostname, port_str, gai_strerror(gai_err));
    856 		log_error(LOG_PROTOCOL, "%s:%s: host lookup failed (%s).\n",
    857 			  parm->hostname, port_str, gai_strerror(gai_err));
    858 	        fd_write_all(parm->pipe_fds[1], &len,
    859                      sizeof(len));
    860                 fd_write_all(parm->pipe_fds[1], (gchar *)ai_member,
    861                              sizeof(ai_member));
    862                 close(parm->pipe_fds[1]);
    863                 parm->pipe_fds[1] = -1;
    864 
    865                 _exit(1);
    866         }
    867 
    868 	if (res != NULL) {
    869 		if (res->ai_canonname && strlen(res->ai_canonname) < 255) {
    870 			gchar len = strlen(res->ai_canonname);
    871 	                fd_write_all(parm->pipe_fds[1], &len,
    872                              sizeof(len));
    873 	                fd_write_all(parm->pipe_fds[1], res->ai_canonname,
    874                              len);
    875 		} else {
    876 			gchar len = 0;
    877 	                fd_write_all(parm->pipe_fds[1], &len,
    878                              sizeof(len));
    879 		}
    880 	} else {
    881 		gchar len = 0;
    882 	        fd_write_all(parm->pipe_fds[1], &len,
    883                      sizeof(len));
    884 	}
    885 
    886         for (ai = res; ai != NULL; ai = ai->ai_next) {
    887                 ai_member[0] = ai->ai_family;
    888                 ai_member[1] = ai->ai_socktype;
    889                 ai_member[2] = ai->ai_protocol;
    890                 ai_member[3] = ai->ai_addrlen;
    891 
    892                 fd_write_all(parm->pipe_fds[1], (gchar *)ai_member,
    893                              sizeof(ai_member));
    894                 fd_write_all(parm->pipe_fds[1], (gchar *)ai->ai_addr,
    895                              ai->ai_addrlen);
    896         }
    897 
    898         if (res != NULL)
    899                 freeaddrinfo(res);
    900 
    901         close(parm->pipe_fds[1]);
    902         parm->pipe_fds[1] = -1;
    903 
    904         _exit(0);
    905 }
    906 
    907 static SockLookupData *sock_get_address_info_async(const gchar *hostname,
    908 						   gushort port,
    909 						   SockAddrFunc func,
    910 						   gpointer data)
    911 {
    912 	SockLookupData *lookup_data = NULL;
    913 
    914         lookup_data = g_new0(SockLookupData, 1);
    915         lookup_data->hostname = g_strdup(hostname);
    916         lookup_data->func = func;
    917         lookup_data->data = data;
    918         lookup_data->port = port;
    919         lookup_data->child_pid = (pid_t)(-1);
    920         lookup_data->pipe_fds[0] = -1;
    921         lookup_data->pipe_fds[1] = -1;
    922 
    923 	if (pipe(lookup_data->pipe_fds) < 0) {
    924 		perror("pipe");
    925 		func(NULL, data);
    926                 g_free (lookup_data->hostname);
    927                 g_free (lookup_data);
    928 		return NULL;
    929 	}
    930 
    931 	if ((lookup_data->child_pid = fork()) < 0) {
    932 		perror("fork");
    933 		func(NULL, data);
    934                 g_free (lookup_data->hostname);
    935                 g_free (lookup_data);
    936 		return NULL;
    937 	}
    938 
    939 	if (lookup_data->child_pid == 0) {
    940                 /* Child process. */
    941                 address_info_async_child (lookup_data);
    942                 g_assert_not_reached ();
    943 	}
    944         /* Parent process. */
    945         close(lookup_data->pipe_fds[1]);
    946         lookup_data->pipe_fds[1] = -1;
    947 
    948         lookup_data->channel = g_io_channel_unix_new(lookup_data->pipe_fds[0]);
    949         lookup_data->io_tag = g_io_add_watch(lookup_data->channel, G_IO_IN,
    950                                              sock_get_address_info_async_cb,
    951                                              lookup_data);
    952 	return lookup_data;
    953 }
    954 
    955 static gint sock_get_address_info_async_cancel(SockLookupData *lookup_data)
    956 {
    957 	if (lookup_data->io_tag > 0)
    958 		g_source_remove(lookup_data->io_tag);
    959 	if (lookup_data->channel) {
    960 		GError *err = NULL;
    961 		g_io_channel_shutdown(lookup_data->channel, TRUE, &err);
    962 		if (err)
    963 			g_error_free(err);
    964 
    965 		g_io_channel_unref(lookup_data->channel);
    966 	}
    967 
    968 	if (lookup_data->child_pid > 0) {
    969 		kill(lookup_data->child_pid, SIGKILL);
    970 		waitpid(lookup_data->child_pid, NULL, 0);
    971 	}
    972 
    973 	g_free(lookup_data->canonical_name);
    974 	g_free(lookup_data->hostname);
    975 	g_free(lookup_data);
    976 
    977 	return 0;
    978 }
    979 
    980 
    981 static SockInfo *sockinfo_from_fd(const gchar *hostname,
    982 				  gushort port,
    983 				  gint sock)
    984 {
    985 	SockInfo *sockinfo;
    986 
    987 	sockinfo = g_new0(SockInfo, 1);
    988 	sockinfo->sock = sock;
    989 	sockinfo->sock_ch = g_io_channel_unix_new(sock);
    990 	sockinfo->hostname = g_strdup(hostname);
    991 	sockinfo->port = port;
    992 	sockinfo->state = CONN_ESTABLISHED;
    993 
    994 	return sockinfo;
    995 }
    996 
    997 static gint fd_read(gint fd, gchar *buf, gint len)
    998 {
    999 	if (fd_check_io(fd, G_IO_IN) < 0)
   1000 		return -1;
   1001 	return read(fd, buf, len);
   1002 }
   1003 
   1004 static gint ssl_read(gnutls_session_t ssl, gchar *buf, gint len)
   1005 {
   1006 	gint r;
   1007 
   1008 	if (gnutls_record_check_pending(ssl) == 0) {
   1009 		if (fd_check_io(GPOINTER_TO_INT(gnutls_transport_get_ptr(ssl)), G_IO_IN) < 0)
   1010 			return -1;
   1011 	}
   1012 
   1013 	while (1) {
   1014 		errno = 0;
   1015 		r = gnutls_record_recv(ssl, buf, len);
   1016 		if (r > 0)
   1017 			return r;
   1018 
   1019 		switch (r) {
   1020 		case 0: /* closed connection */
   1021 			return -1;
   1022 
   1023 		case GNUTLS_E_REHANDSHAKE:
   1024 			do {
   1025 				r = gnutls_handshake(ssl);
   1026 			} while (r == GNUTLS_E_AGAIN || r == GNUTLS_E_INTERRUPTED);
   1027 			break; /* re-receive */
   1028 		case GNUTLS_E_AGAIN:
   1029 		case GNUTLS_E_INTERRUPTED:
   1030 			errno = EAGAIN;
   1031 			return -1;
   1032 		case GNUTLS_E_PREMATURE_TERMINATION:
   1033 			if (errno == 0)
   1034 				return 0;
   1035 			/* fall through */
   1036 		default:
   1037 			debug_print("Unexpected TLS read result %d\n", r);
   1038 			errno = EIO;
   1039 			return -1;
   1040 		}
   1041 	}
   1042 
   1043 }
   1044 
   1045 gint sock_read(SockInfo *sock, gchar *buf, gint len)
   1046 {
   1047 	gint ret;
   1048 
   1049 	cm_return_val_if_fail(sock != NULL, -1);
   1050 
   1051 	if (sock->ssl)
   1052 		ret = ssl_read(sock->ssl, buf, len);
   1053 	else
   1054 		ret = fd_read(sock->sock, buf, len);
   1055 
   1056 	if (ret < 0)
   1057 		sock->state = CONN_DISCONNECTED;
   1058 	return ret;
   1059 }
   1060 
   1061 gint fd_write(gint fd, const gchar *buf, gint len)
   1062 {
   1063 	if (fd_check_io(fd, G_IO_OUT) < 0)
   1064 		return -1;
   1065 	return write(fd, buf, len);
   1066 }
   1067 
   1068 static gint ssl_write(gnutls_session_t ssl, const gchar *buf, gint len)
   1069 {
   1070 	gint ret;
   1071 
   1072 	if (fd_check_io(GPOINTER_TO_INT(gnutls_transport_get_ptr(ssl)), G_IO_OUT) < 0)
   1073 		return -1;
   1074 
   1075 	ret = gnutls_record_send(ssl, buf, len);
   1076 
   1077 	switch (ret) {
   1078 	case 0:
   1079 		return -1;
   1080 	case GNUTLS_E_AGAIN:
   1081 	case GNUTLS_E_INTERRUPTED:
   1082 		return 0;
   1083 
   1084 	default:
   1085 		return ret;
   1086 	}
   1087 }
   1088 
   1089 gint sock_write(SockInfo *sock, const gchar *buf, gint len)
   1090 {
   1091 	gint ret;
   1092 
   1093 	cm_return_val_if_fail(sock != NULL, -1);
   1094 
   1095 	if (sock->ssl)
   1096 		ret = ssl_write(sock->ssl, buf, len);
   1097 	else
   1098 		ret = fd_write(sock->sock, buf, len);
   1099 
   1100 	if (ret < 0)
   1101 		sock->state = CONN_DISCONNECTED;
   1102 	return ret;
   1103 }
   1104 
   1105 gint fd_write_all(gint fd, const gchar *buf, gint len)
   1106 {
   1107 	gint n, wrlen = 0;
   1108 
   1109 	while (len) {
   1110 		if (fd_check_io(fd, G_IO_OUT) < 0)
   1111 			return -1;
   1112 		signal(SIGPIPE, SIG_IGN);
   1113 		n = write(fd, buf, len);
   1114 
   1115 		if (n <= 0) {
   1116 			log_error(LOG_PROTOCOL, "write on fd%d: %s\n", fd, g_strerror(errno));
   1117 			return -1;
   1118 		}
   1119 		len -= n;
   1120 		wrlen += n;
   1121 		buf += n;
   1122 	}
   1123 
   1124 	return wrlen;
   1125 }
   1126 
   1127 static gint ssl_write_all(gnutls_session_t ssl, const gchar *buf, gint len)
   1128 {
   1129 	gint n, wrlen = 0;
   1130 
   1131 	while (len) {
   1132 		n = ssl_write(ssl, buf, len);
   1133 		if (n <= 0)
   1134 			return -1;
   1135 		len -= n;
   1136 		wrlen += n;
   1137 		buf += n;
   1138 	}
   1139 
   1140 	return wrlen;
   1141 }
   1142 
   1143 gint sock_write_all(SockInfo *sock, const gchar *buf, gint len)
   1144 {
   1145 	gint ret;
   1146 
   1147 	cm_return_val_if_fail(sock != NULL, -1);
   1148 
   1149 	if (sock->ssl)
   1150 		ret = ssl_write_all(sock->ssl, buf, len);
   1151 	else
   1152 		ret = fd_write_all(sock->sock, buf, len);
   1153 
   1154 	if (ret < 0)
   1155 		sock->state = CONN_DISCONNECTED;
   1156 	return ret;
   1157 }
   1158 
   1159 gint fd_gets(gint fd, gchar *buf, gint len)
   1160 {
   1161 	gchar *bp = buf;
   1162 
   1163 	if (--len < 1)
   1164 		return -1;
   1165 	*bp = '\0';
   1166 	return bp - buf;
   1167 }
   1168 
   1169 gint sock_close(SockInfo *sock, gboolean close_fd)
   1170 {
   1171 	gint ret = 0;
   1172 
   1173 	if (!sock)
   1174 		return 0;
   1175 
   1176 	if (sock->sock_ch)
   1177 		g_io_channel_unref(sock->sock_ch);
   1178 
   1179 	if (sock->ssl)
   1180 		ssl_done_socket(sock);
   1181 	if (sock->g_source != 0 && g_main_context_find_source_by_id(NULL, sock->g_source) != NULL)
   1182 		g_source_remove(sock->g_source);
   1183 	sock->g_source = 0;
   1184 	if (close_fd)
   1185 		ret = close(sock->sock);
   1186 
   1187 	g_free(sock->canonical_name);
   1188 	g_free(sock->hostname);
   1189 	g_free(sock);
   1190 
   1191 	return ret;
   1192 }