1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2017 Hiroyuki Yamamoto and the Claws Mail team
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 #ifdef HAVE_CONFIG_H
20 #  include "config.h"
21 #include "claws-features.h"
22 #endif
23 
24 #if (defined (_XOPEN_SOURCE) && !defined (_BSD_SOURCE))
25 #define _BSD_SOURCE
26 #endif
27 
28 /* This can probably be handled better, e.g. define it in config.h. */
29 #define _WIN32_WINNT _WIN32_WINNT_WIN6
30 #include <glib.h>
31 #include <glib/gi18n.h>
32 
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #ifdef G_OS_WIN32
36 #  include <ws2tcpip.h>
37 #  ifndef EINPROGRESS
38 #    define EINPROGRESS WSAEINPROGRESS
39 #  endif
40 #  include "w32lib.h"
41 #else
42 #  if HAVE_SYS_WAIT_H
43 #    include <sys/wait.h>
44 #  endif
45 #  include <sys/socket.h>
46 #  include <sys/stat.h>
47 #  include <sys/un.h>
48 #  include <netinet/in.h>
49 #  include <arpa/inet.h>
50 #  include <resolv.h>
51 #  ifndef _PATH_RESCONF
52 #    define _PATH_RESCONF "/etc/resolv.conf"
53 #  endif
54 #  include <netdb.h>
55 #endif /* G_OS_WIN32 */
56 #include <unistd.h>
57 #include <stdio.h>
58 #include <string.h>
59 #include <stdarg.h>
60 #include <fcntl.h>
61 #include <errno.h>
62 #include <signal.h>
63 #include <setjmp.h>
64 #if HAVE_SYS_SELECT_H
65 #  include <sys/select.h>
66 #endif
67 
68 #include "socket.h"
69 #include "utils.h"
70 #include "log.h"
71 #ifdef USE_GNUTLS
72 #  include "ssl.h"
73 #endif
74 
75 #if USE_GIO
76 #error USE_GIO is currently not supported
77 #endif
78 
79 #if G_IO_WIN32
80 #define BUFFSIZE	8191
81 #else
82 #define BUFFSIZE	8192
83 #endif
84 
85 
86 typedef gint (*SockAddrFunc)	(GList		*addr_list,
87 				 gpointer	 data);
88 
89 typedef struct _SockConnectData	SockConnectData;
90 typedef struct _SockLookupData	SockLookupData;
91 typedef struct _SockAddrData	SockAddrData;
92 typedef struct _SockSource	SockSource;
93 
94 struct _SockConnectData {
95 	gint id;
96 	gchar *hostname;
97 	gushort port;
98 	GList *addr_list;
99 	GList *cur_addr;
100 	SockLookupData *lookup_data;
101 	GIOChannel *channel;
102 	guint io_tag;
103 	SockConnectFunc func;
104 	gpointer data;
105 	gchar *canonical_name;
106 };
107 
108 struct _SockLookupData {
109 	gchar *hostname;
110 	pid_t child_pid;
111 	GIOChannel *channel;
112 	guint io_tag;
113 	SockAddrFunc func;
114 	gpointer data;
115 	gushort port;
116         gint pipe_fds[2];
117 	gchar *canonical_name;
118 };
119 
120 struct _SockAddrData {
121 	gint family;
122 	gint socktype;
123 	gint protocol;
124 	gint addr_len;
125 	struct sockaddr *addr;
126 };
127 
128 struct _SockSource {
129 	GSource parent;
130 	SockInfo *sock;
131 };
132 
133 static guint io_timeout = 60;
134 
135 static GList *sock_connect_data_list = NULL;
136 
137 static gboolean ssl_sock_prepare	(GSource	*source,
138 					 gint		*timeout);
139 static gboolean ssl_sock_check		(GSource	*source);
140 static gboolean ssl_sock_dispatch	(GSource	*source,
141 					 GSourceFunc	 callback,
142 					 gpointer	 user_data);
143 
144 #ifdef USE_GNUTLS
145 GSourceFuncs ssl_watch_funcs = {
146 	ssl_sock_prepare,
147 	ssl_sock_check,
148 	ssl_sock_dispatch,
149 	NULL,
150 	NULL,
151 	NULL
152 };
153 #endif
154 
155 static gint sock_connect_with_timeout	(gint			 sock,
156 					 const struct sockaddr	*serv_addr,
157 					 gint			 addrlen,
158 					 guint			 timeout_secs);
159 
160 static gint sock_connect_by_getaddrinfo	(const gchar	*hostname,
161 					 gushort	 port);
162 
163 static SockInfo *sockinfo_from_fd(const gchar *hostname,
164 				  gushort port,
165 				  gint sock);
166 static void sock_address_list_free		(GList		*addr_list);
167 
168 static gboolean sock_connect_async_cb		(GIOChannel	*source,
169 						 GIOCondition	 condition,
170 						 gpointer	 data);
171 static gint sock_connect_async_get_address_info_cb
172 						(GList		*addr_list,
173 						 gpointer	 data);
174 
175 static gint sock_connect_address_list_async	(SockConnectData *conn_data);
176 
177 static gboolean sock_get_address_info_async_cb	(GIOChannel	*source,
178 						 GIOCondition	 condition,
179 						 gpointer	 data);
180 static SockLookupData *sock_get_address_info_async
181 						(const gchar	*hostname,
182 						 gushort	 port,
183 						 SockAddrFunc	 func,
184 						 gpointer	 data);
185 static gint sock_get_address_info_async_cancel	(SockLookupData	*lookup_data);
186 
187 
sock_init(void)188 gint sock_init(void)
189 {
190 #ifdef G_OS_WIN32
191 	WSADATA wsadata;
192 	gint result;
193 
194 	result = WSAStartup(MAKEWORD(2, 2), &wsadata);
195 	if (result != NO_ERROR) {
196 		g_warning("WSAStartup() failed");
197 		return -1;
198 	}
199 #endif
200 	return 0;
201 }
202 
sock_cleanup(void)203 gint sock_cleanup(void)
204 {
205 #ifdef G_OS_WIN32
206 	WSACleanup();
207 #endif
208 	return 0;
209 }
210 
sock_set_io_timeout(guint sec)211 gint sock_set_io_timeout(guint sec)
212 {
213 	io_timeout = sec;
214 	return 0;
215 }
216 
refresh_resolvers(void)217 void refresh_resolvers(void)
218 {
219 #ifdef G_OS_UNIX
220 	static time_t resolv_conf_changed = (time_t)NULL;
221 	GStatBuf s;
222 
223 	/* This makes the glibc re-read resolv.conf, if it changed
224 	 * since our startup. Maybe that should be #ifdef'ed, I don't
225 	 * know if it'd work on BSDs.
226 	 * Why doesn't the glibc do it by itself?
227 	 */
228 	if (g_stat(_PATH_RESCONF, &s) == 0) {
229 		if (s.st_mtime > resolv_conf_changed) {
230 			resolv_conf_changed = s.st_mtime;
231 			res_init();
232 		}
233 	} /* else
234 		we'll have bigger problems. */
235 #endif /*G_OS_UNIX*/
236 }
237 
238 #ifdef G_OS_WIN32
239 #define SOCKET_IS_VALID(s)      ((s) != INVALID_SOCKET)
240 #else
241 #define SOCKET_IS_VALID(s) 	(s != -1)
242 #endif
243 
244 #ifdef G_OS_WIN32
245 /* Due to the fact that socket under Windows are not represented by
246    standard file descriptors, we sometimes need to check whether a
247    given file descriptor is actually a socket.  This is done by
248    testing for an error.  Returns true under W32 if FD is a socket. */
fd_is_w32_socket(gint fd)249 static int fd_is_w32_socket(gint fd)
250 {
251         gint optval;
252         gint retval = sizeof(optval);
253 
254         return !getsockopt(fd, SOL_SOCKET, SO_TYPE, (char*)&optval, &retval);
255 }
256 #endif
257 
fd_connect_inet(gushort port)258 gint fd_connect_inet(gushort port)
259 {
260 	gint sock;
261 	struct sockaddr_in addr;
262 
263 	sock = socket(AF_INET, SOCK_STREAM, 0);
264 	if (!SOCKET_IS_VALID(sock)) {
265 #ifdef G_OS_WIN32
266 		debug_print("fd_connect_inet(): socket() failed: %d\n",
267 			  WSAGetLastError());
268 #else
269 		perror("fd_connect_inet(): socket");
270 #endif
271 		return -1;
272 	}
273 
274 	memset(&addr, 0, sizeof(addr));
275 	addr.sin_family = AF_INET;
276 	addr.sin_port = htons(port);
277 	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
278 
279 	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
280 		fd_close(sock);
281 		return -1;
282 	}
283 
284 	return sock;
285 }
fd_open_inet(gushort port)286 gint fd_open_inet(gushort port)
287 {
288 	gint sock;
289 	struct sockaddr_in addr;
290 	gint val;
291 
292 	sock = socket(AF_INET, SOCK_STREAM, 0);
293 	if (!SOCKET_IS_VALID(sock)) {
294 #ifdef G_OS_WIN32
295 		g_warning("fd_open_inet(): socket() failed: %d",
296 			  WSAGetLastError());
297 #else
298 		perror("fd_open_inet(): socket");
299 #endif
300 		return -1;
301 	}
302 
303 	val = 1;
304 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val,
305 		       sizeof(val)) < 0) {
306 		perror("setsockopt");
307 		fd_close(sock);
308 		return -1;
309 	}
310 
311 	memset(&addr, 0, sizeof(addr));
312 	addr.sin_family = AF_INET;
313 	addr.sin_port = htons(port);
314 	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
315 
316 	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
317 		perror("bind");
318 		fd_close(sock);
319 		return -1;
320 	}
321 
322 	if (listen(sock, 1) < 0) {
323 		perror("listen");
324 		fd_close(sock);
325 		return -1;
326 	}
327 
328 	return sock;
329 }
330 
fd_connect_unix(const gchar * path)331 gint fd_connect_unix(const gchar *path)
332 {
333 #ifdef G_OS_UNIX
334 	gint sock;
335 	struct sockaddr_un addr;
336 
337 	sock = socket(PF_UNIX, SOCK_STREAM, 0);
338 	if (sock < 0) {
339 		perror("sock_connect_unix(): socket");
340 		return -1;
341 	}
342 
343 	memset(&addr, 0, sizeof(addr));
344 	addr.sun_family = AF_UNIX;
345 	strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
346 
347 	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
348 		close(sock);
349 		return -1;
350 	}
351 
352 	return sock;
353 #else
354 	return -1;
355 #endif
356 }
357 
fd_open_unix(const gchar * path)358 gint fd_open_unix(const gchar *path)
359 {
360 #ifdef G_OS_UNIX
361 	gint sock;
362 	struct sockaddr_un addr;
363 
364 	sock = socket(PF_UNIX, SOCK_STREAM, 0);
365 
366 	if (sock < 0) {
367 		perror("sock_open_unix(): socket");
368 		return -1;
369 	}
370 
371 	memset(&addr, 0, sizeof(addr));
372 	addr.sun_family = AF_UNIX;
373 	strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
374 
375 	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
376 		gchar *buf = g_strdup_printf("can't bind to %s", path);
377 		perror(buf);
378 		g_free(buf);
379 		close(sock);
380 		return -1;
381 	}
382 
383 	if (listen(sock, 1) < 0) {
384 		gchar *buf = g_strdup_printf("can't listen on %s", path);
385 		perror(buf);
386 		g_free(buf);
387 		close(sock);
388 		return -1;
389 	}
390 
391 	return sock;
392 #else
393 	return -1;
394 #endif
395 }
396 
fd_accept(gint sock)397 gint fd_accept(gint sock)
398 {
399 	struct sockaddr_in caddr;
400 	guint caddr_len;
401 
402 	caddr_len = sizeof(caddr);
403 	return accept(sock, (struct sockaddr *)&caddr, &caddr_len);
404 }
405 
406 
set_nonblocking_mode(gint fd,gboolean nonblock)407 static gint set_nonblocking_mode(gint fd, gboolean nonblock)
408 {
409 #ifdef G_OS_UNIX
410 	gint flags;
411 
412 	flags = fcntl(fd, F_GETFL, 0);
413 	if (flags < 0) {
414 		perror("fcntl");
415 		return -1;
416 	}
417 
418 	if (nonblock)
419 		flags |= O_NONBLOCK;
420 	else
421 		flags &= ~O_NONBLOCK;
422 
423 	return fcntl(fd, F_SETFL, flags);
424 #else
425 	return -1;
426 #endif
427 }
428 
sock_set_nonblocking_mode(SockInfo * sock,gboolean nonblock)429 gint sock_set_nonblocking_mode(SockInfo *sock, gboolean nonblock)
430 {
431 	cm_return_val_if_fail(sock != NULL, -1);
432 
433 	return set_nonblocking_mode(sock->sock, nonblock);
434 }
435 
is_nonblocking_mode(gint fd)436 static gboolean is_nonblocking_mode(gint fd)
437 {
438 #ifdef G_OS_UNIX
439 	gint flags;
440 
441 	flags = fcntl(fd, F_GETFL, 0);
442 	if (flags < 0) {
443 		perror("fcntl");
444 		return FALSE;
445 	}
446 
447 	return ((flags & O_NONBLOCK) != 0);
448 #else
449 	return FALSE;
450 #endif
451 }
452 
sock_is_nonblocking_mode(SockInfo * sock)453 gboolean sock_is_nonblocking_mode(SockInfo *sock)
454 {
455 	cm_return_val_if_fail(sock != NULL, FALSE);
456 
457 	return is_nonblocking_mode(sock->sock);
458 }
459 
460 
461 #ifdef USE_GNUTLS
ssl_sock_prepare(GSource * source,gint * timeout)462 static gboolean ssl_sock_prepare(GSource *source, gint *timeout)
463 {
464 	*timeout = 1;
465 	return FALSE;
466 }
467 
ssl_sock_check(GSource * source)468 static gboolean ssl_sock_check(GSource *source)
469 {
470 	SockInfo *sock = ((SockSource *)source)->sock;
471 	struct timeval timeout = {0, 0};
472 	fd_set fds;
473 	GIOCondition condition = 0;
474 
475 	if (!sock || !sock->sock)
476 		return FALSE;
477 
478 	condition = sock->condition;
479 
480 	if ((condition & G_IO_IN) == G_IO_IN &&
481 	    gnutls_record_check_pending(sock->ssl) != 0)
482 		return TRUE;
483 
484 	FD_ZERO(&fds);
485 	FD_SET(sock->sock, &fds);
486 
487 	select(sock->sock + 1,
488 	       (condition & G_IO_IN)  ? &fds : NULL,
489 	       (condition & G_IO_OUT) ? &fds : NULL,
490 	       NULL, &timeout);
491 
492 	return FD_ISSET(sock->sock, &fds) != 0;
493 }
494 
ssl_sock_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)495 static gboolean ssl_sock_dispatch(GSource *source, GSourceFunc callback,
496 			      gpointer user_data)
497 {
498 	SockInfo *sock = ((SockSource *)source)->sock;
499 
500 	if (!sock || !sock->callback || !sock->data)
501 		return FALSE;
502 
503 	return sock->callback(sock, sock->condition, sock->data);
504 }
505 #endif
506 
sock_watch_cb(GIOChannel * source,GIOCondition condition,gpointer data)507 static gboolean sock_watch_cb(GIOChannel *source, GIOCondition condition,
508 			      gpointer data)
509 {
510 	SockInfo *sock = (SockInfo *)data;
511 
512 	if ((condition & sock->condition) == 0)
513 		return TRUE;
514 
515 	return sock->callback(sock, sock->condition, sock->data);
516 }
517 
sock_add_watch(SockInfo * sock,GIOCondition condition,SockFunc func,gpointer data)518 guint sock_add_watch(SockInfo *sock, GIOCondition condition, SockFunc func,
519 		     gpointer data)
520 {
521 	if (!sock)
522 		return FALSE;
523 
524 	sock->callback = func;
525 	sock->condition = condition;
526 	sock->data = data;
527 
528 #ifdef USE_GNUTLS
529 	if (sock->ssl)
530 	{
531 		GSource *source = g_source_new(&ssl_watch_funcs,
532 					       sizeof(SockSource));
533 		((SockSource *) source)->sock = sock;
534 		g_source_set_priority(source, G_PRIORITY_DEFAULT);
535 		g_source_set_can_recurse(source, FALSE);
536 		sock->g_source = g_source_attach(source, NULL);
537 		g_source_unref (source); /* Refcount back down to 1 */
538 		return sock->g_source;
539 	}
540 #endif
541 
542 	return g_io_add_watch(sock->sock_ch, condition, sock_watch_cb, sock);
543 }
544 
fd_check_io(gint fd,GIOCondition cond)545 static gint fd_check_io(gint fd, GIOCondition cond)
546 {
547 	struct timeval timeout;
548 	fd_set fds;
549 
550 	if (is_nonblocking_mode(fd))
551 		return 0;
552 
553 	timeout.tv_sec  = io_timeout;
554 	timeout.tv_usec = 0;
555 
556 	FD_ZERO(&fds);
557 	FD_SET(fd, &fds);
558 
559 	if (cond == G_IO_IN) {
560 		select(fd + 1, &fds, NULL, NULL,
561 		       io_timeout > 0 ? &timeout : NULL);
562 	} else {
563 		select(fd + 1, NULL, &fds, NULL,
564 		       io_timeout > 0 ? &timeout : NULL);
565 	}
566 
567 	if (FD_ISSET(fd, &fds)) {
568 		return 0;
569 	} else {
570 		g_warning("Socket IO timeout");
571 		log_error(LOG_PROTOCOL, _("Socket IO timeout.\n"));
572 		return -1;
573 	}
574 }
575 
576 #ifdef G_OS_UNIX
577 static sigjmp_buf jmpenv;
578 
timeout_handler(gint sig)579 static void timeout_handler(gint sig)
580 {
581 	siglongjmp(jmpenv, 1);
582 }
583 #endif /*G_OS_UNIX*/
584 
sock_connect_with_timeout(gint sock,const struct sockaddr * serv_addr,gint addrlen,guint timeout_secs)585 static gint sock_connect_with_timeout(gint sock,
586 				      const struct sockaddr *serv_addr,
587 				      gint addrlen,
588 				      guint timeout_secs)
589 {
590 	gint ret, saved_errno;
591 #ifdef G_OS_UNIX
592 	void (*prev_handler)(gint);
593 
594 	alarm(0);
595 	prev_handler = signal(SIGALRM, timeout_handler);
596 	if (sigsetjmp(jmpenv, 1)) {
597 		alarm(0);
598 		signal(SIGALRM, prev_handler);
599 		errno = ETIMEDOUT;
600 		log_error(LOG_PROTOCOL, _("Connection timed out.\n"));
601 		return -1;
602 	}
603 	alarm(timeout_secs);
604 #endif
605 
606 	ret = connect(sock, serv_addr, addrlen);
607 	saved_errno = errno;
608 
609 	if (ret == -1) {
610 		debug_print("connect() failed: %d (%s)\n",
611 				saved_errno, g_strerror(saved_errno));
612 	}
613 
614 #ifdef G_OS_UNIX
615 	alarm(0);
616 	signal(SIGALRM, prev_handler);
617 #endif
618 
619 	return ret;
620 }
621 
sock_connect_by_getaddrinfo(const gchar * hostname,gushort port)622 static gint sock_connect_by_getaddrinfo(const gchar *hostname, gushort	port)
623 {
624 	gint sock = -1, gai_error;
625 	struct addrinfo hints, *res, *ai;
626 	gchar port_str[6];
627 
628 	refresh_resolvers();
629 
630 	memset(&hints, 0, sizeof(hints));
631 	hints.ai_flags = AI_ADDRCONFIG;
632 
633 #ifdef INET6
634 	hints.ai_family = AF_UNSPEC;
635 #else
636 	hints.ai_family = AF_INET;
637 #endif
638 
639 	hints.ai_socktype = SOCK_STREAM;
640 	hints.ai_protocol = IPPROTO_TCP;
641 
642 	/* convert port from integer to string. */
643 	g_snprintf(port_str, sizeof(port_str), "%d", port);
644 
645 	if ((gai_error = getaddrinfo(hostname, port_str, &hints, &res)) != 0) {
646 		g_printerr("getaddrinfo for %s:%s failed: %s\n",
647 			hostname, port_str, gai_strerror(gai_error));
648 		return -1;
649 	}
650 
651 	for (ai = res; ai != NULL; ai = ai->ai_next) {
652 #ifndef INET6
653 		if (ai->ai_family == AF_INET6)
654 			continue;
655 #endif
656 
657 		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
658 		if (sock < 0 )
659 			continue;
660 #ifdef G_OS_WIN32
661 		if (sock == INVALID_SOCKET)
662 			continue;
663 #endif
664 
665 		if (sock_connect_with_timeout
666 			(sock, ai->ai_addr, ai->ai_addrlen, io_timeout) == 0)
667 			break;
668 
669 		close(sock);
670 	}
671 
672 	if (res != NULL)
673 		freeaddrinfo(res);
674 
675 	if (ai == NULL)
676 		return -1;
677 
678 	return sock;
679 }
680 
sock_connect(const gchar * hostname,gushort port)681 SockInfo *sock_connect(const gchar *hostname, gushort port)
682 {
683 #ifdef G_OS_WIN32
684 	SOCKET sock;
685 #else
686 	gint sock;
687 #endif
688 
689 	if ((sock = sock_connect_by_getaddrinfo(hostname, port)) < 0) {
690 		return NULL;
691 	}
692 
693 	return sockinfo_from_fd(hostname, port, sock);
694 }
695 
696 
sock_address_list_free(GList * addr_list)697 static void sock_address_list_free(GList *addr_list)
698 {
699 	GList *cur;
700 
701 	for (cur = addr_list; cur != NULL; cur = cur->next) {
702 		SockAddrData *addr_data = (SockAddrData *)cur->data;
703 		g_free(addr_data->addr);
704 		g_free(addr_data);
705 	}
706 
707 	g_list_free(addr_list);
708 }
709 
710 /* asynchronous TCP connection */
711 
sock_connect_async_cb(GIOChannel * source,GIOCondition condition,gpointer data)712 static gboolean sock_connect_async_cb(GIOChannel *source,
713 				      GIOCondition condition, gpointer data)
714 {
715 	SockConnectData *conn_data = (SockConnectData *)data;
716 	gint fd;
717 	gint val;
718 	guint len;
719 	SockInfo *sockinfo;
720 
721 	if (conn_data->io_tag == 0 && conn_data->channel == NULL)
722 		return FALSE;
723 
724 	fd = g_io_channel_unix_get_fd(source);
725 
726 	conn_data->io_tag = 0;
727 	conn_data->channel = NULL;
728 	g_io_channel_unref(source);
729 
730 	len = sizeof(val);
731 	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&val, &len) < 0) {
732 		perror("getsockopt");
733 		close(fd);
734 		sock_connect_address_list_async(conn_data);
735 		return FALSE;
736 	}
737 
738 	if (val != 0) {
739 		close(fd);
740 		log_error(LOG_PROTOCOL, _("%s:%d: connection failed (%s).\n"),
741 			  conn_data->hostname, conn_data->port,
742 			  g_strerror(val));
743 		sock_connect_address_list_async(conn_data);
744 		return FALSE;
745 	}
746 
747 	sockinfo = g_new0(SockInfo, 1);
748 	sockinfo->sock = fd;
749 #ifndef G_OS_WIN32
750 	sockinfo->sock_ch = g_io_channel_unix_new(fd);
751 #else
752 	sockinfo->sock_ch = g_io_channel_win32_new_socket(fd);
753 #endif
754 	sockinfo->hostname = g_strdup(conn_data->hostname);
755 	sockinfo->port = conn_data->port;
756 	sockinfo->state = CONN_ESTABLISHED;
757 	sockinfo->canonical_name = g_strdup(conn_data->canonical_name);
758 
759 	conn_data->func(sockinfo, conn_data->data);
760 
761 	sock_connect_async_cancel(conn_data->id);
762 
763 	return FALSE;
764 }
765 
sock_connect_async_get_address_info_cb(GList * addr_list,gpointer data)766 static gint sock_connect_async_get_address_info_cb(GList *addr_list,
767 						   gpointer data)
768 {
769 	SockConnectData *conn_data = (SockConnectData *)data;
770 
771 	conn_data->addr_list = addr_list;
772 	conn_data->cur_addr = addr_list;
773 	if (conn_data->lookup_data) {
774 		conn_data->canonical_name = conn_data->lookup_data->canonical_name;
775 		conn_data->lookup_data->canonical_name = NULL;
776 		conn_data->lookup_data = NULL;
777 	}
778 	return sock_connect_address_list_async(conn_data);
779 }
780 
sock_connect_async(const gchar * hostname,gushort port,SockConnectFunc func,gpointer data)781 gint sock_connect_async(const gchar *hostname, gushort port,
782 			SockConnectFunc func, gpointer data)
783 {
784 	static gint id = 1;
785 	SockConnectData *conn_data;
786 
787 	conn_data = g_new0(SockConnectData, 1);
788 	conn_data->id = id++;
789 	conn_data->hostname = g_strdup(hostname);
790 	conn_data->port = port;
791 	conn_data->addr_list = NULL;
792 	conn_data->cur_addr = NULL;
793 	conn_data->io_tag = 0;
794 	conn_data->func = func;
795 	conn_data->data = data;
796 
797 	conn_data->lookup_data = sock_get_address_info_async
798 		(hostname, port, sock_connect_async_get_address_info_cb,
799 		 conn_data);
800 
801 	if (conn_data->lookup_data == NULL) {
802 		g_free(conn_data->hostname);
803 		g_free(conn_data);
804 		return -1;
805 	}
806 
807 	sock_connect_data_list = g_list_append(sock_connect_data_list,
808 					       conn_data);
809 
810 	return conn_data->id;
811 }
812 
sock_connect_async_cancel(gint id)813 gint sock_connect_async_cancel(gint id)
814 {
815 	SockConnectData *conn_data = NULL;
816 	GList *cur;
817 
818 	for (cur = sock_connect_data_list; cur != NULL; cur = cur->next) {
819 		if (((SockConnectData *)cur->data)->id == id) {
820 			conn_data = (SockConnectData *)cur->data;
821 			break;
822 		}
823 	}
824 
825 	if (conn_data) {
826 		sock_connect_data_list = g_list_remove(sock_connect_data_list,
827 						       conn_data);
828 
829 		if (conn_data->lookup_data)
830 			sock_get_address_info_async_cancel
831 				(conn_data->lookup_data);
832 
833 		if (conn_data->io_tag > 0)
834 			g_source_remove(conn_data->io_tag);
835 		if (conn_data->channel) {
836 			GError *err = NULL;
837 			g_io_channel_shutdown(conn_data->channel, TRUE, &err);
838 			if (err)
839 				g_error_free(err);
840 			g_io_channel_unref(conn_data->channel);
841 		}
842 
843 		sock_address_list_free(conn_data->addr_list);
844 		g_free(conn_data->canonical_name);
845 		g_free(conn_data->hostname);
846 		g_free(conn_data);
847 	} else {
848 		g_warning("sock_connect_async_cancel: id %d not found", id);
849 		return -1;
850 	}
851 
852 	return 0;
853 }
854 
sock_connect_address_list_async(SockConnectData * conn_data)855 static gint sock_connect_address_list_async(SockConnectData *conn_data)
856 {
857 	SockAddrData *addr_data;
858 	gint sock = -1;
859 
860 	for (; conn_data->cur_addr != NULL;
861 	     conn_data->cur_addr = conn_data->cur_addr->next) {
862 		addr_data = (SockAddrData *)conn_data->cur_addr->data;
863 
864 		if ((sock = socket(addr_data->family, addr_data->socktype,
865 				   addr_data->protocol)) < 0) {
866 			perror("socket");
867 
868 			continue;
869 		}
870 
871 		set_nonblocking_mode(sock, TRUE);
872 
873 		if (connect(sock, addr_data->addr, addr_data->addr_len) < 0) {
874 			if (EINPROGRESS == errno) {
875 				break;
876 			} else {
877 				perror("connect");
878 				close(sock);
879 			}
880 		} else {
881 			break;
882 		}
883 	}
884 
885 	if (conn_data->cur_addr == NULL) {
886 		conn_data->func(NULL, conn_data->data);
887 		sock_connect_async_cancel(conn_data->id);
888 		return -1;
889 	}
890 
891 	conn_data->cur_addr = conn_data->cur_addr->next;
892 
893 #ifndef G_OS_WIN32
894 	conn_data->channel = g_io_channel_unix_new(sock);
895 #else
896 	conn_data->channel = g_io_channel_win32_new_socket(sock);
897 #endif
898 	conn_data->io_tag = g_io_add_watch(conn_data->channel, G_IO_IN|G_IO_OUT,
899 					   sock_connect_async_cb, conn_data);
900 
901 	return 0;
902 }
903 
904 /* asynchronous DNS lookup */
905 
sock_get_address_info_async_cb(GIOChannel * source,GIOCondition condition,gpointer data)906 static gboolean sock_get_address_info_async_cb(GIOChannel *source,
907 					       GIOCondition condition,
908 					       gpointer data)
909 {
910 	SockLookupData *lookup_data = (SockLookupData *)data;
911 	GList *addr_list = NULL;
912 	SockAddrData *addr_data;
913 	gsize bytes_read;
914 	gint ai_member[4];
915 	struct sockaddr *addr;
916 	gchar *canonical_name = NULL;
917 	gchar len = 0;
918 	GError *err = NULL;
919 
920 	g_io_channel_set_encoding(source, NULL, &err);
921 	if (err) {
922 		g_warning("can unset encoding: %s", err->message);
923 		g_error_free(err);
924 		return FALSE;
925 	}
926 	g_io_channel_set_buffered(source, FALSE);
927 	if (g_io_channel_read_chars(source, &len, sizeof(len),
928 			      &bytes_read, &err) == G_IO_STATUS_NORMAL) {
929 		if (err != NULL) {
930 			g_warning("g_io_channel_read_chars: %s", err->message);
931 			g_error_free(err);
932 			return FALSE;
933 		}
934 		if (bytes_read == sizeof(len) && len > 0) {
935 			gchar *cur = NULL;
936 			gint todo = len;
937 			canonical_name = g_malloc0(len + 1);
938 			cur = canonical_name;
939 			while (todo > 0) {
940 				if (g_io_channel_read_chars(source, cur, todo,
941 				      &bytes_read, &err) != G_IO_STATUS_NORMAL) {
942 					if (err) {
943 					      g_warning("canonical name not read %s", err->message);
944 					      g_free(canonical_name);
945 					      canonical_name = NULL;
946 					      g_error_free(err);
947 					      err = NULL;
948 					      break;
949 					}
950 				} else {
951 					cur += bytes_read;
952 					todo -= bytes_read;
953 				}
954 				if (bytes_read == 0) {
955 				      g_warning("canonical name not read");
956 				      g_free(canonical_name);
957 				      canonical_name = NULL;
958 				      break;
959 				}
960 			}
961 		}
962 	}
963 	for (;;) {
964 		if (g_io_channel_read_chars(source, (gchar *)ai_member,
965 				      sizeof(ai_member), &bytes_read, &err)
966 		    != G_IO_STATUS_NORMAL) {
967 			if (err != NULL) {
968 				g_warning("g_io_channel_read_chars: addr len %s", err->message);
969 				g_error_free(err);
970 				err = NULL;
971 				break;
972 			}
973 		}
974 
975 		if (bytes_read == 0 || bytes_read != sizeof(ai_member))
976 			break;
977 
978 		if (ai_member[0] == AF_UNSPEC) {
979 			g_warning("DNS lookup failed");
980 			log_error(LOG_PROTOCOL, _("%s:%d: unknown host.\n"),
981 				lookup_data->hostname, lookup_data->port);
982 			break;
983 		}
984 
985 		addr = g_malloc(ai_member[3]);
986 		if (g_io_channel_read_chars(source, (gchar *)addr, ai_member[3],
987 				      &bytes_read, &err)
988 		    != G_IO_STATUS_NORMAL) {
989 			if (err != NULL) {
990 				g_warning("g_io_channel_read_chars: addr data read %s", err->message);
991 				g_error_free(err);
992 				err = NULL;
993 				g_free(addr);
994 				break;
995 			}
996 		}
997 
998 		if (bytes_read != ai_member[3]) {
999 			g_warning("sock_get_address_info_async_cb: "
1000 				  "incomplete address data");
1001 			g_free(addr);
1002 			break;
1003 		}
1004 
1005 		addr_data = g_new0(SockAddrData, 1);
1006 		addr_data->family = ai_member[0];
1007 		addr_data->socktype = ai_member[1];
1008 		addr_data->protocol = ai_member[2];
1009 		addr_data->addr_len = ai_member[3];
1010 		addr_data->addr = addr;
1011 
1012 		addr_list = g_list_append(addr_list, addr_data);
1013 	}
1014 
1015 	g_io_channel_shutdown(source, TRUE, &err);
1016 	if (err)
1017 		g_error_free(err);
1018 	g_io_channel_unref(source);
1019 
1020 #ifdef G_OS_WIN32
1021         /* FIXME: We would need to cancel the thread. */
1022 #else
1023 	kill(lookup_data->child_pid, SIGKILL);
1024 	waitpid(lookup_data->child_pid, NULL, 0);
1025 #endif
1026 	lookup_data->canonical_name = canonical_name;
1027 
1028 	lookup_data->func(addr_list, lookup_data->data);
1029 
1030 	g_free(lookup_data->canonical_name);
1031 	g_free(lookup_data->hostname);
1032 	g_free(lookup_data);
1033 
1034 	return FALSE;
1035 }
1036 
1037 
1038 /* For better readability we use a separate function to implement the
1039    child code of sock_get_address_info_async.  Note, that under W32
1040    this is actually not a child but a thread and this is the reason
1041    why we pass only a void pointer. */
address_info_async_child(void * opaque)1042 static void address_info_async_child(void *opaque)
1043 {
1044         SockLookupData *parm = opaque;
1045         gint gai_err;
1046         struct addrinfo hints, *res, *ai;
1047         gchar port_str[6];
1048         gint ai_member[4] = {AF_UNSPEC, 0, 0, 0};
1049 
1050 #ifndef G_OS_WIN32
1051         close(parm->pipe_fds[0]);
1052         parm->pipe_fds[0] = -1;
1053 #endif
1054 
1055         memset(&hints, 0, sizeof(hints));
1056         hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
1057 #ifdef INET6
1058         hints.ai_family = AF_UNSPEC;
1059 #else
1060 				hints.ai_family = AF_INET;
1061 #endif
1062         hints.ai_socktype = SOCK_STREAM;
1063         hints.ai_protocol = IPPROTO_TCP;
1064 
1065         g_snprintf(port_str, sizeof(port_str), "%d", parm->port);
1066 
1067         gai_err = getaddrinfo(parm->hostname, port_str, &hints, &res);
1068         if (gai_err != 0) {
1069 		gchar len = 0;
1070                 g_warning("getaddrinfo for %s:%s failed: %s",
1071                           parm->hostname, port_str, gai_strerror(gai_err));
1072 		log_error(LOG_PROTOCOL, _("%s:%s: host lookup failed (%s).\n"),
1073 			  parm->hostname, port_str, gai_strerror(gai_err));
1074 	        fd_write_all(parm->pipe_fds[1], &len,
1075                      sizeof(len));
1076                 fd_write_all(parm->pipe_fds[1], (gchar *)ai_member,
1077                              sizeof(ai_member));
1078                 close(parm->pipe_fds[1]);
1079                 parm->pipe_fds[1] = -1;
1080 #ifdef G_OS_WIN32
1081                 _endthread();
1082 #else
1083                 _exit(1);
1084 #endif
1085         }
1086 
1087 	if (res != NULL) {
1088 		if (res->ai_canonname && strlen(res->ai_canonname) < 255) {
1089 			gchar len = strlen(res->ai_canonname);
1090 	                fd_write_all(parm->pipe_fds[1], &len,
1091                              sizeof(len));
1092 	                fd_write_all(parm->pipe_fds[1], res->ai_canonname,
1093                              len);
1094 		} else {
1095 			gchar len = 0;
1096 	                fd_write_all(parm->pipe_fds[1], &len,
1097                              sizeof(len));
1098 		}
1099 	} else {
1100 		gchar len = 0;
1101 	        fd_write_all(parm->pipe_fds[1], &len,
1102                      sizeof(len));
1103 	}
1104 
1105         for (ai = res; ai != NULL; ai = ai->ai_next) {
1106                 ai_member[0] = ai->ai_family;
1107                 ai_member[1] = ai->ai_socktype;
1108                 ai_member[2] = ai->ai_protocol;
1109                 ai_member[3] = ai->ai_addrlen;
1110 
1111                 fd_write_all(parm->pipe_fds[1], (gchar *)ai_member,
1112                              sizeof(ai_member));
1113                 fd_write_all(parm->pipe_fds[1], (gchar *)ai->ai_addr,
1114                              ai->ai_addrlen);
1115         }
1116 
1117         if (res != NULL)
1118                 freeaddrinfo(res);
1119 
1120         close(parm->pipe_fds[1]);
1121         parm->pipe_fds[1] = -1;
1122 
1123 #ifdef G_OS_WIN32
1124         _endthread();
1125 #else
1126         _exit(0);
1127 #endif
1128 }
1129 
sock_get_address_info_async(const gchar * hostname,gushort port,SockAddrFunc func,gpointer data)1130 static SockLookupData *sock_get_address_info_async(const gchar *hostname,
1131 						   gushort port,
1132 						   SockAddrFunc func,
1133 						   gpointer data)
1134 {
1135 	SockLookupData *lookup_data = NULL;
1136 
1137 	refresh_resolvers();
1138 
1139         lookup_data = g_new0(SockLookupData, 1);
1140         lookup_data->hostname = g_strdup(hostname);
1141         lookup_data->func = func;
1142         lookup_data->data = data;
1143         lookup_data->port = port;
1144         lookup_data->child_pid = (pid_t)(-1);
1145         lookup_data->pipe_fds[0] = -1;
1146         lookup_data->pipe_fds[1] = -1;
1147 
1148 	if (pipe(lookup_data->pipe_fds) < 0) {
1149 		perror("pipe");
1150 		func(NULL, data);
1151                 g_free (lookup_data->hostname);
1152                 g_free (lookup_data);
1153 		return NULL;
1154 	}
1155 
1156 #ifndef G_OS_WIN32
1157 	if ((lookup_data->child_pid = fork()) < 0) {
1158 		perror("fork");
1159 		func(NULL, data);
1160                 g_free (lookup_data->hostname);
1161                 g_free (lookup_data);
1162 		return NULL;
1163 	}
1164 
1165 	if (lookup_data->child_pid == 0) {
1166                 /* Child process. */
1167                 address_info_async_child (lookup_data);
1168                 g_assert_not_reached ();
1169 	}
1170         /* Parent process. */
1171         close(lookup_data->pipe_fds[1]);
1172         lookup_data->pipe_fds[1] = -1;
1173 #endif  /*!G_OS_WIN32 */
1174 
1175 #ifndef G_OS_WIN32
1176         lookup_data->channel = g_io_channel_unix_new(lookup_data->pipe_fds[0]);
1177 #else
1178         lookup_data->channel = g_io_channel_win32_new_fd(lookup_data->pipe_fds[0]);
1179 #endif
1180         lookup_data->io_tag = g_io_add_watch(lookup_data->channel, G_IO_IN,
1181                                              sock_get_address_info_async_cb,
1182                                              lookup_data);
1183 #ifdef G_OS_WIN32
1184 	lookup_data->child_pid = _beginthread(
1185 		address_info_async_child, 0, lookup_data);
1186 #endif
1187 
1188 	return lookup_data;
1189 }
1190 
sock_get_address_info_async_cancel(SockLookupData * lookup_data)1191 static gint sock_get_address_info_async_cancel(SockLookupData *lookup_data)
1192 {
1193 	if (lookup_data->io_tag > 0)
1194 		g_source_remove(lookup_data->io_tag);
1195 	if (lookup_data->channel) {
1196 		GError *err = NULL;
1197 		g_io_channel_shutdown(lookup_data->channel, TRUE, &err);
1198 		if (err)
1199 			g_error_free(err);
1200 
1201 		g_io_channel_unref(lookup_data->channel);
1202 	}
1203 
1204 	if (lookup_data->child_pid > 0) {
1205 #ifdef G_OS_WIN32
1206                 /* FIXME: Need a way to cancel the thread. */
1207 #else
1208 		kill(lookup_data->child_pid, SIGKILL);
1209 		waitpid(lookup_data->child_pid, NULL, 0);
1210 #endif
1211 	}
1212 
1213 	g_free(lookup_data->canonical_name);
1214 	g_free(lookup_data->hostname);
1215 	g_free(lookup_data);
1216 
1217 	return 0;
1218 }
1219 
1220 
sockinfo_from_fd(const gchar * hostname,gushort port,gint sock)1221 static SockInfo *sockinfo_from_fd(const gchar *hostname,
1222 				  gushort port,
1223 				  gint sock)
1224 {
1225 	SockInfo *sockinfo;
1226 
1227 	sockinfo = g_new0(SockInfo, 1);
1228 	sockinfo->sock = sock;
1229 #ifndef G_OS_WIN32
1230 	sockinfo->sock_ch = g_io_channel_unix_new(sock);
1231 #else
1232 	sockinfo->sock_ch = g_io_channel_win32_new_socket(sock);
1233 #endif
1234 	sockinfo->hostname = g_strdup(hostname);
1235 	sockinfo->port = port;
1236 	sockinfo->state = CONN_ESTABLISHED;
1237 
1238 	return sockinfo;
1239 }
1240 
fd_read(gint fd,gchar * buf,gint len)1241 static gint fd_read(gint fd, gchar *buf, gint len)
1242 {
1243 	if (fd_check_io(fd, G_IO_IN) < 0)
1244 		return -1;
1245 
1246 #ifdef G_OS_WIN32
1247 	if (fd_is_w32_socket(fd))
1248 		return recv(fd, buf, len, 0);
1249 #endif
1250 
1251 	return read(fd, buf, len);
1252 }
1253 
1254 #if USE_GNUTLS
ssl_read(gnutls_session_t ssl,gchar * buf,gint len)1255 static gint ssl_read(gnutls_session_t ssl, gchar *buf, gint len)
1256 {
1257 	gint r;
1258 
1259 	if (gnutls_record_check_pending(ssl) == 0) {
1260 		if (fd_check_io(GPOINTER_TO_INT(gnutls_transport_get_ptr(ssl)), G_IO_IN) < 0)
1261 			return -1;
1262 	}
1263 
1264 	while (1) {
1265 		r = gnutls_record_recv(ssl, buf, len);
1266 		if (r > 0)
1267 			return r;
1268 
1269 		switch (r) {
1270 		case 0: /* closed connection */
1271 			return -1;
1272 
1273 		case GNUTLS_E_REHANDSHAKE:
1274 			do {
1275 				r = gnutls_handshake(ssl);
1276 			} while (r == GNUTLS_E_AGAIN || r == GNUTLS_E_INTERRUPTED);
1277 			break; /* re-receive */
1278 		case GNUTLS_E_AGAIN:
1279 		case GNUTLS_E_INTERRUPTED:
1280 			errno = EAGAIN;
1281 			return -1;
1282 
1283 		default:
1284 			debug_print("Unexpected SSL/TLS read result %d\n", r);
1285 			errno = EIO;
1286 			return -1;
1287 		}
1288 	}
1289 
1290 }
1291 #endif
1292 
sock_read(SockInfo * sock,gchar * buf,gint len)1293 gint sock_read(SockInfo *sock, gchar *buf, gint len)
1294 {
1295 	gint ret;
1296 
1297 	cm_return_val_if_fail(sock != NULL, -1);
1298 
1299 #ifdef USE_GNUTLS
1300 	if (sock->ssl)
1301 		ret = ssl_read(sock->ssl, buf, len);
1302 	else
1303 #endif
1304 		ret = fd_read(sock->sock, buf, len);
1305 
1306 	if (ret < 0)
1307 		sock->state = CONN_DISCONNECTED;
1308 	return ret;
1309 }
1310 
fd_write(gint fd,const gchar * buf,gint len)1311 gint fd_write(gint fd, const gchar *buf, gint len)
1312 {
1313 	if (fd_check_io(fd, G_IO_OUT) < 0)
1314 		return -1;
1315 
1316 #ifdef G_OS_WIN32
1317 	if (fd_is_w32_socket (fd))
1318 		return send(fd, buf, len, 0);
1319 #endif
1320 
1321 	return write(fd, buf, len);
1322 }
1323 
1324 #if USE_GNUTLS
ssl_write(gnutls_session_t ssl,const gchar * buf,gint len)1325 static gint ssl_write(gnutls_session_t ssl, const gchar *buf, gint len)
1326 {
1327 	gint ret;
1328 
1329 	if (fd_check_io(GPOINTER_TO_INT(gnutls_transport_get_ptr(ssl)), G_IO_OUT) < 0)
1330 		return -1;
1331 
1332 	ret = gnutls_record_send(ssl, buf, len);
1333 
1334 	switch (ret) {
1335 	case 0:
1336 		return -1;
1337 	case GNUTLS_E_AGAIN:
1338 	case GNUTLS_E_INTERRUPTED:
1339 		return 0;
1340 
1341 	default:
1342 		return ret;
1343 	}
1344 }
1345 
1346 #endif
1347 
sock_write(SockInfo * sock,const gchar * buf,gint len)1348 gint sock_write(SockInfo *sock, const gchar *buf, gint len)
1349 {
1350 	gint ret;
1351 
1352 	cm_return_val_if_fail(sock != NULL, -1);
1353 
1354 #ifdef USE_GNUTLS
1355 	if (sock->ssl)
1356 		ret = ssl_write(sock->ssl, buf, len);
1357 	else
1358 #endif
1359 		ret = fd_write(sock->sock, buf, len);
1360 
1361 	if (ret < 0)
1362 		sock->state = CONN_DISCONNECTED;
1363 	return ret;
1364 }
1365 
fd_write_all(gint fd,const gchar * buf,gint len)1366 gint fd_write_all(gint fd, const gchar *buf, gint len)
1367 {
1368 	gint n, wrlen = 0;
1369 
1370 	while (len) {
1371 		if (fd_check_io(fd, G_IO_OUT) < 0)
1372 			return -1;
1373 #ifndef G_OS_WIN32
1374 		signal(SIGPIPE, SIG_IGN);
1375 #endif
1376 
1377 #ifdef G_OS_WIN32
1378 		if (fd_is_w32_socket(fd))
1379 			n = send(fd, buf, len, 0);
1380 		else
1381 #endif
1382 			n = write(fd, buf, len);
1383 
1384 		if (n <= 0) {
1385 			log_error(LOG_PROTOCOL, _("write on fd%d: %s\n"), fd, g_strerror(errno));
1386 			return -1;
1387 		}
1388 		len -= n;
1389 		wrlen += n;
1390 		buf += n;
1391 	}
1392 
1393 	return wrlen;
1394 }
1395 
1396 #ifdef USE_GNUTLS
ssl_write_all(gnutls_session_t ssl,const gchar * buf,gint len)1397 static gint ssl_write_all(gnutls_session_t ssl, const gchar *buf, gint len)
1398 {
1399 	gint n, wrlen = 0;
1400 
1401 	while (len) {
1402 		n = ssl_write(ssl, buf, len);
1403 		if (n <= 0)
1404 			return -1;
1405 		len -= n;
1406 		wrlen += n;
1407 		buf += n;
1408 	}
1409 
1410 	return wrlen;
1411 }
1412 #endif
1413 
sock_write_all(SockInfo * sock,const gchar * buf,gint len)1414 gint sock_write_all(SockInfo *sock, const gchar *buf, gint len)
1415 {
1416 	gint ret;
1417 
1418 	cm_return_val_if_fail(sock != NULL, -1);
1419 
1420 #ifdef USE_GNUTLS
1421 	if (sock->ssl)
1422 		ret = ssl_write_all(sock->ssl, buf, len);
1423 	else
1424 #endif
1425 		ret = fd_write_all(sock->sock, buf, len);
1426 
1427 	if (ret < 0)
1428 		sock->state = CONN_DISCONNECTED;
1429 	return ret;
1430 }
1431 
fd_recv(gint fd,gchar * buf,gint len,gint flags)1432 static gint fd_recv(gint fd, gchar *buf, gint len, gint flags)
1433 {
1434 	if (fd_check_io(fd, G_IO_IN) < 0)
1435 		return -1;
1436 
1437 	return recv(fd, buf, len, flags);
1438 }
1439 
fd_gets(gint fd,gchar * buf,gint len)1440 gint fd_gets(gint fd, gchar *buf, gint len)
1441 {
1442 	gchar *bp = buf;
1443 
1444 	if (--len < 1)
1445 		return -1;
1446 
1447 #ifdef G_OS_WIN32
1448 	fd_check_io(fd, G_IO_IN);
1449 	do {
1450 /*
1451 XXX:tm try nonblock
1452 MSKB Article ID: Q147714
1453 Windows Sockets 2 Service Provider Interface Limitations
1454 Polling with recv(MSG_PEEK) to determine when a complete message
1455 has arrived.
1456     Reason and Workaround not available.
1457 
1458 Single-byte send() and recv().
1459     Reason: Couple one-byte sends with Nagle disabled.
1460     Workaround: Send modest amounts and receive as much as possible.
1461 (still unused)
1462 */
1463 		if (recv(fd, bp, 1, 0) <= 0)
1464 			return -1;
1465 		if (*bp == '\n')
1466 			break;
1467 		bp++;
1468 		len--;
1469 	} while (0 < len);
1470 #else /*!G_OS_WIN32*/
1471 	gchar *newline;
1472 	gint n;
1473 	do {
1474 		if ((n = fd_recv(fd, bp, len, MSG_PEEK)) <= 0)
1475 			return -1;
1476 		if ((newline = memchr(bp, '\n', n)) != NULL)
1477 			n = newline - bp + 1;
1478 		if ((n = fd_read(fd, bp, n)) < 0)
1479 			return -1;
1480 		bp += n;
1481 		len -= n;
1482 	} while (!newline && len);
1483 #endif /*!G_OS_WIN32*/
1484 
1485 	*bp = '\0';
1486 	return bp - buf;
1487 }
1488 
sock_close(SockInfo * sock,gboolean close_fd)1489 gint sock_close(SockInfo *sock, gboolean close_fd)
1490 {
1491 	gint ret = 0;
1492 
1493 	if (!sock)
1494 		return 0;
1495 
1496 	if (sock->sock_ch)
1497 		g_io_channel_unref(sock->sock_ch);
1498 
1499 #ifdef USE_GNUTLS
1500 	if (sock->ssl)
1501 		ssl_done_socket(sock);
1502 	if (sock->g_source != 0 && g_main_context_find_source_by_id(NULL, sock->g_source) != NULL)
1503 		g_source_remove(sock->g_source);
1504 	sock->g_source = 0;
1505 #endif
1506 	if (close_fd) {
1507 #ifdef G_OS_WIN32
1508 		shutdown(sock->sock, 1); /* complete transfer before close */
1509 		ret = closesocket(sock->sock);
1510 #else
1511 		ret = fd_close(sock->sock);
1512 #endif
1513 	}
1514 
1515 	g_free(sock->canonical_name);
1516 	g_free(sock->hostname);
1517 	g_free(sock);
1518 
1519 	return ret;
1520 }
1521 
fd_close(gint fd)1522 gint fd_close(gint fd)
1523 {
1524 	return close(fd);
1525 }
1526