Statistics
| Revision:

root / libsylph / socket.c @ 3188

History | View | Annotate | Download (45 KB)

1
/*
2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2012 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
#endif /* G_OS_UNIX */
95
        SockInfo *sock;
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_info_connect_by_hostname
150
                                        (SockInfo        *sock);
151
#else
152
#ifdef G_OS_WIN32
153
typedef int (*GetAddrInfoFunc)                (const char        *node,
154
                                         const char        *service,
155
                                         const struct addrinfo *hints,
156
                                         struct addrinfo **res);
157
typedef void (*FreeAddrInfoFunc)        (struct addrinfo *res);
158

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

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

    
168
static SockDesc sock_info_connect_by_getaddrinfo(SockInfo        *sock);
169
#endif
170

    
171
#ifdef G_OS_UNIX
172
static void sock_address_list_free                (GList                *addr_list);
173

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

    
181
static gint sock_connect_address_list_async        (SockConnectData *conn_data);
182

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

    
194

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

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

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

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

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

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

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

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

    
250
        return sock;
251
}
252

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

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

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

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

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

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

    
295
        return sock;
296
}
297

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

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

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

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

    
319
        return sock;
320
#else
321
        return -1;
322
#endif
323
}
324

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

    
332
        sock = socket(PF_UNIX, SOCK_STREAM, 0);
333

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

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

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

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

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

    
362
        return sock;
363
#else
364
        return -1;
365
#endif
366
}
367

    
368
gint fd_accept(gint sock)
369
{
370
        struct sockaddr_in caddr;
371
        guint caddr_len;
372

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

    
377

    
378
SockInfo *sock_new(const gchar *hostname, gushort port)
379
{
380
        SockInfo *sockinfo;
381

    
382
        sockinfo = g_new0(SockInfo, 1);
383
        sockinfo->sock = INVALID_SOCKET;
384
        sockinfo->sock_ch = NULL;
385
        sockinfo->hostname = g_strdup(hostname);
386
        sockinfo->port = port;
387
        sockinfo->state = CONN_READY;
388
        sockinfo->flags = 0;
389
        sockinfo->data = NULL;
390

    
391
        return sockinfo;
392
}
393

    
394
static SockInfo *sock_find_from_fd(gint fd)
395
{
396
        GList *cur;
397

    
398
        for (cur = sock_list; cur != NULL; cur = cur->next) {
399
                if (((SockInfo *)cur->data)->sock == fd)
400
                        return (SockInfo *)cur->data;
401
        }
402

    
403
        return NULL;
404
}
405

    
406
static gint set_nonblocking_mode(gint fd, gboolean nonblock)
407
{
408
#ifdef G_OS_WIN32
409
        gulong val = nonblock ? 1 : 0;
410
        SockInfo *sock;
411

    
412
        if (!nonblock)
413
                WSAEventSelect(fd, NULL, 0);
414
        if (ioctlsocket(fd, FIONBIO, &val) == SOCKET_ERROR) {
415
                g_warning("set_nonblocking_mode(): ioctlsocket() failed: %ld\n",
416
                          WSAGetLastError());
417
                return -1;
418
        }
419

    
420
        sock = sock_find_from_fd(fd);
421
        if (sock) {
422
                if (nonblock) {
423
                        SOCK_SET_FLAGS(sock->flags, SYL_SOCK_NONBLOCK);
424
                } else {
425
                        SOCK_UNSET_FLAGS(sock->flags, SYL_SOCK_NONBLOCK);
426
                }
427
        }
428
        debug_print("set nonblocking mode to %d\n", nonblock);
429

    
430
        return 0;
431
#else
432
        gint flags;
433

    
434
        flags = fcntl(fd, F_GETFL, 0);
435
        if (flags < 0) {
436
                perror("fcntl");
437
                return -1;
438
        }
439

    
440
        if (nonblock)
441
                flags |= O_NONBLOCK;
442
        else
443
                flags &= ~O_NONBLOCK;
444

    
445
        return fcntl(fd, F_SETFL, flags);
446
#endif
447
}
448

    
449
gint sock_set_nonblocking_mode(SockInfo *sock, gboolean nonblock)
450
{
451
        gint ret;
452

    
453
        g_return_val_if_fail(sock != NULL, -1);
454

    
455
        ret = set_nonblocking_mode(sock->sock, nonblock);
456
        if (ret == 0) {
457
                if (nonblock) {
458
                        SOCK_SET_FLAGS(sock->flags, SYL_SOCK_NONBLOCK);
459
                } else {
460
                        SOCK_UNSET_FLAGS(sock->flags, SYL_SOCK_NONBLOCK);
461
                }
462
        }
463

    
464
        return ret;
465
}
466

    
467
static gboolean is_nonblocking_mode(gint fd)
468
{
469
#ifdef G_OS_WIN32
470
        SockInfo *sock;
471

    
472
        sock = sock_find_from_fd(fd);
473
        if (sock) {
474
                return SOCK_IS_NONBLOCK(sock->flags);
475
        }
476

    
477
        return FALSE;
478
#else
479
        gint flags;
480

    
481
        flags = fcntl(fd, F_GETFL, 0);
482
        if (flags < 0) {
483
                perror("fcntl");
484
                return FALSE;
485
        }
486

    
487
        return ((flags & O_NONBLOCK) != 0);
488
#endif
489
}
490

    
491
gboolean sock_is_nonblocking_mode(SockInfo *sock)
492
{
493
        g_return_val_if_fail(sock != NULL, FALSE);
494

    
495
#ifdef G_OS_WIN32
496
        return SOCK_IS_NONBLOCK(sock->flags);
497
#else
498
        return is_nonblocking_mode(sock->sock);
499
#endif
500
}
501

    
502
gboolean sock_has_read_data(SockInfo *sock)
503
{
504
#ifdef G_OS_WIN32
505
        gulong val;
506

    
507
#if USE_SSL
508
        if (sock->ssl)
509
                return TRUE;
510
#endif
511
        if (ioctlsocket(sock->sock, FIONREAD, &val) < 0) {
512
                g_warning("sock_has_read_data(): ioctlsocket() failed: %ld\n",
513
                          WSAGetLastError());
514
                return TRUE;
515
        }
516

    
517
        if (val == 0)
518
                return FALSE;
519
        else
520
                return TRUE;
521
#else
522
        return TRUE;
523
#endif
524
}
525

    
526

    
527
static gboolean sock_prepare(GSource *source, gint *timeout)
528
{
529
        *timeout = 1;
530
        return FALSE;
531
}
532

    
533
static gboolean sock_check(GSource *source)
534
{
535
        SockInfo *sock = ((SockSource *)source)->sock;
536
        struct timeval timeout = {0, 0};
537
        fd_set fds;
538
        GIOCondition condition = sock->condition;
539

    
540
#if USE_SSL
541
        if (sock->ssl) {
542
                if (condition & G_IO_IN) {
543
                        if (SSL_pending(sock->ssl) > 0)
544
                                return TRUE;
545
                        if (SSL_want_write(sock->ssl))
546
                                condition |= G_IO_OUT;
547
                }
548

    
549
                if (condition & G_IO_OUT) {
550
                        if (SSL_want_read(sock->ssl))
551
                                condition |= G_IO_IN;
552
                }
553
        }
554
#endif
555

    
556
        FD_ZERO(&fds);
557
        FD_SET(sock->sock, &fds);
558

    
559
        select(sock->sock + 1,
560
               (condition & G_IO_IN)  ? &fds : NULL,
561
               (condition & G_IO_OUT) ? &fds : NULL,
562
               NULL, &timeout);
563

    
564
        return FD_ISSET(sock->sock, &fds) != 0;
565
}
566

    
567
static gboolean sock_dispatch(GSource *source, GSourceFunc callback,
568
                              gpointer user_data)
569
{
570
        SockInfo *sock = ((SockSource *)source)->sock;
571

    
572
        return sock->callback(sock, sock->condition, sock->data);
573
}
574

    
575
static gboolean sock_watch_cb(GIOChannel *source, GIOCondition condition,
576
                              gpointer data)
577
{
578
        SockInfo *sock = (SockInfo *)data;
579

    
580
        if ((condition & sock->condition) == 0)
581
                return TRUE;
582

    
583
        return sock->callback(sock, sock->condition, sock->data);
584
}
585

    
586
guint sock_add_watch(SockInfo *sock, GIOCondition condition, SockFunc func,
587
                     gpointer data)
588
{
589
        sock->callback = func;
590
        sock->condition = condition;
591
        sock->data = data;
592

    
593
#if USE_SSL
594
        if (sock->ssl) {
595
                GSource *source;
596

    
597
                source = g_source_new(&sock_watch_funcs, sizeof(SockSource));
598
                ((SockSource *)source)->sock = sock;
599
                g_source_set_priority(source, G_PRIORITY_DEFAULT);
600
                g_source_set_can_recurse(source, FALSE);
601
                return g_source_attach(source, NULL);
602
        }
603
#endif
604

    
605
        return g_io_add_watch(sock->sock_ch, condition, sock_watch_cb, sock);
606
}
607

    
608
guint sock_add_watch_poll(SockInfo *sock, GIOCondition condition, SockFunc func,
609
                          gpointer data)
610
{
611
        GSource *source;
612

    
613
        sock->callback = func;
614
        sock->condition = condition;
615
        sock->data = data;
616

    
617
        source = g_source_new(&sock_watch_funcs, sizeof(SockSource));
618
        ((SockSource *)source)->sock = sock;
619
        g_source_set_priority(source, G_PRIORITY_DEFAULT);
620
        g_source_set_can_recurse(source, FALSE);
621

    
622
        return g_source_attach(source, NULL);
623
}
624

    
625
static gint fd_check_io(gint fd, GIOCondition cond)
626
{
627
        struct timeval timeout;
628
        fd_set fds;
629
        SockInfo *sock;
630

    
631
        sock = sock_find_from_fd(fd);
632
        if (sock && !SOCK_IS_CHECK_IO(sock->flags))
633
                return 0;
634

    
635
        timeout.tv_sec  = io_timeout;
636
        timeout.tv_usec = 0;
637

    
638
        FD_ZERO(&fds);
639
        FD_SET(fd, &fds);
640

    
641
        if (cond == G_IO_IN) {
642
                select(fd + 1, &fds, NULL, NULL,
643
                       io_timeout > 0 ? &timeout : NULL);
644
        } else {
645
                select(fd + 1, NULL, &fds, NULL,
646
                       io_timeout > 0 ? &timeout : NULL);
647
        }
648

    
649
        if (FD_ISSET(fd, &fds)) {
650
                return 0;
651
        } else {
652
                g_warning("Socket IO timeout\n");
653
                return -1;
654
        }
655
}
656

    
657
#if defined(G_OS_UNIX) && !defined(USE_THREADS)
658
static sigjmp_buf jmpenv;
659

    
660
static void timeout_handler(gint sig)
661
{
662
        siglongjmp(jmpenv, 1);
663
}
664
#endif
665

    
666
static gint sock_connect_with_timeout(gint sock,
667
                                      const struct sockaddr *serv_addr,
668
                                      gint addrlen,
669
                                      guint timeout_secs)
670
{
671
        gint ret;
672

    
673
#ifdef G_OS_WIN32
674
        WSAEVENT hevent;
675
        gint err;
676
        DWORD dwret;
677
        WSANETWORKEVENTS events;
678

    
679
        errno = 0;
680

    
681
        hevent = WSACreateEvent();
682
        if (hevent == WSA_INVALID_EVENT)
683
                return -1;
684

    
685
        ret = WSAEventSelect(sock, hevent, FD_CONNECT);
686
        if (ret == SOCKET_ERROR) {
687
                g_warning("sock_connect_with_timeout: WSAEventSelect");
688
                WSACloseEvent(hevent);
689
                return -1;
690
        }
691

    
692
        ret = connect(sock, serv_addr, addrlen);
693

    
694
        if (ret == SOCKET_ERROR) {
695
                err = WSAGetLastError();
696
                if (err != WSAEWOULDBLOCK) {
697
                        g_warning("sock_connect_with_timeout: connect (%d)", err);
698
                        ret = -1;
699
                        goto end;
700
                }
701
        }
702

    
703
        dwret = WSAWaitForMultipleEvents(1, &hevent, FALSE, timeout_secs * 1000, FALSE);
704
        if (dwret == WSA_WAIT_TIMEOUT) {
705
                g_warning("sock_connect_with_timeout: timeout");
706
                errno = WSAETIMEDOUT;
707
                ret = -1;
708
                goto end;
709
        } else if (dwret != WSA_WAIT_EVENT_0) {
710
                g_warning("sock_connect_with_timeout: WSAWaitForMultipleEvents (%d)", dwret);
711
                ret = -1;
712
                goto end;
713
        }
714

    
715
        ret = WSAEnumNetworkEvents(sock, hevent, &events);
716
        if (ret == SOCKET_ERROR) {
717
                g_warning("sock_connect_with_timeout: WSAEnumNetworkEvents (%d)", ret);
718
                ret = -1;
719
                goto end;
720
        }
721

    
722
        if ((events.lNetworkEvents & FD_CONNECT) &&
723
             events.iErrorCode[FD_CONNECT_BIT] == 0) {
724
                ret = 0;
725
                errno = 0;
726
        } else
727
                ret = -1;
728

    
729
end:
730
        WSAEventSelect(sock, NULL, 0);
731
        WSACloseEvent(hevent);
732

    
733
        set_nonblocking_mode(sock, FALSE);
734
#else
735
        set_nonblocking_mode(sock, TRUE);
736

    
737
        ret = connect(sock, serv_addr, addrlen);
738

    
739
        if (ret < 0) {
740
                if (EINPROGRESS == errno) {
741
                        fd_set fds;
742
                        struct timeval tv;
743

    
744
                        tv.tv_sec = timeout_secs;
745
                        tv.tv_usec = 0;
746
                        FD_ZERO(&fds);
747
                        FD_SET(sock, &fds);
748
                        do {
749
                                ret = select(sock + 1, NULL, &fds, NULL, &tv);
750
                        } while (ret < 0 && EINTR == errno);
751
                        if (ret < 0) {
752
                                perror("sock_connect_with_timeout: select");
753
                                return -1;
754
                        } else if (ret == 0) {
755
                                debug_print("sock_connect_with_timeout: timeout\n");
756
                                errno = ETIMEDOUT;
757
                                return -1;
758
                        } else {
759
                                gint val;
760
                                guint len;
761

    
762
                                if (FD_ISSET(sock, &fds)) {
763
                                        ret = 0;
764
                                } else {
765
                                        debug_print("sock_connect_with_timeout: fd not set\n");
766
                                        return -1;
767
                                }
768

    
769
                                len = sizeof(val);
770
                                if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &val, &len) < 0) {
771
                                        perror("sock_connect_with_timeout: getsockopt");
772
                                        return -1;
773
                                }
774
                                if (val != 0) {
775
                                        debug_print("sock_connect_with_timeout: getsockopt(SOL_SOCKET, SO_ERROR) returned error: %s\n", g_strerror(val));
776
                                        return -1;
777
                                }
778
                        }
779
                } else {
780
                        perror("sock_connect_with_timeout: connect");
781
                        return -1;
782
                }
783
        }
784

    
785
        set_nonblocking_mode(sock, FALSE);
786
#endif
787

    
788
        return ret;
789
}
790

    
791
static void resolver_init(void)
792
{
793
#ifdef G_OS_UNIX
794
        static time_t resolv_conf_mtime = 0;
795
        struct stat s;
796

    
797
        if (g_stat("/etc/resolv.conf", &s) == 0 &&
798
            s.st_mtime != resolv_conf_mtime) {
799
                debug_print("Reloading /etc/resolv.conf\n");
800
                resolv_conf_mtime = s.st_mtime;
801
                res_init();
802
        }
803
#endif
804
}
805

    
806
struct hostent *my_gethostbyname(const gchar *hostname)
807
{
808
        struct hostent *hp;
809
#if defined(G_OS_UNIX) && !defined(USE_THREADS)
810
        void (*prev_handler)(gint);
811

    
812
        alarm(0);
813
        prev_handler = signal(SIGALRM, timeout_handler);
814
        if (sigsetjmp(jmpenv, 1)) {
815
                alarm(0);
816
                signal(SIGALRM, prev_handler);
817
                fprintf(stderr, "%s: host lookup timed out.\n", hostname);
818
                errno = 0;
819
                return NULL;
820
        }
821
        alarm(io_timeout);
822
#endif
823

    
824
        if ((hp = gethostbyname(hostname)) == NULL) {
825
#if defined(G_OS_UNIX) && !defined(USE_THREADS)
826
                alarm(0);
827
                signal(SIGALRM, prev_handler);
828
#endif
829
                fprintf(stderr, "%s: unknown host.\n", hostname);
830
                errno = 0;
831
                return NULL;
832
        }
833

    
834
#if defined(G_OS_UNIX) && !defined(USE_THREADS)
835
        alarm(0);
836
        signal(SIGALRM, prev_handler);
837
#endif
838

    
839
        return hp;
840
}
841

    
842
static void sock_set_buffer_size(gint sock)
843
{
844
#ifdef G_OS_WIN32
845
        gint val;
846
        guint len = sizeof(val);
847

    
848
#define SOCK_BUFFSIZE        32768
849

    
850
        getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&val, &len);
851
        if (val < SOCK_BUFFSIZE) {
852
                val = SOCK_BUFFSIZE;
853
                setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&val, len);
854
        }
855
        getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&val, &len);
856
        if (val < SOCK_BUFFSIZE) {
857
                val = SOCK_BUFFSIZE;
858
                setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&val, len);
859
        }
860
        getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&val, &len);
861
        debug_print("SO_SNDBUF = %d\n", val);
862
        getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&val, &len);
863
        debug_print("SO_RCVBUF = %d\n", val);
864

    
865
#undef SOCK_BUFFSIZE
866
#endif
867
}
868

    
869
#if !defined(INET6) || defined(G_OS_WIN32)
870
static gint my_inet_aton(const gchar *hostname, struct in_addr *inp)
871
{
872
#if HAVE_INET_ATON
873
        return inet_aton(hostname, inp);
874
#else
875
#if HAVE_INET_ADDR
876
        guint32 inaddr;
877

    
878
        inaddr = inet_addr(hostname);
879
        if (inaddr != -1) {
880
                memcpy(inp, &inaddr, sizeof(inaddr));
881
                return 1;
882
        } else
883
                return 0;
884
#else
885
        return 0;
886
#endif
887
#endif /* HAVE_INET_ATON */
888
}
889
#endif /* !defined(INET6) || defined(G_OS_WIN32) */
890

    
891
#ifndef INET6
892
static gint sock_info_connect_by_hostname(SockInfo *sock)
893
{
894
        struct hostent *hp;
895
        struct sockaddr_in ad;
896
        gint ret;
897

    
898
        g_return_val_if_fail(sock != NULL, -1);
899
        g_return_val_if_fail(sock->hostname != NULL && sock->port > 0, -1);
900

    
901
        resolver_init();
902

    
903
        memset(&ad, 0, sizeof(ad));
904
        ad.sin_family = AF_INET;
905
        ad.sin_port = htons(sock->port);
906

    
907
        if (!my_inet_aton(sock->hostname, &ad.sin_addr)) {
908
                if ((hp = my_gethostbyname(sock->hostname)) == NULL) {
909
                        fprintf(stderr, "%s: unknown host.\n", sock->hostname);
910
                        errno = 0;
911
                        sock->state = CONN_LOOKUPFAILED;
912
                        return -1;
913
                }
914

    
915
                if (hp->h_length != 4 && hp->h_length != 8) {
916
                        fprintf(stderr, "illegal address length received for host %s\n", sock->hostname);
917
                        errno = 0;
918
                        sock->state = CONN_LOOKUPFAILED;
919
                        return -1;
920
                }
921

    
922
                memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
923
        }
924

    
925
        sock->state = CONN_LOOKUPSUCCESS;
926

    
927
        ret = sock_connect_with_timeout(sock->sock, (struct sockaddr *)&ad,
928
                                        sizeof(ad), io_timeout);
929
        if (ret < 0)
930
                sock->state = CONN_FAILED;
931
        else
932
                sock->state = CONN_ESTABLISHED;
933

    
934
        return ret;
935
}
936

    
937
#else /* INET6 */
938

    
939
#ifdef G_OS_WIN32
940
static gboolean win32_ipv6_supported(void)
941
{
942
        static gboolean ipv6_checked = FALSE;
943
        HMODULE hmodule;
944

    
945
        if (ipv6_checked)
946
                return getaddrinfo_func != NULL;
947

    
948
        hmodule = GetModuleHandleA("ws2_32");
949
        if (hmodule) {
950
                getaddrinfo_func =
951
                        (GetAddrInfoFunc)GetProcAddress(hmodule, "getaddrinfo");
952
                freeaddrinfo_func =
953
                        (FreeAddrInfoFunc)GetProcAddress(hmodule, "freeaddrinfo");
954
                if (!getaddrinfo_func || !freeaddrinfo_func) {
955
                        getaddrinfo_func = NULL;
956
                        freeaddrinfo_func = NULL;
957
                }
958
        }
959

    
960
        if (getaddrinfo_func)
961
                debug_print("ws2_32 has IPv6 functions.\n");
962
        else
963
                debug_print("ws2_32 does not have IPv6 functions.\n");
964

    
965
        ipv6_checked = TRUE;
966
        return getaddrinfo_func != NULL;
967
}
968

    
969
/* subset of getaddrinfo() */
970
static int my_getaddrinfo(const char *node, const char *service,
971
                          const struct addrinfo *hintp,
972
                          struct addrinfo **res)
973
{
974
        struct addrinfo *ai;
975
        struct sockaddr_in addr, *paddr;
976
        struct addrinfo hints;
977
        gint port = 0;
978

    
979
        if (win32_ipv6_supported())
980
                return getaddrinfo_func(node, service, hintp, res);
981

    
982
        if (!hintp) {
983
                memset(&hints, 0, sizeof(hints));
984
                hints.ai_family = AF_INET;
985
                hints.ai_socktype = SOCK_STREAM;
986
        } else
987
                memcpy(&hints, hintp, sizeof(hints));
988

    
989
        if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET)
990
                return EAI_FAMILY;
991
        if (hints.ai_socktype == 0)
992
                hints.ai_socktype = SOCK_STREAM;
993
        if (hints.ai_protocol == 0)
994
                hints.ai_protocol = IPPROTO_TCP;
995
        if (hints.ai_socktype != SOCK_STREAM)
996
                return EAI_SOCKTYPE;
997
        if (hints.ai_protocol != IPPROTO_TCP)
998
                return EAI_SOCKTYPE;
999
#if 0
1000
        if (!node && !service)
1001
                return EAI_NONAME;
1002
#endif
1003
        if (!node || !service)
1004
                return EAI_NONAME;
1005

    
1006
        port = atoi(service);
1007

    
1008
        memset(&addr, 0, sizeof(addr));
1009
        addr.sin_family = AF_INET;
1010
        addr.sin_port = htons(port);
1011

    
1012
        if (!my_inet_aton(node, &addr.sin_addr)) {
1013
                struct hostent *hp;
1014

    
1015
                if ((hp = my_gethostbyname(node)) == NULL) {
1016
                        fprintf(stderr, "%s: unknown host.\n", node);
1017
                        errno = 0;
1018
                        return EAI_NONAME;
1019
                }
1020
                if (hp->h_length != 4 && hp->h_length != 8) {
1021
                        fprintf(stderr, "illegal address length received for host %s\n", node);
1022
                        errno = 0;
1023
                        return EAI_FAIL;
1024
                }
1025

    
1026
                memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
1027
        }
1028

    
1029
        ai = g_malloc0(sizeof(struct addrinfo));
1030
        paddr = g_malloc(sizeof(struct sockaddr_in));
1031
        memcpy(paddr, &addr, sizeof(struct sockaddr_in));
1032

    
1033
        ai->ai_flags = 0;
1034
        ai->ai_family = AF_INET;
1035
        ai->ai_socktype = hints.ai_socktype;
1036
        ai->ai_protocol = hints.ai_protocol;
1037
        ai->ai_addrlen = sizeof(struct sockaddr_in);
1038
        ai->ai_addr = (struct sockaddr *)paddr;
1039
        ai->ai_canonname = NULL;
1040
        ai->ai_next = NULL;
1041

    
1042
        *res = ai;
1043

    
1044
        return 0;
1045
}
1046

    
1047
static void my_freeaddrinfo(struct addrinfo *res)
1048
{
1049
        if (win32_ipv6_supported()) {
1050
                freeaddrinfo_func(res);
1051
                return;
1052
        }
1053

    
1054
        if (res) {
1055
                g_free(res->ai_addr);
1056
                g_free(res);
1057
        }
1058
}
1059

    
1060
/* MinGW defines gai_strerror() in ws2tcpip.h, but it is not implemented. */
1061
#undef gai_strerror
1062
const gchar *gai_strerror(gint errcode)
1063
{
1064
        static gchar str[32];
1065

    
1066
        g_snprintf(str, sizeof(str), "gai errcode: (%d)", errcode);
1067
        return str;
1068
}
1069
#endif
1070

    
1071
static SockDesc sock_info_connect_by_getaddrinfo(SockInfo *sockinfo)
1072
{
1073
        SockDesc sock = INVALID_SOCKET;
1074
        gint gai_error;
1075
        struct addrinfo hints, *res, *ai;
1076
        gchar port_str[6];
1077

    
1078
        g_return_val_if_fail(sockinfo != NULL, INVALID_SOCKET);
1079
        g_return_val_if_fail(sockinfo->hostname != NULL && sockinfo->port > 0, INVALID_SOCKET);
1080

    
1081
        resolver_init();
1082

    
1083
        memset(&hints, 0, sizeof(hints));
1084
        /* hints.ai_flags = AI_CANONNAME; */
1085
        hints.ai_family = AF_UNSPEC;
1086
        hints.ai_socktype = SOCK_STREAM;
1087
        hints.ai_protocol = IPPROTO_TCP;
1088

    
1089
        /* convert port from integer to string. */
1090
        g_snprintf(port_str, sizeof(port_str), "%d", sockinfo->port);
1091

    
1092
        if ((gai_error = getaddrinfo(sockinfo->hostname, port_str, &hints, &res)) != 0) {
1093
                fprintf(stderr, "getaddrinfo for %s:%s failed: %s\n",
1094
                        sockinfo->hostname, port_str, gai_strerror(gai_error));
1095
                sockinfo->state = CONN_LOOKUPFAILED;
1096
                return INVALID_SOCKET;
1097
        }
1098

    
1099
        for (ai = res; ai != NULL; ai = ai->ai_next) {
1100
                sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1101
                if (!SOCKET_IS_VALID(sock))
1102
                        continue;
1103
                sock_set_buffer_size(sock);
1104

    
1105
                if (sock_connect_with_timeout
1106
                        (sock, ai->ai_addr, ai->ai_addrlen, io_timeout) == 0)
1107
                        break;
1108

    
1109
                fd_close(sock);
1110
        }
1111

    
1112
        if (res != NULL)
1113
                freeaddrinfo(res);
1114

    
1115
        if (ai == NULL) {
1116
                sockinfo->state = CONN_FAILED;
1117
                return INVALID_SOCKET;
1118
        }
1119

    
1120
        sockinfo->state = CONN_ESTABLISHED;
1121
        return sock;
1122
}
1123
#endif /* !INET6 */
1124

    
1125
SockInfo *sock_connect(const gchar *hostname, gushort port)
1126
{
1127
        SockInfo *sockinfo;
1128

    
1129
        sockinfo = sock_new(hostname, port);
1130
        if (sock_info_connect(sockinfo) < 0) {
1131
                sock_close(sockinfo);
1132
                return NULL;
1133
        }
1134

    
1135
        return sockinfo;
1136
}
1137

    
1138
gint sock_info_connect(SockInfo *sockinfo)
1139
{
1140
        SockDesc sock;
1141
#ifndef INET6
1142
        gint ret;
1143
#endif
1144

    
1145
        g_return_val_if_fail(sockinfo != NULL, -1);
1146
        g_return_val_if_fail(sockinfo->hostname != NULL && sockinfo->port > 0,
1147
                             -1);
1148

    
1149
#ifdef INET6
1150
        sock = sock_info_connect_by_getaddrinfo(sockinfo);
1151
        if (!SOCKET_IS_VALID(sock)) {
1152
                return -1;
1153
        }
1154
#else
1155
        sock = socket(AF_INET, SOCK_STREAM, 0);
1156
        if (!SOCKET_IS_VALID(sock)) {
1157
#ifdef G_OS_WIN32
1158
                g_warning("socket() failed: %ld\n", WSAGetLastError());
1159
#else
1160
                perror("socket");
1161
#endif /* G_OS_WIN32 */
1162
                sockinfo->state = CONN_FAILED;
1163
                return -1;
1164
        }
1165
        sock_set_buffer_size(sock);
1166

    
1167
        sockinfo->sock = sock;
1168
        if ((ret = sock_info_connect_by_hostname(sockinfo)) < 0) {
1169
                if (errno != 0) perror("connect");
1170
                fd_close(sock);
1171
                sockinfo->sock = INVALID_SOCKET;
1172
                return ret;
1173
        }
1174
#endif /* INET6 */
1175

    
1176
        sockinfo->sock = sock;
1177
        sockinfo->sock_ch = g_io_channel_unix_new(sock);
1178
        sockinfo->flags = SYL_SOCK_CHECK_IO;
1179

    
1180
        sock_list = g_list_prepend(sock_list, sockinfo);
1181

    
1182
        g_usleep(100000);
1183

    
1184
        return 0;
1185
}
1186

    
1187
#ifdef G_OS_UNIX
1188
static void sock_address_list_free(GList *addr_list)
1189
{
1190
        GList *cur;
1191

    
1192
        for (cur = addr_list; cur != NULL; cur = cur->next) {
1193
                SockAddrData *addr_data = (SockAddrData *)cur->data;
1194
                g_free(addr_data->addr);
1195
                g_free(addr_data);
1196
        }
1197

    
1198
        g_list_free(addr_list);
1199
}
1200

    
1201
/* asynchronous TCP connection */
1202

    
1203
static gboolean sock_connect_async_cb(GIOChannel *source,
1204
                                      GIOCondition condition, gpointer data)
1205
{
1206
        SockConnectData *conn_data = (SockConnectData *)data;
1207
        gint fd;
1208
        gint val;
1209
        guint len;
1210
        SockInfo *sockinfo;
1211

    
1212
        fd = g_io_channel_unix_get_fd(source);
1213

    
1214
        conn_data->io_tag = 0;
1215
        conn_data->channel = NULL;
1216
        g_io_channel_unref(source);
1217

    
1218
        if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
1219
                debug_print("sock_connect_async_cb: condition = %d\n",
1220
                            condition);
1221
                fd_close(fd);
1222
                sock_connect_address_list_async(conn_data);
1223
                return FALSE;
1224
        }
1225

    
1226
        len = sizeof(val);
1227
        if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len) < 0) {
1228
                perror("getsockopt");
1229
                fd_close(fd);
1230
                sock_connect_address_list_async(conn_data);
1231
                return FALSE;
1232
        }
1233

    
1234
        if (val != 0) {
1235
                debug_print("getsockopt(SOL_SOCKET, SO_ERROR) returned error\n");
1236
                fd_close(fd);
1237
                sock_connect_address_list_async(conn_data);
1238
                return FALSE;
1239
        }
1240

    
1241
        sockinfo = conn_data->sock;
1242
        sockinfo->sock = fd;
1243
        sockinfo->sock_ch = g_io_channel_unix_new(fd);
1244
        sockinfo->state = CONN_ESTABLISHED;
1245
        sockinfo->flags = SYL_SOCK_NONBLOCK;
1246

    
1247
        sock_list = g_list_prepend(sock_list, sockinfo);
1248

    
1249
        conn_data->func(sockinfo, conn_data->data);
1250

    
1251
        conn_data->sock = NULL;
1252
        sock_connect_async_cancel(conn_data->id);
1253

    
1254
        return FALSE;
1255
}
1256

    
1257
static gint sock_connect_async_get_address_info_cb(GList *addr_list,
1258
                                                   gpointer data)
1259
{
1260
        SockConnectData *conn_data = (SockConnectData *)data;
1261

    
1262
        conn_data->addr_list = addr_list;
1263
        conn_data->cur_addr = addr_list;
1264
        conn_data->lookup_data = NULL;
1265

    
1266
        return sock_connect_address_list_async(conn_data);
1267
}
1268

    
1269
gint sock_connect_async(const gchar *hostname, gushort port,
1270
                        SockConnectFunc func, gpointer data)
1271
{
1272
        SockInfo *sock;
1273
        gint ret;
1274

    
1275
        sock = sock_new(hostname, port);
1276
        ret = sock_info_connect_async(sock, func, data);
1277
        if (ret < 0)
1278
                sock_close(sock);
1279

    
1280
        return ret;
1281
}
1282

    
1283
gint sock_info_connect_async(SockInfo *sock, SockConnectFunc func,
1284
                             gpointer data)
1285
{
1286
        static gint id = 1;
1287
        SockConnectData *conn_data;
1288

    
1289
        g_return_val_if_fail(sock != NULL, -1);
1290
        g_return_val_if_fail(sock->hostname != NULL && sock->port > 0, -1);
1291

    
1292
        conn_data = g_new0(SockConnectData, 1);
1293
        conn_data->id = id++;
1294
        conn_data->hostname = g_strdup(sock->hostname);
1295
        conn_data->port = sock->port;
1296
        conn_data->addr_list = NULL;
1297
        conn_data->cur_addr = NULL;
1298
        conn_data->io_tag = 0;
1299
        conn_data->sock = sock;
1300
        conn_data->func = func;
1301
        conn_data->data = data;
1302

    
1303
        conn_data->lookup_data = sock_get_address_info_async
1304
                (sock->hostname, sock->port,
1305
                 sock_connect_async_get_address_info_cb, conn_data);
1306

    
1307
        if (conn_data->lookup_data == NULL) {
1308
                g_free(conn_data->hostname);
1309
                g_free(conn_data);
1310
                return -1;
1311
        }
1312

    
1313
        sock_connect_data_list = g_list_append(sock_connect_data_list,
1314
                                               conn_data);
1315

    
1316
        return conn_data->id;
1317
}
1318

    
1319
gint sock_connect_async_cancel(gint id)
1320
{
1321
        SockConnectData *conn_data = NULL;
1322
        GList *cur;
1323

    
1324
        for (cur = sock_connect_data_list; cur != NULL; cur = cur->next) {
1325
                if (((SockConnectData *)cur->data)->id == id) {
1326
                        conn_data = (SockConnectData *)cur->data;
1327
                        break;
1328
                }
1329
        }
1330

    
1331
        if (conn_data) {
1332
                sock_connect_data_list = g_list_remove(sock_connect_data_list,
1333
                                                       conn_data);
1334

    
1335
                if (conn_data->lookup_data)
1336
                        sock_get_address_info_async_cancel
1337
                                (conn_data->lookup_data);
1338

    
1339
                if (conn_data->io_tag > 0)
1340
                        g_source_remove(conn_data->io_tag);
1341
                if (conn_data->channel) {
1342
                        g_io_channel_shutdown(conn_data->channel, FALSE, NULL);
1343
                        g_io_channel_unref(conn_data->channel);
1344
                }
1345
                if (conn_data->sock)
1346
                        sock_close(conn_data->sock);
1347

    
1348
                sock_address_list_free(conn_data->addr_list);
1349
                g_free(conn_data->hostname);
1350
                g_free(conn_data);
1351
        } else {
1352
                g_warning("sock_connect_async_cancel: id %d not found.\n", id);
1353
                return -1;
1354
        }
1355

    
1356
        return 0;
1357
}
1358

    
1359
static gint sock_connect_address_list_async(SockConnectData *conn_data)
1360
{
1361
        SockAddrData *addr_data;
1362
        gint sock = -1;
1363

    
1364
        if (conn_data->addr_list == NULL) {
1365
                g_warning("sock_connect_address_list_async: "
1366
                          "DNS lookup for %s failed", conn_data->hostname);
1367
                conn_data->sock->state = CONN_LOOKUPFAILED;
1368
                conn_data->func(conn_data->sock, conn_data->data);
1369
                sock_connect_async_cancel(conn_data->id);
1370
                return -1;
1371
        }
1372

    
1373
        for (; conn_data->cur_addr != NULL;
1374
             conn_data->cur_addr = conn_data->cur_addr->next) {
1375
                addr_data = (SockAddrData *)conn_data->cur_addr->data;
1376

    
1377
                if ((sock = socket(addr_data->family, addr_data->socktype,
1378
                                   addr_data->protocol)) < 0) {
1379
                        perror("socket");
1380
                        continue;
1381
                }
1382

    
1383
                sock_set_buffer_size(sock);
1384
                set_nonblocking_mode(sock, TRUE);
1385

    
1386
                if (connect(sock, addr_data->addr, addr_data->addr_len) < 0) {
1387
                        if (EINPROGRESS == errno) {
1388
                                break;
1389
                        } else {
1390
                                perror("connect");
1391
                                fd_close(sock);
1392
                        }
1393
                } else
1394
                        break;
1395
        }
1396

    
1397
        if (conn_data->cur_addr == NULL) {
1398
                g_warning("sock_connect_address_list_async: "
1399
                          "connection to %s:%d failed",
1400
                          conn_data->hostname, conn_data->port);
1401
                conn_data->sock->state = CONN_FAILED;
1402
                conn_data->func(conn_data->sock, conn_data->data);
1403
                sock_connect_async_cancel(conn_data->id);
1404
                return -1;
1405
        }
1406

    
1407
        debug_print("sock_connect_address_list_async: waiting for connect\n");
1408

    
1409
        conn_data->cur_addr = conn_data->cur_addr->next;
1410

    
1411
        conn_data->channel = g_io_channel_unix_new(sock);
1412
        conn_data->io_tag = g_io_add_watch
1413
                (conn_data->channel, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
1414
                 sock_connect_async_cb, conn_data);
1415

    
1416
        return 0;
1417
}
1418

    
1419
static gint sock_kill_process(pid_t pid)
1420
{
1421
        pid_t ret = (pid_t)-1;
1422

    
1423
        kill(pid, SIGKILL);
1424

    
1425
        while (ret == (pid_t)-1) {
1426
                if ((ret = waitpid(pid, NULL, 0)) != pid) {
1427
                        if (ret == (pid_t)-1 && errno != EINTR) {
1428
                                perror("sock_kill_process(): waitpid");
1429
                                break;
1430
                        }
1431
                }
1432
        }
1433

    
1434
        return (gint)pid;
1435
}
1436

    
1437
/* asynchronous DNS lookup */
1438

    
1439
static gboolean sock_get_address_info_async_cb(GIOChannel *source,
1440
                                               GIOCondition condition,
1441
                                               gpointer data)
1442
{
1443
        SockLookupData *lookup_data = (SockLookupData *)data;
1444
        GList *addr_list = NULL;
1445
        SockAddrData *addr_data;
1446
        gsize bytes_read;
1447
        gint ai_member[4];
1448
        struct sockaddr *addr;
1449

    
1450
        for (;;) {
1451
                if (g_io_channel_read(source, (gchar *)ai_member,
1452
                                      sizeof(ai_member), &bytes_read)
1453
                    != G_IO_ERROR_NONE) {
1454
                        g_warning("sock_get_address_info_async_cb: "
1455
                                  "address length read error\n");
1456
                        break;
1457
                }
1458

    
1459
                if (bytes_read == 0 || bytes_read != sizeof(ai_member))
1460
                        break;
1461

    
1462
                if (ai_member[0] == AF_UNSPEC) {
1463
                        g_warning("DNS lookup failed");
1464
                        break;
1465
                }
1466

    
1467
                addr = g_malloc(ai_member[3]);
1468
                if (g_io_channel_read(source, (gchar *)addr, ai_member[3],
1469
                                      &bytes_read)
1470
                    != G_IO_ERROR_NONE) {
1471
                        g_warning("sock_get_address_info_async_cb: "
1472
                                  "address data read error\n");
1473
                        g_free(addr);
1474
                        break;
1475
                }
1476

    
1477
                if (bytes_read != ai_member[3]) {
1478
                        g_warning("sock_get_address_info_async_cb: "
1479
                                  "incomplete address data\n");
1480
                        g_free(addr);
1481
                        break;
1482
                }
1483

    
1484
                addr_data = g_new0(SockAddrData, 1);
1485
                addr_data->family = ai_member[0];
1486
                addr_data->socktype = ai_member[1];
1487
                addr_data->protocol = ai_member[2];
1488
                addr_data->addr_len = ai_member[3];
1489
                addr_data->addr = addr;
1490

    
1491
                addr_list = g_list_append(addr_list, addr_data);
1492
        }
1493

    
1494
        g_io_channel_shutdown(source, FALSE, NULL);
1495
        g_io_channel_unref(source);
1496

    
1497
        sock_kill_process(lookup_data->child_pid);
1498

    
1499
        lookup_data->func(addr_list, lookup_data->data);
1500

    
1501
        g_free(lookup_data->hostname);
1502
        g_free(lookup_data);
1503

    
1504
        return FALSE;
1505
}
1506

    
1507
static SockLookupData *sock_get_address_info_async(const gchar *hostname,
1508
                                                   gushort port,
1509
                                                   SockAddrFunc func,
1510
                                                   gpointer data)
1511
{
1512
        SockLookupData *lookup_data = NULL;
1513
        gint pipe_fds[2];
1514
        pid_t pid;
1515

    
1516
        resolver_init();
1517

    
1518
        if (pipe(pipe_fds) < 0) {
1519
                perror("pipe");
1520
                func(NULL, data);
1521
                return NULL;
1522
        }
1523

    
1524
        if ((pid = fork()) < 0) {
1525
                perror("fork");
1526
                func(NULL, data);
1527
                return NULL;
1528
        }
1529

    
1530
        /* child process */
1531
        if (pid == 0) {
1532
#ifdef INET6
1533
                gint gai_err;
1534
                struct addrinfo hints, *res, *ai;
1535
                gchar port_str[6];
1536
#else /* !INET6 */
1537
                struct hostent *hp;
1538
                gchar **addr_list_p;
1539
                struct sockaddr_in ad;
1540
#endif /* INET6 */
1541
                gint ai_member[4] = {AF_UNSPEC, 0, 0, 0};
1542

    
1543
                close(pipe_fds[0]);
1544

    
1545
#ifdef INET6
1546
                memset(&hints, 0, sizeof(hints));
1547
                /* hints.ai_flags = AI_CANONNAME; */
1548
                hints.ai_family = AF_UNSPEC;
1549
                hints.ai_socktype = SOCK_STREAM;
1550
                hints.ai_protocol = IPPROTO_TCP;
1551

    
1552
                g_snprintf(port_str, sizeof(port_str), "%d", port);
1553

    
1554
                gai_err = getaddrinfo(hostname, port_str, &hints, &res);
1555
                if (gai_err != 0) {
1556
                        g_warning("getaddrinfo for %s:%s failed: %s",
1557
                                  hostname, port_str, gai_strerror(gai_err));
1558
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
1559
                                     sizeof(ai_member));
1560
                        close(pipe_fds[1]);
1561
                        _exit(1);
1562
                }
1563

    
1564
                for (ai = res; ai != NULL; ai = ai->ai_next) {
1565
                        ai_member[0] = ai->ai_family;
1566
                        ai_member[1] = ai->ai_socktype;
1567
                        ai_member[2] = ai->ai_protocol;
1568
                        ai_member[3] = ai->ai_addrlen;
1569

    
1570
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
1571
                                     sizeof(ai_member));
1572
                        fd_write_all(pipe_fds[1], (gchar *)ai->ai_addr,
1573
                                     ai->ai_addrlen);
1574
                }
1575

    
1576
                if (res != NULL)
1577
                        freeaddrinfo(res);
1578
#else /* !INET6 */
1579
                hp = my_gethostbyname(hostname);
1580
                if (hp == NULL || hp->h_addrtype != AF_INET) {
1581
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
1582
                                     sizeof(ai_member));
1583
                        close(pipe_fds[1]);
1584
                        _exit(1);
1585
                }
1586

    
1587
                ai_member[0] = AF_INET;
1588
                ai_member[1] = SOCK_STREAM;
1589
                ai_member[2] = IPPROTO_TCP;
1590
                ai_member[3] = sizeof(ad);
1591

    
1592
                memset(&ad, 0, sizeof(ad));
1593
                ad.sin_family = AF_INET;
1594
                ad.sin_port = htons(port);
1595

    
1596
                for (addr_list_p = hp->h_addr_list; *addr_list_p != NULL;
1597
                     addr_list_p++) {
1598
                        memcpy(&ad.sin_addr, *addr_list_p, hp->h_length);
1599
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
1600
                                     sizeof(ai_member));
1601
                        fd_write_all(pipe_fds[1], (gchar *)&ad, sizeof(ad));
1602
                }
1603
#endif /* INET6 */
1604

    
1605
                close(pipe_fds[1]);
1606

    
1607
                _exit(0);
1608
        } else {
1609
                close(pipe_fds[1]);
1610

    
1611
                lookup_data = g_new0(SockLookupData, 1);
1612
                lookup_data->hostname = g_strdup(hostname);
1613
                lookup_data->child_pid = pid;
1614
                lookup_data->func = func;
1615
                lookup_data->data = data;
1616

    
1617
                lookup_data->channel = g_io_channel_unix_new(pipe_fds[0]);
1618
                lookup_data->io_tag = g_io_add_watch
1619
                        (lookup_data->channel, G_IO_IN,
1620
                         sock_get_address_info_async_cb, lookup_data);
1621
        }
1622

    
1623
        return lookup_data;
1624
}
1625

    
1626
static gint sock_get_address_info_async_cancel(SockLookupData *lookup_data)
1627
{
1628
        if (lookup_data->io_tag > 0)
1629
                g_source_remove(lookup_data->io_tag);
1630
        if (lookup_data->channel) {
1631
                g_io_channel_shutdown(lookup_data->channel, FALSE, NULL);
1632
                g_io_channel_unref(lookup_data->channel);
1633
        }
1634

    
1635
        if (lookup_data->child_pid > 0)
1636
                sock_kill_process(lookup_data->child_pid);
1637

    
1638
        g_free(lookup_data->hostname);
1639
        g_free(lookup_data);
1640

    
1641
        return 0;
1642
}
1643
#endif /* G_OS_UNIX */
1644

    
1645
#if USE_THREADS
1646
static gpointer sock_connect_async_func(gpointer data)
1647
{
1648
        SockConnectData *conn_data = (SockConnectData *)data;
1649
        gint ret;
1650

    
1651
        ret = sock_info_connect(conn_data->sock);
1652

    
1653
        if (ret == 0) {
1654
                debug_print("sock_connect_async_func: connected\n");
1655
        } else {
1656
                if (conn_data->sock->state == CONN_LOOKUPFAILED)
1657
                        debug_print("sock_connect_async_func: DNS lookup failed\n");
1658
                else
1659
                        debug_print("sock_connect_async_func: connection failed\n");
1660
        }
1661

    
1662
        g_atomic_int_set(&conn_data->flag, 1);
1663
        g_main_context_wakeup(NULL);
1664

    
1665
        debug_print("sock_connect_async_func: exit\n");
1666
        return GINT_TO_POINTER(ret);
1667
}
1668

    
1669
gint sock_connect_async_thread(const gchar *hostname, gushort port)
1670
{
1671
        SockInfo *sock;
1672
        gint ret;
1673

    
1674
        sock = sock_new(hostname, port);
1675
        ret = sock_info_connect_async_thread(sock);
1676
        if (ret < 0)
1677
                sock_close(sock);
1678

    
1679
        return ret;
1680
}
1681

    
1682
gint sock_info_connect_async_thread(SockInfo *sock)
1683
{
1684
        static gint id = 1;
1685
        SockConnectData *data;
1686

    
1687
        g_return_val_if_fail(sock != NULL, -1);
1688
        g_return_val_if_fail(sock->hostname != NULL && sock->port > 0, -1);
1689

    
1690
        data = g_new0(SockConnectData, 1);
1691
        data->id = id++;
1692
        data->hostname = g_strdup(sock->hostname);
1693
        data->port = sock->port;
1694
        data->flag = 0;
1695
        data->sock = sock;
1696

    
1697
        data->thread = g_thread_create(sock_connect_async_func, data, TRUE,
1698
                                       NULL);
1699
        if (!data->thread) {
1700
                g_free(data->hostname);
1701
                g_free(data);
1702
                return -1;
1703
        }
1704

    
1705
        sock_connect_data_list = g_list_append(sock_connect_data_list, data);
1706

    
1707
        return data->id;
1708
}
1709

    
1710
gint sock_connect_async_thread_wait(gint id, SockInfo **sock)
1711
{
1712
        gint ret;
1713

    
1714
        *sock = NULL;
1715
        ret = sock_info_connect_async_thread_wait(id, sock);
1716
        if (ret < 0) {
1717
                if (*sock) {
1718
                        sock_close(*sock);
1719
                        *sock = NULL;
1720
                }
1721
        }
1722

    
1723
        return ret;
1724
}
1725

    
1726
gint sock_info_connect_async_thread_wait(gint id, SockInfo **sock)
1727
{
1728
        SockConnectData *conn_data = NULL;
1729
        GList *cur;
1730
        gint ret;
1731

    
1732
        for (cur = sock_connect_data_list; cur != NULL; cur = cur->next) {
1733
                if (((SockConnectData *)cur->data)->id == id) {
1734
                        conn_data = (SockConnectData *)cur->data;
1735
                        break;
1736
                }
1737
        }
1738

    
1739
        if (!conn_data) {
1740
                g_warning("sock_info_connect_async_thread_wait: id %d not found.", id);
1741
                return -1;
1742
        }
1743

    
1744
        debug_print("sock_connect_async_thread_wait: waiting thread\n");
1745
        while (g_atomic_int_get(&conn_data->flag) == 0)
1746
                event_loop_iterate();
1747

    
1748
        ret = GPOINTER_TO_INT(g_thread_join(conn_data->thread));
1749
        debug_print("sock_info_connect_async_thread_wait: thread exited with status %d\n", ret);
1750

    
1751
        if (sock)
1752
                *sock = conn_data->sock;
1753

    
1754
        sock_connect_data_list = g_list_remove(sock_connect_data_list,
1755
                                               conn_data);
1756
        g_free(conn_data->hostname);
1757
        g_free(conn_data);
1758

    
1759
        return ret;
1760
}
1761
#endif /* USE_THREADS */
1762

    
1763
gint sock_printf(SockInfo *sock, const gchar *format, ...)
1764
{
1765
        va_list args;
1766
        gchar buf[BUFFSIZE];
1767

    
1768
        va_start(args, format);
1769
        g_vsnprintf(buf, sizeof(buf), format, args);
1770
        va_end(args);
1771

    
1772
        return sock_write_all(sock, buf, strlen(buf));
1773
}
1774

    
1775
#ifdef G_OS_WIN32
1776
static void sock_set_errno_from_last_error(gint error)
1777
{
1778
        switch (error) {
1779
        case WSAEWOULDBLOCK:
1780
                errno = EAGAIN;
1781
                break;
1782
        default:
1783
                debug_print("last error = %d\n", error);
1784
                errno = 0;
1785
                break;
1786
        }
1787
}
1788
#endif
1789

    
1790
gint sock_read(SockInfo *sock, gchar *buf, gint len)
1791
{
1792
        g_return_val_if_fail(sock != NULL, -1);
1793

    
1794
#if USE_SSL
1795
        if (sock->ssl)
1796
                return ssl_read(sock->ssl, buf, len);
1797
#endif
1798
        return fd_read(sock->sock, buf, len);
1799
}
1800

    
1801
gint fd_read(gint fd, gchar *buf, gint len)
1802
{
1803
#ifdef G_OS_WIN32
1804
        return fd_recv(fd, buf, len, 0);
1805
#else
1806
        if (fd_check_io(fd, G_IO_IN) < 0)
1807
                return -1;
1808

    
1809
        return read(fd, buf, len);
1810
#endif
1811
}
1812

    
1813
#if USE_SSL
1814
gint ssl_read(SSL *ssl, gchar *buf, gint len)
1815
{
1816
        gint err, ret;
1817

    
1818
        errno = 0;
1819

    
1820
        if (SSL_pending(ssl) == 0) {
1821
                if (fd_check_io(SSL_get_rfd(ssl), G_IO_IN) < 0)
1822
                        return -1;
1823
        }
1824

    
1825
        ret = SSL_read(ssl, buf, len);
1826

    
1827
        switch ((err = SSL_get_error(ssl, ret))) {
1828
        case SSL_ERROR_NONE:
1829
                return ret;
1830
        case SSL_ERROR_WANT_READ:
1831
        case SSL_ERROR_WANT_WRITE:
1832
                errno = EAGAIN;
1833
                return -1;
1834
        case SSL_ERROR_ZERO_RETURN:
1835
                return 0;
1836
        default:
1837
                g_warning("SSL_read() returned error %d, ret = %d\n", err, ret);
1838
                if (ret == 0)
1839
                        return 0;
1840
#ifdef G_OS_WIN32
1841
                errno = EIO;
1842
#endif
1843
                return -1;
1844
        }
1845
}
1846
#endif
1847

    
1848
gint sock_write(SockInfo *sock, const gchar *buf, gint len)
1849
{
1850
        g_return_val_if_fail(sock != NULL, -1);
1851

    
1852
#if USE_SSL
1853
        if (sock->ssl)
1854
                return ssl_write(sock->ssl, buf, len);
1855
#endif
1856
        return fd_write(sock->sock, buf, len);
1857
}
1858

    
1859
gint fd_write(gint fd, const gchar *buf, gint len)
1860
{
1861
#ifdef G_OS_WIN32
1862
        gint ret;
1863
#endif
1864
        if (fd_check_io(fd, G_IO_OUT) < 0)
1865
                return -1;
1866

    
1867
#ifdef G_OS_WIN32
1868
        ret = send(fd, buf, len, 0);
1869
        if (ret == SOCKET_ERROR) {
1870
                gint err;
1871
                err = WSAGetLastError();
1872
                sock_set_errno_from_last_error(err);
1873
                if (err != WSAEWOULDBLOCK)
1874
                        g_warning("fd_write() failed with %d (errno = %d)\n",
1875
                                  err, errno);
1876
        }
1877
        return ret;
1878
#else
1879
        return write(fd, buf, len);
1880
#endif
1881
}
1882

    
1883
#if USE_SSL
1884
gint ssl_write(SSL *ssl, const gchar *buf, gint len)
1885
{
1886
        gint ret;
1887

    
1888
        ret = SSL_write(ssl, buf, len);
1889

    
1890
        switch (SSL_get_error(ssl, ret)) {
1891
        case SSL_ERROR_NONE:
1892
                return ret;
1893
        case SSL_ERROR_WANT_READ:
1894
        case SSL_ERROR_WANT_WRITE:
1895
                errno = EAGAIN;
1896
                return -1;
1897
        default:
1898
                return -1;
1899
        }
1900
}
1901
#endif
1902

    
1903
gint sock_write_all(SockInfo *sock, const gchar *buf, gint len)
1904
{
1905
        g_return_val_if_fail(sock != NULL, -1);
1906

    
1907
#if USE_SSL
1908
        if (sock->ssl)
1909
                return ssl_write_all(sock->ssl, buf, len);
1910
#endif
1911
        return fd_write_all(sock->sock, buf, len);
1912
}
1913

    
1914
gint fd_write_all(gint fd, const gchar *buf, gint len)
1915
{
1916
        gint n, wrlen = 0;
1917

    
1918
        while (len) {
1919
                n = fd_write(fd, buf, len);
1920
                if (n <= 0)
1921
                        return -1;
1922
                len -= n;
1923
                wrlen += n;
1924
                buf += n;
1925
        }
1926

    
1927
        return wrlen;
1928
}
1929

    
1930
#if USE_SSL
1931
gint ssl_write_all(SSL *ssl, const gchar *buf, gint len)
1932
{
1933
        gint n, wrlen = 0;
1934

    
1935
        while (len) {
1936
                n = ssl_write(ssl, buf, len);
1937
                if (n <= 0)
1938
                        return -1;
1939
                len -= n;
1940
                wrlen += n;
1941
                buf += n;
1942
        }
1943

    
1944
        return wrlen;
1945
}
1946
#endif
1947

    
1948
gint fd_recv(gint fd, gchar *buf, gint len, gint flags)
1949
{
1950
#ifdef G_OS_WIN32
1951
        gint ret;
1952
#endif
1953
        if (fd_check_io(fd, G_IO_IN) < 0)
1954
                return -1;
1955

    
1956
#ifdef G_OS_WIN32
1957
        ret = recv(fd, buf, len, flags);
1958
        if (ret == SOCKET_ERROR) {
1959
                gint err;
1960
                err = WSAGetLastError();
1961
                sock_set_errno_from_last_error(err);
1962
                if (err != WSAEWOULDBLOCK)
1963
                        g_warning("fd_recv(): failed with %d (errno = %d)\n",
1964
                                  err, errno);
1965
        }
1966
        return ret;
1967
#else
1968
        return recv(fd, buf, len, flags);
1969
#endif
1970
}
1971

    
1972
gint fd_gets(gint fd, gchar *buf, gint len)
1973
{
1974
        gchar *newline, *bp = buf;
1975
        gint n;
1976

    
1977
        if (--len < 1)
1978
                return -1;
1979
        do {
1980
                if ((n = fd_recv(fd, bp, len, MSG_PEEK)) <= 0)
1981
                        return -1;
1982
                if ((newline = memchr(bp, '\n', n)) != NULL)
1983
                        n = newline - bp + 1;
1984
                if ((n = fd_read(fd, bp, n)) < 0)
1985
                        return -1;
1986
                bp += n;
1987
                len -= n;
1988
        } while (!newline && len);
1989

    
1990
        *bp = '\0';
1991
        return bp - buf;
1992
}
1993

    
1994
#if USE_SSL
1995
gint ssl_gets(SSL *ssl, gchar *buf, gint len)
1996
{
1997
        gchar *newline, *bp = buf;
1998
        gint n;
1999

    
2000
        if (--len < 1)
2001
                return -1;
2002
        do {
2003
                if ((n = ssl_peek(ssl, bp, len)) <= 0)
2004
                        return -1;
2005
                if ((newline = memchr(bp, '\n', n)) != NULL)
2006
                        n = newline - bp + 1;
2007
                if ((n = ssl_read(ssl, bp, n)) < 0)
2008
                        return -1;
2009
                bp += n;
2010
                len -= n;
2011
        } while (!newline && len);
2012

    
2013
        *bp = '\0';
2014
        return bp - buf;
2015
}
2016
#endif
2017

    
2018
gint sock_gets(SockInfo *sock, gchar *buf, gint len)
2019
{
2020
        g_return_val_if_fail(sock != NULL, -1);
2021

    
2022
#if USE_SSL
2023
        if (sock->ssl)
2024
                return ssl_gets(sock->ssl, buf, len);
2025
#endif
2026
        return fd_gets(sock->sock, buf, len);
2027
}
2028

    
2029
gint fd_getline(gint fd, gchar **line)
2030
{
2031
        gchar buf[BUFFSIZE];
2032
        gchar *str = NULL;
2033
        gint len;
2034
        gulong size = 0;
2035
        gulong cur_offset = 0;
2036

    
2037
        while ((len = fd_gets(fd, buf, sizeof(buf))) > 0) {
2038
                size += len;
2039
                str = g_realloc(str, size + 1);
2040
                memcpy(str + cur_offset, buf, len + 1);
2041
                cur_offset += len;
2042
                if (buf[len - 1] == '\n')
2043
                        break;
2044
        }
2045

    
2046
        *line = str;
2047

    
2048
        if (!str)
2049
                return -1;
2050
        else
2051
                return (gint)size;
2052
}
2053

    
2054
#if USE_SSL
2055
gint ssl_getline(SSL *ssl, gchar **line)
2056
{
2057
        gchar buf[BUFFSIZE];
2058
        gchar *str = NULL;
2059
        gint len;
2060
        gulong size = 0;
2061
        gulong cur_offset = 0;
2062

    
2063
        while ((len = ssl_gets(ssl, buf, sizeof(buf))) > 0) {
2064
                size += len;
2065
                str = g_realloc(str, size + 1);
2066
                memcpy(str + cur_offset, buf, len + 1);
2067
                cur_offset += len;
2068
                if (buf[len - 1] == '\n')
2069
                        break;
2070
        }
2071

    
2072
        *line = str;
2073

    
2074
        if (!str)
2075
                return -1;
2076
        else
2077
                return (gint)size;
2078
}
2079
#endif
2080

    
2081
gint sock_getline(SockInfo *sock, gchar **line)
2082
{
2083
        g_return_val_if_fail(sock != NULL, -1);
2084
        g_return_val_if_fail(line != NULL, -1);
2085

    
2086
#if USE_SSL
2087
        if (sock->ssl)
2088
                return ssl_getline(sock->ssl, line);
2089
#endif
2090
        return fd_getline(sock->sock, line);
2091
}
2092

    
2093
gint sock_puts(SockInfo *sock, const gchar *buf)
2094
{
2095
        gint ret;
2096

    
2097
        if ((ret = sock_write_all(sock, buf, strlen(buf))) < 0)
2098
                return ret;
2099
        return sock_write_all(sock, "\r\n", 2);
2100
}
2101

    
2102
/* peek at the socket data without actually reading it */
2103
#if USE_SSL
2104
gint ssl_peek(SSL *ssl, gchar *buf, gint len)
2105
{
2106
        gint err, ret;
2107

    
2108
        if (SSL_pending(ssl) == 0) {
2109
                if (fd_check_io(SSL_get_rfd(ssl), G_IO_IN) < 0)
2110
                        return -1;
2111
        }
2112

    
2113
        ret = SSL_peek(ssl, buf, len);
2114

    
2115
        switch ((err = SSL_get_error(ssl, ret))) {
2116
        case SSL_ERROR_NONE:
2117
                return ret;
2118
        case SSL_ERROR_WANT_READ:
2119
        case SSL_ERROR_WANT_WRITE:
2120
                errno = EAGAIN;
2121
                return -1;
2122
        case SSL_ERROR_ZERO_RETURN:
2123
                return 0;
2124
        default:
2125
                g_warning("SSL_peek() returned error %d, ret = %d\n", err, ret);
2126
                if (ret == 0)
2127
                        return 0;
2128
                return -1;
2129
        }
2130
}
2131
#endif
2132

    
2133
gint sock_peek(SockInfo *sock, gchar *buf, gint len)
2134
{
2135
        g_return_val_if_fail(sock != NULL, -1);
2136

    
2137
#if USE_SSL
2138
        if (sock->ssl)
2139
                return ssl_peek(sock->ssl, buf, len);
2140
#endif
2141
        return fd_recv(sock->sock, buf, len, MSG_PEEK);
2142
}
2143

    
2144
gint sock_close(SockInfo *sock)
2145
{
2146
        GList *cur;
2147

    
2148
        if (!sock)
2149
                return 0;
2150

    
2151
        debug_print("sock_close: %s:%u (%p)\n", sock->hostname ? sock->hostname : "(none)", sock->port, sock);
2152

    
2153
#if USE_SSL
2154
        if (sock->ssl)
2155
                ssl_done_socket(sock);
2156
#endif
2157

    
2158
        if (sock->sock_ch) {
2159
                g_io_channel_shutdown(sock->sock_ch, FALSE, NULL);
2160
                g_io_channel_unref(sock->sock_ch);
2161
        }
2162

    
2163
        for (cur = sock_list; cur != NULL; cur = cur->next) {
2164
                if ((SockInfo *)cur->data == sock) {
2165
                        sock_list = g_list_remove(sock_list, sock);
2166
                        break;
2167
                }
2168
        }
2169

    
2170
        g_free(sock->hostname);
2171
        g_free(sock);
2172

    
2173
        return 0;
2174
}
2175

    
2176
gint fd_close(gint fd)
2177
{
2178
#ifdef G_OS_WIN32
2179
        return closesocket(fd);
2180
#else
2181
        return close(fd);
2182
#endif
2183
}