Statistics
| Revision:

root / src / socket.c @ 1

History | View | Annotate | Download (26 KB)

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/un.h>
30
#include <netinet/in.h>
31
#include <arpa/inet.h>
32
#include <netdb.h>
33
#include <unistd.h>
34
#include <stdio.h>
35
#include <string.h>
36
#include <stdarg.h>
37
#include <fcntl.h>
38
#include <errno.h>
39
#include <signal.h>
40
#include <setjmp.h>
41
#if HAVE_SYS_SELECT_H
42
#  include <sys/select.h>
43
#endif
44

    
45
#include "socket.h"
46
#if USE_SSL
47
#  include "ssl.h"
48
#endif
49

    
50
#define BUFFSIZE        8192
51

    
52
typedef gint (*SockAddrFunc)        (GList                *addr_list,
53
                                 gpointer         data);
54

    
55
typedef struct _SockConnectData        SockConnectData;
56
typedef struct _SockLookupData        SockLookupData;
57
typedef struct _SockAddrData        SockAddrData;
58
typedef struct _SockSource        SockSource;
59

    
60
struct _SockConnectData {
61
        gint id;
62
        gchar *hostname;
63
        gushort port;
64
        GList *addr_list;
65
        GList *cur_addr;
66
        SockLookupData *lookup_data;
67
        GIOChannel *channel;
68
        guint io_tag;
69
        SockConnectFunc func;
70
        gpointer data;
71
};
72

    
73
struct _SockLookupData {
74
        gchar *hostname;
75
        pid_t child_pid;
76
        GIOChannel *channel;
77
        guint io_tag;
78
        SockAddrFunc func;
79
        gpointer data;
80
};
81

    
82
struct _SockAddrData {
83
        gint family;
84
        gint socktype;
85
        gint protocol;
86
        gint addr_len;
87
        struct sockaddr *addr;
88
};
89

    
90
struct _SockSource {
91
        GSource parent;
92
        SockInfo *sock;
93
};
94

    
95
static guint io_timeout = 60;
96

    
97
static GList *sock_connect_data_list = NULL;
98

    
99
static gboolean sock_prepare                (GSource        *source,
100
                                         gint                *timeout);
101
static gboolean sock_check                (GSource        *source);
102
static gboolean sock_dispatch                (GSource        *source,
103
                                         GSourceFunc         callback,
104
                                         gpointer         user_data);
105

    
106
GSourceFuncs sock_watch_funcs = {
107
        sock_prepare,
108
        sock_check,
109
        sock_dispatch,
110
        NULL
111
};
112

    
113
static gint sock_connect_with_timeout        (gint                         sock,
114
                                         const struct sockaddr        *serv_addr,
115
                                         gint                         addrlen,
116
                                         guint                         timeout_secs);
117

    
118
#ifndef INET6
119
static gint sock_connect_by_hostname        (gint                 sock,
120
                                         const gchar        *hostname,
121
                                         gushort         port);
122
#else
123
static gint sock_connect_by_getaddrinfo        (const gchar        *hostname,
124
                                         gushort         port);
125
#endif
126

    
127
static void sock_address_list_free                (GList                *addr_list);
128

    
129
static gboolean sock_connect_async_cb                (GIOChannel        *source,
130
                                                 GIOCondition         condition,
131
                                                 gpointer         data);
132
static gint sock_connect_async_get_address_info_cb
133
                                                (GList                *addr_list,
134
                                                 gpointer         data);
135

    
136
static gint sock_connect_address_list_async        (SockConnectData *conn_data);
137

    
138
static gboolean sock_get_address_info_async_cb        (GIOChannel        *source,
139
                                                 GIOCondition         condition,
140
                                                 gpointer         data);
141
static SockLookupData *sock_get_address_info_async
142
                                                (const gchar        *hostname,
143
                                                 gushort         port,
144
                                                 SockAddrFunc         func,
145
                                                 gpointer         data);
146
static gint sock_get_address_info_async_cancel        (SockLookupData        *lookup_data);
147

    
148

    
149
gint sock_set_io_timeout(guint sec)
150
{
151
        io_timeout = sec;
152
        return 0;
153
}
154

    
155
gint fd_connect_unix(const gchar *path)
156
{
157
        gint sock;
158
        struct sockaddr_un addr;
159

    
160
        sock = socket(PF_UNIX, SOCK_STREAM, 0);
161
        if (sock < 0) {
162
                perror("sock_connect_unix(): socket");
163
                return -1;
164
        }
165

    
166
        memset(&addr, 0, sizeof(addr));
167
        addr.sun_family = AF_UNIX;
168
        strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
169

    
170
        if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
171
                close(sock);
172
                return -1;
173
        }
174

    
175
        return sock;
176
}
177

    
178
gint fd_open_unix(const gchar *path)
179
{
180
        gint sock;
181
        struct sockaddr_un addr;
182

    
183
        sock = socket(PF_UNIX, SOCK_STREAM, 0);
184

    
185
        if (sock < 0) {
186
                perror("sock_open_unix(): socket");
187
                return -1;
188
        }
189

    
190
        memset(&addr, 0, sizeof(addr));
191
        addr.sun_family = AF_UNIX;
192
        strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
193

    
194
        if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
195
                perror("bind");
196
                close(sock);
197
                return -1;
198
        }
199

    
200
        if (listen(sock, 1) < 0) {
201
                perror("listen");
202
                close(sock);
203
                return -1;                
204
        }
205

    
206
        return sock;
207
}
208

    
209
gint fd_accept(gint sock)
210
{
211
        struct sockaddr_in caddr;
212
        gint caddr_len;
213

    
214
        caddr_len = sizeof(caddr);
215
        return accept(sock, (struct sockaddr *)&caddr, &caddr_len);
216
}
217

    
218

    
219
static gint set_nonblocking_mode(gint fd, gboolean nonblock)
220
{
221
        gint flags;
222

    
223
        flags = fcntl(fd, F_GETFL, 0);
224
        if (flags < 0) {
225
                perror("fcntl");
226
                return -1;
227
        }
228

    
229
        if (nonblock)
230
                flags |= O_NONBLOCK;
231
        else
232
                flags &= ~O_NONBLOCK;
233

    
234
        return fcntl(fd, F_SETFL, flags);
235
}
236

    
237
gint sock_set_nonblocking_mode(SockInfo *sock, gboolean nonblock)
238
{
239
        g_return_val_if_fail(sock != NULL, -1);
240

    
241
        return set_nonblocking_mode(sock->sock, nonblock);
242
}
243

    
244
static gboolean is_nonblocking_mode(gint fd)
245
{
246
        gint flags;
247

    
248
        flags = fcntl(fd, F_GETFL, 0);
249
        if (flags < 0) {
250
                perror("fcntl");
251
                return FALSE;
252
        }
253

    
254
        return ((flags & O_NONBLOCK) != 0);
255
}
256

    
257
gboolean sock_is_nonblocking_mode(SockInfo *sock)
258
{
259
        g_return_val_if_fail(sock != NULL, FALSE);
260

    
261
        return is_nonblocking_mode(sock->sock);
262
}
263

    
264

    
265
static gboolean sock_prepare(GSource *source, gint *timeout)
266
{
267
        *timeout = 1;
268
        return FALSE;
269
}
270

    
271
static gboolean sock_check(GSource *source)
272
{
273
        SockInfo *sock = ((SockSource *)source)->sock;
274
        struct timeval timeout = {0, 0};
275
        fd_set fds;
276
        GIOCondition condition = sock->condition;
277

    
278
#if USE_SSL
279
        if (sock->ssl) {
280
                if (condition & G_IO_IN) {
281
                        if (SSL_pending(sock->ssl) > 0)
282
                                return TRUE;
283
                        if (SSL_want_write(sock->ssl))
284
                                condition |= G_IO_OUT;
285
                }
286

    
287
                if (condition & G_IO_OUT) {
288
                        if (SSL_want_read(sock->ssl))
289
                                condition |= G_IO_IN;
290
                }
291
        }
292
#endif
293

    
294
        FD_ZERO(&fds);
295
        FD_SET(sock->sock, &fds);
296

    
297
        select(sock->sock + 1,
298
               (condition & G_IO_IN)  ? &fds : NULL,
299
               (condition & G_IO_OUT) ? &fds : NULL,
300
               NULL, &timeout);
301

    
302
        return FD_ISSET(sock->sock, &fds) != 0;
303
}
304

    
305
static gboolean sock_dispatch(GSource *source, GSourceFunc callback,
306
                              gpointer user_data)
307
{
308
        SockInfo *sock = ((SockSource *)source)->sock;
309

    
310
        return sock->callback(sock, sock->condition, sock->data);
311
}
312

    
313
static gboolean sock_watch_cb(GIOChannel *source, GIOCondition condition,
314
                              gpointer data)
315
{
316
        SockInfo *sock = (SockInfo *)data;
317

    
318
        return sock->callback(sock, condition, sock->data);
319
}
320

    
321
guint sock_add_watch(SockInfo *sock, GIOCondition condition, SockFunc func,
322
                     gpointer data)
323
{
324
        sock->callback = func;
325
        sock->condition = condition;
326
        sock->data = data;
327

    
328
#if USE_SSL
329
        if (sock->ssl) {
330
                GSource *source;
331

    
332
                source = g_source_new(&sock_watch_funcs, sizeof(SockSource));
333
                ((SockSource *)source)->sock = sock;
334
                g_source_set_priority(source, G_PRIORITY_DEFAULT);
335
                g_source_set_can_recurse(source, FALSE);
336
                g_source_attach(source, NULL);
337
        }
338
#endif
339

    
340
        return g_io_add_watch(sock->sock_ch, condition, sock_watch_cb, sock);
341
}
342

    
343
static gint fd_check_io(gint fd, GIOCondition cond)
344
{
345
        struct timeval timeout;
346
        fd_set fds;
347

    
348
        if (is_nonblocking_mode(fd))
349
                return 0;
350

    
351
        timeout.tv_sec  = io_timeout;
352
        timeout.tv_usec = 0;
353

    
354
        FD_ZERO(&fds);
355
        FD_SET(fd, &fds);
356

    
357
        if (cond == G_IO_IN) {
358
                select(fd + 1, &fds, NULL, NULL,
359
                       io_timeout > 0 ? &timeout : NULL);
360
        } else {
361
                select(fd + 1, NULL, &fds, NULL,
362
                       io_timeout > 0 ? &timeout : NULL);
363
        }
364

    
365
        if (FD_ISSET(fd, &fds)) {
366
                return 0;
367
        } else {
368
                g_warning("Socket IO timeout\n");
369
                return -1;
370
        }
371
}
372

    
373
static sigjmp_buf jmpenv;
374

    
375
static void timeout_handler(gint sig)
376
{
377
        siglongjmp(jmpenv, 1);
378
}
379

    
380
static gint sock_connect_with_timeout(gint sock,
381
                                      const struct sockaddr *serv_addr,
382
                                      gint addrlen,
383
                                      guint timeout_secs)
384
{
385
        gint ret;
386
        void (*prev_handler)(gint);
387

    
388
        alarm(0);
389
        prev_handler = signal(SIGALRM, timeout_handler);
390
        if (sigsetjmp(jmpenv, 1)) {
391
                alarm(0);
392
                signal(SIGALRM, prev_handler);
393
                errno = ETIMEDOUT;
394
                return -1;
395
        }
396
        alarm(timeout_secs);
397

    
398
        ret = connect(sock, serv_addr, addrlen);
399

    
400
        alarm(0);
401
        signal(SIGALRM, prev_handler);
402

    
403
        return ret;
404
}
405

    
406
struct hostent *my_gethostbyname(const gchar *hostname)
407
{
408
        struct hostent *hp;
409
        void (*prev_handler)(gint);
410

    
411
        alarm(0);
412
        prev_handler = signal(SIGALRM, timeout_handler);
413
        if (sigsetjmp(jmpenv, 1)) {
414
                alarm(0);
415
                signal(SIGALRM, prev_handler);
416
                fprintf(stderr, "%s: host lookup timed out.\n", hostname);
417
                errno = 0;
418
                return NULL;
419
        }
420
        alarm(io_timeout);
421

    
422
        if ((hp = gethostbyname(hostname)) == NULL) {
423
                alarm(0);
424
                signal(SIGALRM, prev_handler);
425
                fprintf(stderr, "%s: unknown host.\n", hostname);
426
                errno = 0;
427
                return NULL;
428
        }
429

    
430
        alarm(0);
431
        signal(SIGALRM, prev_handler);
432

    
433
        return hp;
434
}
435

    
436
#ifndef INET6
437
static gint my_inet_aton(const gchar *hostname, struct in_addr *inp)
438
{
439
#if HAVE_INET_ATON
440
        return inet_aton(hostname, inp);
441
#else
442
#if HAVE_INET_ADDR
443
        guint32 inaddr;
444

    
445
        inaddr = inet_addr(hostname);
446
        if (inaddr != -1) {
447
                memcpy(inp, &inaddr, sizeof(inaddr));
448
                return 1;
449
        } else
450
                return 0;
451
#else
452
        return 0;
453
#endif
454
#endif /* HAVE_INET_ATON */
455
}
456

    
457
static gint sock_connect_by_hostname(gint sock, const gchar *hostname,
458
                                     gushort port)
459
{
460
        struct hostent *hp;
461
        struct sockaddr_in ad;
462

    
463
        memset(&ad, 0, sizeof(ad));
464
        ad.sin_family = AF_INET;
465
        ad.sin_port = htons(port);
466

    
467
        if (!my_inet_aton(hostname, &ad.sin_addr)) {
468
                if ((hp = my_gethostbyname(hostname)) == NULL) {
469
                        fprintf(stderr, "%s: unknown host.\n", hostname);
470
                        errno = 0;
471
                        return -1;
472
                }
473

    
474
                if (hp->h_length != 4 && hp->h_length != 8) {
475
                        fprintf(stderr, "illegal address length received for host %s\n", hostname);
476
                        errno = 0;
477
                        return -1;
478
                }
479

    
480
                memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
481
        }
482

    
483
        return sock_connect_with_timeout(sock, (struct sockaddr *)&ad,
484
                                         sizeof(ad), io_timeout);
485
}
486

    
487
#else /* INET6 */
488
static gint sock_connect_by_getaddrinfo(const gchar *hostname, gushort        port)
489
{
490
        gint sock = -1, gai_error;
491
        struct addrinfo hints, *res, *ai;
492
        gchar port_str[6];
493

    
494
        memset(&hints, 0, sizeof(hints));
495
        /* hints.ai_flags = AI_CANONNAME; */
496
        hints.ai_family = AF_UNSPEC;
497
        hints.ai_socktype = SOCK_STREAM;
498
        hints.ai_protocol = IPPROTO_TCP;
499

    
500
        /* convert port from integer to string. */
501
        g_snprintf(port_str, sizeof(port_str), "%d", port);
502

    
503
        if ((gai_error = getaddrinfo(hostname, port_str, &hints, &res)) != 0) {
504
                fprintf(stderr, "getaddrinfo for %s:%s failed: %s\n",
505
                        hostname, port_str, gai_strerror(gai_error));
506
                return -1;
507
        }
508

    
509
        for (ai = res; ai != NULL; ai = ai->ai_next) {
510
                sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
511
                if (sock < 0)
512
                        continue;
513

    
514
                if (sock_connect_with_timeout
515
                        (sock, ai->ai_addr, ai->ai_addrlen, io_timeout) == 0)
516
                        break;
517

    
518
                close(sock);
519
        }
520

    
521
        if (res != NULL)
522
                freeaddrinfo(res);
523

    
524
        if (ai == NULL)
525
                return -1;
526

    
527
        return sock;
528
}
529
#endif /* !INET6 */
530

    
531
SockInfo *sock_connect(const gchar *hostname, gushort port)
532
{
533
        gint sock;
534
        SockInfo *sockinfo;
535

    
536
#ifdef INET6
537
        if ((sock = sock_connect_by_getaddrinfo(hostname, port)) < 0)
538
                return NULL;
539
#else
540
        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
541
                perror("socket");
542
                return NULL;
543
        }
544

    
545
        if (sock_connect_by_hostname(sock, hostname, port) < 0) {
546
                if (errno != 0) perror("connect");
547
                close(sock);
548
                return NULL;
549
        }
550
#endif /* INET6 */
551

    
552
        sockinfo = g_new0(SockInfo, 1);
553
        sockinfo->sock = sock;
554
        sockinfo->sock_ch = g_io_channel_unix_new(sock);
555
        sockinfo->hostname = g_strdup(hostname);
556
        sockinfo->port = port;
557
        sockinfo->state = CONN_ESTABLISHED;
558

    
559
        usleep(100000);
560

    
561
        return sockinfo;
562
}
563

    
564
static void sock_address_list_free(GList *addr_list)
565
{
566
        GList *cur;
567

    
568
        for (cur = addr_list; cur != NULL; cur = cur->next) {
569
                SockAddrData *addr_data = (SockAddrData *)cur->data;
570
                g_free(addr_data->addr);
571
                g_free(addr_data);
572
        }
573

    
574
        g_list_free(addr_list);
575
}
576

    
577
/* asynchronous TCP connection */
578

    
579
static gboolean sock_connect_async_cb(GIOChannel *source,
580
                                      GIOCondition condition, gpointer data)
581
{
582
        SockConnectData *conn_data = (SockConnectData *)data;
583
        gint fd;
584
        gint val;
585
        gint len;
586
        SockInfo *sockinfo;
587

    
588
        fd = g_io_channel_unix_get_fd(source);
589

    
590
        conn_data->io_tag = 0;
591
        conn_data->channel = NULL;
592
        g_io_channel_unref(source);
593

    
594
        len = sizeof(val);
595
        if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len) < 0) {
596
                perror("getsockopt");
597
                close(fd);
598
                sock_connect_address_list_async(conn_data);
599
                return FALSE;
600
        }
601

    
602
        if (val != 0) {
603
                close(fd);
604
                sock_connect_address_list_async(conn_data);
605
                return FALSE;
606
        }
607

    
608
        sockinfo = g_new0(SockInfo, 1);
609
        sockinfo->sock = fd;
610
        sockinfo->sock_ch = g_io_channel_unix_new(fd);
611
        sockinfo->hostname = g_strdup(conn_data->hostname);
612
        sockinfo->port = conn_data->port;
613
        sockinfo->state = CONN_ESTABLISHED;
614

    
615
        conn_data->func(sockinfo, conn_data->data);
616

    
617
        sock_connect_async_cancel(conn_data->id);
618

    
619
        return FALSE;
620
}
621

    
622
static gint sock_connect_async_get_address_info_cb(GList *addr_list,
623
                                                   gpointer data)
624
{
625
        SockConnectData *conn_data = (SockConnectData *)data;
626

    
627
        conn_data->addr_list = addr_list;
628
        conn_data->cur_addr = addr_list;
629
        conn_data->lookup_data = NULL;
630

    
631
        return sock_connect_address_list_async(conn_data);
632
}
633

    
634
gint sock_connect_async(const gchar *hostname, gushort port,
635
                        SockConnectFunc func, gpointer data)
636
{
637
        static gint id = 1;
638
        SockConnectData *conn_data;
639

    
640
        conn_data = g_new0(SockConnectData, 1);
641
        conn_data->id = id++;
642
        conn_data->hostname = g_strdup(hostname);
643
        conn_data->port = port;
644
        conn_data->addr_list = NULL;
645
        conn_data->cur_addr = NULL;
646
        conn_data->io_tag = 0;
647
        conn_data->func = func;
648
        conn_data->data = data;
649

    
650
        conn_data->lookup_data = sock_get_address_info_async
651
                (hostname, port, sock_connect_async_get_address_info_cb,
652
                 conn_data);
653

    
654
        if (conn_data->lookup_data == NULL) {
655
                g_free(conn_data->hostname);
656
                g_free(conn_data);
657
                return -1;
658
        }
659

    
660
        sock_connect_data_list = g_list_append(sock_connect_data_list,
661
                                               conn_data);
662

    
663
        return conn_data->id;
664
}
665

    
666
gint sock_connect_async_cancel(gint id)
667
{
668
        SockConnectData *conn_data = NULL;
669
        GList *cur;
670

    
671
        for (cur = sock_connect_data_list; cur != NULL; cur = cur->next) {
672
                if (((SockConnectData *)cur->data)->id == id) {
673
                        conn_data = (SockConnectData *)cur->data;
674
                        break;
675
                }
676
        }
677

    
678
        if (conn_data) {
679
                sock_connect_data_list = g_list_remove(sock_connect_data_list,
680
                                                       conn_data);
681

    
682
                if (conn_data->lookup_data)
683
                        sock_get_address_info_async_cancel
684
                                (conn_data->lookup_data);
685

    
686
                if (conn_data->io_tag > 0)
687
                        g_source_remove(conn_data->io_tag);
688
                if (conn_data->channel) {
689
                        g_io_channel_close(conn_data->channel);
690
                        g_io_channel_unref(conn_data->channel);
691
                }
692

    
693
                sock_address_list_free(conn_data->addr_list);
694
                g_free(conn_data->hostname);
695
                g_free(conn_data);
696
        } else {
697
                g_warning("sock_connect_async_cancel: id %d not found.\n", id);
698
                return -1;
699
        }
700

    
701
        return 0;
702
}
703

    
704
static gint sock_connect_address_list_async(SockConnectData *conn_data)
705
{
706
        SockAddrData *addr_data;
707
        gint sock = -1;
708

    
709
        for (; conn_data->cur_addr != NULL;
710
             conn_data->cur_addr = conn_data->cur_addr->next) {
711
                addr_data = (SockAddrData *)conn_data->cur_addr->data;
712

    
713
                if ((sock = socket(addr_data->family, addr_data->socktype,
714
                                   addr_data->protocol)) < 0) {
715
                        perror("socket");
716
                        continue;
717
                }
718

    
719
                set_nonblocking_mode(sock, TRUE);
720

    
721
                if (connect(sock, addr_data->addr, addr_data->addr_len) < 0) {
722
                        if (EINPROGRESS == errno) {
723
                                break;
724
                        } else {
725
                                perror("connect");
726
                                close(sock);
727
                        }
728
                } else
729
                        break;
730
        }
731

    
732
        if (conn_data->cur_addr == NULL) {
733
                g_warning("sock_connect_address_list_async: "
734
                          "connection to %s:%d failed\n",
735
                          conn_data->hostname, conn_data->port);
736
                conn_data->func(NULL, conn_data->data);
737
                sock_connect_async_cancel(conn_data->id);
738
                return -1;
739
        }
740

    
741
        conn_data->cur_addr = conn_data->cur_addr->next;
742

    
743
        conn_data->channel = g_io_channel_unix_new(sock);
744
        conn_data->io_tag = g_io_add_watch(conn_data->channel, G_IO_IN|G_IO_OUT,
745
                                           sock_connect_async_cb, conn_data);
746

    
747
        return 0;
748
}
749

    
750
/* asynchronous DNS lookup */
751

    
752
static gboolean sock_get_address_info_async_cb(GIOChannel *source,
753
                                               GIOCondition condition,
754
                                               gpointer data)
755
{
756
        SockLookupData *lookup_data = (SockLookupData *)data;
757
        GList *addr_list = NULL;
758
        SockAddrData *addr_data;
759
        gsize bytes_read;
760
        gint ai_member[4];
761
        struct sockaddr *addr;
762

    
763
        for (;;) {
764
                if (g_io_channel_read(source, (gchar *)ai_member,
765
                                      sizeof(ai_member), &bytes_read)
766
                    != G_IO_ERROR_NONE) {
767
                        g_warning("sock_get_address_info_async_cb: "
768
                                  "address length read error\n");
769
                        break;
770
                }
771

    
772
                if (bytes_read == 0 || bytes_read != sizeof(ai_member))
773
                        break;
774

    
775
                if (ai_member[0] == AF_UNSPEC) {
776
                        g_warning("DNS lookup failed\n");
777
                        break;
778
                }
779

    
780
                addr = g_malloc(ai_member[3]);
781
                if (g_io_channel_read(source, (gchar *)addr, ai_member[3],
782
                                      &bytes_read)
783
                    != G_IO_ERROR_NONE) {
784
                        g_warning("sock_get_address_info_async_cb: "
785
                                  "address data read error\n");
786
                        g_free(addr);
787
                        break;
788
                }
789

    
790
                if (bytes_read != ai_member[3]) {
791
                        g_warning("sock_get_address_info_async_cb: "
792
                                  "incomplete address data\n");
793
                        g_free(addr);
794
                        break;
795
                }
796

    
797
                addr_data = g_new0(SockAddrData, 1);
798
                addr_data->family = ai_member[0];
799
                addr_data->socktype = ai_member[1];
800
                addr_data->protocol = ai_member[2];
801
                addr_data->addr_len = ai_member[3];
802
                addr_data->addr = addr;
803

    
804
                addr_list = g_list_append(addr_list, addr_data);
805
        }
806

    
807
        g_io_channel_close(source);
808
        g_io_channel_unref(source);
809

    
810
        kill(lookup_data->child_pid, SIGKILL);
811
        waitpid(lookup_data->child_pid, NULL, 0);
812

    
813
        lookup_data->func(addr_list, lookup_data->data);
814

    
815
        g_free(lookup_data->hostname);
816
        g_free(lookup_data);
817

    
818
        return FALSE;
819
}
820

    
821
static SockLookupData *sock_get_address_info_async(const gchar *hostname,
822
                                                   gushort port,
823
                                                   SockAddrFunc func,
824
                                                   gpointer data)
825
{
826
        SockLookupData *lookup_data = NULL;
827
        gint pipe_fds[2];
828
        pid_t pid;
829

    
830
        if (pipe(pipe_fds) < 0) {
831
                perror("pipe");
832
                func(NULL, data);
833
                return NULL;
834
        }
835

    
836
        if ((pid = fork()) < 0) {
837
                perror("fork");
838
                func(NULL, data);
839
                return NULL;
840
        }
841

    
842
        /* child process */
843
        if (pid == 0) {
844
#ifdef INET6
845
                gint gai_err;
846
                struct addrinfo hints, *res, *ai;
847
                gchar port_str[6];
848
#else /* !INET6 */
849
                struct hostent *hp;
850
                gchar **addr_list_p;
851
                struct sockaddr_in ad;
852
#endif /* INET6 */
853
                gint ai_member[4] = {AF_UNSPEC, 0, 0, 0};
854

    
855
                close(pipe_fds[0]);
856

    
857
#ifdef INET6
858
                memset(&hints, 0, sizeof(hints));
859
                /* hints.ai_flags = AI_CANONNAME; */
860
                hints.ai_family = AF_UNSPEC;
861
                hints.ai_socktype = SOCK_STREAM;
862
                hints.ai_protocol = IPPROTO_TCP;
863

    
864
                g_snprintf(port_str, sizeof(port_str), "%d", port);
865

    
866
                gai_err = getaddrinfo(hostname, port_str, &hints, &res);
867
                if (gai_err != 0) {
868
                        g_warning("getaddrinfo for %s:%s failed: %s\n",
869
                                  hostname, port_str, gai_strerror(gai_err));
870
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
871
                                     sizeof(ai_member));
872
                        close(pipe_fds[1]);
873
                        _exit(1);
874
                }
875

    
876
                for (ai = res; ai != NULL; ai = ai->ai_next) {
877
                        ai_member[0] = ai->ai_family;
878
                        ai_member[1] = ai->ai_socktype;
879
                        ai_member[2] = ai->ai_protocol;
880
                        ai_member[3] = ai->ai_addrlen;
881

    
882
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
883
                                     sizeof(ai_member));
884
                        fd_write_all(pipe_fds[1], (gchar *)ai->ai_addr,
885
                                     ai->ai_addrlen);
886
                }
887

    
888
                if (res != NULL)
889
                        freeaddrinfo(res);
890
#else /* !INET6 */
891
                hp = my_gethostbyname(hostname);
892
                if (hp == NULL || hp->h_addrtype != AF_INET) {
893
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
894
                                     sizeof(ai_member));
895
                        close(pipe_fds[1]);
896
                        _exit(1);
897
                }
898

    
899
                ai_member[0] = AF_INET;
900
                ai_member[1] = SOCK_STREAM;
901
                ai_member[2] = IPPROTO_TCP;
902
                ai_member[3] = sizeof(ad);
903

    
904
                memset(&ad, 0, sizeof(ad));
905
                ad.sin_family = AF_INET;
906
                ad.sin_port = htons(port);
907

    
908
                for (addr_list_p = hp->h_addr_list; *addr_list_p != NULL;
909
                     addr_list_p++) {
910
                        memcpy(&ad.sin_addr, *addr_list_p, hp->h_length);
911
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
912
                                     sizeof(ai_member));
913
                        fd_write_all(pipe_fds[1], (gchar *)&ad, sizeof(ad));
914
                }
915
#endif /* INET6 */
916

    
917
                close(pipe_fds[1]);
918

    
919
                _exit(0);
920
        } else {
921
                close(pipe_fds[1]);
922

    
923
                lookup_data = g_new0(SockLookupData, 1);
924
                lookup_data->hostname = g_strdup(hostname);
925
                lookup_data->child_pid = pid;
926
                lookup_data->func = func;
927
                lookup_data->data = data;
928

    
929
                lookup_data->channel = g_io_channel_unix_new(pipe_fds[0]);
930
                lookup_data->io_tag = g_io_add_watch
931
                        (lookup_data->channel, G_IO_IN,
932
                         sock_get_address_info_async_cb, lookup_data);
933
        }
934

    
935
        return lookup_data;
936
}
937

    
938
static gint sock_get_address_info_async_cancel(SockLookupData *lookup_data)
939
{
940
        if (lookup_data->io_tag > 0)
941
                g_source_remove(lookup_data->io_tag);
942
        if (lookup_data->channel) {
943
                g_io_channel_close(lookup_data->channel);
944
                g_io_channel_unref(lookup_data->channel);
945
        }
946

    
947
        if (lookup_data->child_pid > 0) {
948
                kill(lookup_data->child_pid, SIGKILL);
949
                waitpid(lookup_data->child_pid, NULL, 0);
950
        }
951

    
952
        g_free(lookup_data->hostname);
953
        g_free(lookup_data);
954

    
955
        return 0;
956
}
957

    
958

    
959
gint sock_printf(SockInfo *sock, const gchar *format, ...)
960
{
961
        va_list args;
962
        gchar buf[BUFFSIZE];
963

    
964
        va_start(args, format);
965
        g_vsnprintf(buf, sizeof(buf), format, args);
966
        va_end(args);
967

    
968
        return sock_write_all(sock, buf, strlen(buf));
969
}
970

    
971
gint sock_read(SockInfo *sock, gchar *buf, gint len)
972
{
973
        g_return_val_if_fail(sock != NULL, -1);
974

    
975
#if USE_SSL
976
        if (sock->ssl)
977
                return ssl_read(sock->ssl, buf, len);
978
#endif
979
        return fd_read(sock->sock, buf, len);
980
}
981

    
982
gint fd_read(gint fd, gchar *buf, gint len)
983
{
984
        if (fd_check_io(fd, G_IO_IN) < 0)
985
                return -1;
986

    
987
        return read(fd, buf, len);
988
}
989

    
990
#if USE_SSL
991
gint ssl_read(SSL *ssl, gchar *buf, gint len)
992
{
993
        gint ret;
994

    
995
        if (SSL_pending(ssl) == 0) {
996
                if (fd_check_io(SSL_get_rfd(ssl), G_IO_IN) < 0)
997
                        return -1;
998
        }
999

    
1000
        ret = SSL_read(ssl, buf, len);
1001

    
1002
        switch (SSL_get_error(ssl, ret)) {
1003
        case SSL_ERROR_NONE:
1004
                return ret;
1005
        case SSL_ERROR_WANT_READ:
1006
        case SSL_ERROR_WANT_WRITE:
1007
                errno = EAGAIN;
1008
                return -1;
1009
        default:
1010
                return -1;
1011
        }
1012
}
1013
#endif
1014

    
1015
gint sock_write(SockInfo *sock, const gchar *buf, gint len)
1016
{
1017
        g_return_val_if_fail(sock != NULL, -1);
1018

    
1019
#if USE_SSL
1020
        if (sock->ssl)
1021
                return ssl_write(sock->ssl, buf, len);
1022
#endif
1023
        return fd_write(sock->sock, buf, len);
1024
}
1025

    
1026
gint fd_write(gint fd, const gchar *buf, gint len)
1027
{
1028
        if (fd_check_io(fd, G_IO_OUT) < 0)
1029
                return -1;
1030

    
1031
        return write(fd, buf, len);
1032
}
1033

    
1034
#if USE_SSL
1035
gint ssl_write(SSL *ssl, const gchar *buf, gint len)
1036
{
1037
        gint ret;
1038

    
1039
        ret = SSL_write(ssl, buf, len);
1040

    
1041
        switch (SSL_get_error(ssl, ret)) {
1042
        case SSL_ERROR_NONE:
1043
                return ret;
1044
        case SSL_ERROR_WANT_READ:
1045
        case SSL_ERROR_WANT_WRITE:
1046
                errno = EAGAIN;
1047
                return -1;
1048
        default:
1049
                return -1;
1050
        }
1051
}
1052
#endif
1053

    
1054
gint sock_write_all(SockInfo *sock, const gchar *buf, gint len)
1055
{
1056
        g_return_val_if_fail(sock != NULL, -1);
1057

    
1058
#if USE_SSL
1059
        if (sock->ssl)
1060
                return ssl_write_all(sock->ssl, buf, len);
1061
#endif
1062
        return fd_write_all(sock->sock, buf, len);
1063
}
1064

    
1065
gint fd_write_all(gint fd, const gchar *buf, gint len)
1066
{
1067
        gint n, wrlen = 0;
1068

    
1069
        while (len) {
1070
                if (fd_check_io(fd, G_IO_OUT) < 0)
1071
                        return -1;
1072
                n = write(fd, buf, len);
1073
                if (n <= 0)
1074
                        return -1;
1075
                len -= n;
1076
                wrlen += n;
1077
                buf += n;
1078
        }
1079

    
1080
        return wrlen;
1081
}
1082

    
1083
#if USE_SSL
1084
gint ssl_write_all(SSL *ssl, const gchar *buf, gint len)
1085
{
1086
        gint n, wrlen = 0;
1087

    
1088
        while (len) {
1089
                n = ssl_write(ssl, buf, len);
1090
                if (n <= 0)
1091
                        return -1;
1092
                len -= n;
1093
                wrlen += n;
1094
                buf += n;
1095
        }
1096

    
1097
        return wrlen;
1098
}
1099
#endif
1100

    
1101
gint fd_recv(gint fd, gchar *buf, gint len, gint flags)
1102
{
1103
        if (fd_check_io(fd, G_IO_IN) < 0)
1104
                return -1;
1105

    
1106
        return recv(fd, buf, len, flags);
1107
}
1108

    
1109
gint fd_gets(gint fd, gchar *buf, gint len)
1110
{
1111
        gchar *newline, *bp = buf;
1112
        gint n;
1113

    
1114
        if (--len < 1)
1115
                return -1;
1116
        do {
1117
                if ((n = fd_recv(fd, bp, len, MSG_PEEK)) <= 0)
1118
                        return -1;
1119
                if ((newline = memchr(bp, '\n', n)) != NULL)
1120
                        n = newline - bp + 1;
1121
                if ((n = fd_read(fd, bp, n)) < 0)
1122
                        return -1;
1123
                bp += n;
1124
                len -= n;
1125
        } while (!newline && len);
1126

    
1127
        *bp = '\0';
1128
        return bp - buf;
1129
}
1130

    
1131
#if USE_SSL
1132
gint ssl_gets(SSL *ssl, gchar *buf, gint len)
1133
{
1134
        gchar *newline, *bp = buf;
1135
        gint n;
1136

    
1137
        if (--len < 1)
1138
                return -1;
1139
        do {
1140
                if ((n = ssl_peek(ssl, bp, len)) <= 0)
1141
                        return -1;
1142
                if ((newline = memchr(bp, '\n', n)) != NULL)
1143
                        n = newline - bp + 1;
1144
                if ((n = ssl_read(ssl, bp, n)) < 0)
1145
                        return -1;
1146
                bp += n;
1147
                len -= n;
1148
        } while (!newline && len);
1149

    
1150
        *bp = '\0';
1151
        return bp - buf;
1152
}
1153
#endif
1154

    
1155
gint sock_gets(SockInfo *sock, gchar *buf, gint len)
1156
{
1157
        g_return_val_if_fail(sock != NULL, -1);
1158

    
1159
#if USE_SSL
1160
        if (sock->ssl)
1161
                return ssl_gets(sock->ssl, buf, len);
1162
#endif
1163
        return fd_gets(sock->sock, buf, len);
1164
}
1165

    
1166
gchar *fd_getline(gint fd)
1167
{
1168
        gchar buf[BUFFSIZE];
1169
        gchar *str = NULL;
1170
        gint len;
1171
        gulong size = 1;
1172

    
1173
        while ((len = fd_gets(fd, buf, sizeof(buf))) > 0) {
1174
                size += len;
1175
                if (!str)
1176
                        str = g_strdup(buf);
1177
                else {
1178
                        str = g_realloc(str, size);
1179
                        strcat(str, buf);
1180
                }
1181
                if (buf[len - 1] == '\n')
1182
                        break;
1183
        }
1184

    
1185
        return str;
1186
}
1187

    
1188
#if USE_SSL
1189
gchar *ssl_getline(SSL *ssl)
1190
{
1191
        gchar buf[BUFFSIZE];
1192
        gchar *str = NULL;
1193
        gint len;
1194
        gulong size = 1;
1195

    
1196
        while ((len = ssl_gets(ssl, buf, sizeof(buf))) > 0) {
1197
                size += len;
1198
                if (!str)
1199
                        str = g_strdup(buf);
1200
                else {
1201
                        str = g_realloc(str, size);
1202
                        strcat(str, buf);
1203
                }
1204
                if (buf[len - 1] == '\n')
1205
                        break;
1206
        }
1207

    
1208
        return str;
1209
}
1210
#endif
1211

    
1212
gchar *sock_getline(SockInfo *sock)
1213
{
1214
        g_return_val_if_fail(sock != NULL, NULL);
1215

    
1216
#if USE_SSL
1217
        if (sock->ssl)
1218
                return ssl_getline(sock->ssl);
1219
#endif
1220
        return fd_getline(sock->sock);
1221
}
1222

    
1223
gint sock_puts(SockInfo *sock, const gchar *buf)
1224
{
1225
        gint ret;
1226

    
1227
        if ((ret = sock_write_all(sock, buf, strlen(buf))) < 0)
1228
                return ret;
1229
        return sock_write_all(sock, "\r\n", 2);
1230
}
1231

    
1232
/* peek at the socket data without actually reading it */
1233
#if USE_SSL
1234
gint ssl_peek(SSL *ssl, gchar *buf, gint len)
1235
{
1236
        gint ret;
1237

    
1238
        if (SSL_pending(ssl) == 0) {
1239
                if (fd_check_io(SSL_get_rfd(ssl), G_IO_IN) < 0)
1240
                        return -1;
1241
        }
1242

    
1243
        ret = SSL_peek(ssl, buf, len);
1244

    
1245
        switch (SSL_get_error(ssl, ret)) {
1246
        case SSL_ERROR_NONE:
1247
                return ret;
1248
        case SSL_ERROR_WANT_READ:
1249
        case SSL_ERROR_WANT_WRITE:
1250
                errno = EAGAIN;
1251
                return -1;
1252
        default:
1253
                return -1;
1254
        }
1255
}
1256
#endif
1257

    
1258
gint sock_peek(SockInfo *sock, gchar *buf, gint len)
1259
{
1260
        g_return_val_if_fail(sock != NULL, -1);
1261

    
1262
#if USE_SSL
1263
        if (sock->ssl)
1264
                return ssl_peek(sock->ssl, buf, len);
1265
#endif
1266
        return fd_recv(sock->sock, buf, len, MSG_PEEK);
1267
}
1268

    
1269
gint sock_close(SockInfo *sock)
1270
{
1271
        gint ret;
1272

    
1273
        if (!sock)
1274
                return 0;
1275

    
1276
        if (sock->sock_ch)
1277
                g_io_channel_unref(sock->sock_ch);
1278

    
1279
#if USE_SSL
1280
        if (sock->ssl)
1281
                ssl_done_socket(sock);
1282
#endif
1283
        ret = fd_close(sock->sock); 
1284
        g_free(sock->hostname);
1285
        g_free(sock);
1286

    
1287
        return ret;
1288
}
1289

    
1290
gint fd_close(gint fd)
1291
{
1292
        return close(fd);
1293
}