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