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"
24 /* This can probably be handled better, e.g. define it in config.h. */
25 #define _WIN32_WINNT _WIN32_WINNT_WIN6
27 #include <glib/gi18n.h>
30 #include <sys/types.h>
32 # include <ws2tcpip.h>
34 # define EINPROGRESS WSAEINPROGRESS
38 # include <sys/wait.h>
40 # include <sys/socket.h>
41 # include <sys/stat.h>
43 # include <netinet/in.h>
44 # include <arpa/inet.h>
46 # ifndef _PATH_RESCONF
47 # define _PATH_RESCONF "/etc/resolv.conf"
50 #endif /* G_OS_WIN32 */
60 # include <sys/select.h>
71 #error USE_GIO is currently not supported
81 typedef gint (*SockAddrFunc
) (GList
*addr_list
,
84 typedef struct _SockConnectData SockConnectData
;
85 typedef struct _SockLookupData SockLookupData
;
86 typedef struct _SockAddrData SockAddrData
;
87 typedef struct _SockSource SockSource
;
89 struct _SockConnectData
{
95 SockLookupData
*lookup_data
;
100 gchar
*canonical_name
;
103 struct _SockLookupData
{
112 gchar
*canonical_name
;
115 struct _SockAddrData
{
120 struct sockaddr
*addr
;
128 static guint io_timeout
= 60;
130 static GList
*sock_connect_data_list
= NULL
;
133 static gboolean
ssl_sock_prepare (GSource
*source
,
135 static gboolean
ssl_sock_check (GSource
*source
);
136 static gboolean
ssl_sock_dispatch (GSource
*source
,
137 GSourceFunc callback
,
139 GSourceFuncs ssl_watch_funcs
= {
149 static gint
sock_connect_with_timeout (gint sock
,
150 const struct sockaddr
*serv_addr
,
154 static gint
sock_connect_by_getaddrinfo (const gchar
*hostname
,
157 static SockInfo
*sockinfo_from_fd(const gchar
*hostname
,
160 static void sock_address_list_free (GList
*addr_list
);
162 static gboolean
sock_connect_async_cb (GIOChannel
*source
,
163 GIOCondition condition
,
165 static gint sock_connect_async_get_address_info_cb
169 static gint
sock_connect_address_list_async (SockConnectData
*conn_data
);
171 static gboolean
sock_get_address_info_async_cb (GIOChannel
*source
,
172 GIOCondition condition
,
174 static SockLookupData
*sock_get_address_info_async
175 (const gchar
*hostname
,
179 static gint
sock_get_address_info_async_cancel (SockLookupData
*lookup_data
);
188 result
= WSAStartup(MAKEWORD(2, 2), &wsadata
);
189 if (result
!= NO_ERROR
) {
190 g_warning("WSAStartup() failed");
197 gint
sock_cleanup(void)
205 gint
sock_set_io_timeout(guint sec
)
211 void refresh_resolvers(void)
214 static time_t resolv_conf_changed
= (time_t)NULL
;
217 /* This makes the glibc re-read resolv.conf, if it changed
218 * since our startup. Maybe that should be #ifdef'ed, I don't
219 * know if it'd work on BSDs.
220 * Why doesn't the glibc do it by itself?
222 if (g_stat(_PATH_RESCONF
, &s
) == 0) {
223 if (s
.st_mtime
> resolv_conf_changed
) {
224 resolv_conf_changed
= s
.st_mtime
;
228 we'll have bigger problems. */
233 #define SOCKET_IS_VALID(s) ((s) != INVALID_SOCKET)
235 #define SOCKET_IS_VALID(s) (s != -1)
239 /* Due to the fact that socket under Windows are not represented by
240 standard file descriptors, we sometimes need to check whether a
241 given file descriptor is actually a socket. This is done by
242 testing for an error. Returns true under W32 if FD is a socket. */
243 static int fd_is_w32_socket(gint fd
)
246 gint retval
= sizeof(optval
);
248 return !getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, (char*)&optval
, &retval
);
252 gint
fd_connect_inet(gushort port
)
255 struct sockaddr_in addr
;
257 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
258 if (!SOCKET_IS_VALID(sock
)) {
260 debug_print("fd_connect_inet(): socket() failed: %d\n",
263 perror("fd_connect_inet(): socket");
268 memset(&addr
, 0, sizeof(addr
));
269 addr
.sin_family
= AF_INET
;
270 addr
.sin_port
= htons(port
);
271 addr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
273 if (connect(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
280 gint
fd_open_inet(gushort port
)
283 struct sockaddr_in addr
;
286 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
287 if (!SOCKET_IS_VALID(sock
)) {
289 g_warning("fd_open_inet(): socket() failed: %d",
292 perror("fd_open_inet(): socket");
298 if (setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&val
,
300 perror("setsockopt");
305 memset(&addr
, 0, sizeof(addr
));
306 addr
.sin_family
= AF_INET
;
307 addr
.sin_port
= htons(port
);
308 addr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
310 if (bind(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
316 if (listen(sock
, 1) < 0) {
325 gint
fd_connect_unix(const gchar
*path
)
329 struct sockaddr_un addr
;
331 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
333 perror("sock_connect_unix(): socket");
337 memset(&addr
, 0, sizeof(addr
));
338 addr
.sun_family
= AF_UNIX
;
339 strncpy(addr
.sun_path
, path
, sizeof(addr
.sun_path
) - 1);
341 if (connect(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
352 gint
fd_open_unix(const gchar
*path
)
356 struct sockaddr_un addr
;
358 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
361 perror("sock_open_unix(): socket");
365 memset(&addr
, 0, sizeof(addr
));
366 addr
.sun_family
= AF_UNIX
;
367 strncpy(addr
.sun_path
, path
, sizeof(addr
.sun_path
) - 1);
369 if (bind(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
370 gchar
*buf
= g_strdup_printf("can't bind to %s", path
);
377 if (listen(sock
, 1) < 0) {
378 gchar
*buf
= g_strdup_printf("can't listen on %s", path
);
391 gint
fd_accept(gint sock
)
393 struct sockaddr_in caddr
;
396 caddr_len
= sizeof(caddr
);
397 return accept(sock
, (struct sockaddr
*)&caddr
, &caddr_len
);
401 static gint
set_nonblocking_mode(gint fd
, gboolean nonblock
)
406 flags
= fcntl(fd
, F_GETFL
, 0);
415 flags
&= ~O_NONBLOCK
;
417 return fcntl(fd
, F_SETFL
, flags
);
423 gint
sock_set_nonblocking_mode(SockInfo
*sock
, gboolean nonblock
)
425 cm_return_val_if_fail(sock
!= NULL
, -1);
427 return set_nonblocking_mode(sock
->sock
, nonblock
);
430 static gboolean
is_nonblocking_mode(gint fd
)
435 flags
= fcntl(fd
, F_GETFL
, 0);
441 return ((flags
& O_NONBLOCK
) != 0);
447 gboolean
sock_is_nonblocking_mode(SockInfo
*sock
)
449 cm_return_val_if_fail(sock
!= NULL
, FALSE
);
451 return is_nonblocking_mode(sock
->sock
);
456 static gboolean
ssl_sock_prepare(GSource
*source
, gint
*timeout
)
462 static gboolean
ssl_sock_check(GSource
*source
)
464 SockInfo
*sock
= ((SockSource
*)source
)->sock
;
465 struct timeval timeout
= {0, 0};
467 GIOCondition condition
= 0;
469 if (!sock
|| !sock
->sock
)
472 condition
= sock
->condition
;
474 if ((condition
& G_IO_IN
) == G_IO_IN
&&
475 gnutls_record_check_pending(sock
->ssl
) != 0)
479 FD_SET(sock
->sock
, &fds
);
481 select(sock
->sock
+ 1,
482 (condition
& G_IO_IN
) ? &fds
: NULL
,
483 (condition
& G_IO_OUT
) ? &fds
: NULL
,
486 return FD_ISSET(sock
->sock
, &fds
) != 0;
489 static gboolean
ssl_sock_dispatch(GSource
*source
, GSourceFunc callback
,
492 SockInfo
*sock
= ((SockSource
*)source
)->sock
;
494 if (!sock
|| !sock
->callback
|| !sock
->data
)
497 return sock
->callback(sock
, sock
->condition
, sock
->data
);
501 static gboolean
sock_watch_cb(GIOChannel
*source
, GIOCondition condition
,
504 SockInfo
*sock
= (SockInfo
*)data
;
506 if ((condition
& sock
->condition
) == 0)
509 return sock
->callback(sock
, sock
->condition
, sock
->data
);
512 guint
sock_add_watch(SockInfo
*sock
, GIOCondition condition
, SockFunc func
,
518 sock
->callback
= func
;
519 sock
->condition
= condition
;
525 GSource
*source
= g_source_new(&ssl_watch_funcs
,
527 ((SockSource
*) source
)->sock
= sock
;
528 g_source_set_priority(source
, G_PRIORITY_DEFAULT
);
529 g_source_set_can_recurse(source
, FALSE
);
530 sock
->g_source
= g_source_attach(source
, NULL
);
531 g_source_unref (source
); /* Refcount back down to 1 */
532 return sock
->g_source
;
536 return g_io_add_watch(sock
->sock_ch
, condition
, sock_watch_cb
, sock
);
539 static gint
fd_check_io(gint fd
, GIOCondition cond
)
541 struct timeval timeout
;
544 if (is_nonblocking_mode(fd
))
547 timeout
.tv_sec
= io_timeout
;
553 if (cond
== G_IO_IN
) {
554 select(fd
+ 1, &fds
, NULL
, NULL
,
555 io_timeout
> 0 ? &timeout
: NULL
);
557 select(fd
+ 1, NULL
, &fds
, NULL
,
558 io_timeout
> 0 ? &timeout
: NULL
);
561 if (FD_ISSET(fd
, &fds
)) {
564 g_warning("socket IO timeout");
565 log_error(LOG_PROTOCOL
, _("Socket IO timeout.\n"));
571 static sigjmp_buf jmpenv
;
573 static void timeout_handler(gint sig
)
575 siglongjmp(jmpenv
, 1);
579 static gint
sock_connect_with_timeout(gint sock
,
580 const struct sockaddr
*serv_addr
,
584 gint ret
, saved_errno
;
586 void (*prev_handler
)(gint
);
589 prev_handler
= signal(SIGALRM
, timeout_handler
);
590 if (sigsetjmp(jmpenv
, 1)) {
592 signal(SIGALRM
, prev_handler
);
594 log_error(LOG_PROTOCOL
, _("Connection timed out.\n"));
600 ret
= connect(sock
, serv_addr
, addrlen
);
604 debug_print("connect() failed: %d (%s)\n",
605 saved_errno
, g_strerror(saved_errno
));
610 signal(SIGALRM
, prev_handler
);
616 static gint
sock_connect_by_getaddrinfo(const gchar
*hostname
, gushort port
)
618 gint sock
= -1, gai_error
;
619 struct addrinfo hints
, *res
, *ai
;
624 memset(&hints
, 0, sizeof(hints
));
625 hints
.ai_flags
= AI_ADDRCONFIG
;
628 hints
.ai_family
= AF_UNSPEC
;
630 hints
.ai_family
= AF_INET
;
633 hints
.ai_socktype
= SOCK_STREAM
;
634 hints
.ai_protocol
= IPPROTO_TCP
;
636 /* convert port from integer to string. */
637 g_snprintf(port_str
, sizeof(port_str
), "%d", port
);
639 if ((gai_error
= getaddrinfo(hostname
, port_str
, &hints
, &res
)) != 0) {
640 g_printerr("getaddrinfo for %s:%s failed: %s\n",
641 hostname
, port_str
, gai_strerror(gai_error
));
645 for (ai
= res
; ai
!= NULL
; ai
= ai
->ai_next
) {
647 if (ai
->ai_family
== AF_INET6
)
651 sock
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
655 if (sock
== INVALID_SOCKET
)
659 if (sock_connect_with_timeout
660 (sock
, ai
->ai_addr
, ai
->ai_addrlen
, io_timeout
) == 0)
675 SockInfo
*sock_connect(const gchar
*hostname
, gushort port
)
683 if ((sock
= sock_connect_by_getaddrinfo(hostname
, port
)) < 0) {
687 return sockinfo_from_fd(hostname
, port
, sock
);
691 static void sock_address_list_free(GList
*addr_list
)
695 for (cur
= addr_list
; cur
!= NULL
; cur
= cur
->next
) {
696 SockAddrData
*addr_data
= (SockAddrData
*)cur
->data
;
697 g_free(addr_data
->addr
);
701 g_list_free(addr_list
);
704 /* asynchronous TCP connection */
706 static gboolean
sock_connect_async_cb(GIOChannel
*source
,
707 GIOCondition condition
, gpointer data
)
709 SockConnectData
*conn_data
= (SockConnectData
*)data
;
715 if (conn_data
->io_tag
== 0 && conn_data
->channel
== NULL
)
718 fd
= g_io_channel_unix_get_fd(source
);
720 conn_data
->io_tag
= 0;
721 conn_data
->channel
= NULL
;
722 g_io_channel_unref(source
);
725 if (getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, (void*)&val
, &len
) < 0) {
726 perror("getsockopt");
728 sock_connect_address_list_async(conn_data
);
734 log_error(LOG_PROTOCOL
, _("%s:%d: connection failed (%s).\n"),
735 conn_data
->hostname
, conn_data
->port
,
737 sock_connect_address_list_async(conn_data
);
741 sockinfo
= g_new0(SockInfo
, 1);
744 sockinfo
->sock_ch
= g_io_channel_unix_new(fd
);
746 sockinfo
->sock_ch
= g_io_channel_win32_new_socket(fd
);
748 sockinfo
->hostname
= g_strdup(conn_data
->hostname
);
749 sockinfo
->port
= conn_data
->port
;
750 sockinfo
->state
= CONN_ESTABLISHED
;
751 sockinfo
->canonical_name
= g_strdup(conn_data
->canonical_name
);
753 conn_data
->func(sockinfo
, conn_data
->data
);
755 sock_connect_async_cancel(conn_data
->id
);
760 static gint
sock_connect_async_get_address_info_cb(GList
*addr_list
,
763 SockConnectData
*conn_data
= (SockConnectData
*)data
;
765 conn_data
->addr_list
= addr_list
;
766 conn_data
->cur_addr
= addr_list
;
767 if (conn_data
->lookup_data
) {
768 conn_data
->canonical_name
= conn_data
->lookup_data
->canonical_name
;
769 conn_data
->lookup_data
->canonical_name
= NULL
;
770 conn_data
->lookup_data
= NULL
;
772 return sock_connect_address_list_async(conn_data
);
775 gint
sock_connect_async(const gchar
*hostname
, gushort port
,
776 SockConnectFunc func
, gpointer data
)
779 SockConnectData
*conn_data
;
781 conn_data
= g_new0(SockConnectData
, 1);
782 conn_data
->id
= id
++;
783 conn_data
->hostname
= g_strdup(hostname
);
784 conn_data
->port
= port
;
785 conn_data
->addr_list
= NULL
;
786 conn_data
->cur_addr
= NULL
;
787 conn_data
->io_tag
= 0;
788 conn_data
->func
= func
;
789 conn_data
->data
= data
;
791 conn_data
->lookup_data
= sock_get_address_info_async
792 (hostname
, port
, sock_connect_async_get_address_info_cb
,
795 if (conn_data
->lookup_data
== NULL
) {
796 g_free(conn_data
->hostname
);
801 sock_connect_data_list
= g_list_append(sock_connect_data_list
,
804 return conn_data
->id
;
807 gint
sock_connect_async_cancel(gint id
)
809 SockConnectData
*conn_data
= NULL
;
812 for (cur
= sock_connect_data_list
; cur
!= NULL
; cur
= cur
->next
) {
813 if (((SockConnectData
*)cur
->data
)->id
== id
) {
814 conn_data
= (SockConnectData
*)cur
->data
;
820 sock_connect_data_list
= g_list_remove(sock_connect_data_list
,
823 if (conn_data
->lookup_data
)
824 sock_get_address_info_async_cancel
825 (conn_data
->lookup_data
);
827 if (conn_data
->io_tag
> 0)
828 g_source_remove(conn_data
->io_tag
);
829 if (conn_data
->channel
) {
831 g_io_channel_shutdown(conn_data
->channel
, TRUE
, &err
);
834 g_io_channel_unref(conn_data
->channel
);
837 sock_address_list_free(conn_data
->addr_list
);
838 g_free(conn_data
->canonical_name
);
839 g_free(conn_data
->hostname
);
842 g_warning("sock_connect_async_cancel: id %d not found", id
);
849 static gint
sock_connect_address_list_async(SockConnectData
*conn_data
)
851 SockAddrData
*addr_data
;
854 for (; conn_data
->cur_addr
!= NULL
;
855 conn_data
->cur_addr
= conn_data
->cur_addr
->next
) {
856 addr_data
= (SockAddrData
*)conn_data
->cur_addr
->data
;
858 if ((sock
= socket(addr_data
->family
, addr_data
->socktype
,
859 addr_data
->protocol
)) < 0) {
865 set_nonblocking_mode(sock
, TRUE
);
867 if (connect(sock
, addr_data
->addr
, addr_data
->addr_len
) < 0) {
868 if (EINPROGRESS
== errno
) {
879 if (conn_data
->cur_addr
== NULL
) {
880 conn_data
->func(NULL
, conn_data
->data
);
881 sock_connect_async_cancel(conn_data
->id
);
885 conn_data
->cur_addr
= conn_data
->cur_addr
->next
;
888 conn_data
->channel
= g_io_channel_unix_new(sock
);
890 conn_data
->channel
= g_io_channel_win32_new_socket(sock
);
892 conn_data
->io_tag
= g_io_add_watch(conn_data
->channel
, G_IO_IN
|G_IO_OUT
,
893 sock_connect_async_cb
, conn_data
);
898 /* asynchronous DNS lookup */
900 static gboolean
sock_get_address_info_async_cb(GIOChannel
*source
,
901 GIOCondition condition
,
904 SockLookupData
*lookup_data
= (SockLookupData
*)data
;
905 GList
*addr_list
= NULL
;
906 SockAddrData
*addr_data
;
909 struct sockaddr
*addr
;
910 gchar
*canonical_name
= NULL
;
914 g_io_channel_set_encoding(source
, NULL
, &err
);
916 g_warning("can't unset encoding: %s", err
->message
);
920 g_io_channel_set_buffered(source
, FALSE
);
921 if (g_io_channel_read_chars(source
, &len
, sizeof(len
),
922 &bytes_read
, &err
) == G_IO_STATUS_NORMAL
) {
924 g_warning("g_io_channel_read_chars: %s", err
->message
);
928 if (bytes_read
== sizeof(len
) && len
> 0) {
931 canonical_name
= g_malloc0(len
+ 1);
932 cur
= canonical_name
;
934 if (g_io_channel_read_chars(source
, cur
, todo
,
935 &bytes_read
, &err
) != G_IO_STATUS_NORMAL
) {
937 g_warning("canonical name not read %s", err
->message
);
938 g_free(canonical_name
);
939 canonical_name
= NULL
;
948 if (bytes_read
== 0) {
949 g_warning("canonical name not read");
950 g_free(canonical_name
);
951 canonical_name
= NULL
;
958 if (g_io_channel_read_chars(source
, (gchar
*)ai_member
,
959 sizeof(ai_member
), &bytes_read
, &err
)
960 != G_IO_STATUS_NORMAL
) {
962 g_warning("g_io_channel_read_chars: addr len %s", err
->message
);
969 if (bytes_read
== 0 || bytes_read
!= sizeof(ai_member
))
972 if (ai_member
[0] == AF_UNSPEC
) {
973 g_warning("DNS lookup failed");
974 log_error(LOG_PROTOCOL
, _("%s:%d: unknown host.\n"),
975 lookup_data
->hostname
, lookup_data
->port
);
979 addr
= g_malloc(ai_member
[3]);
980 if (g_io_channel_read_chars(source
, (gchar
*)addr
, ai_member
[3],
982 != G_IO_STATUS_NORMAL
) {
984 g_warning("g_io_channel_read_chars: addr data read %s", err
->message
);
992 if (bytes_read
!= ai_member
[3]) {
993 g_warning("sock_get_address_info_async_cb: "
994 "incomplete address data");
999 addr_data
= g_new0(SockAddrData
, 1);
1000 addr_data
->family
= ai_member
[0];
1001 addr_data
->socktype
= ai_member
[1];
1002 addr_data
->protocol
= ai_member
[2];
1003 addr_data
->addr_len
= ai_member
[3];
1004 addr_data
->addr
= addr
;
1006 addr_list
= g_list_append(addr_list
, addr_data
);
1009 g_io_channel_shutdown(source
, TRUE
, &err
);
1012 g_io_channel_unref(source
);
1015 /* FIXME: We would need to cancel the thread. */
1017 kill(lookup_data
->child_pid
, SIGKILL
);
1018 waitpid(lookup_data
->child_pid
, NULL
, 0);
1020 lookup_data
->canonical_name
= canonical_name
;
1022 lookup_data
->func(addr_list
, lookup_data
->data
);
1024 g_free(lookup_data
->canonical_name
);
1025 g_free(lookup_data
->hostname
);
1026 g_free(lookup_data
);
1032 /* For better readability we use a separate function to implement the
1033 child code of sock_get_address_info_async. Note, that under W32
1034 this is actually not a child but a thread and this is the reason
1035 why we pass only a void pointer. */
1036 static void address_info_async_child(void *opaque
)
1038 SockLookupData
*parm
= opaque
;
1040 struct addrinfo hints
, *res
, *ai
;
1042 gint ai_member
[4] = {AF_UNSPEC
, 0, 0, 0};
1045 close(parm
->pipe_fds
[0]);
1046 parm
->pipe_fds
[0] = -1;
1049 memset(&hints
, 0, sizeof(hints
));
1050 hints
.ai_flags
= AI_CANONNAME
| AI_ADDRCONFIG
;
1052 hints
.ai_family
= AF_UNSPEC
;
1054 hints
.ai_family
= AF_INET
;
1056 hints
.ai_socktype
= SOCK_STREAM
;
1057 hints
.ai_protocol
= IPPROTO_TCP
;
1059 g_snprintf(port_str
, sizeof(port_str
), "%d", parm
->port
);
1061 gai_err
= getaddrinfo(parm
->hostname
, port_str
, &hints
, &res
);
1064 g_warning("getaddrinfo for %s:%s failed: %s",
1065 parm
->hostname
, port_str
, gai_strerror(gai_err
));
1066 log_error(LOG_PROTOCOL
, _("%s:%s: host lookup failed (%s).\n"),
1067 parm
->hostname
, port_str
, gai_strerror(gai_err
));
1068 fd_write_all(parm
->pipe_fds
[1], &len
,
1070 fd_write_all(parm
->pipe_fds
[1], (gchar
*)ai_member
,
1072 close(parm
->pipe_fds
[1]);
1073 parm
->pipe_fds
[1] = -1;
1082 if (res
->ai_canonname
&& strlen(res
->ai_canonname
) < 255) {
1083 gchar len
= strlen(res
->ai_canonname
);
1084 fd_write_all(parm
->pipe_fds
[1], &len
,
1086 fd_write_all(parm
->pipe_fds
[1], res
->ai_canonname
,
1090 fd_write_all(parm
->pipe_fds
[1], &len
,
1095 fd_write_all(parm
->pipe_fds
[1], &len
,
1099 for (ai
= res
; ai
!= NULL
; ai
= ai
->ai_next
) {
1100 ai_member
[0] = ai
->ai_family
;
1101 ai_member
[1] = ai
->ai_socktype
;
1102 ai_member
[2] = ai
->ai_protocol
;
1103 ai_member
[3] = ai
->ai_addrlen
;
1105 fd_write_all(parm
->pipe_fds
[1], (gchar
*)ai_member
,
1107 fd_write_all(parm
->pipe_fds
[1], (gchar
*)ai
->ai_addr
,
1114 close(parm
->pipe_fds
[1]);
1115 parm
->pipe_fds
[1] = -1;
1124 static SockLookupData
*sock_get_address_info_async(const gchar
*hostname
,
1129 SockLookupData
*lookup_data
= NULL
;
1131 refresh_resolvers();
1133 lookup_data
= g_new0(SockLookupData
, 1);
1134 lookup_data
->hostname
= g_strdup(hostname
);
1135 lookup_data
->func
= func
;
1136 lookup_data
->data
= data
;
1137 lookup_data
->port
= port
;
1138 lookup_data
->child_pid
= (pid_t
)(-1);
1139 lookup_data
->pipe_fds
[0] = -1;
1140 lookup_data
->pipe_fds
[1] = -1;
1142 if (pipe(lookup_data
->pipe_fds
) < 0) {
1145 g_free (lookup_data
->hostname
);
1146 g_free (lookup_data
);
1151 if ((lookup_data
->child_pid
= fork()) < 0) {
1154 g_free (lookup_data
->hostname
);
1155 g_free (lookup_data
);
1159 if (lookup_data
->child_pid
== 0) {
1160 /* Child process. */
1161 address_info_async_child (lookup_data
);
1162 g_assert_not_reached ();
1164 /* Parent process. */
1165 close(lookup_data
->pipe_fds
[1]);
1166 lookup_data
->pipe_fds
[1] = -1;
1167 #endif /*!G_OS_WIN32 */
1170 lookup_data
->channel
= g_io_channel_unix_new(lookup_data
->pipe_fds
[0]);
1172 lookup_data
->channel
= g_io_channel_win32_new_fd(lookup_data
->pipe_fds
[0]);
1174 lookup_data
->io_tag
= g_io_add_watch(lookup_data
->channel
, G_IO_IN
,
1175 sock_get_address_info_async_cb
,
1178 lookup_data
->child_pid
= _beginthread(
1179 address_info_async_child
, 0, lookup_data
);
1185 static gint
sock_get_address_info_async_cancel(SockLookupData
*lookup_data
)
1187 if (lookup_data
->io_tag
> 0)
1188 g_source_remove(lookup_data
->io_tag
);
1189 if (lookup_data
->channel
) {
1191 g_io_channel_shutdown(lookup_data
->channel
, TRUE
, &err
);
1195 g_io_channel_unref(lookup_data
->channel
);
1198 if (lookup_data
->child_pid
> 0) {
1200 /* FIXME: Need a way to cancel the thread. */
1202 kill(lookup_data
->child_pid
, SIGKILL
);
1203 waitpid(lookup_data
->child_pid
, NULL
, 0);
1207 g_free(lookup_data
->canonical_name
);
1208 g_free(lookup_data
->hostname
);
1209 g_free(lookup_data
);
1215 static SockInfo
*sockinfo_from_fd(const gchar
*hostname
,
1221 sockinfo
= g_new0(SockInfo
, 1);
1222 sockinfo
->sock
= sock
;
1224 sockinfo
->sock_ch
= g_io_channel_unix_new(sock
);
1226 sockinfo
->sock_ch
= g_io_channel_win32_new_socket(sock
);
1228 sockinfo
->hostname
= g_strdup(hostname
);
1229 sockinfo
->port
= port
;
1230 sockinfo
->state
= CONN_ESTABLISHED
;
1235 static gint
fd_read(gint fd
, gchar
*buf
, gint len
)
1237 if (fd_check_io(fd
, G_IO_IN
) < 0)
1241 if (fd_is_w32_socket(fd
))
1242 return recv(fd
, buf
, len
, 0);
1245 return read(fd
, buf
, len
);
1249 static gint
ssl_read(gnutls_session_t ssl
, gchar
*buf
, gint len
)
1253 if (gnutls_record_check_pending(ssl
) == 0) {
1254 if (fd_check_io(GPOINTER_TO_INT(gnutls_transport_get_ptr(ssl
)), G_IO_IN
) < 0)
1259 r
= gnutls_record_recv(ssl
, buf
, len
);
1264 case 0: /* closed connection */
1267 case GNUTLS_E_REHANDSHAKE
:
1269 r
= gnutls_handshake(ssl
);
1270 } while (r
== GNUTLS_E_AGAIN
|| r
== GNUTLS_E_INTERRUPTED
);
1271 break; /* re-receive */
1272 case GNUTLS_E_AGAIN
:
1273 case GNUTLS_E_INTERRUPTED
:
1278 debug_print("Unexpected TLS read result %d\n", r
);
1287 gint
sock_read(SockInfo
*sock
, gchar
*buf
, gint len
)
1291 cm_return_val_if_fail(sock
!= NULL
, -1);
1295 ret
= ssl_read(sock
->ssl
, buf
, len
);
1298 ret
= fd_read(sock
->sock
, buf
, len
);
1301 sock
->state
= CONN_DISCONNECTED
;
1305 gint
fd_write(gint fd
, const gchar
*buf
, gint len
)
1307 if (fd_check_io(fd
, G_IO_OUT
) < 0)
1311 if (fd_is_w32_socket (fd
))
1312 return send(fd
, buf
, len
, 0);
1315 return write(fd
, buf
, len
);
1319 static gint
ssl_write(gnutls_session_t ssl
, const gchar
*buf
, gint len
)
1323 if (fd_check_io(GPOINTER_TO_INT(gnutls_transport_get_ptr(ssl
)), G_IO_OUT
) < 0)
1326 ret
= gnutls_record_send(ssl
, buf
, len
);
1331 case GNUTLS_E_AGAIN
:
1332 case GNUTLS_E_INTERRUPTED
:
1342 gint
sock_write(SockInfo
*sock
, const gchar
*buf
, gint len
)
1346 cm_return_val_if_fail(sock
!= NULL
, -1);
1350 ret
= ssl_write(sock
->ssl
, buf
, len
);
1353 ret
= fd_write(sock
->sock
, buf
, len
);
1356 sock
->state
= CONN_DISCONNECTED
;
1360 gint
fd_write_all(gint fd
, const gchar
*buf
, gint len
)
1365 if (fd_check_io(fd
, G_IO_OUT
) < 0)
1368 signal(SIGPIPE
, SIG_IGN
);
1372 if (fd_is_w32_socket(fd
))
1373 n
= send(fd
, buf
, len
, 0);
1376 n
= write(fd
, buf
, len
);
1379 log_error(LOG_PROTOCOL
, _("write on fd%d: %s\n"), fd
, g_strerror(errno
));
1391 static gint
ssl_write_all(gnutls_session_t ssl
, const gchar
*buf
, gint len
)
1396 n
= ssl_write(ssl
, buf
, len
);
1408 gint
sock_write_all(SockInfo
*sock
, const gchar
*buf
, gint len
)
1412 cm_return_val_if_fail(sock
!= NULL
, -1);
1416 ret
= ssl_write_all(sock
->ssl
, buf
, len
);
1419 ret
= fd_write_all(sock
->sock
, buf
, len
);
1422 sock
->state
= CONN_DISCONNECTED
;
1427 static gint
fd_recv(gint fd
, gchar
*buf
, gint len
, gint flags
)
1429 if (fd_check_io(fd
, G_IO_IN
) < 0)
1432 return recv(fd
, buf
, len
, flags
);
1436 gint
fd_gets(gint fd
, gchar
*buf
, gint len
)
1444 fd_check_io(fd
, G_IO_IN
);
1448 MSKB Article ID: Q147714
1449 Windows Sockets 2 Service Provider Interface Limitations
1450 Polling with recv(MSG_PEEK) to determine when a complete message
1452 Reason and Workaround not available.
1454 Single-byte send() and recv().
1455 Reason: Couple one-byte sends with Nagle disabled.
1456 Workaround: Send modest amounts and receive as much as possible.
1459 if (recv(fd
, bp
, 1, 0) <= 0)
1466 #else /*!G_OS_WIN32*/
1470 if ((n
= fd_recv(fd
, bp
, len
, MSG_PEEK
)) <= 0)
1472 if ((newline
= memchr(bp
, '\n', n
)) != NULL
)
1473 n
= newline
- bp
+ 1;
1474 if ((n
= fd_read(fd
, bp
, n
)) < 0)
1478 } while (!newline
&& len
);
1479 #endif /*!G_OS_WIN32*/
1485 gint
sock_close(SockInfo
*sock
, gboolean close_fd
)
1493 g_io_channel_unref(sock
->sock_ch
);
1497 ssl_done_socket(sock
);
1498 if (sock
->g_source
!= 0 && g_main_context_find_source_by_id(NULL
, sock
->g_source
) != NULL
)
1499 g_source_remove(sock
->g_source
);
1504 shutdown(sock
->sock
, 1); /* complete transfer before close */
1505 ret
= closesocket(sock
->sock
);
1507 ret
= fd_close(sock
->sock
);
1511 g_free(sock
->canonical_name
);
1512 g_free(sock
->hostname
);
1518 gint
fd_close(gint fd
)