2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2022 the Claws Mail team and Hiroyuki Yamamoto
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.
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.
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/>.
21 #include "claws-features.h"
25 #include <glib/gi18n.h>
28 #include <sys/types.h>
30 # include <ws2tcpip.h>
32 # define EINPROGRESS WSAEINPROGRESS
36 # include <sys/wait.h>
38 # include <sys/socket.h>
39 # include <sys/stat.h>
41 # include <netinet/in.h>
42 # include <arpa/inet.h>
44 # ifndef _PATH_RESCONF
45 # define _PATH_RESCONF "/etc/resolv.conf"
48 #endif /* G_OS_WIN32 */
58 # include <sys/select.h>
69 #error USE_GIO is currently not supported
79 typedef gint (*SockAddrFunc
) (GList
*addr_list
,
82 typedef struct _SockConnectData SockConnectData
;
83 typedef struct _SockLookupData SockLookupData
;
84 typedef struct _SockAddrData SockAddrData
;
85 typedef struct _SockSource SockSource
;
87 struct _SockConnectData
{
93 SockLookupData
*lookup_data
;
98 gchar
*canonical_name
;
101 struct _SockLookupData
{
110 gchar
*canonical_name
;
113 struct _SockAddrData
{
118 struct sockaddr
*addr
;
126 static guint io_timeout
= 60;
128 static GList
*sock_connect_data_list
= NULL
;
131 static gboolean
ssl_sock_prepare (GSource
*source
,
133 static gboolean
ssl_sock_check (GSource
*source
);
134 static gboolean
ssl_sock_dispatch (GSource
*source
,
135 GSourceFunc callback
,
137 GSourceFuncs ssl_watch_funcs
= {
147 static gint
sock_connect_with_timeout (gint sock
,
148 const struct sockaddr
*serv_addr
,
152 static gint
sock_connect_by_getaddrinfo (const gchar
*hostname
,
155 static SockInfo
*sockinfo_from_fd(const gchar
*hostname
,
158 static void sock_address_list_free (GList
*addr_list
);
160 static gboolean
sock_connect_async_cb (GIOChannel
*source
,
161 GIOCondition condition
,
163 static gint sock_connect_async_get_address_info_cb
167 static gint
sock_connect_address_list_async (SockConnectData
*conn_data
);
169 static gboolean
sock_get_address_info_async_cb (GIOChannel
*source
,
170 GIOCondition condition
,
172 static SockLookupData
*sock_get_address_info_async
173 (const gchar
*hostname
,
177 static gint
sock_get_address_info_async_cancel (SockLookupData
*lookup_data
);
186 result
= WSAStartup(MAKEWORD(2, 2), &wsadata
);
187 if (result
!= NO_ERROR
) {
188 g_warning("WSAStartup() failed");
195 gint
sock_cleanup(void)
203 gint
sock_set_io_timeout(guint sec
)
209 void refresh_resolvers(void)
212 static time_t resolv_conf_changed
= (time_t)NULL
;
215 /* This makes the glibc re-read resolv.conf, if it changed
216 * since our startup. Maybe that should be #ifdef'ed, I don't
217 * know if it'd work on BSDs.
218 * Why doesn't the glibc do it by itself?
220 if (g_stat(_PATH_RESCONF
, &s
) == 0) {
221 if (s
.st_mtime
> resolv_conf_changed
) {
222 resolv_conf_changed
= s
.st_mtime
;
226 we'll have bigger problems. */
231 #define SOCKET_IS_VALID(s) ((s) != INVALID_SOCKET)
233 #define SOCKET_IS_VALID(s) (s != -1)
237 /* Due to the fact that socket under Windows are not represented by
238 standard file descriptors, we sometimes need to check whether a
239 given file descriptor is actually a socket. This is done by
240 testing for an error. Returns true under W32 if FD is a socket. */
241 static int fd_is_w32_socket(gint fd
)
244 gint retval
= sizeof(optval
);
246 return !getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, (char*)&optval
, &retval
);
250 gint
fd_connect_inet(gushort port
)
253 struct sockaddr_in addr
;
255 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
256 if (!SOCKET_IS_VALID(sock
)) {
258 debug_print("fd_connect_inet(): socket() failed: %d\n",
261 perror("fd_connect_inet(): socket");
266 memset(&addr
, 0, sizeof(addr
));
267 addr
.sin_family
= AF_INET
;
268 addr
.sin_port
= htons(port
);
269 addr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
271 if (connect(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
278 gint
fd_open_inet(gushort port
)
281 struct sockaddr_in addr
;
284 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
285 if (!SOCKET_IS_VALID(sock
)) {
287 g_warning("fd_open_inet(): socket() failed: %d",
290 perror("fd_open_inet(): socket");
296 if (setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&val
,
298 perror("setsockopt");
303 memset(&addr
, 0, sizeof(addr
));
304 addr
.sin_family
= AF_INET
;
305 addr
.sin_port
= htons(port
);
306 addr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
308 if (bind(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
314 if (listen(sock
, 1) < 0) {
323 gint
fd_connect_unix(const gchar
*path
)
327 struct sockaddr_un addr
;
329 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
331 perror("sock_connect_unix(): socket");
335 memset(&addr
, 0, sizeof(addr
));
336 addr
.sun_family
= AF_UNIX
;
337 strncpy(addr
.sun_path
, path
, sizeof(addr
.sun_path
) - 1);
339 if (connect(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
350 gint
fd_open_unix(const gchar
*path
)
354 struct sockaddr_un addr
;
356 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
359 perror("sock_open_unix(): socket");
363 memset(&addr
, 0, sizeof(addr
));
364 addr
.sun_family
= AF_UNIX
;
365 strncpy(addr
.sun_path
, path
, sizeof(addr
.sun_path
) - 1);
367 if (bind(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
368 gchar
*buf
= g_strdup_printf("can't bind to %s", path
);
375 if (listen(sock
, 1) < 0) {
376 gchar
*buf
= g_strdup_printf("can't listen on %s", path
);
389 gint
fd_accept(gint sock
)
391 struct sockaddr_in caddr
;
394 caddr_len
= sizeof(caddr
);
395 return accept(sock
, (struct sockaddr
*)&caddr
, &caddr_len
);
399 static gint
set_nonblocking_mode(gint fd
, gboolean nonblock
)
404 flags
= fcntl(fd
, F_GETFL
, 0);
413 flags
&= ~O_NONBLOCK
;
415 return fcntl(fd
, F_SETFL
, flags
);
421 gint
sock_set_nonblocking_mode(SockInfo
*sock
, gboolean nonblock
)
423 cm_return_val_if_fail(sock
!= NULL
, -1);
425 return set_nonblocking_mode(sock
->sock
, nonblock
);
428 static gboolean
is_nonblocking_mode(gint fd
)
433 flags
= fcntl(fd
, F_GETFL
, 0);
439 return ((flags
& O_NONBLOCK
) != 0);
445 gboolean
sock_is_nonblocking_mode(SockInfo
*sock
)
447 cm_return_val_if_fail(sock
!= NULL
, FALSE
);
449 return is_nonblocking_mode(sock
->sock
);
454 static gboolean
ssl_sock_prepare(GSource
*source
, gint
*timeout
)
460 static gboolean
ssl_sock_check(GSource
*source
)
462 SockInfo
*sock
= ((SockSource
*)source
)->sock
;
463 struct timeval timeout
= {0, 0};
465 GIOCondition condition
= 0;
467 if (!sock
|| !sock
->sock
)
470 condition
= sock
->condition
;
472 if ((condition
& G_IO_IN
) == G_IO_IN
&&
473 gnutls_record_check_pending(sock
->ssl
) != 0)
477 FD_SET(sock
->sock
, &fds
);
479 select(sock
->sock
+ 1,
480 (condition
& G_IO_IN
) ? &fds
: NULL
,
481 (condition
& G_IO_OUT
) ? &fds
: NULL
,
484 return FD_ISSET(sock
->sock
, &fds
) != 0;
487 static gboolean
ssl_sock_dispatch(GSource
*source
, GSourceFunc callback
,
490 SockInfo
*sock
= ((SockSource
*)source
)->sock
;
492 if (!sock
|| !sock
->callback
|| !sock
->data
)
495 return sock
->callback(sock
, sock
->condition
, sock
->data
);
499 static gboolean
sock_watch_cb(GIOChannel
*source
, GIOCondition condition
,
502 SockInfo
*sock
= (SockInfo
*)data
;
504 if ((condition
& sock
->condition
) == 0)
507 return sock
->callback(sock
, sock
->condition
, sock
->data
);
510 guint
sock_add_watch(SockInfo
*sock
, GIOCondition condition
, SockFunc func
,
516 sock
->callback
= func
;
517 sock
->condition
= condition
;
523 GSource
*source
= g_source_new(&ssl_watch_funcs
,
525 ((SockSource
*) source
)->sock
= sock
;
526 g_source_set_priority(source
, G_PRIORITY_DEFAULT
);
527 g_source_set_can_recurse(source
, FALSE
);
528 sock
->g_source
= g_source_attach(source
, NULL
);
529 g_source_unref (source
); /* Refcount back down to 1 */
530 return sock
->g_source
;
534 return g_io_add_watch(sock
->sock_ch
, condition
, sock_watch_cb
, sock
);
537 static gint
fd_check_io(gint fd
, GIOCondition cond
)
539 struct timeval timeout
;
542 if (is_nonblocking_mode(fd
))
545 timeout
.tv_sec
= io_timeout
;
551 if (cond
== G_IO_IN
) {
552 select(fd
+ 1, &fds
, NULL
, NULL
,
553 io_timeout
> 0 ? &timeout
: NULL
);
555 select(fd
+ 1, NULL
, &fds
, NULL
,
556 io_timeout
> 0 ? &timeout
: NULL
);
559 if (FD_ISSET(fd
, &fds
)) {
562 g_warning("socket IO timeout");
563 log_error(LOG_PROTOCOL
, _("Socket IO timeout.\n"));
569 static sigjmp_buf jmpenv
;
571 static void timeout_handler(gint sig
)
573 siglongjmp(jmpenv
, 1);
577 static gint
sock_connect_with_timeout(gint sock
,
578 const struct sockaddr
*serv_addr
,
582 gint ret
, saved_errno
;
584 void (*prev_handler
)(gint
);
587 prev_handler
= signal(SIGALRM
, timeout_handler
);
588 if (sigsetjmp(jmpenv
, 1)) {
590 signal(SIGALRM
, prev_handler
);
592 log_error(LOG_PROTOCOL
, _("Connection timed out.\n"));
598 ret
= connect(sock
, serv_addr
, addrlen
);
602 debug_print("connect() failed: %d (%s)\n",
603 saved_errno
, g_strerror(saved_errno
));
608 signal(SIGALRM
, prev_handler
);
614 static gint
sock_connect_by_getaddrinfo(const gchar
*hostname
, gushort port
)
616 gint sock
= -1, gai_error
;
617 struct addrinfo hints
, *res
, *ai
;
622 memset(&hints
, 0, sizeof(hints
));
623 hints
.ai_flags
= AI_ADDRCONFIG
;
626 hints
.ai_family
= AF_UNSPEC
;
628 hints
.ai_family
= AF_INET
;
631 hints
.ai_socktype
= SOCK_STREAM
;
632 hints
.ai_protocol
= IPPROTO_TCP
;
634 /* convert port from integer to string. */
635 g_snprintf(port_str
, sizeof(port_str
), "%d", port
);
637 if ((gai_error
= getaddrinfo(hostname
, port_str
, &hints
, &res
)) != 0) {
638 g_printerr("getaddrinfo for %s:%s failed: %s\n",
639 hostname
, port_str
, gai_strerror(gai_error
));
643 for (ai
= res
; ai
!= NULL
; ai
= ai
->ai_next
) {
645 if (ai
->ai_family
== AF_INET6
)
649 sock
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
653 if (sock
== INVALID_SOCKET
)
657 if (sock_connect_with_timeout
658 (sock
, ai
->ai_addr
, ai
->ai_addrlen
, io_timeout
) == 0)
673 SockInfo
*sock_connect(const gchar
*hostname
, gushort port
)
681 if ((sock
= sock_connect_by_getaddrinfo(hostname
, port
)) < 0) {
685 return sockinfo_from_fd(hostname
, port
, sock
);
689 static void sock_address_list_free(GList
*addr_list
)
693 for (cur
= addr_list
; cur
!= NULL
; cur
= cur
->next
) {
694 SockAddrData
*addr_data
= (SockAddrData
*)cur
->data
;
695 g_free(addr_data
->addr
);
699 g_list_free(addr_list
);
702 /* asynchronous TCP connection */
704 static gboolean
sock_connect_async_cb(GIOChannel
*source
,
705 GIOCondition condition
, gpointer data
)
707 SockConnectData
*conn_data
= (SockConnectData
*)data
;
713 if (conn_data
->io_tag
== 0 && conn_data
->channel
== NULL
)
716 fd
= g_io_channel_unix_get_fd(source
);
718 conn_data
->io_tag
= 0;
719 conn_data
->channel
= NULL
;
720 g_io_channel_unref(source
);
723 if (getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, &val
, &len
) < 0) {
724 perror("getsockopt");
726 sock_connect_address_list_async(conn_data
);
732 log_error(LOG_PROTOCOL
, _("%s:%d: connection failed (%s).\n"),
733 conn_data
->hostname
, conn_data
->port
,
735 sock_connect_address_list_async(conn_data
);
739 sockinfo
= g_new0(SockInfo
, 1);
742 sockinfo
->sock_ch
= g_io_channel_unix_new(fd
);
744 sockinfo
->sock_ch
= g_io_channel_win32_new_socket(fd
);
746 sockinfo
->hostname
= g_strdup(conn_data
->hostname
);
747 sockinfo
->port
= conn_data
->port
;
748 sockinfo
->state
= CONN_ESTABLISHED
;
749 sockinfo
->canonical_name
= g_strdup(conn_data
->canonical_name
);
751 conn_data
->func(sockinfo
, conn_data
->data
);
753 sock_connect_async_cancel(conn_data
->id
);
758 static gint
sock_connect_async_get_address_info_cb(GList
*addr_list
,
761 SockConnectData
*conn_data
= (SockConnectData
*)data
;
763 conn_data
->addr_list
= addr_list
;
764 conn_data
->cur_addr
= addr_list
;
765 if (conn_data
->lookup_data
) {
766 conn_data
->canonical_name
= conn_data
->lookup_data
->canonical_name
;
767 conn_data
->lookup_data
->canonical_name
= NULL
;
768 conn_data
->lookup_data
= NULL
;
770 return sock_connect_address_list_async(conn_data
);
773 gint
sock_connect_async(const gchar
*hostname
, gushort port
,
774 SockConnectFunc func
, gpointer data
)
777 SockConnectData
*conn_data
;
779 conn_data
= g_new0(SockConnectData
, 1);
780 conn_data
->id
= id
++;
781 conn_data
->hostname
= g_strdup(hostname
);
782 conn_data
->port
= port
;
783 conn_data
->addr_list
= NULL
;
784 conn_data
->cur_addr
= NULL
;
785 conn_data
->io_tag
= 0;
786 conn_data
->func
= func
;
787 conn_data
->data
= data
;
789 conn_data
->lookup_data
= sock_get_address_info_async
790 (hostname
, port
, sock_connect_async_get_address_info_cb
,
793 if (conn_data
->lookup_data
== NULL
) {
794 g_free(conn_data
->hostname
);
799 sock_connect_data_list
= g_list_append(sock_connect_data_list
,
802 return conn_data
->id
;
805 gint
sock_connect_async_cancel(gint id
)
807 SockConnectData
*conn_data
= NULL
;
810 for (cur
= sock_connect_data_list
; cur
!= NULL
; cur
= cur
->next
) {
811 if (((SockConnectData
*)cur
->data
)->id
== id
) {
812 conn_data
= (SockConnectData
*)cur
->data
;
818 sock_connect_data_list
= g_list_remove(sock_connect_data_list
,
821 if (conn_data
->lookup_data
)
822 sock_get_address_info_async_cancel
823 (conn_data
->lookup_data
);
825 if (conn_data
->io_tag
> 0)
826 g_source_remove(conn_data
->io_tag
);
827 if (conn_data
->channel
) {
829 g_io_channel_shutdown(conn_data
->channel
, TRUE
, &err
);
832 g_io_channel_unref(conn_data
->channel
);
835 sock_address_list_free(conn_data
->addr_list
);
836 g_free(conn_data
->canonical_name
);
837 g_free(conn_data
->hostname
);
840 g_warning("sock_connect_async_cancel: id %d not found", id
);
847 static gint
sock_connect_address_list_async(SockConnectData
*conn_data
)
849 SockAddrData
*addr_data
;
852 for (; conn_data
->cur_addr
!= NULL
;
853 conn_data
->cur_addr
= conn_data
->cur_addr
->next
) {
854 addr_data
= (SockAddrData
*)conn_data
->cur_addr
->data
;
856 if ((sock
= socket(addr_data
->family
, addr_data
->socktype
,
857 addr_data
->protocol
)) < 0) {
863 set_nonblocking_mode(sock
, TRUE
);
865 if (connect(sock
, addr_data
->addr
, addr_data
->addr_len
) < 0) {
866 if (EINPROGRESS
== errno
) {
877 if (conn_data
->cur_addr
== NULL
) {
878 conn_data
->func(NULL
, conn_data
->data
);
879 sock_connect_async_cancel(conn_data
->id
);
883 conn_data
->cur_addr
= conn_data
->cur_addr
->next
;
886 conn_data
->channel
= g_io_channel_unix_new(sock
);
888 conn_data
->channel
= g_io_channel_win32_new_socket(sock
);
890 conn_data
->io_tag
= g_io_add_watch(conn_data
->channel
, G_IO_IN
|G_IO_OUT
,
891 sock_connect_async_cb
, conn_data
);
896 /* asynchronous DNS lookup */
898 static gboolean
sock_get_address_info_async_cb(GIOChannel
*source
,
899 GIOCondition condition
,
902 SockLookupData
*lookup_data
= (SockLookupData
*)data
;
903 GList
*addr_list
= NULL
;
904 SockAddrData
*addr_data
;
907 struct sockaddr
*addr
;
908 gchar
*canonical_name
= NULL
;
912 g_io_channel_set_encoding(source
, NULL
, &err
);
914 g_warning("can't unset encoding: %s", err
->message
);
918 g_io_channel_set_buffered(source
, FALSE
);
919 if (g_io_channel_read_chars(source
, &len
, sizeof(len
),
920 &bytes_read
, &err
) == G_IO_STATUS_NORMAL
) {
922 g_warning("g_io_channel_read_chars: %s", err
->message
);
926 if (bytes_read
== sizeof(len
) && len
> 0) {
929 canonical_name
= g_malloc0(len
+ 1);
930 cur
= canonical_name
;
932 if (g_io_channel_read_chars(source
, cur
, todo
,
933 &bytes_read
, &err
) != G_IO_STATUS_NORMAL
) {
935 g_warning("canonical name not read %s", err
->message
);
936 g_free(canonical_name
);
937 canonical_name
= NULL
;
946 if (bytes_read
== 0) {
947 g_warning("canonical name not read");
948 g_free(canonical_name
);
949 canonical_name
= NULL
;
956 if (g_io_channel_read_chars(source
, (gchar
*)ai_member
,
957 sizeof(ai_member
), &bytes_read
, &err
)
958 != G_IO_STATUS_NORMAL
) {
960 g_warning("g_io_channel_read_chars: addr len %s", err
->message
);
967 if (bytes_read
== 0 || bytes_read
!= sizeof(ai_member
))
970 if (ai_member
[0] == AF_UNSPEC
) {
971 g_warning("DNS lookup failed");
972 log_error(LOG_PROTOCOL
, _("%s:%d: unknown host.\n"),
973 lookup_data
->hostname
, lookup_data
->port
);
977 addr
= g_malloc(ai_member
[3]);
978 if (g_io_channel_read_chars(source
, (gchar
*)addr
, ai_member
[3],
980 != G_IO_STATUS_NORMAL
) {
982 g_warning("g_io_channel_read_chars: addr data read %s", err
->message
);
990 if (bytes_read
!= ai_member
[3]) {
991 g_warning("sock_get_address_info_async_cb: "
992 "incomplete address data");
997 addr_data
= g_new0(SockAddrData
, 1);
998 addr_data
->family
= ai_member
[0];
999 addr_data
->socktype
= ai_member
[1];
1000 addr_data
->protocol
= ai_member
[2];
1001 addr_data
->addr_len
= ai_member
[3];
1002 addr_data
->addr
= addr
;
1004 addr_list
= g_list_append(addr_list
, addr_data
);
1007 g_io_channel_shutdown(source
, TRUE
, &err
);
1010 g_io_channel_unref(source
);
1013 /* FIXME: We would need to cancel the thread. */
1015 kill(lookup_data
->child_pid
, SIGKILL
);
1016 waitpid(lookup_data
->child_pid
, NULL
, 0);
1018 lookup_data
->canonical_name
= canonical_name
;
1020 lookup_data
->func(addr_list
, lookup_data
->data
);
1022 g_free(lookup_data
->canonical_name
);
1023 g_free(lookup_data
->hostname
);
1024 g_free(lookup_data
);
1030 /* For better readability we use a separate function to implement the
1031 child code of sock_get_address_info_async. Note, that under W32
1032 this is actually not a child but a thread and this is the reason
1033 why we pass only a void pointer. */
1034 static void address_info_async_child(void *opaque
)
1036 SockLookupData
*parm
= opaque
;
1038 struct addrinfo hints
, *res
, *ai
;
1040 gint ai_member
[4] = {AF_UNSPEC
, 0, 0, 0};
1043 close(parm
->pipe_fds
[0]);
1044 parm
->pipe_fds
[0] = -1;
1047 memset(&hints
, 0, sizeof(hints
));
1048 hints
.ai_flags
= AI_CANONNAME
| AI_ADDRCONFIG
;
1050 hints
.ai_family
= AF_UNSPEC
;
1052 hints
.ai_family
= AF_INET
;
1054 hints
.ai_socktype
= SOCK_STREAM
;
1055 hints
.ai_protocol
= IPPROTO_TCP
;
1057 g_snprintf(port_str
, sizeof(port_str
), "%d", parm
->port
);
1059 gai_err
= getaddrinfo(parm
->hostname
, port_str
, &hints
, &res
);
1062 g_warning("getaddrinfo for %s:%s failed: %s",
1063 parm
->hostname
, port_str
, gai_strerror(gai_err
));
1064 log_error(LOG_PROTOCOL
, _("%s:%s: host lookup failed (%s).\n"),
1065 parm
->hostname
, port_str
, gai_strerror(gai_err
));
1066 fd_write_all(parm
->pipe_fds
[1], &len
,
1068 fd_write_all(parm
->pipe_fds
[1], (gchar
*)ai_member
,
1070 close(parm
->pipe_fds
[1]);
1071 parm
->pipe_fds
[1] = -1;
1080 if (res
->ai_canonname
&& strlen(res
->ai_canonname
) < 255) {
1081 gchar len
= strlen(res
->ai_canonname
);
1082 fd_write_all(parm
->pipe_fds
[1], &len
,
1084 fd_write_all(parm
->pipe_fds
[1], res
->ai_canonname
,
1088 fd_write_all(parm
->pipe_fds
[1], &len
,
1093 fd_write_all(parm
->pipe_fds
[1], &len
,
1097 for (ai
= res
; ai
!= NULL
; ai
= ai
->ai_next
) {
1098 ai_member
[0] = ai
->ai_family
;
1099 ai_member
[1] = ai
->ai_socktype
;
1100 ai_member
[2] = ai
->ai_protocol
;
1101 ai_member
[3] = ai
->ai_addrlen
;
1103 fd_write_all(parm
->pipe_fds
[1], (gchar
*)ai_member
,
1105 fd_write_all(parm
->pipe_fds
[1], (gchar
*)ai
->ai_addr
,
1112 close(parm
->pipe_fds
[1]);
1113 parm
->pipe_fds
[1] = -1;
1122 static SockLookupData
*sock_get_address_info_async(const gchar
*hostname
,
1127 SockLookupData
*lookup_data
= NULL
;
1129 refresh_resolvers();
1131 lookup_data
= g_new0(SockLookupData
, 1);
1132 lookup_data
->hostname
= g_strdup(hostname
);
1133 lookup_data
->func
= func
;
1134 lookup_data
->data
= data
;
1135 lookup_data
->port
= port
;
1136 lookup_data
->child_pid
= (pid_t
)(-1);
1137 lookup_data
->pipe_fds
[0] = -1;
1138 lookup_data
->pipe_fds
[1] = -1;
1140 if (pipe(lookup_data
->pipe_fds
) < 0) {
1143 g_free (lookup_data
->hostname
);
1144 g_free (lookup_data
);
1149 if ((lookup_data
->child_pid
= fork()) < 0) {
1152 g_free (lookup_data
->hostname
);
1153 g_free (lookup_data
);
1157 if (lookup_data
->child_pid
== 0) {
1158 /* Child process. */
1159 address_info_async_child (lookup_data
);
1160 g_assert_not_reached ();
1162 /* Parent process. */
1163 close(lookup_data
->pipe_fds
[1]);
1164 lookup_data
->pipe_fds
[1] = -1;
1165 #endif /*!G_OS_WIN32 */
1168 lookup_data
->channel
= g_io_channel_unix_new(lookup_data
->pipe_fds
[0]);
1170 lookup_data
->channel
= g_io_channel_win32_new_fd(lookup_data
->pipe_fds
[0]);
1172 lookup_data
->io_tag
= g_io_add_watch(lookup_data
->channel
, G_IO_IN
,
1173 sock_get_address_info_async_cb
,
1176 lookup_data
->child_pid
= _beginthread(
1177 address_info_async_child
, 0, lookup_data
);
1183 static gint
sock_get_address_info_async_cancel(SockLookupData
*lookup_data
)
1185 if (lookup_data
->io_tag
> 0)
1186 g_source_remove(lookup_data
->io_tag
);
1187 if (lookup_data
->channel
) {
1189 g_io_channel_shutdown(lookup_data
->channel
, TRUE
, &err
);
1193 g_io_channel_unref(lookup_data
->channel
);
1196 if (lookup_data
->child_pid
> 0) {
1198 /* FIXME: Need a way to cancel the thread. */
1200 kill(lookup_data
->child_pid
, SIGKILL
);
1201 waitpid(lookup_data
->child_pid
, NULL
, 0);
1205 g_free(lookup_data
->canonical_name
);
1206 g_free(lookup_data
->hostname
);
1207 g_free(lookup_data
);
1213 static SockInfo
*sockinfo_from_fd(const gchar
*hostname
,
1219 sockinfo
= g_new0(SockInfo
, 1);
1220 sockinfo
->sock
= sock
;
1222 sockinfo
->sock_ch
= g_io_channel_unix_new(sock
);
1224 sockinfo
->sock_ch
= g_io_channel_win32_new_socket(sock
);
1226 sockinfo
->hostname
= g_strdup(hostname
);
1227 sockinfo
->port
= port
;
1228 sockinfo
->state
= CONN_ESTABLISHED
;
1233 static gint
fd_read(gint fd
, gchar
*buf
, gint len
)
1235 if (fd_check_io(fd
, G_IO_IN
) < 0)
1239 if (fd_is_w32_socket(fd
))
1240 return recv(fd
, buf
, len
, 0);
1243 return read(fd
, buf
, len
);
1247 static gint
ssl_read(gnutls_session_t ssl
, gchar
*buf
, gint len
)
1251 if (gnutls_record_check_pending(ssl
) == 0) {
1252 if (fd_check_io(GPOINTER_TO_INT(gnutls_transport_get_ptr(ssl
)), G_IO_IN
) < 0)
1258 r
= gnutls_record_recv(ssl
, buf
, len
);
1263 case 0: /* closed connection */
1266 case GNUTLS_E_REHANDSHAKE
:
1268 r
= gnutls_handshake(ssl
);
1269 } while (r
== GNUTLS_E_AGAIN
|| r
== GNUTLS_E_INTERRUPTED
);
1270 break; /* re-receive */
1271 case GNUTLS_E_AGAIN
:
1272 case GNUTLS_E_INTERRUPTED
:
1275 case GNUTLS_E_PREMATURE_TERMINATION
:
1280 debug_print("Unexpected TLS read result %d\n", r
);
1289 gint
sock_read(SockInfo
*sock
, gchar
*buf
, gint len
)
1293 cm_return_val_if_fail(sock
!= NULL
, -1);
1297 ret
= ssl_read(sock
->ssl
, buf
, len
);
1300 ret
= fd_read(sock
->sock
, buf
, len
);
1303 sock
->state
= CONN_DISCONNECTED
;
1307 gint
fd_write(gint fd
, const gchar
*buf
, gint len
)
1309 if (fd_check_io(fd
, G_IO_OUT
) < 0)
1313 if (fd_is_w32_socket (fd
))
1314 return send(fd
, buf
, len
, 0);
1317 return write(fd
, buf
, len
);
1321 static gint
ssl_write(gnutls_session_t ssl
, const gchar
*buf
, gint len
)
1325 if (fd_check_io(GPOINTER_TO_INT(gnutls_transport_get_ptr(ssl
)), G_IO_OUT
) < 0)
1328 ret
= gnutls_record_send(ssl
, buf
, len
);
1333 case GNUTLS_E_AGAIN
:
1334 case GNUTLS_E_INTERRUPTED
:
1344 gint
sock_write(SockInfo
*sock
, const gchar
*buf
, gint len
)
1348 cm_return_val_if_fail(sock
!= NULL
, -1);
1352 ret
= ssl_write(sock
->ssl
, buf
, len
);
1355 ret
= fd_write(sock
->sock
, buf
, len
);
1358 sock
->state
= CONN_DISCONNECTED
;
1362 gint
fd_write_all(gint fd
, const gchar
*buf
, gint len
)
1367 if (fd_check_io(fd
, G_IO_OUT
) < 0)
1370 signal(SIGPIPE
, SIG_IGN
);
1374 if (fd_is_w32_socket(fd
))
1375 n
= send(fd
, buf
, len
, 0);
1378 n
= write(fd
, buf
, len
);
1381 log_error(LOG_PROTOCOL
, _("write on fd%d: %s\n"), fd
, g_strerror(errno
));
1393 static gint
ssl_write_all(gnutls_session_t ssl
, const gchar
*buf
, gint len
)
1398 n
= ssl_write(ssl
, buf
, len
);
1410 gint
sock_write_all(SockInfo
*sock
, const gchar
*buf
, gint len
)
1414 cm_return_val_if_fail(sock
!= NULL
, -1);
1418 ret
= ssl_write_all(sock
->ssl
, buf
, len
);
1421 ret
= fd_write_all(sock
->sock
, buf
, len
);
1424 sock
->state
= CONN_DISCONNECTED
;
1429 static gint
fd_recv(gint fd
, gchar
*buf
, gint len
, gint flags
)
1431 if (fd_check_io(fd
, G_IO_IN
) < 0)
1434 return recv(fd
, buf
, len
, flags
);
1438 gint
fd_gets(gint fd
, gchar
*buf
, gint len
)
1446 fd_check_io(fd
, G_IO_IN
);
1450 MSKB Article ID: Q147714
1451 Windows Sockets 2 Service Provider Interface Limitations
1452 Polling with recv(MSG_PEEK) to determine when a complete message
1454 Reason and Workaround not available.
1456 Single-byte send() and recv().
1457 Reason: Couple one-byte sends with Nagle disabled.
1458 Workaround: Send modest amounts and receive as much as possible.
1461 if (recv(fd
, bp
, 1, 0) <= 0)
1468 #else /*!G_OS_WIN32*/
1472 if ((n
= fd_recv(fd
, bp
, len
, MSG_PEEK
)) <= 0)
1474 if ((newline
= memchr(bp
, '\n', n
)) != NULL
)
1475 n
= newline
- bp
+ 1;
1476 if ((n
= fd_read(fd
, bp
, n
)) < 0)
1480 } while (!newline
&& len
);
1481 #endif /*!G_OS_WIN32*/
1487 gint
sock_close(SockInfo
*sock
, gboolean close_fd
)
1495 g_io_channel_unref(sock
->sock_ch
);
1499 ssl_done_socket(sock
);
1500 if (sock
->g_source
!= 0 && g_main_context_find_source_by_id(NULL
, sock
->g_source
) != NULL
)
1501 g_source_remove(sock
->g_source
);
1506 shutdown(sock
->sock
, 1); /* complete transfer before close */
1507 ret
= closesocket(sock
->sock
);
1509 ret
= fd_close(sock
->sock
);
1513 g_free(sock
->canonical_name
);
1514 g_free(sock
->hostname
);
1520 gint
fd_close(gint fd
)