Statistics
| Revision:

root / libsylph / socket.c @ 578

History | View | Annotate | Download (27.9 kB)

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