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