1 /*
2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2017 Hiroyuki Yamamoto and the Claws Mail team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #include "claws-features.h"
22 #endif
23
24 #if (defined (_XOPEN_SOURCE) && !defined (_BSD_SOURCE))
25 #define _BSD_SOURCE
26 #endif
27
28 /* This can probably be handled better, e.g. define it in config.h. */
29 #define _WIN32_WINNT _WIN32_WINNT_WIN6
30 #include <glib.h>
31 #include <glib/gi18n.h>
32
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #ifdef G_OS_WIN32
36 # include <ws2tcpip.h>
37 # ifndef EINPROGRESS
38 # define EINPROGRESS WSAEINPROGRESS
39 # endif
40 # include "w32lib.h"
41 #else
42 # if HAVE_SYS_WAIT_H
43 # include <sys/wait.h>
44 # endif
45 # include <sys/socket.h>
46 # include <sys/stat.h>
47 # include <sys/un.h>
48 # include <netinet/in.h>
49 # include <arpa/inet.h>
50 # include <resolv.h>
51 # ifndef _PATH_RESCONF
52 # define _PATH_RESCONF "/etc/resolv.conf"
53 # endif
54 # include <netdb.h>
55 #endif /* G_OS_WIN32 */
56 #include <unistd.h>
57 #include <stdio.h>
58 #include <string.h>
59 #include <stdarg.h>
60 #include <fcntl.h>
61 #include <errno.h>
62 #include <signal.h>
63 #include <setjmp.h>
64 #if HAVE_SYS_SELECT_H
65 # include <sys/select.h>
66 #endif
67
68 #include "socket.h"
69 #include "utils.h"
70 #include "log.h"
71 #ifdef USE_GNUTLS
72 # include "ssl.h"
73 #endif
74
75 #if USE_GIO
76 #error USE_GIO is currently not supported
77 #endif
78
79 #if G_IO_WIN32
80 #define BUFFSIZE 8191
81 #else
82 #define BUFFSIZE 8192
83 #endif
84
85
86 typedef gint (*SockAddrFunc) (GList *addr_list,
87 gpointer data);
88
89 typedef struct _SockConnectData SockConnectData;
90 typedef struct _SockLookupData SockLookupData;
91 typedef struct _SockAddrData SockAddrData;
92 typedef struct _SockSource SockSource;
93
94 struct _SockConnectData {
95 gint id;
96 gchar *hostname;
97 gushort port;
98 GList *addr_list;
99 GList *cur_addr;
100 SockLookupData *lookup_data;
101 GIOChannel *channel;
102 guint io_tag;
103 SockConnectFunc func;
104 gpointer data;
105 gchar *canonical_name;
106 };
107
108 struct _SockLookupData {
109 gchar *hostname;
110 pid_t child_pid;
111 GIOChannel *channel;
112 guint io_tag;
113 SockAddrFunc func;
114 gpointer data;
115 gushort port;
116 gint pipe_fds[2];
117 gchar *canonical_name;
118 };
119
120 struct _SockAddrData {
121 gint family;
122 gint socktype;
123 gint protocol;
124 gint addr_len;
125 struct sockaddr *addr;
126 };
127
128 struct _SockSource {
129 GSource parent;
130 SockInfo *sock;
131 };
132
133 static guint io_timeout = 60;
134
135 static GList *sock_connect_data_list = NULL;
136
137 static gboolean ssl_sock_prepare (GSource *source,
138 gint *timeout);
139 static gboolean ssl_sock_check (GSource *source);
140 static gboolean ssl_sock_dispatch (GSource *source,
141 GSourceFunc callback,
142 gpointer user_data);
143
144 #ifdef USE_GNUTLS
145 GSourceFuncs ssl_watch_funcs = {
146 ssl_sock_prepare,
147 ssl_sock_check,
148 ssl_sock_dispatch,
149 NULL,
150 NULL,
151 NULL
152 };
153 #endif
154
155 static gint sock_connect_with_timeout (gint sock,
156 const struct sockaddr *serv_addr,
157 gint addrlen,
158 guint timeout_secs);
159
160 static gint sock_connect_by_getaddrinfo (const gchar *hostname,
161 gushort port);
162
163 static SockInfo *sockinfo_from_fd(const gchar *hostname,
164 gushort port,
165 gint sock);
166 static void sock_address_list_free (GList *addr_list);
167
168 static gboolean sock_connect_async_cb (GIOChannel *source,
169 GIOCondition condition,
170 gpointer data);
171 static gint sock_connect_async_get_address_info_cb
172 (GList *addr_list,
173 gpointer data);
174
175 static gint sock_connect_address_list_async (SockConnectData *conn_data);
176
177 static gboolean sock_get_address_info_async_cb (GIOChannel *source,
178 GIOCondition condition,
179 gpointer data);
180 static SockLookupData *sock_get_address_info_async
181 (const gchar *hostname,
182 gushort port,
183 SockAddrFunc func,
184 gpointer data);
185 static gint sock_get_address_info_async_cancel (SockLookupData *lookup_data);
186
187
sock_init(void)188 gint sock_init(void)
189 {
190 #ifdef G_OS_WIN32
191 WSADATA wsadata;
192 gint result;
193
194 result = WSAStartup(MAKEWORD(2, 2), &wsadata);
195 if (result != NO_ERROR) {
196 g_warning("WSAStartup() failed");
197 return -1;
198 }
199 #endif
200 return 0;
201 }
202
sock_cleanup(void)203 gint sock_cleanup(void)
204 {
205 #ifdef G_OS_WIN32
206 WSACleanup();
207 #endif
208 return 0;
209 }
210
sock_set_io_timeout(guint sec)211 gint sock_set_io_timeout(guint sec)
212 {
213 io_timeout = sec;
214 return 0;
215 }
216
refresh_resolvers(void)217 void refresh_resolvers(void)
218 {
219 #ifdef G_OS_UNIX
220 static time_t resolv_conf_changed = (time_t)NULL;
221 GStatBuf s;
222
223 /* This makes the glibc re-read resolv.conf, if it changed
224 * since our startup. Maybe that should be #ifdef'ed, I don't
225 * know if it'd work on BSDs.
226 * Why doesn't the glibc do it by itself?
227 */
228 if (g_stat(_PATH_RESCONF, &s) == 0) {
229 if (s.st_mtime > resolv_conf_changed) {
230 resolv_conf_changed = s.st_mtime;
231 res_init();
232 }
233 } /* else
234 we'll have bigger problems. */
235 #endif /*G_OS_UNIX*/
236 }
237
238 #ifdef G_OS_WIN32
239 #define SOCKET_IS_VALID(s) ((s) != INVALID_SOCKET)
240 #else
241 #define SOCKET_IS_VALID(s) (s != -1)
242 #endif
243
244 #ifdef G_OS_WIN32
245 /* Due to the fact that socket under Windows are not represented by
246 standard file descriptors, we sometimes need to check whether a
247 given file descriptor is actually a socket. This is done by
248 testing for an error. Returns true under W32 if FD is a socket. */
fd_is_w32_socket(gint fd)249 static int fd_is_w32_socket(gint fd)
250 {
251 gint optval;
252 gint retval = sizeof(optval);
253
254 return !getsockopt(fd, SOL_SOCKET, SO_TYPE, (char*)&optval, &retval);
255 }
256 #endif
257
fd_connect_inet(gushort port)258 gint fd_connect_inet(gushort port)
259 {
260 gint sock;
261 struct sockaddr_in addr;
262
263 sock = socket(AF_INET, SOCK_STREAM, 0);
264 if (!SOCKET_IS_VALID(sock)) {
265 #ifdef G_OS_WIN32
266 debug_print("fd_connect_inet(): socket() failed: %d\n",
267 WSAGetLastError());
268 #else
269 perror("fd_connect_inet(): socket");
270 #endif
271 return -1;
272 }
273
274 memset(&addr, 0, sizeof(addr));
275 addr.sin_family = AF_INET;
276 addr.sin_port = htons(port);
277 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
278
279 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
280 fd_close(sock);
281 return -1;
282 }
283
284 return sock;
285 }
fd_open_inet(gushort port)286 gint fd_open_inet(gushort port)
287 {
288 gint sock;
289 struct sockaddr_in addr;
290 gint val;
291
292 sock = socket(AF_INET, SOCK_STREAM, 0);
293 if (!SOCKET_IS_VALID(sock)) {
294 #ifdef G_OS_WIN32
295 g_warning("fd_open_inet(): socket() failed: %d",
296 WSAGetLastError());
297 #else
298 perror("fd_open_inet(): socket");
299 #endif
300 return -1;
301 }
302
303 val = 1;
304 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val,
305 sizeof(val)) < 0) {
306 perror("setsockopt");
307 fd_close(sock);
308 return -1;
309 }
310
311 memset(&addr, 0, sizeof(addr));
312 addr.sin_family = AF_INET;
313 addr.sin_port = htons(port);
314 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
315
316 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
317 perror("bind");
318 fd_close(sock);
319 return -1;
320 }
321
322 if (listen(sock, 1) < 0) {
323 perror("listen");
324 fd_close(sock);
325 return -1;
326 }
327
328 return sock;
329 }
330
fd_connect_unix(const gchar * path)331 gint fd_connect_unix(const gchar *path)
332 {
333 #ifdef G_OS_UNIX
334 gint sock;
335 struct sockaddr_un addr;
336
337 sock = socket(PF_UNIX, SOCK_STREAM, 0);
338 if (sock < 0) {
339 perror("sock_connect_unix(): socket");
340 return -1;
341 }
342
343 memset(&addr, 0, sizeof(addr));
344 addr.sun_family = AF_UNIX;
345 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
346
347 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
348 close(sock);
349 return -1;
350 }
351
352 return sock;
353 #else
354 return -1;
355 #endif
356 }
357
fd_open_unix(const gchar * path)358 gint fd_open_unix(const gchar *path)
359 {
360 #ifdef G_OS_UNIX
361 gint sock;
362 struct sockaddr_un addr;
363
364 sock = socket(PF_UNIX, SOCK_STREAM, 0);
365
366 if (sock < 0) {
367 perror("sock_open_unix(): socket");
368 return -1;
369 }
370
371 memset(&addr, 0, sizeof(addr));
372 addr.sun_family = AF_UNIX;
373 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
374
375 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
376 gchar *buf = g_strdup_printf("can't bind to %s", path);
377 perror(buf);
378 g_free(buf);
379 close(sock);
380 return -1;
381 }
382
383 if (listen(sock, 1) < 0) {
384 gchar *buf = g_strdup_printf("can't listen on %s", path);
385 perror(buf);
386 g_free(buf);
387 close(sock);
388 return -1;
389 }
390
391 return sock;
392 #else
393 return -1;
394 #endif
395 }
396
fd_accept(gint sock)397 gint fd_accept(gint sock)
398 {
399 struct sockaddr_in caddr;
400 guint caddr_len;
401
402 caddr_len = sizeof(caddr);
403 return accept(sock, (struct sockaddr *)&caddr, &caddr_len);
404 }
405
406
set_nonblocking_mode(gint fd,gboolean nonblock)407 static gint set_nonblocking_mode(gint fd, gboolean nonblock)
408 {
409 #ifdef G_OS_UNIX
410 gint flags;
411
412 flags = fcntl(fd, F_GETFL, 0);
413 if (flags < 0) {
414 perror("fcntl");
415 return -1;
416 }
417
418 if (nonblock)
419 flags |= O_NONBLOCK;
420 else
421 flags &= ~O_NONBLOCK;
422
423 return fcntl(fd, F_SETFL, flags);
424 #else
425 return -1;
426 #endif
427 }
428
sock_set_nonblocking_mode(SockInfo * sock,gboolean nonblock)429 gint sock_set_nonblocking_mode(SockInfo *sock, gboolean nonblock)
430 {
431 cm_return_val_if_fail(sock != NULL, -1);
432
433 return set_nonblocking_mode(sock->sock, nonblock);
434 }
435
is_nonblocking_mode(gint fd)436 static gboolean is_nonblocking_mode(gint fd)
437 {
438 #ifdef G_OS_UNIX
439 gint flags;
440
441 flags = fcntl(fd, F_GETFL, 0);
442 if (flags < 0) {
443 perror("fcntl");
444 return FALSE;
445 }
446
447 return ((flags & O_NONBLOCK) != 0);
448 #else
449 return FALSE;
450 #endif
451 }
452
sock_is_nonblocking_mode(SockInfo * sock)453 gboolean sock_is_nonblocking_mode(SockInfo *sock)
454 {
455 cm_return_val_if_fail(sock != NULL, FALSE);
456
457 return is_nonblocking_mode(sock->sock);
458 }
459
460
461 #ifdef USE_GNUTLS
ssl_sock_prepare(GSource * source,gint * timeout)462 static gboolean ssl_sock_prepare(GSource *source, gint *timeout)
463 {
464 *timeout = 1;
465 return FALSE;
466 }
467
ssl_sock_check(GSource * source)468 static gboolean ssl_sock_check(GSource *source)
469 {
470 SockInfo *sock = ((SockSource *)source)->sock;
471 struct timeval timeout = {0, 0};
472 fd_set fds;
473 GIOCondition condition = 0;
474
475 if (!sock || !sock->sock)
476 return FALSE;
477
478 condition = sock->condition;
479
480 if ((condition & G_IO_IN) == G_IO_IN &&
481 gnutls_record_check_pending(sock->ssl) != 0)
482 return TRUE;
483
484 FD_ZERO(&fds);
485 FD_SET(sock->sock, &fds);
486
487 select(sock->sock + 1,
488 (condition & G_IO_IN) ? &fds : NULL,
489 (condition & G_IO_OUT) ? &fds : NULL,
490 NULL, &timeout);
491
492 return FD_ISSET(sock->sock, &fds) != 0;
493 }
494
ssl_sock_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)495 static gboolean ssl_sock_dispatch(GSource *source, GSourceFunc callback,
496 gpointer user_data)
497 {
498 SockInfo *sock = ((SockSource *)source)->sock;
499
500 if (!sock || !sock->callback || !sock->data)
501 return FALSE;
502
503 return sock->callback(sock, sock->condition, sock->data);
504 }
505 #endif
506
sock_watch_cb(GIOChannel * source,GIOCondition condition,gpointer data)507 static gboolean sock_watch_cb(GIOChannel *source, GIOCondition condition,
508 gpointer data)
509 {
510 SockInfo *sock = (SockInfo *)data;
511
512 if ((condition & sock->condition) == 0)
513 return TRUE;
514
515 return sock->callback(sock, sock->condition, sock->data);
516 }
517
sock_add_watch(SockInfo * sock,GIOCondition condition,SockFunc func,gpointer data)518 guint sock_add_watch(SockInfo *sock, GIOCondition condition, SockFunc func,
519 gpointer data)
520 {
521 if (!sock)
522 return FALSE;
523
524 sock->callback = func;
525 sock->condition = condition;
526 sock->data = data;
527
528 #ifdef USE_GNUTLS
529 if (sock->ssl)
530 {
531 GSource *source = g_source_new(&ssl_watch_funcs,
532 sizeof(SockSource));
533 ((SockSource *) source)->sock = sock;
534 g_source_set_priority(source, G_PRIORITY_DEFAULT);
535 g_source_set_can_recurse(source, FALSE);
536 sock->g_source = g_source_attach(source, NULL);
537 g_source_unref (source); /* Refcount back down to 1 */
538 return sock->g_source;
539 }
540 #endif
541
542 return g_io_add_watch(sock->sock_ch, condition, sock_watch_cb, sock);
543 }
544
fd_check_io(gint fd,GIOCondition cond)545 static gint fd_check_io(gint fd, GIOCondition cond)
546 {
547 struct timeval timeout;
548 fd_set fds;
549
550 if (is_nonblocking_mode(fd))
551 return 0;
552
553 timeout.tv_sec = io_timeout;
554 timeout.tv_usec = 0;
555
556 FD_ZERO(&fds);
557 FD_SET(fd, &fds);
558
559 if (cond == G_IO_IN) {
560 select(fd + 1, &fds, NULL, NULL,
561 io_timeout > 0 ? &timeout : NULL);
562 } else {
563 select(fd + 1, NULL, &fds, NULL,
564 io_timeout > 0 ? &timeout : NULL);
565 }
566
567 if (FD_ISSET(fd, &fds)) {
568 return 0;
569 } else {
570 g_warning("Socket IO timeout");
571 log_error(LOG_PROTOCOL, _("Socket IO timeout.\n"));
572 return -1;
573 }
574 }
575
576 #ifdef G_OS_UNIX
577 static sigjmp_buf jmpenv;
578
timeout_handler(gint sig)579 static void timeout_handler(gint sig)
580 {
581 siglongjmp(jmpenv, 1);
582 }
583 #endif /*G_OS_UNIX*/
584
sock_connect_with_timeout(gint sock,const struct sockaddr * serv_addr,gint addrlen,guint timeout_secs)585 static gint sock_connect_with_timeout(gint sock,
586 const struct sockaddr *serv_addr,
587 gint addrlen,
588 guint timeout_secs)
589 {
590 gint ret, saved_errno;
591 #ifdef G_OS_UNIX
592 void (*prev_handler)(gint);
593
594 alarm(0);
595 prev_handler = signal(SIGALRM, timeout_handler);
596 if (sigsetjmp(jmpenv, 1)) {
597 alarm(0);
598 signal(SIGALRM, prev_handler);
599 errno = ETIMEDOUT;
600 log_error(LOG_PROTOCOL, _("Connection timed out.\n"));
601 return -1;
602 }
603 alarm(timeout_secs);
604 #endif
605
606 ret = connect(sock, serv_addr, addrlen);
607 saved_errno = errno;
608
609 if (ret == -1) {
610 debug_print("connect() failed: %d (%s)\n",
611 saved_errno, g_strerror(saved_errno));
612 }
613
614 #ifdef G_OS_UNIX
615 alarm(0);
616 signal(SIGALRM, prev_handler);
617 #endif
618
619 return ret;
620 }
621
sock_connect_by_getaddrinfo(const gchar * hostname,gushort port)622 static gint sock_connect_by_getaddrinfo(const gchar *hostname, gushort port)
623 {
624 gint sock = -1, gai_error;
625 struct addrinfo hints, *res, *ai;
626 gchar port_str[6];
627
628 refresh_resolvers();
629
630 memset(&hints, 0, sizeof(hints));
631 hints.ai_flags = AI_ADDRCONFIG;
632
633 #ifdef INET6
634 hints.ai_family = AF_UNSPEC;
635 #else
636 hints.ai_family = AF_INET;
637 #endif
638
639 hints.ai_socktype = SOCK_STREAM;
640 hints.ai_protocol = IPPROTO_TCP;
641
642 /* convert port from integer to string. */
643 g_snprintf(port_str, sizeof(port_str), "%d", port);
644
645 if ((gai_error = getaddrinfo(hostname, port_str, &hints, &res)) != 0) {
646 g_printerr("getaddrinfo for %s:%s failed: %s\n",
647 hostname, port_str, gai_strerror(gai_error));
648 return -1;
649 }
650
651 for (ai = res; ai != NULL; ai = ai->ai_next) {
652 #ifndef INET6
653 if (ai->ai_family == AF_INET6)
654 continue;
655 #endif
656
657 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
658 if (sock < 0 )
659 continue;
660 #ifdef G_OS_WIN32
661 if (sock == INVALID_SOCKET)
662 continue;
663 #endif
664
665 if (sock_connect_with_timeout
666 (sock, ai->ai_addr, ai->ai_addrlen, io_timeout) == 0)
667 break;
668
669 close(sock);
670 }
671
672 if (res != NULL)
673 freeaddrinfo(res);
674
675 if (ai == NULL)
676 return -1;
677
678 return sock;
679 }
680
sock_connect(const gchar * hostname,gushort port)681 SockInfo *sock_connect(const gchar *hostname, gushort port)
682 {
683 #ifdef G_OS_WIN32
684 SOCKET sock;
685 #else
686 gint sock;
687 #endif
688
689 if ((sock = sock_connect_by_getaddrinfo(hostname, port)) < 0) {
690 return NULL;
691 }
692
693 return sockinfo_from_fd(hostname, port, sock);
694 }
695
696
sock_address_list_free(GList * addr_list)697 static void sock_address_list_free(GList *addr_list)
698 {
699 GList *cur;
700
701 for (cur = addr_list; cur != NULL; cur = cur->next) {
702 SockAddrData *addr_data = (SockAddrData *)cur->data;
703 g_free(addr_data->addr);
704 g_free(addr_data);
705 }
706
707 g_list_free(addr_list);
708 }
709
710 /* asynchronous TCP connection */
711
sock_connect_async_cb(GIOChannel * source,GIOCondition condition,gpointer data)712 static gboolean sock_connect_async_cb(GIOChannel *source,
713 GIOCondition condition, gpointer data)
714 {
715 SockConnectData *conn_data = (SockConnectData *)data;
716 gint fd;
717 gint val;
718 guint len;
719 SockInfo *sockinfo;
720
721 if (conn_data->io_tag == 0 && conn_data->channel == NULL)
722 return FALSE;
723
724 fd = g_io_channel_unix_get_fd(source);
725
726 conn_data->io_tag = 0;
727 conn_data->channel = NULL;
728 g_io_channel_unref(source);
729
730 len = sizeof(val);
731 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&val, &len) < 0) {
732 perror("getsockopt");
733 close(fd);
734 sock_connect_address_list_async(conn_data);
735 return FALSE;
736 }
737
738 if (val != 0) {
739 close(fd);
740 log_error(LOG_PROTOCOL, _("%s:%d: connection failed (%s).\n"),
741 conn_data->hostname, conn_data->port,
742 g_strerror(val));
743 sock_connect_address_list_async(conn_data);
744 return FALSE;
745 }
746
747 sockinfo = g_new0(SockInfo, 1);
748 sockinfo->sock = fd;
749 #ifndef G_OS_WIN32
750 sockinfo->sock_ch = g_io_channel_unix_new(fd);
751 #else
752 sockinfo->sock_ch = g_io_channel_win32_new_socket(fd);
753 #endif
754 sockinfo->hostname = g_strdup(conn_data->hostname);
755 sockinfo->port = conn_data->port;
756 sockinfo->state = CONN_ESTABLISHED;
757 sockinfo->canonical_name = g_strdup(conn_data->canonical_name);
758
759 conn_data->func(sockinfo, conn_data->data);
760
761 sock_connect_async_cancel(conn_data->id);
762
763 return FALSE;
764 }
765
sock_connect_async_get_address_info_cb(GList * addr_list,gpointer data)766 static gint sock_connect_async_get_address_info_cb(GList *addr_list,
767 gpointer data)
768 {
769 SockConnectData *conn_data = (SockConnectData *)data;
770
771 conn_data->addr_list = addr_list;
772 conn_data->cur_addr = addr_list;
773 if (conn_data->lookup_data) {
774 conn_data->canonical_name = conn_data->lookup_data->canonical_name;
775 conn_data->lookup_data->canonical_name = NULL;
776 conn_data->lookup_data = NULL;
777 }
778 return sock_connect_address_list_async(conn_data);
779 }
780
sock_connect_async(const gchar * hostname,gushort port,SockConnectFunc func,gpointer data)781 gint sock_connect_async(const gchar *hostname, gushort port,
782 SockConnectFunc func, gpointer data)
783 {
784 static gint id = 1;
785 SockConnectData *conn_data;
786
787 conn_data = g_new0(SockConnectData, 1);
788 conn_data->id = id++;
789 conn_data->hostname = g_strdup(hostname);
790 conn_data->port = port;
791 conn_data->addr_list = NULL;
792 conn_data->cur_addr = NULL;
793 conn_data->io_tag = 0;
794 conn_data->func = func;
795 conn_data->data = data;
796
797 conn_data->lookup_data = sock_get_address_info_async
798 (hostname, port, sock_connect_async_get_address_info_cb,
799 conn_data);
800
801 if (conn_data->lookup_data == NULL) {
802 g_free(conn_data->hostname);
803 g_free(conn_data);
804 return -1;
805 }
806
807 sock_connect_data_list = g_list_append(sock_connect_data_list,
808 conn_data);
809
810 return conn_data->id;
811 }
812
sock_connect_async_cancel(gint id)813 gint sock_connect_async_cancel(gint id)
814 {
815 SockConnectData *conn_data = NULL;
816 GList *cur;
817
818 for (cur = sock_connect_data_list; cur != NULL; cur = cur->next) {
819 if (((SockConnectData *)cur->data)->id == id) {
820 conn_data = (SockConnectData *)cur->data;
821 break;
822 }
823 }
824
825 if (conn_data) {
826 sock_connect_data_list = g_list_remove(sock_connect_data_list,
827 conn_data);
828
829 if (conn_data->lookup_data)
830 sock_get_address_info_async_cancel
831 (conn_data->lookup_data);
832
833 if (conn_data->io_tag > 0)
834 g_source_remove(conn_data->io_tag);
835 if (conn_data->channel) {
836 GError *err = NULL;
837 g_io_channel_shutdown(conn_data->channel, TRUE, &err);
838 if (err)
839 g_error_free(err);
840 g_io_channel_unref(conn_data->channel);
841 }
842
843 sock_address_list_free(conn_data->addr_list);
844 g_free(conn_data->canonical_name);
845 g_free(conn_data->hostname);
846 g_free(conn_data);
847 } else {
848 g_warning("sock_connect_async_cancel: id %d not found", id);
849 return -1;
850 }
851
852 return 0;
853 }
854
sock_connect_address_list_async(SockConnectData * conn_data)855 static gint sock_connect_address_list_async(SockConnectData *conn_data)
856 {
857 SockAddrData *addr_data;
858 gint sock = -1;
859
860 for (; conn_data->cur_addr != NULL;
861 conn_data->cur_addr = conn_data->cur_addr->next) {
862 addr_data = (SockAddrData *)conn_data->cur_addr->data;
863
864 if ((sock = socket(addr_data->family, addr_data->socktype,
865 addr_data->protocol)) < 0) {
866 perror("socket");
867
868 continue;
869 }
870
871 set_nonblocking_mode(sock, TRUE);
872
873 if (connect(sock, addr_data->addr, addr_data->addr_len) < 0) {
874 if (EINPROGRESS == errno) {
875 break;
876 } else {
877 perror("connect");
878 close(sock);
879 }
880 } else {
881 break;
882 }
883 }
884
885 if (conn_data->cur_addr == NULL) {
886 conn_data->func(NULL, conn_data->data);
887 sock_connect_async_cancel(conn_data->id);
888 return -1;
889 }
890
891 conn_data->cur_addr = conn_data->cur_addr->next;
892
893 #ifndef G_OS_WIN32
894 conn_data->channel = g_io_channel_unix_new(sock);
895 #else
896 conn_data->channel = g_io_channel_win32_new_socket(sock);
897 #endif
898 conn_data->io_tag = g_io_add_watch(conn_data->channel, G_IO_IN|G_IO_OUT,
899 sock_connect_async_cb, conn_data);
900
901 return 0;
902 }
903
904 /* asynchronous DNS lookup */
905
sock_get_address_info_async_cb(GIOChannel * source,GIOCondition condition,gpointer data)906 static gboolean sock_get_address_info_async_cb(GIOChannel *source,
907 GIOCondition condition,
908 gpointer data)
909 {
910 SockLookupData *lookup_data = (SockLookupData *)data;
911 GList *addr_list = NULL;
912 SockAddrData *addr_data;
913 gsize bytes_read;
914 gint ai_member[4];
915 struct sockaddr *addr;
916 gchar *canonical_name = NULL;
917 gchar len = 0;
918 GError *err = NULL;
919
920 g_io_channel_set_encoding(source, NULL, &err);
921 if (err) {
922 g_warning("can unset encoding: %s", err->message);
923 g_error_free(err);
924 return FALSE;
925 }
926 g_io_channel_set_buffered(source, FALSE);
927 if (g_io_channel_read_chars(source, &len, sizeof(len),
928 &bytes_read, &err) == G_IO_STATUS_NORMAL) {
929 if (err != NULL) {
930 g_warning("g_io_channel_read_chars: %s", err->message);
931 g_error_free(err);
932 return FALSE;
933 }
934 if (bytes_read == sizeof(len) && len > 0) {
935 gchar *cur = NULL;
936 gint todo = len;
937 canonical_name = g_malloc0(len + 1);
938 cur = canonical_name;
939 while (todo > 0) {
940 if (g_io_channel_read_chars(source, cur, todo,
941 &bytes_read, &err) != G_IO_STATUS_NORMAL) {
942 if (err) {
943 g_warning("canonical name not read %s", err->message);
944 g_free(canonical_name);
945 canonical_name = NULL;
946 g_error_free(err);
947 err = NULL;
948 break;
949 }
950 } else {
951 cur += bytes_read;
952 todo -= bytes_read;
953 }
954 if (bytes_read == 0) {
955 g_warning("canonical name not read");
956 g_free(canonical_name);
957 canonical_name = NULL;
958 break;
959 }
960 }
961 }
962 }
963 for (;;) {
964 if (g_io_channel_read_chars(source, (gchar *)ai_member,
965 sizeof(ai_member), &bytes_read, &err)
966 != G_IO_STATUS_NORMAL) {
967 if (err != NULL) {
968 g_warning("g_io_channel_read_chars: addr len %s", err->message);
969 g_error_free(err);
970 err = NULL;
971 break;
972 }
973 }
974
975 if (bytes_read == 0 || bytes_read != sizeof(ai_member))
976 break;
977
978 if (ai_member[0] == AF_UNSPEC) {
979 g_warning("DNS lookup failed");
980 log_error(LOG_PROTOCOL, _("%s:%d: unknown host.\n"),
981 lookup_data->hostname, lookup_data->port);
982 break;
983 }
984
985 addr = g_malloc(ai_member[3]);
986 if (g_io_channel_read_chars(source, (gchar *)addr, ai_member[3],
987 &bytes_read, &err)
988 != G_IO_STATUS_NORMAL) {
989 if (err != NULL) {
990 g_warning("g_io_channel_read_chars: addr data read %s", err->message);
991 g_error_free(err);
992 err = NULL;
993 g_free(addr);
994 break;
995 }
996 }
997
998 if (bytes_read != ai_member[3]) {
999 g_warning("sock_get_address_info_async_cb: "
1000 "incomplete address data");
1001 g_free(addr);
1002 break;
1003 }
1004
1005 addr_data = g_new0(SockAddrData, 1);
1006 addr_data->family = ai_member[0];
1007 addr_data->socktype = ai_member[1];
1008 addr_data->protocol = ai_member[2];
1009 addr_data->addr_len = ai_member[3];
1010 addr_data->addr = addr;
1011
1012 addr_list = g_list_append(addr_list, addr_data);
1013 }
1014
1015 g_io_channel_shutdown(source, TRUE, &err);
1016 if (err)
1017 g_error_free(err);
1018 g_io_channel_unref(source);
1019
1020 #ifdef G_OS_WIN32
1021 /* FIXME: We would need to cancel the thread. */
1022 #else
1023 kill(lookup_data->child_pid, SIGKILL);
1024 waitpid(lookup_data->child_pid, NULL, 0);
1025 #endif
1026 lookup_data->canonical_name = canonical_name;
1027
1028 lookup_data->func(addr_list, lookup_data->data);
1029
1030 g_free(lookup_data->canonical_name);
1031 g_free(lookup_data->hostname);
1032 g_free(lookup_data);
1033
1034 return FALSE;
1035 }
1036
1037
1038 /* For better readability we use a separate function to implement the
1039 child code of sock_get_address_info_async. Note, that under W32
1040 this is actually not a child but a thread and this is the reason
1041 why we pass only a void pointer. */
address_info_async_child(void * opaque)1042 static void address_info_async_child(void *opaque)
1043 {
1044 SockLookupData *parm = opaque;
1045 gint gai_err;
1046 struct addrinfo hints, *res, *ai;
1047 gchar port_str[6];
1048 gint ai_member[4] = {AF_UNSPEC, 0, 0, 0};
1049
1050 #ifndef G_OS_WIN32
1051 close(parm->pipe_fds[0]);
1052 parm->pipe_fds[0] = -1;
1053 #endif
1054
1055 memset(&hints, 0, sizeof(hints));
1056 hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
1057 #ifdef INET6
1058 hints.ai_family = AF_UNSPEC;
1059 #else
1060 hints.ai_family = AF_INET;
1061 #endif
1062 hints.ai_socktype = SOCK_STREAM;
1063 hints.ai_protocol = IPPROTO_TCP;
1064
1065 g_snprintf(port_str, sizeof(port_str), "%d", parm->port);
1066
1067 gai_err = getaddrinfo(parm->hostname, port_str, &hints, &res);
1068 if (gai_err != 0) {
1069 gchar len = 0;
1070 g_warning("getaddrinfo for %s:%s failed: %s",
1071 parm->hostname, port_str, gai_strerror(gai_err));
1072 log_error(LOG_PROTOCOL, _("%s:%s: host lookup failed (%s).\n"),
1073 parm->hostname, port_str, gai_strerror(gai_err));
1074 fd_write_all(parm->pipe_fds[1], &len,
1075 sizeof(len));
1076 fd_write_all(parm->pipe_fds[1], (gchar *)ai_member,
1077 sizeof(ai_member));
1078 close(parm->pipe_fds[1]);
1079 parm->pipe_fds[1] = -1;
1080 #ifdef G_OS_WIN32
1081 _endthread();
1082 #else
1083 _exit(1);
1084 #endif
1085 }
1086
1087 if (res != NULL) {
1088 if (res->ai_canonname && strlen(res->ai_canonname) < 255) {
1089 gchar len = strlen(res->ai_canonname);
1090 fd_write_all(parm->pipe_fds[1], &len,
1091 sizeof(len));
1092 fd_write_all(parm->pipe_fds[1], res->ai_canonname,
1093 len);
1094 } else {
1095 gchar len = 0;
1096 fd_write_all(parm->pipe_fds[1], &len,
1097 sizeof(len));
1098 }
1099 } else {
1100 gchar len = 0;
1101 fd_write_all(parm->pipe_fds[1], &len,
1102 sizeof(len));
1103 }
1104
1105 for (ai = res; ai != NULL; ai = ai->ai_next) {
1106 ai_member[0] = ai->ai_family;
1107 ai_member[1] = ai->ai_socktype;
1108 ai_member[2] = ai->ai_protocol;
1109 ai_member[3] = ai->ai_addrlen;
1110
1111 fd_write_all(parm->pipe_fds[1], (gchar *)ai_member,
1112 sizeof(ai_member));
1113 fd_write_all(parm->pipe_fds[1], (gchar *)ai->ai_addr,
1114 ai->ai_addrlen);
1115 }
1116
1117 if (res != NULL)
1118 freeaddrinfo(res);
1119
1120 close(parm->pipe_fds[1]);
1121 parm->pipe_fds[1] = -1;
1122
1123 #ifdef G_OS_WIN32
1124 _endthread();
1125 #else
1126 _exit(0);
1127 #endif
1128 }
1129
sock_get_address_info_async(const gchar * hostname,gushort port,SockAddrFunc func,gpointer data)1130 static SockLookupData *sock_get_address_info_async(const gchar *hostname,
1131 gushort port,
1132 SockAddrFunc func,
1133 gpointer data)
1134 {
1135 SockLookupData *lookup_data = NULL;
1136
1137 refresh_resolvers();
1138
1139 lookup_data = g_new0(SockLookupData, 1);
1140 lookup_data->hostname = g_strdup(hostname);
1141 lookup_data->func = func;
1142 lookup_data->data = data;
1143 lookup_data->port = port;
1144 lookup_data->child_pid = (pid_t)(-1);
1145 lookup_data->pipe_fds[0] = -1;
1146 lookup_data->pipe_fds[1] = -1;
1147
1148 if (pipe(lookup_data->pipe_fds) < 0) {
1149 perror("pipe");
1150 func(NULL, data);
1151 g_free (lookup_data->hostname);
1152 g_free (lookup_data);
1153 return NULL;
1154 }
1155
1156 #ifndef G_OS_WIN32
1157 if ((lookup_data->child_pid = fork()) < 0) {
1158 perror("fork");
1159 func(NULL, data);
1160 g_free (lookup_data->hostname);
1161 g_free (lookup_data);
1162 return NULL;
1163 }
1164
1165 if (lookup_data->child_pid == 0) {
1166 /* Child process. */
1167 address_info_async_child (lookup_data);
1168 g_assert_not_reached ();
1169 }
1170 /* Parent process. */
1171 close(lookup_data->pipe_fds[1]);
1172 lookup_data->pipe_fds[1] = -1;
1173 #endif /*!G_OS_WIN32 */
1174
1175 #ifndef G_OS_WIN32
1176 lookup_data->channel = g_io_channel_unix_new(lookup_data->pipe_fds[0]);
1177 #else
1178 lookup_data->channel = g_io_channel_win32_new_fd(lookup_data->pipe_fds[0]);
1179 #endif
1180 lookup_data->io_tag = g_io_add_watch(lookup_data->channel, G_IO_IN,
1181 sock_get_address_info_async_cb,
1182 lookup_data);
1183 #ifdef G_OS_WIN32
1184 lookup_data->child_pid = _beginthread(
1185 address_info_async_child, 0, lookup_data);
1186 #endif
1187
1188 return lookup_data;
1189 }
1190
sock_get_address_info_async_cancel(SockLookupData * lookup_data)1191 static gint sock_get_address_info_async_cancel(SockLookupData *lookup_data)
1192 {
1193 if (lookup_data->io_tag > 0)
1194 g_source_remove(lookup_data->io_tag);
1195 if (lookup_data->channel) {
1196 GError *err = NULL;
1197 g_io_channel_shutdown(lookup_data->channel, TRUE, &err);
1198 if (err)
1199 g_error_free(err);
1200
1201 g_io_channel_unref(lookup_data->channel);
1202 }
1203
1204 if (lookup_data->child_pid > 0) {
1205 #ifdef G_OS_WIN32
1206 /* FIXME: Need a way to cancel the thread. */
1207 #else
1208 kill(lookup_data->child_pid, SIGKILL);
1209 waitpid(lookup_data->child_pid, NULL, 0);
1210 #endif
1211 }
1212
1213 g_free(lookup_data->canonical_name);
1214 g_free(lookup_data->hostname);
1215 g_free(lookup_data);
1216
1217 return 0;
1218 }
1219
1220
sockinfo_from_fd(const gchar * hostname,gushort port,gint sock)1221 static SockInfo *sockinfo_from_fd(const gchar *hostname,
1222 gushort port,
1223 gint sock)
1224 {
1225 SockInfo *sockinfo;
1226
1227 sockinfo = g_new0(SockInfo, 1);
1228 sockinfo->sock = sock;
1229 #ifndef G_OS_WIN32
1230 sockinfo->sock_ch = g_io_channel_unix_new(sock);
1231 #else
1232 sockinfo->sock_ch = g_io_channel_win32_new_socket(sock);
1233 #endif
1234 sockinfo->hostname = g_strdup(hostname);
1235 sockinfo->port = port;
1236 sockinfo->state = CONN_ESTABLISHED;
1237
1238 return sockinfo;
1239 }
1240
fd_read(gint fd,gchar * buf,gint len)1241 static gint fd_read(gint fd, gchar *buf, gint len)
1242 {
1243 if (fd_check_io(fd, G_IO_IN) < 0)
1244 return -1;
1245
1246 #ifdef G_OS_WIN32
1247 if (fd_is_w32_socket(fd))
1248 return recv(fd, buf, len, 0);
1249 #endif
1250
1251 return read(fd, buf, len);
1252 }
1253
1254 #if USE_GNUTLS
ssl_read(gnutls_session_t ssl,gchar * buf,gint len)1255 static gint ssl_read(gnutls_session_t ssl, gchar *buf, gint len)
1256 {
1257 gint r;
1258
1259 if (gnutls_record_check_pending(ssl) == 0) {
1260 if (fd_check_io(GPOINTER_TO_INT(gnutls_transport_get_ptr(ssl)), G_IO_IN) < 0)
1261 return -1;
1262 }
1263
1264 while (1) {
1265 r = gnutls_record_recv(ssl, buf, len);
1266 if (r > 0)
1267 return r;
1268
1269 switch (r) {
1270 case 0: /* closed connection */
1271 return -1;
1272
1273 case GNUTLS_E_REHANDSHAKE:
1274 do {
1275 r = gnutls_handshake(ssl);
1276 } while (r == GNUTLS_E_AGAIN || r == GNUTLS_E_INTERRUPTED);
1277 break; /* re-receive */
1278 case GNUTLS_E_AGAIN:
1279 case GNUTLS_E_INTERRUPTED:
1280 errno = EAGAIN;
1281 return -1;
1282
1283 default:
1284 debug_print("Unexpected SSL/TLS read result %d\n", r);
1285 errno = EIO;
1286 return -1;
1287 }
1288 }
1289
1290 }
1291 #endif
1292
sock_read(SockInfo * sock,gchar * buf,gint len)1293 gint sock_read(SockInfo *sock, gchar *buf, gint len)
1294 {
1295 gint ret;
1296
1297 cm_return_val_if_fail(sock != NULL, -1);
1298
1299 #ifdef USE_GNUTLS
1300 if (sock->ssl)
1301 ret = ssl_read(sock->ssl, buf, len);
1302 else
1303 #endif
1304 ret = fd_read(sock->sock, buf, len);
1305
1306 if (ret < 0)
1307 sock->state = CONN_DISCONNECTED;
1308 return ret;
1309 }
1310
fd_write(gint fd,const gchar * buf,gint len)1311 gint fd_write(gint fd, const gchar *buf, gint len)
1312 {
1313 if (fd_check_io(fd, G_IO_OUT) < 0)
1314 return -1;
1315
1316 #ifdef G_OS_WIN32
1317 if (fd_is_w32_socket (fd))
1318 return send(fd, buf, len, 0);
1319 #endif
1320
1321 return write(fd, buf, len);
1322 }
1323
1324 #if USE_GNUTLS
ssl_write(gnutls_session_t ssl,const gchar * buf,gint len)1325 static gint ssl_write(gnutls_session_t ssl, const gchar *buf, gint len)
1326 {
1327 gint ret;
1328
1329 if (fd_check_io(GPOINTER_TO_INT(gnutls_transport_get_ptr(ssl)), G_IO_OUT) < 0)
1330 return -1;
1331
1332 ret = gnutls_record_send(ssl, buf, len);
1333
1334 switch (ret) {
1335 case 0:
1336 return -1;
1337 case GNUTLS_E_AGAIN:
1338 case GNUTLS_E_INTERRUPTED:
1339 return 0;
1340
1341 default:
1342 return ret;
1343 }
1344 }
1345
1346 #endif
1347
sock_write(SockInfo * sock,const gchar * buf,gint len)1348 gint sock_write(SockInfo *sock, const gchar *buf, gint len)
1349 {
1350 gint ret;
1351
1352 cm_return_val_if_fail(sock != NULL, -1);
1353
1354 #ifdef USE_GNUTLS
1355 if (sock->ssl)
1356 ret = ssl_write(sock->ssl, buf, len);
1357 else
1358 #endif
1359 ret = fd_write(sock->sock, buf, len);
1360
1361 if (ret < 0)
1362 sock->state = CONN_DISCONNECTED;
1363 return ret;
1364 }
1365
fd_write_all(gint fd,const gchar * buf,gint len)1366 gint fd_write_all(gint fd, const gchar *buf, gint len)
1367 {
1368 gint n, wrlen = 0;
1369
1370 while (len) {
1371 if (fd_check_io(fd, G_IO_OUT) < 0)
1372 return -1;
1373 #ifndef G_OS_WIN32
1374 signal(SIGPIPE, SIG_IGN);
1375 #endif
1376
1377 #ifdef G_OS_WIN32
1378 if (fd_is_w32_socket(fd))
1379 n = send(fd, buf, len, 0);
1380 else
1381 #endif
1382 n = write(fd, buf, len);
1383
1384 if (n <= 0) {
1385 log_error(LOG_PROTOCOL, _("write on fd%d: %s\n"), fd, g_strerror(errno));
1386 return -1;
1387 }
1388 len -= n;
1389 wrlen += n;
1390 buf += n;
1391 }
1392
1393 return wrlen;
1394 }
1395
1396 #ifdef USE_GNUTLS
ssl_write_all(gnutls_session_t ssl,const gchar * buf,gint len)1397 static gint ssl_write_all(gnutls_session_t ssl, const gchar *buf, gint len)
1398 {
1399 gint n, wrlen = 0;
1400
1401 while (len) {
1402 n = ssl_write(ssl, buf, len);
1403 if (n <= 0)
1404 return -1;
1405 len -= n;
1406 wrlen += n;
1407 buf += n;
1408 }
1409
1410 return wrlen;
1411 }
1412 #endif
1413
sock_write_all(SockInfo * sock,const gchar * buf,gint len)1414 gint sock_write_all(SockInfo *sock, const gchar *buf, gint len)
1415 {
1416 gint ret;
1417
1418 cm_return_val_if_fail(sock != NULL, -1);
1419
1420 #ifdef USE_GNUTLS
1421 if (sock->ssl)
1422 ret = ssl_write_all(sock->ssl, buf, len);
1423 else
1424 #endif
1425 ret = fd_write_all(sock->sock, buf, len);
1426
1427 if (ret < 0)
1428 sock->state = CONN_DISCONNECTED;
1429 return ret;
1430 }
1431
fd_recv(gint fd,gchar * buf,gint len,gint flags)1432 static gint fd_recv(gint fd, gchar *buf, gint len, gint flags)
1433 {
1434 if (fd_check_io(fd, G_IO_IN) < 0)
1435 return -1;
1436
1437 return recv(fd, buf, len, flags);
1438 }
1439
fd_gets(gint fd,gchar * buf,gint len)1440 gint fd_gets(gint fd, gchar *buf, gint len)
1441 {
1442 gchar *bp = buf;
1443
1444 if (--len < 1)
1445 return -1;
1446
1447 #ifdef G_OS_WIN32
1448 fd_check_io(fd, G_IO_IN);
1449 do {
1450 /*
1451 XXX:tm try nonblock
1452 MSKB Article ID: Q147714
1453 Windows Sockets 2 Service Provider Interface Limitations
1454 Polling with recv(MSG_PEEK) to determine when a complete message
1455 has arrived.
1456 Reason and Workaround not available.
1457
1458 Single-byte send() and recv().
1459 Reason: Couple one-byte sends with Nagle disabled.
1460 Workaround: Send modest amounts and receive as much as possible.
1461 (still unused)
1462 */
1463 if (recv(fd, bp, 1, 0) <= 0)
1464 return -1;
1465 if (*bp == '\n')
1466 break;
1467 bp++;
1468 len--;
1469 } while (0 < len);
1470 #else /*!G_OS_WIN32*/
1471 gchar *newline;
1472 gint n;
1473 do {
1474 if ((n = fd_recv(fd, bp, len, MSG_PEEK)) <= 0)
1475 return -1;
1476 if ((newline = memchr(bp, '\n', n)) != NULL)
1477 n = newline - bp + 1;
1478 if ((n = fd_read(fd, bp, n)) < 0)
1479 return -1;
1480 bp += n;
1481 len -= n;
1482 } while (!newline && len);
1483 #endif /*!G_OS_WIN32*/
1484
1485 *bp = '\0';
1486 return bp - buf;
1487 }
1488
sock_close(SockInfo * sock,gboolean close_fd)1489 gint sock_close(SockInfo *sock, gboolean close_fd)
1490 {
1491 gint ret = 0;
1492
1493 if (!sock)
1494 return 0;
1495
1496 if (sock->sock_ch)
1497 g_io_channel_unref(sock->sock_ch);
1498
1499 #ifdef USE_GNUTLS
1500 if (sock->ssl)
1501 ssl_done_socket(sock);
1502 if (sock->g_source != 0 && g_main_context_find_source_by_id(NULL, sock->g_source) != NULL)
1503 g_source_remove(sock->g_source);
1504 sock->g_source = 0;
1505 #endif
1506 if (close_fd) {
1507 #ifdef G_OS_WIN32
1508 shutdown(sock->sock, 1); /* complete transfer before close */
1509 ret = closesocket(sock->sock);
1510 #else
1511 ret = fd_close(sock->sock);
1512 #endif
1513 }
1514
1515 g_free(sock->canonical_name);
1516 g_free(sock->hostname);
1517 g_free(sock);
1518
1519 return ret;
1520 }
1521
fd_close(gint fd)1522 gint fd_close(gint fd)
1523 {
1524 return close(fd);
1525 }
1526