Statistics
| Revision:

root / libsylph / socket.c @ 3419

History | View | Annotate | Download (44.9 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
        GStatBuf 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
#endif
1060

    
1061
static SockDesc sock_info_connect_by_getaddrinfo(SockInfo *sockinfo)
1062
{
1063
        SockDesc sock = INVALID_SOCKET;
1064
        gint gai_error;
1065
        struct addrinfo hints, *res, *ai;
1066
        gchar port_str[6];
1067

    
1068
        g_return_val_if_fail(sockinfo != NULL, INVALID_SOCKET);
1069
        g_return_val_if_fail(sockinfo->hostname != NULL && sockinfo->port > 0, INVALID_SOCKET);
1070

    
1071
        resolver_init();
1072

    
1073
        memset(&hints, 0, sizeof(hints));
1074
        /* hints.ai_flags = AI_CANONNAME; */
1075
        hints.ai_family = AF_UNSPEC;
1076
        hints.ai_socktype = SOCK_STREAM;
1077
        hints.ai_protocol = IPPROTO_TCP;
1078

    
1079
        /* convert port from integer to string. */
1080
        g_snprintf(port_str, sizeof(port_str), "%d", sockinfo->port);
1081

    
1082
        if ((gai_error = getaddrinfo(sockinfo->hostname, port_str, &hints, &res)) != 0) {
1083
#ifdef G_OS_WIN32
1084
                fprintf(stderr, "getaddrinfo for %s:%s failed: errno: %d\n",
1085
                        sockinfo->hostname, port_str, gai_error);
1086
#else
1087
                fprintf(stderr, "getaddrinfo for %s:%s failed: %s\n",
1088
                        sockinfo->hostname, port_str, gai_strerror(gai_error));
1089
#endif
1090
                debug_print("getaddrinfo failed\n");
1091
                sockinfo->state = CONN_LOOKUPFAILED;
1092
                return INVALID_SOCKET;
1093
        }
1094

    
1095
        for (ai = res; ai != NULL; ai = ai->ai_next) {
1096
                sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1097
                if (!SOCKET_IS_VALID(sock))
1098
                        continue;
1099
                sock_set_buffer_size(sock);
1100

    
1101
                if (sock_connect_with_timeout
1102
                        (sock, ai->ai_addr, ai->ai_addrlen, io_timeout) == 0)
1103
                        break;
1104

    
1105
                fd_close(sock);
1106
        }
1107

    
1108
        if (res != NULL)
1109
                freeaddrinfo(res);
1110

    
1111
        if (ai == NULL) {
1112
                sockinfo->state = CONN_FAILED;
1113
                return INVALID_SOCKET;
1114
        }
1115

    
1116
        sockinfo->state = CONN_ESTABLISHED;
1117
        return sock;
1118
}
1119
#endif /* !INET6 */
1120

    
1121
SockInfo *sock_connect(const gchar *hostname, gushort port)
1122
{
1123
        SockInfo *sockinfo;
1124

    
1125
        sockinfo = sock_new(hostname, port);
1126
        if (sock_info_connect(sockinfo) < 0) {
1127
                sock_close(sockinfo);
1128
                return NULL;
1129
        }
1130

    
1131
        return sockinfo;
1132
}
1133

    
1134
gint sock_info_connect(SockInfo *sockinfo)
1135
{
1136
        SockDesc sock;
1137
#ifndef INET6
1138
        gint ret;
1139
#endif
1140

    
1141
        g_return_val_if_fail(sockinfo != NULL, -1);
1142
        g_return_val_if_fail(sockinfo->hostname != NULL && sockinfo->port > 0,
1143
                             -1);
1144

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

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

    
1172
        sockinfo->sock = sock;
1173
        sockinfo->sock_ch = g_io_channel_unix_new(sock);
1174
        sockinfo->flags = SYL_SOCK_CHECK_IO;
1175

    
1176
        sock_list = g_list_prepend(sock_list, sockinfo);
1177

    
1178
        g_usleep(100000);
1179

    
1180
        return 0;
1181
}
1182

    
1183
#ifdef G_OS_UNIX
1184
static void sock_address_list_free(GList *addr_list)
1185
{
1186
        GList *cur;
1187

    
1188
        for (cur = addr_list; cur != NULL; cur = cur->next) {
1189
                SockAddrData *addr_data = (SockAddrData *)cur->data;
1190
                g_free(addr_data->addr);
1191
                g_free(addr_data);
1192
        }
1193

    
1194
        g_list_free(addr_list);
1195
}
1196

    
1197
/* asynchronous TCP connection */
1198

    
1199
static gboolean sock_connect_async_cb(GIOChannel *source,
1200
                                      GIOCondition condition, gpointer data)
1201
{
1202
        SockConnectData *conn_data = (SockConnectData *)data;
1203
        gint fd;
1204
        gint val;
1205
        guint len;
1206
        SockInfo *sockinfo;
1207

    
1208
        fd = g_io_channel_unix_get_fd(source);
1209

    
1210
        conn_data->io_tag = 0;
1211
        conn_data->channel = NULL;
1212
        g_io_channel_unref(source);
1213

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

    
1222
        len = sizeof(val);
1223
        if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len) < 0) {
1224
                perror("getsockopt");
1225
                fd_close(fd);
1226
                sock_connect_address_list_async(conn_data);
1227
                return FALSE;
1228
        }
1229

    
1230
        if (val != 0) {
1231
                debug_print("getsockopt(SOL_SOCKET, SO_ERROR) returned error\n");
1232
                fd_close(fd);
1233
                sock_connect_address_list_async(conn_data);
1234
                return FALSE;
1235
        }
1236

    
1237
        sockinfo = conn_data->sock;
1238
        sockinfo->sock = fd;
1239
        sockinfo->sock_ch = g_io_channel_unix_new(fd);
1240
        sockinfo->state = CONN_ESTABLISHED;
1241
        sockinfo->flags = SYL_SOCK_NONBLOCK;
1242

    
1243
        sock_list = g_list_prepend(sock_list, sockinfo);
1244

    
1245
        conn_data->func(sockinfo, conn_data->data);
1246

    
1247
        conn_data->sock = NULL;
1248
        sock_connect_async_cancel(conn_data->id);
1249

    
1250
        return FALSE;
1251
}
1252

    
1253
static gint sock_connect_async_get_address_info_cb(GList *addr_list,
1254
                                                   gpointer data)
1255
{
1256
        SockConnectData *conn_data = (SockConnectData *)data;
1257

    
1258
        conn_data->addr_list = addr_list;
1259
        conn_data->cur_addr = addr_list;
1260
        conn_data->lookup_data = NULL;
1261

    
1262
        return sock_connect_address_list_async(conn_data);
1263
}
1264

    
1265
gint sock_connect_async(const gchar *hostname, gushort port,
1266
                        SockConnectFunc func, gpointer data)
1267
{
1268
        SockInfo *sock;
1269
        gint ret;
1270

    
1271
        sock = sock_new(hostname, port);
1272
        ret = sock_info_connect_async(sock, func, data);
1273
        if (ret < 0)
1274
                sock_close(sock);
1275

    
1276
        return ret;
1277
}
1278

    
1279
gint sock_info_connect_async(SockInfo *sock, SockConnectFunc func,
1280
                             gpointer data)
1281
{
1282
        static gint id = 1;
1283
        SockConnectData *conn_data;
1284

    
1285
        g_return_val_if_fail(sock != NULL, -1);
1286
        g_return_val_if_fail(sock->hostname != NULL && sock->port > 0, -1);
1287

    
1288
        conn_data = g_new0(SockConnectData, 1);
1289
        conn_data->id = id++;
1290
        conn_data->hostname = g_strdup(sock->hostname);
1291
        conn_data->port = sock->port;
1292
        conn_data->addr_list = NULL;
1293
        conn_data->cur_addr = NULL;
1294
        conn_data->io_tag = 0;
1295
        conn_data->sock = sock;
1296
        conn_data->func = func;
1297
        conn_data->data = data;
1298

    
1299
        conn_data->lookup_data = sock_get_address_info_async
1300
                (sock->hostname, sock->port,
1301
                 sock_connect_async_get_address_info_cb, conn_data);
1302

    
1303
        if (conn_data->lookup_data == NULL) {
1304
                g_free(conn_data->hostname);
1305
                g_free(conn_data);
1306
                return -1;
1307
        }
1308

    
1309
        sock_connect_data_list = g_list_append(sock_connect_data_list,
1310
                                               conn_data);
1311

    
1312
        return conn_data->id;
1313
}
1314

    
1315
gint sock_connect_async_cancel(gint id)
1316
{
1317
        SockConnectData *conn_data = NULL;
1318
        GList *cur;
1319

    
1320
        for (cur = sock_connect_data_list; cur != NULL; cur = cur->next) {
1321
                if (((SockConnectData *)cur->data)->id == id) {
1322
                        conn_data = (SockConnectData *)cur->data;
1323
                        break;
1324
                }
1325
        }
1326

    
1327
        if (conn_data) {
1328
                sock_connect_data_list = g_list_remove(sock_connect_data_list,
1329
                                                       conn_data);
1330

    
1331
                if (conn_data->lookup_data)
1332
                        sock_get_address_info_async_cancel
1333
                                (conn_data->lookup_data);
1334

    
1335
                if (conn_data->io_tag > 0)
1336
                        g_source_remove(conn_data->io_tag);
1337
                if (conn_data->channel) {
1338
                        g_io_channel_shutdown(conn_data->channel, FALSE, NULL);
1339
                        g_io_channel_unref(conn_data->channel);
1340
                }
1341
                if (conn_data->sock)
1342
                        sock_close(conn_data->sock);
1343

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

    
1352
        return 0;
1353
}
1354

    
1355
static gint sock_connect_address_list_async(SockConnectData *conn_data)
1356
{
1357
        SockAddrData *addr_data;
1358
        gint sock = -1;
1359

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

    
1369
        for (; conn_data->cur_addr != NULL;
1370
             conn_data->cur_addr = conn_data->cur_addr->next) {
1371
                addr_data = (SockAddrData *)conn_data->cur_addr->data;
1372

    
1373
                if ((sock = socket(addr_data->family, addr_data->socktype,
1374
                                   addr_data->protocol)) < 0) {
1375
                        perror("socket");
1376
                        continue;
1377
                }
1378

    
1379
                sock_set_buffer_size(sock);
1380
                set_nonblocking_mode(sock, TRUE);
1381

    
1382
                if (connect(sock, addr_data->addr, addr_data->addr_len) < 0) {
1383
                        if (EINPROGRESS == errno) {
1384
                                break;
1385
                        } else {
1386
                                perror("connect");
1387
                                fd_close(sock);
1388
                        }
1389
                } else
1390
                        break;
1391
        }
1392

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

    
1403
        debug_print("sock_connect_address_list_async: waiting for connect\n");
1404

    
1405
        conn_data->cur_addr = conn_data->cur_addr->next;
1406

    
1407
        conn_data->channel = g_io_channel_unix_new(sock);
1408
        conn_data->io_tag = g_io_add_watch
1409
                (conn_data->channel, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
1410
                 sock_connect_async_cb, conn_data);
1411

    
1412
        return 0;
1413
}
1414

    
1415
static gint sock_kill_process(pid_t pid)
1416
{
1417
        pid_t ret = (pid_t)-1;
1418

    
1419
        kill(pid, SIGKILL);
1420

    
1421
        while (ret == (pid_t)-1) {
1422
                if ((ret = waitpid(pid, NULL, 0)) != pid) {
1423
                        if (ret == (pid_t)-1 && errno != EINTR) {
1424
                                perror("sock_kill_process(): waitpid");
1425
                                break;
1426
                        }
1427
                }
1428
        }
1429

    
1430
        return (gint)pid;
1431
}
1432

    
1433
/* asynchronous DNS lookup */
1434

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

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

    
1455
                if (bytes_read == 0 || bytes_read != sizeof(ai_member))
1456
                        break;
1457

    
1458
                if (ai_member[0] == AF_UNSPEC) {
1459
                        g_warning("DNS lookup failed");
1460
                        break;
1461
                }
1462

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

    
1473
                if (bytes_read != ai_member[3]) {
1474
                        g_warning("sock_get_address_info_async_cb: "
1475
                                  "incomplete address data\n");
1476
                        g_free(addr);
1477
                        break;
1478
                }
1479

    
1480
                addr_data = g_new0(SockAddrData, 1);
1481
                addr_data->family = ai_member[0];
1482
                addr_data->socktype = ai_member[1];
1483
                addr_data->protocol = ai_member[2];
1484
                addr_data->addr_len = ai_member[3];
1485
                addr_data->addr = addr;
1486

    
1487
                addr_list = g_list_append(addr_list, addr_data);
1488
        }
1489

    
1490
        g_io_channel_shutdown(source, FALSE, NULL);
1491
        g_io_channel_unref(source);
1492

    
1493
        sock_kill_process(lookup_data->child_pid);
1494

    
1495
        lookup_data->func(addr_list, lookup_data->data);
1496

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

    
1500
        return FALSE;
1501
}
1502

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

    
1512
        resolver_init();
1513

    
1514
        if (pipe(pipe_fds) < 0) {
1515
                perror("pipe");
1516
                func(NULL, data);
1517
                return NULL;
1518
        }
1519

    
1520
        if ((pid = fork()) < 0) {
1521
                perror("fork");
1522
                func(NULL, data);
1523
                return NULL;
1524
        }
1525

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

    
1539
                close(pipe_fds[0]);
1540

    
1541
#ifdef INET6
1542
                memset(&hints, 0, sizeof(hints));
1543
                /* hints.ai_flags = AI_CANONNAME; */
1544
                hints.ai_family = AF_UNSPEC;
1545
                hints.ai_socktype = SOCK_STREAM;
1546
                hints.ai_protocol = IPPROTO_TCP;
1547

    
1548
                g_snprintf(port_str, sizeof(port_str), "%d", port);
1549

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

    
1560
                for (ai = res; ai != NULL; ai = ai->ai_next) {
1561
                        ai_member[0] = ai->ai_family;
1562
                        ai_member[1] = ai->ai_socktype;
1563
                        ai_member[2] = ai->ai_protocol;
1564
                        ai_member[3] = ai->ai_addrlen;
1565

    
1566
                        fd_write_all(pipe_fds[1], (gchar *)ai_member,
1567
                                     sizeof(ai_member));
1568
                        fd_write_all(pipe_fds[1], (gchar *)ai->ai_addr,
1569
                                     ai->ai_addrlen);
1570
                }
1571

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

    
1583
                ai_member[0] = AF_INET;
1584
                ai_member[1] = SOCK_STREAM;
1585
                ai_member[2] = IPPROTO_TCP;
1586
                ai_member[3] = sizeof(ad);
1587

    
1588
                memset(&ad, 0, sizeof(ad));
1589
                ad.sin_family = AF_INET;
1590
                ad.sin_port = htons(port);
1591

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

    
1601
                close(pipe_fds[1]);
1602

    
1603
                _exit(0);
1604
        } else {
1605
                close(pipe_fds[1]);
1606

    
1607
                lookup_data = g_new0(SockLookupData, 1);
1608
                lookup_data->hostname = g_strdup(hostname);
1609
                lookup_data->child_pid = pid;
1610
                lookup_data->func = func;
1611
                lookup_data->data = data;
1612

    
1613
                lookup_data->channel = g_io_channel_unix_new(pipe_fds[0]);
1614
                lookup_data->io_tag = g_io_add_watch
1615
                        (lookup_data->channel, G_IO_IN,
1616
                         sock_get_address_info_async_cb, lookup_data);
1617
        }
1618

    
1619
        return lookup_data;
1620
}
1621

    
1622
static gint sock_get_address_info_async_cancel(SockLookupData *lookup_data)
1623
{
1624
        if (lookup_data->io_tag > 0)
1625
                g_source_remove(lookup_data->io_tag);
1626
        if (lookup_data->channel) {
1627
                g_io_channel_shutdown(lookup_data->channel, FALSE, NULL);
1628
                g_io_channel_unref(lookup_data->channel);
1629
        }
1630

    
1631
        if (lookup_data->child_pid > 0)
1632
                sock_kill_process(lookup_data->child_pid);
1633

    
1634
        g_free(lookup_data->hostname);
1635
        g_free(lookup_data);
1636

    
1637
        return 0;
1638
}
1639
#endif /* G_OS_UNIX */
1640

    
1641
#if USE_THREADS
1642
static gpointer sock_connect_async_func(gpointer data)
1643
{
1644
        SockConnectData *conn_data = (SockConnectData *)data;
1645
        gint ret;
1646

    
1647
        ret = sock_info_connect(conn_data->sock);
1648

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

    
1658
        g_atomic_int_set(&conn_data->flag, 1);
1659
        g_main_context_wakeup(NULL);
1660

    
1661
        debug_print("sock_connect_async_func: exit\n");
1662
        return GINT_TO_POINTER(ret);
1663
}
1664

    
1665
gint sock_connect_async_thread(const gchar *hostname, gushort port)
1666
{
1667
        SockInfo *sock;
1668
        gint ret;
1669

    
1670
        sock = sock_new(hostname, port);
1671
        ret = sock_info_connect_async_thread(sock);
1672
        if (ret < 0)
1673
                sock_close(sock);
1674

    
1675
        return ret;
1676
}
1677

    
1678
gint sock_info_connect_async_thread(SockInfo *sock)
1679
{
1680
        static gint id = 1;
1681
        SockConnectData *data;
1682

    
1683
        g_return_val_if_fail(sock != NULL, -1);
1684
        g_return_val_if_fail(sock->hostname != NULL && sock->port > 0, -1);
1685

    
1686
        data = g_new0(SockConnectData, 1);
1687
        data->id = id++;
1688
        data->hostname = g_strdup(sock->hostname);
1689
        data->port = sock->port;
1690
        data->flag = 0;
1691
        data->sock = sock;
1692

    
1693
        data->thread = g_thread_create(sock_connect_async_func, data, TRUE,
1694
                                       NULL);
1695
        if (!data->thread) {
1696
                g_free(data->hostname);
1697
                g_free(data);
1698
                return -1;
1699
        }
1700

    
1701
        sock_connect_data_list = g_list_append(sock_connect_data_list, data);
1702

    
1703
        return data->id;
1704
}
1705

    
1706
gint sock_connect_async_thread_wait(gint id, SockInfo **sock)
1707
{
1708
        gint ret;
1709

    
1710
        *sock = NULL;
1711
        ret = sock_info_connect_async_thread_wait(id, sock);
1712
        if (ret < 0) {
1713
                if (*sock) {
1714
                        sock_close(*sock);
1715
                        *sock = NULL;
1716
                }
1717
        }
1718

    
1719
        return ret;
1720
}
1721

    
1722
gint sock_info_connect_async_thread_wait(gint id, SockInfo **sock)
1723
{
1724
        SockConnectData *conn_data = NULL;
1725
        GList *cur;
1726
        gint ret;
1727

    
1728
        for (cur = sock_connect_data_list; cur != NULL; cur = cur->next) {
1729
                if (((SockConnectData *)cur->data)->id == id) {
1730
                        conn_data = (SockConnectData *)cur->data;
1731
                        break;
1732
                }
1733
        }
1734

    
1735
        if (!conn_data) {
1736
                g_warning("sock_info_connect_async_thread_wait: id %d not found.", id);
1737
                return -1;
1738
        }
1739

    
1740
        debug_print("sock_connect_async_thread_wait: waiting thread\n");
1741
        while (g_atomic_int_get(&conn_data->flag) == 0)
1742
                event_loop_iterate();
1743

    
1744
        ret = GPOINTER_TO_INT(g_thread_join(conn_data->thread));
1745
        debug_print("sock_info_connect_async_thread_wait: thread exited with status %d\n", ret);
1746

    
1747
        if (sock)
1748
                *sock = conn_data->sock;
1749

    
1750
        sock_connect_data_list = g_list_remove(sock_connect_data_list,
1751
                                               conn_data);
1752
        g_free(conn_data->hostname);
1753
        g_free(conn_data);
1754

    
1755
        return ret;
1756
}
1757
#endif /* USE_THREADS */
1758

    
1759
gint sock_printf(SockInfo *sock, const gchar *format, ...)
1760
{
1761
        va_list args;
1762
        gchar buf[BUFFSIZE];
1763

    
1764
        va_start(args, format);
1765
        g_vsnprintf(buf, sizeof(buf), format, args);
1766
        va_end(args);
1767

    
1768
        return sock_write_all(sock, buf, strlen(buf));
1769
}
1770

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

    
1786
gint sock_read(SockInfo *sock, gchar *buf, gint len)
1787
{
1788
        g_return_val_if_fail(sock != NULL, -1);
1789

    
1790
#if USE_SSL
1791
        if (sock->ssl)
1792
                return ssl_read(sock->ssl, buf, len);
1793
#endif
1794
        return fd_read(sock->sock, buf, len);
1795
}
1796

    
1797
gint fd_read(gint fd, gchar *buf, gint len)
1798
{
1799
#ifdef G_OS_WIN32
1800
        return fd_recv(fd, buf, len, 0);
1801
#else
1802
        if (fd_check_io(fd, G_IO_IN) < 0)
1803
                return -1;
1804

    
1805
        return read(fd, buf, len);
1806
#endif
1807
}
1808

    
1809
#if USE_SSL
1810
gint ssl_read(SSL *ssl, gchar *buf, gint len)
1811
{
1812
        gint err, ret;
1813

    
1814
        errno = 0;
1815

    
1816
        if (SSL_pending(ssl) == 0) {
1817
                if (fd_check_io(SSL_get_rfd(ssl), G_IO_IN) < 0)
1818
                        return -1;
1819
        }
1820

    
1821
        ret = SSL_read(ssl, buf, len);
1822

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

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

    
1848
#if USE_SSL
1849
        if (sock->ssl)
1850
                return ssl_write(sock->ssl, buf, len);
1851
#endif
1852
        return fd_write(sock->sock, buf, len);
1853
}
1854

    
1855
gint fd_write(gint fd, const gchar *buf, gint len)
1856
{
1857
#ifdef G_OS_WIN32
1858
        gint ret;
1859
#endif
1860
        if (fd_check_io(fd, G_IO_OUT) < 0)
1861
                return -1;
1862

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

    
1879
#if USE_SSL
1880
gint ssl_write(SSL *ssl, const gchar *buf, gint len)
1881
{
1882
        gint ret;
1883

    
1884
        ret = SSL_write(ssl, buf, len);
1885

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

    
1899
gint sock_write_all(SockInfo *sock, const gchar *buf, gint len)
1900
{
1901
        g_return_val_if_fail(sock != NULL, -1);
1902

    
1903
#if USE_SSL
1904
        if (sock->ssl)
1905
                return ssl_write_all(sock->ssl, buf, len);
1906
#endif
1907
        return fd_write_all(sock->sock, buf, len);
1908
}
1909

    
1910
gint fd_write_all(gint fd, const gchar *buf, gint len)
1911
{
1912
        gint n, wrlen = 0;
1913

    
1914
        while (len) {
1915
                n = fd_write(fd, buf, len);
1916
                if (n <= 0)
1917
                        return -1;
1918
                len -= n;
1919
                wrlen += n;
1920
                buf += n;
1921
        }
1922

    
1923
        return wrlen;
1924
}
1925

    
1926
#if USE_SSL
1927
gint ssl_write_all(SSL *ssl, const gchar *buf, gint len)
1928
{
1929
        gint n, wrlen = 0;
1930

    
1931
        while (len) {
1932
                n = ssl_write(ssl, buf, len);
1933
                if (n <= 0)
1934
                        return -1;
1935
                len -= n;
1936
                wrlen += n;
1937
                buf += n;
1938
        }
1939

    
1940
        return wrlen;
1941
}
1942
#endif
1943

    
1944
gint fd_recv(gint fd, gchar *buf, gint len, gint flags)
1945
{
1946
#ifdef G_OS_WIN32
1947
        gint ret;
1948
#endif
1949
        if (fd_check_io(fd, G_IO_IN) < 0)
1950
                return -1;
1951

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

    
1968
gint fd_gets(gint fd, gchar *buf, gint len)
1969
{
1970
        gchar *newline, *bp = buf;
1971
        gint n;
1972

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

    
1986
        *bp = '\0';
1987
        return bp - buf;
1988
}
1989

    
1990
#if USE_SSL
1991
gint ssl_gets(SSL *ssl, gchar *buf, gint len)
1992
{
1993
        gchar *newline, *bp = buf;
1994
        gint n;
1995

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

    
2009
        *bp = '\0';
2010
        return bp - buf;
2011
}
2012
#endif
2013

    
2014
gint sock_gets(SockInfo *sock, gchar *buf, gint len)
2015
{
2016
        g_return_val_if_fail(sock != NULL, -1);
2017

    
2018
#if USE_SSL
2019
        if (sock->ssl)
2020
                return ssl_gets(sock->ssl, buf, len);
2021
#endif
2022
        return fd_gets(sock->sock, buf, len);
2023
}
2024

    
2025
gint fd_getline(gint fd, gchar **line)
2026
{
2027
        gchar buf[BUFFSIZE];
2028
        gchar *str = NULL;
2029
        gint len;
2030
        gulong size = 0;
2031
        gulong cur_offset = 0;
2032

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

    
2042
        *line = str;
2043

    
2044
        if (!str)
2045
                return -1;
2046
        else
2047
                return (gint)size;
2048
}
2049

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

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

    
2068
        *line = str;
2069

    
2070
        if (!str)
2071
                return -1;
2072
        else
2073
                return (gint)size;
2074
}
2075
#endif
2076

    
2077
gint sock_getline(SockInfo *sock, gchar **line)
2078
{
2079
        g_return_val_if_fail(sock != NULL, -1);
2080
        g_return_val_if_fail(line != NULL, -1);
2081

    
2082
#if USE_SSL
2083
        if (sock->ssl)
2084
                return ssl_getline(sock->ssl, line);
2085
#endif
2086
        return fd_getline(sock->sock, line);
2087
}
2088

    
2089
gint sock_puts(SockInfo *sock, const gchar *buf)
2090
{
2091
        gint ret;
2092

    
2093
        if ((ret = sock_write_all(sock, buf, strlen(buf))) < 0)
2094
                return ret;
2095
        return sock_write_all(sock, "\r\n", 2);
2096
}
2097

    
2098
/* peek at the socket data without actually reading it */
2099
#if USE_SSL
2100
gint ssl_peek(SSL *ssl, gchar *buf, gint len)
2101
{
2102
        gint err, ret;
2103

    
2104
        if (SSL_pending(ssl) == 0) {
2105
                if (fd_check_io(SSL_get_rfd(ssl), G_IO_IN) < 0)
2106
                        return -1;
2107
        }
2108

    
2109
        ret = SSL_peek(ssl, buf, len);
2110

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

    
2129
gint sock_peek(SockInfo *sock, gchar *buf, gint len)
2130
{
2131
        g_return_val_if_fail(sock != NULL, -1);
2132

    
2133
#if USE_SSL
2134
        if (sock->ssl)
2135
                return ssl_peek(sock->ssl, buf, len);
2136
#endif
2137
        return fd_recv(sock->sock, buf, len, MSG_PEEK);
2138
}
2139

    
2140
gint sock_close(SockInfo *sock)
2141
{
2142
        GList *cur;
2143

    
2144
        if (!sock)
2145
                return 0;
2146

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

    
2149
#if USE_SSL
2150
        if (sock->ssl)
2151
                ssl_done_socket(sock);
2152
#endif
2153

    
2154
        if (sock->sock_ch) {
2155
                g_io_channel_shutdown(sock->sock_ch, FALSE, NULL);
2156
                g_io_channel_unref(sock->sock_ch);
2157
        }
2158

    
2159
        for (cur = sock_list; cur != NULL; cur = cur->next) {
2160
                if ((SockInfo *)cur->data == sock) {
2161
                        sock_list = g_list_remove(sock_list, sock);
2162
                        break;
2163
                }
2164
        }
2165

    
2166
        g_free(sock->hostname);
2167
        g_free(sock);
2168

    
2169
        return 0;
2170
}
2171

    
2172
gint fd_close(gint fd)
2173
{
2174
#ifdef G_OS_WIN32
2175
        return closesocket(fd);
2176
#else
2177
        return close(fd);
2178
#endif
2179
}