Statistics
| Revision:

root / libsylph / socket.c @ 2919

History | View | Annotate | Download (41 KB)

1
/*
2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2011 Hiroyuki Yamamoto
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9
 *
10
 * This library 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 GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin St, 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 <sys/time.h>
26
#include <sys/types.h>
27
#ifdef G_OS_WIN32
28
#  include <winsock2.h>
29
#  include <ws2tcpip.h>
30
#else
31
#  if HAVE_SYS_WAIT_H
32
#    include <sys/wait.h>
33
#  endif
34
#  include <sys/socket.h>
35
#  include <sys/un.h>
36
#  include <netinet/in.h>
37
#  include <arpa/inet.h>
38
#  include <resolv.h>
39
#  include <netdb.h>
40
#  include <sys/stat.h>
41
#endif /* G_OS_WIN32 */
42
#include <unistd.h>
43
#include <stdio.h>
44
#include <string.h>
45
#include <stdarg.h>
46
#include <fcntl.h>
47
#include <errno.h>
48
#include <signal.h>
49
#include <setjmp.h>
50
#if HAVE_SYS_SELECT_H
51
#  include <sys/select.h>
52
#endif
53

    
54
#include "socket.h"
55
#if USE_SSL
56
#  include "ssl.h"
57
#endif
58

    
59
#include "utils.h"
60

    
61
#define BUFFSIZE        8192
62

    
63
#ifdef G_OS_WIN32
64
#define SockDesc                SOCKET
65
#define SOCKET_IS_VALID(s)        ((s) != INVALID_SOCKET)
66
#else
67
#define SockDesc                gint
68
#define SOCKET_IS_VALID(s)        ((s) >= 0)
69
#define INVALID_SOCKET                (-1)
70
#endif
71

    
72
typedef gint (*SockAddrFunc)        (GList                *addr_list,
73
                                 gpointer         data);
74

    
75
typedef struct _SockConnectData        SockConnectData;
76
typedef struct _SockLookupData        SockLookupData;
77
typedef struct _SockAddrData        SockAddrData;
78
typedef struct _SockSource        SockSource;
79

    
80
struct _SockConnectData {
81
        gint id;
82
        gchar *hostname;
83
        gushort port;
84
#ifdef G_OS_UNIX
85
        GList *addr_list;
86
        GList *cur_addr;
87
        SockLookupData *lookup_data;
88
        GIOChannel *channel;
89
        guint io_tag;
90
#endif /* G_OS_UNIX */
91
#if USE_THREADS
92
        gint flag;
93
        GThread *thread;
94
        SockInfo *sock;
95
#endif /* G_OS_UNIX */
96
        SockConnectFunc func;
97
        gpointer data;
98
};
99

    
100
struct _SockLookupData {
101
        gchar *hostname;
102
        pid_t child_pid;
103
        GIOChannel *channel;
104
        guint io_tag;
105
        SockAddrFunc func;
106
        gpointer data;
107
};
108

    
109
struct _SockAddrData {
110
        gint family;
111
        gint socktype;
112
        gint protocol;
113
        gint addr_len;
114
        struct sockaddr *addr;
115
};
116

    
117
struct _SockSource {
118
        GSource parent;
119
        SockInfo *sock;
120
};
121

    
122
static guint io_timeout = 60;
123

    
124
static GList *sock_connect_data_list = NULL;
125
static GList *sock_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 SockInfo *sock_find_from_fd        (gint        fd);
142

    
143
static gint sock_connect_with_timeout        (gint                         sock,
144
                                         const struct sockaddr        *serv_addr,
145
                                         gint                         addrlen,
146
                                         guint                         timeout_secs);
147

    
148
#ifndef INET6
149
static gint sock_connect_by_hostname        (gint                 sock,
150
                                         const gchar        *hostname,
151
                                         gushort         port);
152
#else
153
#ifdef G_OS_WIN32
154
typedef int (*GetAddrInfoFunc)                (const char        *node,
155
                                         const char        *service,
156
                                         const struct addrinfo *hints,
157
                                         struct addrinfo **res);
158
typedef void (*FreeAddrInfoFunc)        (struct addrinfo *res);
159

    
160
static GetAddrInfoFunc getaddrinfo_func = NULL;
161
static FreeAddrInfoFunc freeaddrinfo_func = NULL;
162

    
163
#undef getaddrinfo
164
#define getaddrinfo        my_getaddrinfo
165
#undef freeaddrinfo
166
#define freeaddrinfo        my_freeaddrinfo
167
#endif
168

    
169
static SockDesc sock_connect_by_getaddrinfo        (const gchar        *hostname,
170
                                                 gushort         port);
171
#endif
172

    
173
#ifdef G_OS_UNIX
174
static void sock_address_list_free                (GList                *addr_list);
175

    
176
static gboolean sock_connect_async_cb                (GIOChannel        *source,
177
                                                 GIOCondition         condition,
178
                                                 gpointer         data);
179
static gint sock_connect_async_get_address_info_cb
180
                                                (GList                *addr_list,
181
                                                 gpointer         data);
182

    
183
static gint sock_connect_address_list_async        (SockConnectData *conn_data);
184

    
185
static gboolean sock_get_address_info_async_cb        (GIOChannel        *source,
186
                                                 GIOCondition         condition,
187
                                                 gpointer         data);
188
static SockLookupData *sock_get_address_info_async
189
                                                (const gchar        *hostname,
190
                                                 gushort         port,
191
                                                 SockAddrFunc         func,
192
                                                 gpointer         data);
193
static gint sock_get_address_info_async_cancel        (SockLookupData        *lookup_data);
194
#endif /* G_OS_UNIX */
195

    
196

    
197
gint sock_init(void)
198
{
199
#ifdef G_OS_WIN32
200
        WSADATA wsadata;
201
        gint result;
202

    
203
        result = WSAStartup(MAKEWORD(2, 2), &wsadata);
204
        if (result != NO_ERROR) {
205
                g_warning("WSAStartup() failed\n");
206
                return -1;
207
        }
208
#endif
209
        return 0;
210
}
211

    
212
gint sock_cleanup(void)
213
{
214
#ifdef G_OS_WIN32
215
        WSACleanup();
216
#endif
217
        return 0;
218
}
219

    
220
gint sock_set_io_timeout(guint sec)
221
{
222
        io_timeout = sec;
223
        return 0;
224
}
225

    
226
gint fd_connect_inet(gushort port)
227
{
228
        SockDesc sock;
229
        struct sockaddr_in addr;
230

    
231
        sock = socket(AF_INET, SOCK_STREAM, 0);
232
        if (!SOCKET_IS_VALID(sock)) {
233
#ifdef G_OS_WIN32
234
                g_warning("fd_connect_inet(): socket() failed: %ld\n",
235
                          WSAGetLastError());
236
#else
237
                perror("fd_connect_inet(): socket");
238
#endif
239
                return -1;
240
        }
241

    
242
        memset(&addr, 0, sizeof(addr));
243
        addr.sin_family = AF_INET;
244
        addr.sin_port = htons(port);
245
        addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
246

    
247
        if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
248
                fd_close(sock);
249
                return -1;
250
        }
251

    
252
        return sock;
253
}
254

    
255
gint fd_open_inet(gushort port)
256
{
257
        SockDesc sock;
258
        struct sockaddr_in addr;
259
        gint val;
260

    
261
        sock = socket(AF_INET, SOCK_STREAM, 0);
262
        if (!SOCKET_IS_VALID(sock)) {
263
#ifdef G_OS_WIN32
264
                g_warning("fd_open_inet(): socket() failed: %ld\n",
265
                          WSAGetLastError());
266
#else
267
                perror("fd_open_inet(): socket");
268
#endif
269
                return -1;
270
        }
271

    
272
        val = 1;
273
        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val,
274
                       sizeof(val)) < 0) {
275
                perror("setsockopt");
276
                fd_close(sock);
277
                return -1;
278
        }
279

    
280
        memset(&addr, 0, sizeof(addr));
281
        addr.sin_family = AF_INET;
282
        addr.sin_port = htons(port);
283
        addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
284

    
285
        if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
286
                perror("bind");
287
                fd_close(sock);
288
                return -1;
289
        }
290

    
291
        if (listen(sock, 1) < 0) {
292
                perror("listen");
293
                fd_close(sock);
294
                return -1;                
295
        }
296

    
297
        return sock;
298
}
299

    
300
gint fd_connect_unix(const gchar *path)
301
{
302
#ifdef G_OS_UNIX
303
        gint sock;
304
        struct sockaddr_un addr;
305

    
306
        sock = socket(PF_UNIX, SOCK_STREAM, 0);
307
        if (sock < 0) {
308
                perror("fd_connect_unix(): socket");
309
                return -1;
310
        }
311

    
312
        memset(&addr, 0, sizeof(addr));
313
        addr.sun_family = AF_UNIX;
314
        strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
315

    
316
        if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
317
                fd_close(sock);
318
                return -1;
319
        }
320

    
321
        return sock;
322
#else
323
        return -1;
324
#endif
325
}
326

    
327
gint fd_open_unix(const gchar *path)
328
{
329
#ifdef G_OS_UNIX
330
        gint sock;
331
        struct sockaddr_un addr;
332
        gint val;
333

    
334
        sock = socket(PF_UNIX, SOCK_STREAM, 0);
335

    
336
        if (sock < 0) {
337
                perror("sock_open_unix(): socket");
338
                return -1;
339
        }
340

    
341
        val = 1;
342
        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
343
                perror("setsockopt");
344
                fd_close(sock);
345
                return -1;
346
        }
347

    
348
        memset(&addr, 0, sizeof(addr));
349
        addr.sun_family = AF_UNIX;
350
        strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
351

    
352
        if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
353
                perror("bind");
354
                fd_close(sock);
355
                return -1;
356
        }
357

    
358
        if (listen(sock, 1) < 0) {
359
                perror("listen");
360
                fd_close(sock);
361
                return -1;                
362
        }
363

    
364
        return sock;
365
#else
366
        return -1;
367
#endif
368
}
369

    
370
gint fd_accept(gint sock)
371
{
372
        struct sockaddr_in caddr;
373
        guint caddr_len;
374

    
375
        caddr_len = sizeof(caddr);
376
        return accept(sock, (struct sockaddr *)&caddr, &caddr_len);
377
}
378

    
379

    
380
static SockInfo *sock_find_from_fd(gint fd)
381
{
382
        GList *cur;
383

    
384
        for (cur = sock_list; cur != NULL; cur = cur->next) {
385
                if (((SockInfo *)cur->data)->sock == fd)
386
                        return (SockInfo *)cur->data;
387
        }
388

    
389
        return NULL;
390
}
391

    
392
static gint set_nonblocking_mode(gint fd, gboolean nonblock)
393
{
394
#ifdef G_OS_WIN32
395
        gulong val = nonblock ? 1 : 0;
396
        SockInfo *sock;
397

    
398
        if (!nonblock)
399
                WSAEventSelect(fd, NULL, 0);
400
        if (ioctlsocket(fd, FIONBIO, &val) == SOCKET_ERROR) {
401
                g_warning("set_nonblocking_mode(): ioctlsocket() failed: %ld\n",
402
                          WSAGetLastError());
403
                return -1;
404
        }
405

    
406
        sock = sock_find_from_fd(fd);
407
        if (sock) {
408
                if (nonblock) {
409
                        SOCK_SET_FLAGS(sock->flags, SYL_SOCK_NONBLOCK);
410
                } else {
411
                        SOCK_UNSET_FLAGS(sock->flags, SYL_SOCK_NONBLOCK);
412
                }
413
        }
414
        debug_print("set nonblocking mode to %d\n", nonblock);
415

    
416
        return 0;
417
#else
418
        gint flags;
419

    
420
        flags = fcntl(fd, F_GETFL, 0);
421
        if (flags < 0) {
422
                perror("fcntl");
423
                return -1;
424
        }
425

    
426
        if (nonblock)
427
                flags |= O_NONBLOCK;
428
        else
429
                flags &= ~O_NONBLOCK;
430

    
431
        return fcntl(fd, F_SETFL, flags);
432
#endif
433
}
434

    
435
gint sock_set_nonblocking_mode(SockInfo *sock, gboolean nonblock)
436
{
437
        gint ret;
438

    
439
        g_return_val_if_fail(sock != NULL, -1);
440

    
441
        ret = set_nonblocking_mode(sock->sock, nonblock);
442
        if (ret == 0) {
443
                if (nonblock) {
444
                        SOCK_SET_FLAGS(sock->flags, SYL_SOCK_NONBLOCK);
445
                } else {
446
                        SOCK_UNSET_FLAGS(sock->flags, SYL_SOCK_NONBLOCK);
447
                }
448
        }
449

    
450
        return ret;
451
}
452

    
453
static gboolean is_nonblocking_mode(gint fd)
454
{
455
#ifdef G_OS_WIN32
456
        SockInfo *sock;
457

    
458
        sock = sock_find_from_fd(fd);
459
        if (sock) {
460
                return SOCK_IS_NONBLOCK(sock->flags);
461
        }
462

    
463
        return FALSE;
464
#else
465
        gint flags;
466

    
467
        flags = fcntl(fd, F_GETFL, 0);
468
        if (flags < 0) {
469
                perror("fcntl");
470
                return FALSE;
471
        }
472

    
473
        return ((flags & O_NONBLOCK) != 0);
474
#endif
475
}
476

    
477
gboolean sock_is_nonblocking_mode(SockInfo *sock)
478
{
479
        g_return_val_if_fail(sock != NULL, FALSE);
480

    
481
#ifdef G_OS_WIN32
482
        return SOCK_IS_NONBLOCK(sock->flags);
483
#else
484
        return is_nonblocking_mode(sock->sock);
485
#endif
486
}
487

    
488
gboolean sock_has_read_data(SockInfo *sock)
489
{
490
#ifdef G_OS_WIN32
491
        gulong val;
492

    
493
#if USE_SSL
494
        if (sock->ssl)
495
                return TRUE;
496
#endif
497
        if (ioctlsocket(sock->sock, FIONREAD, &val) < 0) {
498
                g_warning("sock_has_read_data(): ioctlsocket() failed: %ld\n",
499
                          WSAGetLastError());
500
                return TRUE;
501
        }
502

    
503
        if (val == 0)
504
                return FALSE;
505
        else
506
                return TRUE;
507
#else
508
        return TRUE;
509
#endif
510
}
511

    
512

    
513
static gboolean sock_prepare(GSource *source, gint *timeout)
514
{
515
        *timeout = 1;
516
        return FALSE;
517
}
518

    
519
static gboolean sock_check(GSource *source)
520
{
521
        SockInfo *sock = ((SockSource *)source)->sock;
522
        struct timeval timeout = {0, 0};
523
        fd_set fds;
524
        GIOCondition condition = sock->condition;
525

    
526
#if USE_SSL
527
        if (sock->ssl) {
528
                if (condition & G_IO_IN) {
529
                        if (SSL_pending(sock->ssl) > 0)
530
                                return TRUE;
531
                        if (SSL_want_write(sock->ssl))
532
                                condition |= G_IO_OUT;
533
                }
534

    
535
                if (condition & G_IO_OUT) {
536
                        if (SSL_want_read(sock->ssl))
537
                                condition |= G_IO_IN;
538
                }
539
        }
540
#endif
541

    
542
        FD_ZERO(&fds);
543
        FD_SET(sock->sock, &fds);
544

    
545
        select(sock->sock + 1,
546
               (condition & G_IO_IN)  ? &fds : NULL,
547
               (condition & G_IO_OUT) ? &fds : NULL,
548
               NULL, &timeout);
549

    
550
        return FD_ISSET(sock->sock, &fds) != 0;
551
}
552

    
553
static gboolean sock_dispatch(GSource *source, GSourceFunc callback,
554
                              gpointer user_data)
555
{
556
        SockInfo *sock = ((SockSource *)source)->sock;
557

    
558
        return sock->callback(sock, sock->condition, sock->data);
559
}
560

    
561
static gboolean sock_watch_cb(GIOChannel *source, GIOCondition condition,
562
                              gpointer data)
563
{
564
        SockInfo *sock = (SockInfo *)data;
565

    
566
        if ((condition & sock->condition) == 0)
567
                return TRUE;
568

    
569
        return sock->callback(sock, sock->condition, sock->data);
570
}
571

    
572
guint sock_add_watch(SockInfo *sock, GIOCondition condition, SockFunc func,
573
                     gpointer data)
574
{
575
        sock->callback = func;
576
        sock->condition = condition;
577
        sock->data = data;
578

    
579
#if USE_SSL
580
        if (sock->ssl) {
581
                GSource *source;
582

    
583
                source = g_source_new(&sock_watch_funcs, sizeof(SockSource));
584
                ((SockSource *)source)->sock = sock;
585
                g_source_set_priority(source, G_PRIORITY_DEFAULT);
586
                g_source_set_can_recurse(source, FALSE);
587
                return g_source_attach(source, NULL);
588
        }
589
#endif
590

    
591
        return g_io_add_watch(sock->sock_ch, condition, sock_watch_cb, sock);
592
}
593

    
594
guint sock_add_watch_poll(SockInfo *sock, GIOCondition condition, SockFunc func,
595
                          gpointer data)
596
{
597
        GSource *source;
598

    
599
        sock->callback = func;
600
        sock->condition = condition;
601
        sock->data = data;
602

    
603
        source = g_source_new(&sock_watch_funcs, sizeof(SockSource));
604
        ((SockSource *)source)->sock = sock;
605
        g_source_set_priority(source, G_PRIORITY_DEFAULT);
606
        g_source_set_can_recurse(source, FALSE);
607

    
608
        return g_source_attach(source, NULL);
609
}
610

    
611
static gint fd_check_io(gint fd, GIOCondition cond)
612
{
613
        struct timeval timeout;
614
        fd_set fds;
615
        SockInfo *sock;
616

    
617
        sock = sock_find_from_fd(fd);
618
        if (sock && !SOCK_IS_CHECK_IO(sock->flags))
619
                return 0;
620

    
621
        timeout.tv_sec  = io_timeout;
622
        timeout.tv_usec = 0;
623

    
624
        FD_ZERO(&fds);
625
        FD_SET(fd, &fds);
626

    
627
        if (cond == G_IO_IN) {
628
                select(fd + 1, &fds, NULL, NULL,
629
                       io_timeout > 0 ? &timeout : NULL);
630
        } else {
631
                select(fd + 1, NULL, &fds, NULL,
632
                       io_timeout > 0 ? &timeout : NULL);
633
        }
634

    
635
        if (FD_ISSET(fd, &fds)) {
636
                return 0;
637
        } else {
638
                g_warning("Socket IO timeout\n");
639
                return -1;
640
        }
641
}
642

    
643
#if defined(G_OS_UNIX) && !defined(USE_THREADS)
644
static sigjmp_buf jmpenv;
645

    
646
static void timeout_handler(gint sig)
647
{
648
        siglongjmp(jmpenv, 1);
649
}
650
#endif
651

    
652
static gint sock_connect_with_timeout(gint sock,
653
                                      const struct sockaddr *serv_addr,
654
                                      gint addrlen,
655
                                      guint timeout_secs)
656
{
657
        gint ret;
658

    
659
#ifdef G_OS_UNIX
660
        set_nonblocking_mode(sock, TRUE);
661
#endif
662

    
663
        ret = connect(sock, serv_addr, addrlen);
664

    
665
#ifdef G_OS_UNIX
666
        if (ret < 0) {
667
                if (EINPROGRESS == errno) {
668
                        fd_set fds;
669
                        struct timeval tv;
670

    
671
                        tv.tv_sec = timeout_secs;
672
                        tv.tv_usec = 0;
673
                        FD_ZERO(&fds);
674
                        FD_SET(sock, &fds);
675
                        do {
676
                                ret = select(sock + 1, NULL, &fds, NULL, &tv);
677
                        } while (ret < 0 && EINTR == errno);
678
                        if (ret < 0) {
679
                                perror("sock_connect_with_timeout: select");
680
                                return -1;
681
                        } else if (ret == 0) {
682
                                debug_print("sock_connect_with_timeout: timeout\n");
683
                                errno = ETIMEDOUT;
684
                                return -1;
685
                        } else {
686
                                gint val;
687
                                guint len;
688

    
689
                                if (FD_ISSET(sock, &fds)) {
690
                                        ret = 0;
691
                                } else {
692
                                        debug_print("sock_connect_with_timeout: fd not set\n");
693
                                        return -1;
694
                                }
695

    
696
                                len = sizeof(val);
697
                                if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &val, &len) < 0) {
698
                                        perror("sock_connect_with_timeout: getsockopt");
699
                                        return -1;
700
                                }
701
                                if (val != 0) {
702
                                        debug_print("sock_connect_with_timeout: getsockopt(SOL_SOCKET, SO_ERROR) returned error: %s\n", g_strerror(val));
703
                                        return -1;
704
                                }
705
                        }
706
                } else {
707
                        perror("sock_connect_with_timeout: connect");
708
                        return -1;
709
                }
710
        }
711

    
712
        set_nonblocking_mode(sock, FALSE);
713
#endif
714

    
715
        return ret;
716
}
717

    
718
static void resolver_init(void)
719
{
720
#ifdef G_OS_UNIX
721
        static time_t resolv_conf_mtime = 0;
722
        struct stat s;
723

    
724
        if (g_stat("/etc/resolv.conf", &s) == 0 &&
725
            s.st_mtime != resolv_conf_mtime) {
726
                debug_print("Reloading /etc/resolv.conf\n");
727
                resolv_conf_mtime = s.st_mtime;
728
                res_init();
729
        }
730
#endif
731
}
732

    
733
struct hostent *my_gethostbyname(const gchar *hostname)
734
{
735
        struct hostent *hp;
736
#if defined(G_OS_UNIX) && !defined(USE_THREADS)
737
        void (*prev_handler)(gint);
738

    
739
        alarm(0);
740
        prev_handler = signal(SIGALRM, timeout_handler);
741
        if (sigsetjmp(jmpenv, 1)) {
742
                alarm(0);
743
                signal(SIGALRM, prev_handler);
744
                fprintf(stderr, "%s: host lookup timed out.\n", hostname);
745
                errno = 0;
746
                return NULL;
747
        }
748
        alarm(io_timeout);
749
#endif
750

    
751
        if ((hp = gethostbyname(hostname)) == NULL) {
752
#if defined(G_OS_UNIX) && !defined(USE_THREADS)
753
                alarm(0);
754
                signal(SIGALRM, prev_handler);
755
#endif
756
                fprintf(stderr, "%s: unknown host.\n", hostname);
757
                errno = 0;
758
                return NULL;
759
        }
760

    
761
#if defined(G_OS_UNIX) && !defined(USE_THREADS)
762
        alarm(0);
763
        signal(SIGALRM, prev_handler);
764
#endif
765

    
766
        return hp;
767
}
768

    
769
static void sock_set_buffer_size(gint sock)
770
{
771
#ifdef G_OS_WIN32
772
        gint val;
773
        guint len = sizeof(val);
774

    
775
#define SOCK_BUFFSIZE        32768
776

    
777
        getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&val, &len);
778
        if (val < SOCK_BUFFSIZE) {
779
                val = SOCK_BUFFSIZE;
780
                setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&val, len);
781
        }
782
        getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&val, &len);
783
        if (val < SOCK_BUFFSIZE) {
784
                val = SOCK_BUFFSIZE;
785
                setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&val, len);
786
        }
787
        getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&val, &len);
788
        debug_print("SO_SNDBUF = %d\n", val);
789
        getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&val, &len);
790
        debug_print("SO_RCVBUF = %d\n", val);
791

    
792
#undef SOCK_BUFFSIZE
793
#endif
794
}
795

    
796
#if !defined(INET6) || defined(G_OS_WIN32)
797
static gint my_inet_aton(const gchar *hostname, struct in_addr *inp)
798
{
799
#if HAVE_INET_ATON
800
        return inet_aton(hostname, inp);
801
#else
802
#if HAVE_INET_ADDR
803
        guint32 inaddr;
804

    
805
        inaddr = inet_addr(hostname);
806
        if (inaddr != -1) {
807
                memcpy(inp, &inaddr, sizeof(inaddr));
808
                return 1;
809
        } else
810
                return 0;
811
#else
812
        return 0;
813
#endif
814
#endif /* HAVE_INET_ATON */
815
}
816
#endif /* !defined(INET6) || defined(G_OS_WIN32) */
817

    
818
#ifndef INET6
819
static gint sock_connect_by_hostname(gint sock, const gchar *hostname,
820
                                     gushort port)
821
{
822
        struct hostent *hp;
823
        struct sockaddr_in ad;
824

    
825
        resolver_init();
826

    
827
        memset(&ad, 0, sizeof(ad));
828
        ad.sin_family = AF_INET;
829
        ad.sin_port = htons(port);
830

    
831
        if (!my_inet_aton(hostname, &ad.sin_addr)) {
832
                if ((hp = my_gethostbyname(hostname)) == NULL) {
833
                        fprintf(stderr, "%s: unknown host.\n", hostname);
834
                        errno = 0;
835
                        return -1;
836
                }
837

    
838
                if (hp->h_length != 4 && hp->h_length != 8) {
839
                        fprintf(stderr, "illegal address length received for host %s\n", hostname);
840
                        errno = 0;
841
                        return -1;
842
                }
843

    
844
                memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
845
        }
846

    
847
        return sock_connect_with_timeout(sock, (struct sockaddr *)&ad,
848
                                         sizeof(ad), io_timeout);
849
}
850

    
851
#else /* INET6 */
852

    
853
#ifdef G_OS_WIN32
854
static gboolean win32_ipv6_supported(void)
855
{
856
        static gboolean ipv6_checked = FALSE;
857
        HMODULE hmodule;
858

    
859
        if (ipv6_checked)
860
                return getaddrinfo_func != NULL;
861

    
862
        hmodule = GetModuleHandleA("ws2_32");
863
        if (hmodule) {
864
                getaddrinfo_func =
865
                        (GetAddrInfoFunc)GetProcAddress(hmodule, "getaddrinfo");
866
                freeaddrinfo_func =
867
                        (FreeAddrInfoFunc)GetProcAddress(hmodule, "freeaddrinfo");
868
                if (!getaddrinfo_func || !freeaddrinfo_func) {
869
                        getaddrinfo_func = NULL;
870
                        freeaddrinfo_func = NULL;
871
                }
872
        }
873

    
874
        if (getaddrinfo_func)
875
                debug_print("ws2_32 has IPv6 functions.\n");
876
        else
877
                debug_print("ws2_32 does not have IPv6 functions.\n");
878

    
879
        ipv6_checked = TRUE;
880
        return getaddrinfo_func != NULL;
881
}
882

    
883
/* subset of getaddrinfo() */
884
static int my_getaddrinfo(const char *node, const char *service,
885
                          const struct addrinfo *hintp,
886
                          struct addrinfo **res)
887
{
888
        struct addrinfo *ai;
889
        struct sockaddr_in addr, *paddr;
890
        struct addrinfo hints;
891
        gint port = 0;
892

    
893
        if (win32_ipv6_supported())
894
                return getaddrinfo_func(node, service, hintp, res);
895

    
896
        if (!hintp) {
897
                memset(&hints, 0, sizeof(hints));
898
                hints.ai_family = AF_INET;
899
                hints.ai_socktype = SOCK_STREAM;
900
        } else
901
                memcpy(&hints, hintp, sizeof(hints));
902

    
903
        if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET)
904
                return EAI_FAMILY;
905
        if (hints.ai_socktype == 0)
906
                hints.ai_socktype = SOCK_STREAM;
907
        if (hints.ai_protocol == 0)
908
                hints.ai_protocol = IPPROTO_TCP;
909
        if (hints.ai_socktype != SOCK_STREAM)
910
                return EAI_SOCKTYPE;
911
        if (hints.ai_protocol != IPPROTO_TCP)
912
                return EAI_SOCKTYPE;
913
#if 0
914
        if (!node && !service)
915
                return EAI_NONAME;
916
#endif
917
        if (!node || !service)
918
                return EAI_NONAME;
919

    
920
        port = atoi(service);
921

    
922
        memset(&addr, 0, sizeof(addr));
923
        addr.sin_family = AF_INET;
924
        addr.sin_port = htons(port);
925

    
926
        if (!my_inet_aton(node, &addr.sin_addr)) {
927
                struct hostent *hp;
928

    
929
                if ((hp = my_gethostbyname(node)) == NULL) {
930
                        fprintf(stderr, "%s: unknown host.\n", node);
931
                        errno = 0;
932
                        return EAI_NONAME;
933
                }
934
                if (hp->h_length != 4 && hp->h_length != 8) {
935
                        fprintf(stderr, "illegal address length received for host %s\n", node);
936
                        errno = 0;
937
                        return EAI_FAIL;
938
                }
939

    
940
                memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
941
        }
942

    
943
        ai = g_malloc0(sizeof(struct addrinfo));
944
        paddr = g_malloc0(sizeof(struct sockaddr_in));
945
        memcpy(paddr, &addr, sizeof(struct sockaddr_in));
946

    
947
        ai->ai_flags = 0;
948
        ai->ai_family = AF_INET;
949
        ai->ai_socktype = hints.ai_socktype;
950
        ai->ai_protocol = hints.ai_protocol;
951
        ai->ai_addrlen = sizeof(struct sockaddr_in);
952
        ai->ai_addr = (struct sockaddr *)paddr;
953
        ai->ai_canonname = NULL;
954
        ai->ai_next = NULL;
955

    
956
        *res = ai;
957

    
958
        return 0;
959
}
960

    
961
static void my_freeaddrinfo(struct addrinfo *res)
962
{
963
        if (win32_ipv6_supported()) {
964
                freeaddrinfo_func(res);
965
                return;
966
        }
967

    
968
        if (res) {
969
                g_free(res->ai_addr);
970
                g_free(res);
971
        }
972
}
973

    
974
/* MinGW defines gai_strerror() in ws2tcpip.h, but it is not implemented. */
975
#undef gai_strerror
976
const gchar *gai_strerror(gint errcode)
977
{
978
        static gchar str[32];
979

    
980
        g_snprintf(str, sizeof(str), "gai errcode: (%d)", errcode);
981
        return str;
982
}
983
#endif
984

    
985
static SockDesc sock_connect_by_getaddrinfo(const gchar *hostname, gushort port)
986
{
987
        SockDesc sock = INVALID_SOCKET;
988
        gint gai_error;
989
        struct addrinfo hints, *res, *ai;
990
        gchar port_str[6];
991

    
992
        resolver_init();
993

    
994
        memset(&hints, 0, sizeof(hints));
995
        /* hints.ai_flags = AI_CANONNAME; */
996
        hints.ai_family = AF_UNSPEC;
997
        hints.ai_socktype = SOCK_STREAM;
998
        hints.ai_protocol = IPPROTO_TCP;
999

    
1000
        /* convert port from integer to string. */
1001
        g_snprintf(port_str, sizeof(port_str), "%d", port);
1002

    
1003
        if ((gai_error = getaddrinfo(hostname, port_str, &hints, &res)) != 0) {
1004
                fprintf(stderr, "getaddrinfo for %s:%s failed: %s\n",
1005
                        hostname, port_str, gai_strerror(gai_error));
1006
                return INVALID_SOCKET;
1007
        }
1008

    
1009
        for (ai = res; ai != NULL; ai = ai->ai_next) {
1010
                sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1011
                if (!SOCKET_IS_VALID(sock))
1012
                        continue;
1013
                sock_set_buffer_size(sock);
1014

    
1015
                if (sock_connect_with_timeout
1016
                        (sock, ai->ai_addr, ai->ai_addrlen, io_timeout) == 0)
1017
                        break;
1018

    
1019
                fd_close(sock);
1020
        }
1021

    
1022
        if (res != NULL)
1023
                freeaddrinfo(res);
1024

    
1025
        if (ai == NULL)
1026
                return INVALID_SOCKET;
1027

    
1028
        return sock;
1029
}
1030
#endif /* !INET6 */
1031

    
1032
SockInfo *sock_connect(const gchar *hostname, gushort port)
1033
{
1034
        SockDesc sock;
1035
        SockInfo *sockinfo;
1036

    
1037
#ifdef INET6
1038
        sock = sock_connect_by_getaddrinfo(hostname, port);
1039
        if (!SOCKET_IS_VALID(sock))
1040
                return NULL;
1041
#else
1042
        sock = socket(AF_INET, SOCK_STREAM, 0);
1043
        if (!SOCKET_IS_VALID(sock)) {
1044
#ifdef G_OS_WIN32
1045
                g_warning("socket() failed: %ld\n", WSAGetLastError());
1046
#else
1047
                perror("socket");
1048
#endif /* G_OS_WIN32 */
1049
                return NULL;
1050
        }
1051
        sock_set_buffer_size(sock);
1052

    
1053
        if (sock_connect_by_hostname(sock, hostname, port) < 0) {
1054
                if (errno != 0) perror("connect");
1055
                fd_close(sock);
1056
                return NULL;
1057
        }
1058
#endif /* INET6 */
1059

    
1060
        sockinfo = g_new0(SockInfo, 1);
1061
        sockinfo->sock = sock;
1062
        sockinfo->sock_ch = g_io_channel_unix_new(sock);
1063
        sockinfo->hostname = g_strdup(hostname);
1064
        sockinfo->port = port;
1065
        sockinfo->state = CONN_ESTABLISHED;
1066
        sockinfo->flags = SYL_SOCK_CHECK_IO;
1067

    
1068
        sock_list = g_list_prepend(sock_list, sockinfo);
1069

    
1070
        g_usleep(100000);
1071

    
1072
        return sockinfo;
1073
}
1074

    
1075
#ifdef G_OS_UNIX
1076
static void sock_address_list_free(GList *addr_list)
1077
{
1078
        GList *cur;
1079

    
1080
        for (cur = addr_list; cur != NULL; cur = cur->next) {
1081
                SockAddrData *addr_data = (SockAddrData *)cur->data;
1082
                g_free(addr_data->addr);
1083
                g_free(addr_data);
1084
        }
1085

    
1086
        g_list_free(addr_list);
1087
}
1088

    
1089
/* asynchronous TCP connection */
1090

    
1091
static gboolean sock_connect_async_cb(GIOChannel *source,
1092
                                      GIOCondition condition, gpointer data)
1093
{
1094
        SockConnectData *conn_data = (SockConnectData *)data;
1095
        gint fd;
1096
        gint val;
1097
        guint len;
1098
        SockInfo *sockinfo;
1099

    
1100
        fd = g_io_channel_unix_get_fd(source);
1101

    
1102
        conn_data->io_tag = 0;
1103
        conn_data->channel = NULL;
1104
        g_io_channel_unref(source);
1105

    
1106
        if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
1107
                debug_print("sock_connect_async_cb: condition = %d\n",
1108
                            condition);
1109
                fd_close(fd);
1110
                sock_connect_address_list_async(conn_data);
1111
                return FALSE;
1112
        }
1113

    
1114
        len = sizeof(val);
1115
        if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len) < 0) {
1116
                perror("getsockopt");
1117
                fd_close(fd);
1118
                sock_connect_address_list_async(conn_data);
1119
                return FALSE;
1120
        }
1121

    
1122
        if (val != 0) {
1123
                debug_print("getsockopt(SOL_SOCKET, SO_ERROR) returned error\n");
1124
                fd_close(fd);
1125
                sock_connect_address_list_async(conn_data);
1126
                return FALSE;
1127
        }
1128

    
1129
        sockinfo = g_new0(SockInfo, 1);
1130
        sockinfo->sock = fd;
1131
        sockinfo->sock_ch = g_io_channel_unix_new(fd);
1132
        sockinfo->hostname = g_strdup(conn_data->hostname);
1133
        sockinfo->port = conn_data->port;
1134
        sockinfo->state = CONN_ESTABLISHED;
1135
        sockinfo->flags = SYL_SOCK_NONBLOCK;
1136

    
1137
        sock_list = g_list_prepend(sock_list, sockinfo);
1138

    
1139
        conn_data->func(sockinfo, conn_data->data);
1140

    
1141
        sock_connect_async_cancel(conn_data->id);
1142

    
1143
        return FALSE;
1144
}
1145

    
1146
static gint sock_connect_async_get_address_info_cb(GList *addr_list,
1147
                                                   gpointer data)
1148
{
1149
        SockConnectData *conn_data = (SockConnectData *)data;
1150

    
1151
        conn_data->addr_list = addr_list;
1152
        conn_data->cur_addr = addr_list;
1153
        conn_data->lookup_data = NULL;
1154

    
1155
        return sock_connect_address_list_async(conn_data);
1156
}
1157

    
1158
gint sock_connect_async(const gchar *hostname, gushort port,
1159
                        SockConnectFunc func, gpointer data)
1160
{
1161
        static gint id = 1;
1162
        SockConnectData *conn_data;
1163

    
1164
        conn_data = g_new0(SockConnectData, 1);
1165
        conn_data->id = id++;
1166
        conn_data->hostname = g_strdup(hostname);
1167
        conn_data->port = port;
1168
        conn_data->addr_list = NULL;
1169
        conn_data->cur_addr = NULL;
1170
        conn_data->io_tag = 0;
1171
        conn_data->func = func;
1172
        conn_data->data = data;
1173

    
1174
        conn_data->lookup_data = sock_get_address_info_async
1175
                (hostname, port, sock_connect_async_get_address_info_cb,
1176
                 conn_data);
1177

    
1178
        if (conn_data->lookup_data == NULL) {
1179
                g_free(conn_data->hostname);
1180
                g_free(conn_data);
1181
                return -1;
1182
        }
1183

    
1184
        sock_connect_data_list = g_list_append(sock_connect_data_list,
1185
                                               conn_data);
1186

    
1187
        return conn_data->id;
1188
}
1189

    
1190
gint sock_connect_async_cancel(gint id)
1191
{
1192
        SockConnectData *conn_data = NULL;
1193
        GList *cur;
1194

    
1195
        for (cur = sock_connect_data_list; cur != NULL; cur = cur->next) {
1196
                if (((SockConnectData *)cur->data)->id == id) {
1197
                        conn_data = (SockConnectData *)cur->data;
1198
                        break;
1199
                }
1200
        }
1201

    
1202
        if (conn_data) {
1203
                sock_connect_data_list = g_list_remove(sock_connect_data_list,
1204
                                                       conn_data);
1205

    
1206
                if (conn_data->lookup_data)
1207
                        sock_get_address_info_async_cancel
1208
                                (conn_data->lookup_data);
1209

    
1210
                if (conn_data->io_tag > 0)
1211
                        g_source_remove(conn_data->io_tag);
1212
                if (conn_data->channel) {
1213
                        g_io_channel_shutdown(conn_data->channel, FALSE, NULL);
1214
                        g_io_channel_unref(conn_data->channel);
1215
                }
1216

    
1217
                sock_address_list_free(conn_data->addr_list);
1218
                g_free(conn_data->hostname);
1219
                g_free(conn_data);
1220
        } else {
1221
                g_warning("sock_connect_async_cancel: id %d not found.\n", id);
1222
                return -1;
1223
        }
1224

    
1225
        return 0;
1226
}
1227

    
1228
static gint sock_connect_address_list_async(SockConnectData *conn_data)
1229
{
1230
        SockAddrData *addr_data;
1231
        gint sock = -1;
1232

    
1233
        for (; conn_data->cur_addr != NULL;
1234
             conn_data->cur_addr = conn_data->cur_addr->next) {
1235
                addr_data = (SockAddrData *)conn_data->cur_addr->data;
1236

    
1237
                if ((sock = socket(addr_data->family, addr_data->socktype,
1238
                                   addr_data->protocol)) < 0) {
1239
                        perror("socket");
1240
                        continue;
1241
                }
1242

    
1243
                sock_set_buffer_size(sock);
1244
                set_nonblocking_mode(sock, TRUE);
1245

    
1246
                if (connect(sock, addr_data->addr, addr_data->addr_len) < 0) {
1247
                        if (EINPROGRESS == errno) {
1248
                                break;
1249
                        } else {
1250
                                perror("connect");
1251
                                fd_close(sock);
1252
                        }
1253
                } else
1254
                        break;
1255
        }
1256

    
1257
        if (conn_data->cur_addr == NULL) {
1258
                g_warning("sock_connect_address_list_async: "
1259
                          "connection to %s:%d failed\n",
1260
                          conn_data->hostname, conn_data->port);
1261
                conn_data->func(NULL, conn_data->data);
1262
                sock_connect_async_cancel(conn_data->id);
1263
                return -1;
1264
        }
1265

    
1266
        debug_print("sock_connect_address_list_async: waiting for connect\n");
1267

    
1268
        conn_data->cur_addr = conn_data->cur_addr->next;
1269

    
1270
        conn_data->channel = g_io_channel_unix_new(sock);
1271
        conn_data->io_tag = g_io_add_watch
1272
                (conn_data->channel, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
1273
                 sock_connect_async_cb, conn_data);
1274

    
1275
        return 0;
1276
}
1277

    
1278
static gint sock_kill_process(pid_t pid)
1279
{
1280
        pid_t ret = (pid_t)-1;
1281

    
1282
        kill(pid, SIGKILL);
1283

    
1284
        while (ret == (pid_t)-1) {
1285
                if ((ret = waitpid(pid, NULL, 0)) != pid) {
1286
                        if (ret == (pid_t)-1 && errno != EINTR) {
1287
                                perror("sock_kill_process(): waitpid");
1288
                                break;
1289
                        }
1290
                }
1291
        }
1292

    
1293
        return (gint)pid;
1294
}
1295

    
1296
/* asynchronous DNS lookup */
1297

    
1298
static gboolean sock_get_address_info_async_cb(GIOChannel *source,
1299
                                               GIOCondition condition,
1300
                                               gpointer data)
1301
{
1302
        SockLookupData *lookup_data = (SockLookupData *)data;
1303
        GList *addr_list = NULL;
1304
        SockAddrData *addr_data;
1305
        gsize bytes_read;
1306
        gint ai_member[4];
1307
        struct sockaddr *addr;
1308

    
1309
        for (;;) {
1310
                if (g_io_channel_read(source, (gchar *)ai_member,
1311
                                      sizeof(ai_member), &bytes_read)
1312
                    != G_IO_ERROR_NONE) {
1313
                        g_warning("sock_get_address_info_async_cb: "
1314
                                  "address length read error\n");
1315
                        break;
1316
                }
1317

    
1318
                if (bytes_read == 0 || bytes_read != sizeof(ai_member))
1319
                        break;
1320

    
1321
                if (ai_member[0] == AF_UNSPEC) {
1322
                        g_warning("DNS lookup failed\n");
1323
                        break;
1324
                }
1325

    
1326
                addr = g_malloc(ai_member[3]);
1327
                if (g_io_channel_read(source, (gchar *)addr, ai_member[3],
1328
                                      &bytes_read)
1329
                    != G_IO_ERROR_NONE) {
1330
                        g_warning("sock_get_address_info_async_cb: "
1331
                                  "address data read error\n");
1332
                        g_free(addr);
1333
                        break;
1334
                }
1335

    
1336
                if (bytes_read != ai_member[3]) {
1337
                        g_warning("sock_get_address_info_async_cb: "
1338
                                  "incomplete address data\n");
1339
                        g_free(addr);
1340
                        break;
1341
                }
1342

    
1343
                addr_data = g_new0(SockAddrData, 1);
1344
                addr_data->family = ai_member[0];
1345
                addr_data->socktype = ai_member[1];
1346
                addr_data->protocol = ai_member[2];
1347
                addr_data->addr_len = ai_member[3];
1348
                addr_data->addr = addr;
1349

    
1350
                addr_list = g_list_append(addr_list, addr_data);
1351
        }
1352

    
1353
        g_io_channel_shutdown(source, FALSE, NULL);
1354
        g_io_channel_unref(source);
1355

    
1356
        sock_kill_process(lookup_data->child_pid);
1357

    
1358
        lookup_data->func(addr_list, lookup_data->data);
1359

    
1360
        g_free(lookup_data->hostname);
1361
        g_free(lookup_data);
1362

    
1363
        return FALSE;
1364
}
1365

    
1366
static SockLookupData *sock_get_address_info_async(const gchar *hostname,
1367
                                                   gushort port,
1368
                                                   SockAddrFunc func,
1369
                                                   gpointer data)
1370
{
1371
        SockLookupData *lookup_data = NULL;
1372
        gint pipe_fds[2];
1373
        pid_t pid;
1374

    
1375
        resolver_init();
1376

    
1377
        if (pipe(pipe_fds) < 0) {
1378
                perror("pipe");
1379
                func(NULL, data);
1380
                return NULL;
1381
        }
1382

    
1383
        if ((pid = fork()) < 0) {
1384
                perror("fork");
1385
                func(NULL, data);
1386
                return NULL;
1387
        }
1388

    
1389
        /* child process */
1390
        if (pid == 0) {
1391
#ifdef INET6
1392
                gint gai_err;
1393
                struct addrinfo hints, *res, *ai;
1394
                gchar port_str[6];
1395
#else /* !INET6 */
1396
                struct hostent *hp;
1397
                gchar **addr_list_p;
1398
                struct sockaddr_in ad;
1399
#endif /* INET6 */
1400
                gint ai_member[4] = {AF_UNSPEC, 0, 0, 0};
1401

    
1402
                close(pipe_fds[0]);
1403

    
1404
#ifdef INET6
1405
                memset(&hints, 0, sizeof(hints));
1406
                /* hints.ai_flags = AI_CANONNAME; */
1407
                hints.ai_family = AF_UNSPEC;
1408
                hints.ai_socktype = SOCK_STREAM;
1409
                hints.ai_protocol = IPPROTO_TCP;
1410

    
1411
                g_snprintf(port_str, sizeof(port_str), "%d", port);
1412

    
1413
                gai_err = getaddrinfo(hostname, port_str, &hints, &res);
1414
                if (gai_err != 0) {
1415
                        g_warning("getaddrinfo for %s:%s failed: %s\n",
1416
                                  hostname, port_str, gai_strerror(gai_err));
1417
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
1418
                                     sizeof(ai_member));
1419
                        close(pipe_fds[1]);
1420
                        _exit(1);
1421
                }
1422

    
1423
                for (ai = res; ai != NULL; ai = ai->ai_next) {
1424
                        ai_member[0] = ai->ai_family;
1425
                        ai_member[1] = ai->ai_socktype;
1426
                        ai_member[2] = ai->ai_protocol;
1427
                        ai_member[3] = ai->ai_addrlen;
1428

    
1429
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
1430
                                     sizeof(ai_member));
1431
                        fd_write_all(pipe_fds[1], (gchar *)ai->ai_addr,
1432
                                     ai->ai_addrlen);
1433
                }
1434

    
1435
                if (res != NULL)
1436
                        freeaddrinfo(res);
1437
#else /* !INET6 */
1438
                hp = my_gethostbyname(hostname);
1439
                if (hp == NULL || hp->h_addrtype != AF_INET) {
1440
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
1441
                                     sizeof(ai_member));
1442
                        close(pipe_fds[1]);
1443
                        _exit(1);
1444
                }
1445

    
1446
                ai_member[0] = AF_INET;
1447
                ai_member[1] = SOCK_STREAM;
1448
                ai_member[2] = IPPROTO_TCP;
1449
                ai_member[3] = sizeof(ad);
1450

    
1451
                memset(&ad, 0, sizeof(ad));
1452
                ad.sin_family = AF_INET;
1453
                ad.sin_port = htons(port);
1454

    
1455
                for (addr_list_p = hp->h_addr_list; *addr_list_p != NULL;
1456
                     addr_list_p++) {
1457
                        memcpy(&ad.sin_addr, *addr_list_p, hp->h_length);
1458
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
1459
                                     sizeof(ai_member));
1460
                        fd_write_all(pipe_fds[1], (gchar *)&ad, sizeof(ad));
1461
                }
1462
#endif /* INET6 */
1463

    
1464
                close(pipe_fds[1]);
1465

    
1466
                _exit(0);
1467
        } else {
1468
                close(pipe_fds[1]);
1469

    
1470
                lookup_data = g_new0(SockLookupData, 1);
1471
                lookup_data->hostname = g_strdup(hostname);
1472
                lookup_data->child_pid = pid;
1473
                lookup_data->func = func;
1474
                lookup_data->data = data;
1475

    
1476
                lookup_data->channel = g_io_channel_unix_new(pipe_fds[0]);
1477
                lookup_data->io_tag = g_io_add_watch
1478
                        (lookup_data->channel, G_IO_IN,
1479
                         sock_get_address_info_async_cb, lookup_data);
1480
        }
1481

    
1482
        return lookup_data;
1483
}
1484

    
1485
static gint sock_get_address_info_async_cancel(SockLookupData *lookup_data)
1486
{
1487
        if (lookup_data->io_tag > 0)
1488
                g_source_remove(lookup_data->io_tag);
1489
        if (lookup_data->channel) {
1490
                g_io_channel_shutdown(lookup_data->channel, FALSE, NULL);
1491
                g_io_channel_unref(lookup_data->channel);
1492
        }
1493

    
1494
        if (lookup_data->child_pid > 0)
1495
                sock_kill_process(lookup_data->child_pid);
1496

    
1497
        g_free(lookup_data->hostname);
1498
        g_free(lookup_data);
1499

    
1500
        return 0;
1501
}
1502
#endif /* G_OS_UNIX */
1503

    
1504
#if USE_THREADS
1505
static gpointer sock_connect_async_func(gpointer data)
1506
{
1507
        SockConnectData *conn_data = (SockConnectData *)data;
1508
        gint ret;
1509

    
1510
        conn_data->sock = sock_connect(conn_data->hostname, conn_data->port);
1511

    
1512
        if (conn_data->sock) {
1513
                debug_print("sock_connect_async_func: connected\n");
1514
                ret = 0;
1515
        } else {
1516
                debug_print("sock_connect_async_func: connection failed\n");
1517
                ret = -1;
1518
        }
1519

    
1520
        g_atomic_int_set(&conn_data->flag, 1);
1521
        g_main_context_wakeup(NULL);
1522

    
1523
        debug_print("sock_connect_async_func: exit\n");
1524
        return GINT_TO_POINTER(ret);
1525
}
1526

    
1527
gint sock_connect_async_thread(const gchar *hostname, gushort port)
1528
{
1529
        static gint id = 1;
1530
        SockConnectData *data;
1531

    
1532
        data = g_new0(SockConnectData, 1);
1533
        data->id = id++;
1534
        data->hostname = g_strdup(hostname);
1535
        data->port = port;
1536
        data->flag = 0;
1537
        data->sock = NULL;
1538

    
1539
        data->thread = g_thread_create(sock_connect_async_func, data, TRUE,
1540
                                       NULL);
1541
        if (!data->thread) {
1542
                g_free(data->hostname);
1543
                g_free(data);
1544
                return -1;
1545
        }
1546

    
1547
        sock_connect_data_list = g_list_append(sock_connect_data_list, data);
1548

    
1549
        return data->id;
1550
}
1551

    
1552
gint sock_connect_async_thread_wait(gint id, SockInfo **sock)
1553
{
1554
        SockConnectData *conn_data = NULL;
1555
        GList *cur;
1556
        gint ret;
1557

    
1558
        for (cur = sock_connect_data_list; cur != NULL; cur = cur->next) {
1559
                if (((SockConnectData *)cur->data)->id == id) {
1560
                        conn_data = (SockConnectData *)cur->data;
1561
                        break;
1562
                }
1563
        }
1564

    
1565
        if (!conn_data) {
1566
                g_warning("sock_connect_async_thread_wait: id %d not found.", id);
1567
                return -1;
1568
        }
1569

    
1570
        debug_print("sock_connect_async_thread_wait: waiting thread\n");
1571
        while (g_atomic_int_get(&conn_data->flag) == 0)
1572
                event_loop_iterate();
1573

    
1574
        ret = GPOINTER_TO_INT(g_thread_join(conn_data->thread));
1575
        debug_print("sock_connect_async_thread_wait: thread exited with status %d\n", ret);
1576

    
1577
        *sock = conn_data->sock;
1578

    
1579
        sock_connect_data_list = g_list_remove(sock_connect_data_list,
1580
                                               conn_data);
1581
        g_free(conn_data->hostname);
1582
        g_free(conn_data);
1583

    
1584
        return ret;
1585
}
1586
#endif /* USE_THREADS */
1587

    
1588
gint sock_printf(SockInfo *sock, const gchar *format, ...)
1589
{
1590
        va_list args;
1591
        gchar buf[BUFFSIZE];
1592

    
1593
        va_start(args, format);
1594
        g_vsnprintf(buf, sizeof(buf), format, args);
1595
        va_end(args);
1596

    
1597
        return sock_write_all(sock, buf, strlen(buf));
1598
}
1599

    
1600
#ifdef G_OS_WIN32
1601
static void sock_set_errno_from_last_error(gint error)
1602
{
1603
        switch (error) {
1604
        case WSAEWOULDBLOCK:
1605
                errno = EAGAIN;
1606
                break;
1607
        default:
1608
                debug_print("last error = %d\n", error);
1609
                errno = 0;
1610
                break;
1611
        }
1612
}
1613
#endif
1614

    
1615
gint sock_read(SockInfo *sock, gchar *buf, gint len)
1616
{
1617
        g_return_val_if_fail(sock != NULL, -1);
1618

    
1619
#if USE_SSL
1620
        if (sock->ssl)
1621
                return ssl_read(sock->ssl, buf, len);
1622
#endif
1623
        return fd_read(sock->sock, buf, len);
1624
}
1625

    
1626
gint fd_read(gint fd, gchar *buf, gint len)
1627
{
1628
#ifdef G_OS_WIN32
1629
        return fd_recv(fd, buf, len, 0);
1630
#else
1631
        if (fd_check_io(fd, G_IO_IN) < 0)
1632
                return -1;
1633

    
1634
        return read(fd, buf, len);
1635
#endif
1636
}
1637

    
1638
#if USE_SSL
1639
gint ssl_read(SSL *ssl, gchar *buf, gint len)
1640
{
1641
        gint err, ret;
1642

    
1643
        errno = 0;
1644

    
1645
        if (SSL_pending(ssl) == 0) {
1646
                if (fd_check_io(SSL_get_rfd(ssl), G_IO_IN) < 0)
1647
                        return -1;
1648
        }
1649

    
1650
        ret = SSL_read(ssl, buf, len);
1651

    
1652
        switch ((err = SSL_get_error(ssl, ret))) {
1653
        case SSL_ERROR_NONE:
1654
                return ret;
1655
        case SSL_ERROR_WANT_READ:
1656
        case SSL_ERROR_WANT_WRITE:
1657
                errno = EAGAIN;
1658
                return -1;
1659
        case SSL_ERROR_ZERO_RETURN:
1660
                return 0;
1661
        default:
1662
                g_warning("SSL_read() returned error %d, ret = %d\n", err, ret);
1663
                if (ret == 0)
1664
                        return 0;
1665
#ifdef G_OS_WIN32
1666
                errno = EIO;
1667
#endif
1668
                return -1;
1669
        }
1670
}
1671
#endif
1672

    
1673
gint sock_write(SockInfo *sock, const gchar *buf, gint len)
1674
{
1675
        g_return_val_if_fail(sock != NULL, -1);
1676

    
1677
#if USE_SSL
1678
        if (sock->ssl)
1679
                return ssl_write(sock->ssl, buf, len);
1680
#endif
1681
        return fd_write(sock->sock, buf, len);
1682
}
1683

    
1684
gint fd_write(gint fd, const gchar *buf, gint len)
1685
{
1686
#ifdef G_OS_WIN32
1687
        gint ret;
1688
#endif
1689
        if (fd_check_io(fd, G_IO_OUT) < 0)
1690
                return -1;
1691

    
1692
#ifdef G_OS_WIN32
1693
        ret = send(fd, buf, len, 0);
1694
        if (ret == SOCKET_ERROR) {
1695
                gint err;
1696
                err = WSAGetLastError();
1697
                sock_set_errno_from_last_error(err);
1698
                if (err != WSAEWOULDBLOCK)
1699
                        g_warning("fd_write() failed with %d (errno = %d)\n",
1700
                                  err, errno);
1701
        }
1702
        return ret;
1703
#else
1704
        return write(fd, buf, len);
1705
#endif
1706
}
1707

    
1708
#if USE_SSL
1709
gint ssl_write(SSL *ssl, const gchar *buf, gint len)
1710
{
1711
        gint ret;
1712

    
1713
        ret = SSL_write(ssl, buf, len);
1714

    
1715
        switch (SSL_get_error(ssl, ret)) {
1716
        case SSL_ERROR_NONE:
1717
                return ret;
1718
        case SSL_ERROR_WANT_READ:
1719
        case SSL_ERROR_WANT_WRITE:
1720
                errno = EAGAIN;
1721
                return -1;
1722
        default:
1723
                return -1;
1724
        }
1725
}
1726
#endif
1727

    
1728
gint sock_write_all(SockInfo *sock, const gchar *buf, gint len)
1729
{
1730
        g_return_val_if_fail(sock != NULL, -1);
1731

    
1732
#if USE_SSL
1733
        if (sock->ssl)
1734
                return ssl_write_all(sock->ssl, buf, len);
1735
#endif
1736
        return fd_write_all(sock->sock, buf, len);
1737
}
1738

    
1739
gint fd_write_all(gint fd, const gchar *buf, gint len)
1740
{
1741
        gint n, wrlen = 0;
1742

    
1743
        while (len) {
1744
                n = fd_write(fd, buf, len);
1745
                if (n <= 0)
1746
                        return -1;
1747
                len -= n;
1748
                wrlen += n;
1749
                buf += n;
1750
        }
1751

    
1752
        return wrlen;
1753
}
1754

    
1755
#if USE_SSL
1756
gint ssl_write_all(SSL *ssl, const gchar *buf, gint len)
1757
{
1758
        gint n, wrlen = 0;
1759

    
1760
        while (len) {
1761
                n = ssl_write(ssl, buf, len);
1762
                if (n <= 0)
1763
                        return -1;
1764
                len -= n;
1765
                wrlen += n;
1766
                buf += n;
1767
        }
1768

    
1769
        return wrlen;
1770
}
1771
#endif
1772

    
1773
gint fd_recv(gint fd, gchar *buf, gint len, gint flags)
1774
{
1775
#ifdef G_OS_WIN32
1776
        gint ret;
1777
#endif
1778
        if (fd_check_io(fd, G_IO_IN) < 0)
1779
                return -1;
1780

    
1781
#ifdef G_OS_WIN32
1782
        ret = recv(fd, buf, len, flags);
1783
        if (ret == SOCKET_ERROR) {
1784
                gint err;
1785
                err = WSAGetLastError();
1786
                sock_set_errno_from_last_error(err);
1787
                if (err != WSAEWOULDBLOCK)
1788
                        g_warning("fd_recv(): failed with %d (errno = %d)\n",
1789
                                  err, errno);
1790
        }
1791
        return ret;
1792
#else
1793
        return recv(fd, buf, len, flags);
1794
#endif
1795
}
1796

    
1797
gint fd_gets(gint fd, gchar *buf, gint len)
1798
{
1799
        gchar *newline, *bp = buf;
1800
        gint n;
1801

    
1802
        if (--len < 1)
1803
                return -1;
1804
        do {
1805
                if ((n = fd_recv(fd, bp, len, MSG_PEEK)) <= 0)
1806
                        return -1;
1807
                if ((newline = memchr(bp, '\n', n)) != NULL)
1808
                        n = newline - bp + 1;
1809
                if ((n = fd_read(fd, bp, n)) < 0)
1810
                        return -1;
1811
                bp += n;
1812
                len -= n;
1813
        } while (!newline && len);
1814

    
1815
        *bp = '\0';
1816
        return bp - buf;
1817
}
1818

    
1819
#if USE_SSL
1820
gint ssl_gets(SSL *ssl, gchar *buf, gint len)
1821
{
1822
        gchar *newline, *bp = buf;
1823
        gint n;
1824

    
1825
        if (--len < 1)
1826
                return -1;
1827
        do {
1828
                if ((n = ssl_peek(ssl, bp, len)) <= 0)
1829
                        return -1;
1830
                if ((newline = memchr(bp, '\n', n)) != NULL)
1831
                        n = newline - bp + 1;
1832
                if ((n = ssl_read(ssl, bp, n)) < 0)
1833
                        return -1;
1834
                bp += n;
1835
                len -= n;
1836
        } while (!newline && len);
1837

    
1838
        *bp = '\0';
1839
        return bp - buf;
1840
}
1841
#endif
1842

    
1843
gint sock_gets(SockInfo *sock, gchar *buf, gint len)
1844
{
1845
        g_return_val_if_fail(sock != NULL, -1);
1846

    
1847
#if USE_SSL
1848
        if (sock->ssl)
1849
                return ssl_gets(sock->ssl, buf, len);
1850
#endif
1851
        return fd_gets(sock->sock, buf, len);
1852
}
1853

    
1854
gint fd_getline(gint fd, gchar **line)
1855
{
1856
        gchar buf[BUFFSIZE];
1857
        gchar *str = NULL;
1858
        gint len;
1859
        gulong size = 0;
1860
        gulong cur_offset = 0;
1861

    
1862
        while ((len = fd_gets(fd, buf, sizeof(buf))) > 0) {
1863
                size += len;
1864
                str = g_realloc(str, size + 1);
1865
                memcpy(str + cur_offset, buf, len + 1);
1866
                cur_offset += len;
1867
                if (buf[len - 1] == '\n')
1868
                        break;
1869
        }
1870

    
1871
        *line = str;
1872

    
1873
        if (!str)
1874
                return -1;
1875
        else
1876
                return (gint)size;
1877
}
1878

    
1879
#if USE_SSL
1880
gint ssl_getline(SSL *ssl, gchar **line)
1881
{
1882
        gchar buf[BUFFSIZE];
1883
        gchar *str = NULL;
1884
        gint len;
1885
        gulong size = 0;
1886
        gulong cur_offset = 0;
1887

    
1888
        while ((len = ssl_gets(ssl, buf, sizeof(buf))) > 0) {
1889
                size += len;
1890
                str = g_realloc(str, size + 1);
1891
                memcpy(str + cur_offset, buf, len + 1);
1892
                cur_offset += len;
1893
                if (buf[len - 1] == '\n')
1894
                        break;
1895
        }
1896

    
1897
        *line = str;
1898

    
1899
        if (!str)
1900
                return -1;
1901
        else
1902
                return (gint)size;
1903
}
1904
#endif
1905

    
1906
gint sock_getline(SockInfo *sock, gchar **line)
1907
{
1908
        g_return_val_if_fail(sock != NULL, -1);
1909
        g_return_val_if_fail(line != NULL, -1);
1910

    
1911
#if USE_SSL
1912
        if (sock->ssl)
1913
                return ssl_getline(sock->ssl, line);
1914
#endif
1915
        return fd_getline(sock->sock, line);
1916
}
1917

    
1918
gint sock_puts(SockInfo *sock, const gchar *buf)
1919
{
1920
        gint ret;
1921

    
1922
        if ((ret = sock_write_all(sock, buf, strlen(buf))) < 0)
1923
                return ret;
1924
        return sock_write_all(sock, "\r\n", 2);
1925
}
1926

    
1927
/* peek at the socket data without actually reading it */
1928
#if USE_SSL
1929
gint ssl_peek(SSL *ssl, gchar *buf, gint len)
1930
{
1931
        gint err, ret;
1932

    
1933
        if (SSL_pending(ssl) == 0) {
1934
                if (fd_check_io(SSL_get_rfd(ssl), G_IO_IN) < 0)
1935
                        return -1;
1936
        }
1937

    
1938
        ret = SSL_peek(ssl, buf, len);
1939

    
1940
        switch ((err = SSL_get_error(ssl, ret))) {
1941
        case SSL_ERROR_NONE:
1942
                return ret;
1943
        case SSL_ERROR_WANT_READ:
1944
        case SSL_ERROR_WANT_WRITE:
1945
                errno = EAGAIN;
1946
                return -1;
1947
        case SSL_ERROR_ZERO_RETURN:
1948
                return 0;
1949
        default:
1950
                g_warning("SSL_peek() returned error %d, ret = %d\n", err, ret);
1951
                if (ret == 0)
1952
                        return 0;
1953
                return -1;
1954
        }
1955
}
1956
#endif
1957

    
1958
gint sock_peek(SockInfo *sock, gchar *buf, gint len)
1959
{
1960
        g_return_val_if_fail(sock != NULL, -1);
1961

    
1962
#if USE_SSL
1963
        if (sock->ssl)
1964
                return ssl_peek(sock->ssl, buf, len);
1965
#endif
1966
        return fd_recv(sock->sock, buf, len, MSG_PEEK);
1967
}
1968

    
1969
gint sock_close(SockInfo *sock)
1970
{
1971
        GList *cur;
1972

    
1973
        if (!sock)
1974
                return 0;
1975

    
1976
#if USE_SSL
1977
        if (sock->ssl)
1978
                ssl_done_socket(sock);
1979
#endif
1980

    
1981
        if (sock->sock_ch) {
1982
                g_io_channel_shutdown(sock->sock_ch, FALSE, NULL);
1983
                g_io_channel_unref(sock->sock_ch);
1984
        }
1985

    
1986
        for (cur = sock_list; cur != NULL; cur = cur->next) {
1987
                if ((SockInfo *)cur->data == sock) {
1988
                        sock_list = g_list_remove(sock_list, sock);
1989
                        break;
1990
                }
1991
        }
1992

    
1993
        g_free(sock->hostname);
1994
        g_free(sock);
1995

    
1996
        return 0;
1997
}
1998

    
1999
gint fd_close(gint fd)
2000
{
2001
#ifdef G_OS_WIN32
2002
        return closesocket(fd);
2003
#else
2004
        return close(fd);
2005
#endif
2006
}