summaryrefslogtreecommitdiff
path: root/libsylph/socket.c
diff options
context:
space:
mode:
authorSimeon Simeonov2018-02-26 11:23:00 +0100
committerSimeon Simeonov2018-02-26 11:23:00 +0100
commit0b3cbf57875fd692e4ba0b336fefa4bee1ed00dc (patch)
treeaf916a30553c78ce9d4f2d8658656a175c5b6921 /libsylph/socket.c
Initial commit for sylpheed 3.7.0
Diffstat (limited to 'libsylph/socket.c')
-rw-r--r--libsylph/socket.c2179
1 files changed, 2179 insertions, 0 deletions
diff --git a/libsylph/socket.c b/libsylph/socket.c
new file mode 100644
index 0000000..228c8db
--- /dev/null
+++ b/libsylph/socket.c
@@ -0,0 +1,2179 @@
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
72typedef gint (*SockAddrFunc) (GList *addr_list,
73 gpointer data);
74
75typedef struct _SockConnectData SockConnectData;
76typedef struct _SockLookupData SockLookupData;
77typedef struct _SockAddrData SockAddrData;
78typedef struct _SockSource SockSource;
79
80struct _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
100struct _SockLookupData {
101 gchar *hostname;
102 pid_t child_pid;
103 GIOChannel *channel;
104 guint io_tag;
105 SockAddrFunc func;
106 gpointer data;
107};
108
109struct _SockAddrData {
110 gint family;
111 gint socktype;
112 gint protocol;
113 gint addr_len;
114 struct sockaddr *addr;
115};
116
117struct _SockSource {
118 GSource parent;
119 SockInfo *sock;
120};
121
122static guint io_timeout = 60;
123
124static GList *sock_connect_data_list = NULL;
125static GList *sock_list = NULL;
126
127static gboolean sock_prepare (GSource *source,
128 gint *timeout);
129static gboolean sock_check (GSource *source);
130static gboolean sock_dispatch (GSource *source,
131 GSourceFunc callback,
132 gpointer user_data);
133
134GSourceFuncs sock_watch_funcs = {
135 sock_prepare,
136 sock_check,
137 sock_dispatch,
138 NULL
139};
140
141static SockInfo *sock_find_from_fd (gint fd);
142
143static gint sock_connect_with_timeout (gint sock,
144 const struct sockaddr *serv_addr,
145 gint addrlen,
146 guint timeout_secs);
147
148#ifndef INET6
149static gint sock_info_connect_by_hostname
150 (SockInfo *sock);
151#else
152#ifdef G_OS_WIN32
153typedef int (*GetAddrInfoFunc) (const char *node,
154 const char *service,
155 const struct addrinfo *hints,
156 struct addrinfo **res);
157typedef void (*FreeAddrInfoFunc) (struct addrinfo *res);
158
159static GetAddrInfoFunc getaddrinfo_func = NULL;
160static FreeAddrInfoFunc freeaddrinfo_func = NULL;
161
162#undef getaddrinfo
163#define getaddrinfo my_getaddrinfo
164#undef freeaddrinfo
165#define freeaddrinfo my_freeaddrinfo
166#endif
167
168static SockDesc sock_info_connect_by_getaddrinfo(SockInfo *sock);
169#endif
170
171#ifdef G_OS_UNIX
172static void sock_address_list_free (GList *addr_list);
173
174static gboolean sock_connect_async_cb (GIOChannel *source,
175 GIOCondition condition,
176 gpointer data);
177static gint sock_connect_async_get_address_info_cb
178 (GList *addr_list,
179 gpointer data);
180
181static gint sock_connect_address_list_async (SockConnectData *conn_data);
182
183static gboolean sock_get_address_info_async_cb (GIOChannel *source,
184 GIOCondition condition,
185 gpointer data);
186static SockLookupData *sock_get_address_info_async
187 (const gchar *hostname,
188 gushort port,
189 SockAddrFunc func,
190 gpointer data);
191static gint sock_get_address_info_async_cancel (SockLookupData *lookup_data);
192#endif /* G_OS_UNIX */
193
194
195gint 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
210gint sock_cleanup(void)
211{
212#ifdef G_OS_WIN32
213 WSACleanup();
214#endif
215 return 0;
216}
217
218gint sock_set_io_timeout(guint sec)
219{
220 io_timeout = sec;
221 return 0;
222}
223
224gint 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
253gint 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
298gint 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
325gint 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
368gint 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
378SockInfo *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
394static 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
406static 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
449gint 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
467static 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
491gboolean 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
502gboolean 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
527static gboolean sock_prepare(GSource *source, gint *timeout)
528{
529 *timeout = 1;
530 return FALSE;
531}
532
533static 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
567static 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
575static 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
586guint 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
608guint 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
625static 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)
658static sigjmp_buf jmpenv;
659
660static void timeout_handler(gint sig)
661{
662 siglongjmp(jmpenv, 1);
663}
664#endif
665
666static 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
729end:
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
791static 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
806struct 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
842static 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)
870static 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
892static 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
940static 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() */
970static 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
1047static 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
1061static 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
1121SockInfo *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
1134gint 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
1184static 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
1199static 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
1253static 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
1265gint 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
1279gint 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
1315gint 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
1355static 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
1415static 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
1435static 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
1503static 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
1622static 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
1642static 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
1665gint 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
1678gint 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
1706gint 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
1722gint 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
1759gint 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
1772static 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
1786gint 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
1797gint 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
1810gint 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
1844gint 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
1855gint 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
1880gint 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
1899gint 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
1910gint 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
1927gint 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
1944gint 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
1968gint 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
1991gint 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
2014gint 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
2025gint 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
2051gint 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
2077gint 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
2089gint 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
2100gint 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
2129gint 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
2140gint 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
2172gint fd_close(gint fd)
2173{
2174#ifdef G_OS_WIN32
2175 return closesocket(fd);
2176#else
2177 return close(fd);
2178#endif
2179}