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