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