2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
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/>.
24 #if (defined (_XOPEN_SOURCE) && !defined (_BSD_SOURCE))
29 #include <glib/gi18n.h>
32 #include <sys/types.h>
34 # include <winsock2.h>
36 # define EINPROGRESS WSAEINPROGRESS
40 # include <sys/wait.h>
42 # include <sys/socket.h>
43 # include <sys/stat.h>
45 # include <netinet/in.h>
46 # include <arpa/inet.h>
49 #endif /* G_OS_WIN32 */
59 # include <sys/select.h>
70 #error USE_GIO is currently not supported
80 typedef gint (*SockAddrFunc
) (GList
*addr_list
,
83 typedef struct _SockConnectData SockConnectData
;
84 typedef struct _SockLookupData SockLookupData
;
85 typedef struct _SockAddrData SockAddrData
;
86 typedef struct _SockSource SockSource
;
88 struct _SockConnectData
{
94 SockLookupData
*lookup_data
;
99 gchar
*canonical_name
;
102 struct _SockLookupData
{
111 gchar
*canonical_name
;
114 struct _SockAddrData
{
119 struct sockaddr
*addr
;
127 static guint io_timeout
= 60;
129 static GList
*sock_connect_data_list
= NULL
;
131 static gboolean
sock_prepare (GSource
*source
,
133 static gboolean
sock_check (GSource
*source
);
134 static gboolean
sock_dispatch (GSource
*source
,
135 GSourceFunc callback
,
138 GSourceFuncs sock_watch_funcs
= {
145 static gint
sock_connect_with_timeout (gint sock
,
146 const struct sockaddr
*serv_addr
,
151 static gint
sock_connect_by_hostname (gint sock
,
152 const gchar
*hostname
,
155 static gint
sock_connect_by_getaddrinfo (const gchar
*hostname
,
159 static SockInfo
*sockinfo_from_fd(const gchar
*hostname
,
162 static void sock_address_list_free (GList
*addr_list
);
164 static gboolean
sock_connect_async_cb (GIOChannel
*source
,
165 GIOCondition condition
,
167 static gint sock_connect_async_get_address_info_cb
171 static gint
sock_connect_address_list_async (SockConnectData
*conn_data
);
173 static gboolean
sock_get_address_info_async_cb (GIOChannel
*source
,
174 GIOCondition condition
,
176 static SockLookupData
*sock_get_address_info_async
177 (const gchar
*hostname
,
181 static gint
sock_get_address_info_async_cancel (SockLookupData
*lookup_data
);
190 result
= WSAStartup(MAKEWORD(2, 2), &wsadata
);
191 if (result
!= NO_ERROR
) {
192 g_warning("WSAStartup() failed\n");
199 gint
sock_cleanup(void)
207 gint
sock_set_io_timeout(guint sec
)
213 void refresh_resolvers(void)
216 static time_t resolv_conf_changed
= (time_t)NULL
;
219 /* This makes the glibc re-read resolv.conf, if it changed
220 * since our startup. Maybe that should be #ifdef'ed, I don't
221 * know if it'd work on BSDs.
222 * Why doesn't the glibc do it by itself?
224 if (stat("/etc/resolv.conf", &s
) == 0) {
225 if (s
.st_mtime
> resolv_conf_changed
) {
226 resolv_conf_changed
= s
.st_mtime
;
230 we'll have bigger problems. */
235 /* Due to the fact that socket under Windows are not represented by
236 standard file descriptors, we sometimes need to check whether a
237 given file descriptor is actually a socket. This is done by
238 testing for an error. Returns true under W32 if FD is a socket. */
239 static int fd_is_w32_socket(gint fd
)
243 gint retval
= sizeof(optval
);
245 return !getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, (char*)&optval
, &retval
);
252 gint
fd_connect_unix(const gchar
*path
)
256 struct sockaddr_un addr
;
258 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
260 perror("sock_connect_unix(): socket");
264 memset(&addr
, 0, sizeof(addr
));
265 addr
.sun_family
= AF_UNIX
;
266 strncpy(addr
.sun_path
, path
, sizeof(addr
.sun_path
) - 1);
268 if (connect(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
279 gint
fd_open_unix(const gchar
*path
)
283 struct sockaddr_un addr
;
285 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
288 perror("sock_open_unix(): socket");
292 memset(&addr
, 0, sizeof(addr
));
293 addr
.sun_family
= AF_UNIX
;
294 strncpy(addr
.sun_path
, path
, sizeof(addr
.sun_path
) - 1);
296 if (bind(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
297 gchar
*buf
= g_strdup_printf("can't bind to %s", path
);
304 if (listen(sock
, 1) < 0) {
305 gchar
*buf
= g_strdup_printf("can't listen on %s", path
);
318 gint
fd_accept(gint sock
)
320 struct sockaddr_in caddr
;
323 caddr_len
= sizeof(caddr
);
324 return accept(sock
, (struct sockaddr
*)&caddr
, &caddr_len
);
328 static gint
set_nonblocking_mode(gint fd
, gboolean nonblock
)
333 flags
= fcntl(fd
, F_GETFL
, 0);
342 flags
&= ~O_NONBLOCK
;
344 return fcntl(fd
, F_SETFL
, flags
);
350 gint
sock_set_nonblocking_mode(SockInfo
*sock
, gboolean nonblock
)
352 g_return_val_if_fail(sock
!= NULL
, -1);
354 return set_nonblocking_mode(sock
->sock
, nonblock
);
357 static gboolean
is_nonblocking_mode(gint fd
)
362 flags
= fcntl(fd
, F_GETFL
, 0);
368 return ((flags
& O_NONBLOCK
) != 0);
374 gboolean
sock_is_nonblocking_mode(SockInfo
*sock
)
376 g_return_val_if_fail(sock
!= NULL
, FALSE
);
378 return is_nonblocking_mode(sock
->sock
);
382 static gboolean
sock_prepare(GSource
*source
, gint
*timeout
)
388 static gboolean
sock_check(GSource
*source
)
390 SockInfo
*sock
= ((SockSource
*)source
)->sock
;
391 struct timeval timeout
= {0, 0};
393 GIOCondition condition
= sock
->condition
;
395 if (!sock
|| !sock
->sock
)
400 if (condition
& G_IO_IN
) {
401 if (SSL_pending(sock
->ssl
) > 0)
403 if (SSL_want_write(sock
->ssl
))
404 condition
|= G_IO_OUT
;
407 if (condition
& G_IO_OUT
) {
408 if (SSL_want_read(sock
->ssl
))
409 condition
|= G_IO_IN
;
415 FD_SET(sock
->sock
, &fds
);
417 select(sock
->sock
+ 1,
418 (condition
& G_IO_IN
) ? &fds
: NULL
,
419 (condition
& G_IO_OUT
) ? &fds
: NULL
,
422 return FD_ISSET(sock
->sock
, &fds
) != 0;
425 static gboolean
sock_dispatch(GSource
*source
, GSourceFunc callback
,
428 SockInfo
*sock
= ((SockSource
*)source
)->sock
;
430 if (!sock
|| !sock
->callback
|| !sock
->data
)
433 return sock
->callback(sock
, sock
->condition
, sock
->data
);
436 static gboolean
sock_watch_cb(GIOChannel
*source
, GIOCondition condition
,
439 SockInfo
*sock
= (SockInfo
*)data
;
441 if ((condition
& sock
->condition
) == 0)
444 return sock
->callback(sock
, sock
->condition
, sock
->data
);
447 guint
sock_add_watch(SockInfo
*sock
, GIOCondition condition
, SockFunc func
,
453 sock
->callback
= func
;
454 sock
->condition
= condition
;
460 GSource
*source
= g_source_new(&sock_watch_funcs
,
462 ((SockSource
*) source
)->sock
= sock
;
463 g_source_set_priority(source
, G_PRIORITY_DEFAULT
);
464 g_source_set_can_recurse(source
, FALSE
);
465 sock
->g_source
= g_source_attach(source
, NULL
);
466 g_source_unref (source
); /* Refcount back down to 1 */
467 return sock
->g_source
;
471 return g_io_add_watch(sock
->sock_ch
, condition
, sock_watch_cb
, sock
);
474 static gint
fd_check_io(gint fd
, GIOCondition cond
)
476 struct timeval timeout
;
479 if (is_nonblocking_mode(fd
))
482 timeout
.tv_sec
= io_timeout
;
488 if (cond
== G_IO_IN
) {
489 select(fd
+ 1, &fds
, NULL
, NULL
,
490 io_timeout
> 0 ? &timeout
: NULL
);
492 select(fd
+ 1, NULL
, &fds
, NULL
,
493 io_timeout
> 0 ? &timeout
: NULL
);
496 if (FD_ISSET(fd
, &fds
)) {
499 g_warning("Socket IO timeout\n");
505 static sigjmp_buf jmpenv
;
507 static void timeout_handler(gint sig
)
509 siglongjmp(jmpenv
, 1);
513 static gint
sock_connect_with_timeout(gint sock
,
514 const struct sockaddr
*serv_addr
,
520 void (*prev_handler
)(gint
);
523 prev_handler
= signal(SIGALRM
, timeout_handler
);
524 if (sigsetjmp(jmpenv
, 1)) {
526 signal(SIGALRM
, prev_handler
);
533 ret
= connect(sock
, serv_addr
, addrlen
);
537 signal(SIGALRM
, prev_handler
);
543 struct hostent
*my_gethostbyname(const gchar
*hostname
)
547 void (*prev_handler
)(gint
);
550 prev_handler
= signal(SIGALRM
, timeout_handler
);
551 if (sigsetjmp(jmpenv
, 1)) {
553 signal(SIGALRM
, prev_handler
);
554 g_printerr("%s: host lookup timed out.\n", hostname
);
561 if ((hp
= gethostbyname(hostname
)) == NULL
) {
564 signal(SIGALRM
, prev_handler
);
566 g_printerr("%s: unknown host.\n", hostname
);
573 signal(SIGALRM
, prev_handler
);
580 static gint
my_inet_aton(const gchar
*hostname
, struct in_addr
*inp
)
583 return inet_aton(hostname
, inp
);
588 inaddr
= inet_addr(hostname
);
590 memcpy(inp
, &inaddr
, sizeof(inaddr
));
597 #endif /* HAVE_INET_ATON */
600 static gint
sock_connect_by_hostname(gint sock
, const gchar
*hostname
,
604 struct sockaddr_in ad
;
606 memset(&ad
, 0, sizeof(ad
));
607 ad
.sin_family
= AF_INET
;
608 ad
.sin_port
= htons(port
);
612 if (!my_inet_aton(hostname
, &ad
.sin_addr
)) {
613 if ((hp
= my_gethostbyname(hostname
)) == NULL
) {
614 g_printerr("%s: unknown host.\n", hostname
);
619 if (hp
->h_length
!= 4 && hp
->h_length
!= 8) {
620 g_printerr("illegal address length received for host %s\n", hostname
);
625 memcpy(&ad
.sin_addr
, hp
->h_addr
, hp
->h_length
);
628 return sock_connect_with_timeout(sock
, (struct sockaddr
*)&ad
,
629 sizeof(ad
), io_timeout
);
633 static gint
sock_connect_by_getaddrinfo(const gchar
*hostname
, gushort port
)
635 gint sock
= -1, gai_error
;
636 struct addrinfo hints
, *res
, *ai
;
641 memset(&hints
, 0, sizeof(hints
));
642 /* hints.ai_flags = AI_CANONNAME; */
643 hints
.ai_family
= AF_UNSPEC
;
644 hints
.ai_socktype
= SOCK_STREAM
;
645 hints
.ai_protocol
= IPPROTO_TCP
;
647 /* convert port from integer to string. */
648 g_snprintf(port_str
, sizeof(port_str
), "%d", port
);
650 if ((gai_error
= getaddrinfo(hostname
, port_str
, &hints
, &res
)) != 0) {
651 g_printerr("getaddrinfo for %s:%s failed: %s\n",
652 hostname
, port_str
, gai_strerror(gai_error
));
656 for (ai
= res
; ai
!= NULL
; ai
= ai
->ai_next
) {
657 sock
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
661 if (sock_connect_with_timeout
662 (sock
, ai
->ai_addr
, ai
->ai_addrlen
, io_timeout
) == 0)
679 /* Open a connection using an external program. May be useful when
680 * you need to tunnel through a SOCKS or other firewall, or to
681 * establish an IMAP-over-SSH connection. */
682 /* TODO: Recreate this for sock_connect_thread() */
683 SockInfo
*sock_connect_cmd(const gchar
*hostname
, const gchar
*tunnelcmd
)
689 if ((r
= socketpair(AF_UNIX
, SOCK_STREAM
, 0, fd
)) == -1) {
690 perror("socketpair");
693 log_message(LOG_PROTOCOL
, "launching tunnel command \"%s\"\n", tunnelcmd
);
698 dup(fd
[1]); /* set onto stdin */
700 execlp("/bin/sh", "/bin/sh", "-c", tunnelcmd
, NULL
);
704 return sockinfo_from_fd(hostname
, 0, fd
[0]);
706 /* We would need a special implementation for W32. */
712 SockInfo
*sock_connect(const gchar
*hostname
, gushort port
)
721 if ((sock
= sock_connect_by_getaddrinfo(hostname
, port
)) < 0)
725 if ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) == INVALID_SOCKET
) {
726 g_warning("socket() failed: %d\n", WSAGetLastError());
728 if ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
730 #endif /* G_OS_WIN32 */
734 if (sock_connect_by_hostname(sock
, hostname
, port
) < 0) {
735 if (errno
!= 0) perror("connect");
741 return sockinfo_from_fd(hostname
, port
, sock
);
745 static void sock_address_list_free(GList
*addr_list
)
749 for (cur
= addr_list
; cur
!= NULL
; cur
= cur
->next
) {
750 SockAddrData
*addr_data
= (SockAddrData
*)cur
->data
;
751 g_free(addr_data
->addr
);
755 g_list_free(addr_list
);
758 /* asynchronous TCP connection */
760 static gboolean
sock_connect_async_cb(GIOChannel
*source
,
761 GIOCondition condition
, gpointer data
)
763 SockConnectData
*conn_data
= (SockConnectData
*)data
;
769 if (conn_data
->io_tag
== 0 && conn_data
->channel
== NULL
)
772 fd
= g_io_channel_unix_get_fd(source
);
774 conn_data
->io_tag
= 0;
775 conn_data
->channel
= NULL
;
776 g_io_channel_unref(source
);
779 if (getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, &val
, &len
) < 0) {
780 perror("getsockopt");
782 sock_connect_address_list_async(conn_data
);
788 sock_connect_address_list_async(conn_data
);
792 sockinfo
= g_new0(SockInfo
, 1);
794 sockinfo
->sock_ch
= g_io_channel_unix_new(fd
);
795 sockinfo
->hostname
= g_strdup(conn_data
->hostname
);
796 sockinfo
->port
= conn_data
->port
;
797 sockinfo
->state
= CONN_ESTABLISHED
;
798 sockinfo
->canonical_name
= g_strdup(conn_data
->canonical_name
);
800 conn_data
->func(sockinfo
, conn_data
->data
);
802 sock_connect_async_cancel(conn_data
->id
);
807 static gint
sock_connect_async_get_address_info_cb(GList
*addr_list
,
810 SockConnectData
*conn_data
= (SockConnectData
*)data
;
812 conn_data
->addr_list
= addr_list
;
813 conn_data
->cur_addr
= addr_list
;
814 if (conn_data
->lookup_data
) {
815 conn_data
->canonical_name
= conn_data
->lookup_data
->canonical_name
;
816 conn_data
->lookup_data
->canonical_name
= NULL
;
817 conn_data
->lookup_data
= NULL
;
819 return sock_connect_address_list_async(conn_data
);
822 gint
sock_connect_async(const gchar
*hostname
, gushort port
,
823 SockConnectFunc func
, gpointer data
)
826 SockConnectData
*conn_data
;
828 conn_data
= g_new0(SockConnectData
, 1);
829 conn_data
->id
= id
++;
830 conn_data
->hostname
= g_strdup(hostname
);
831 conn_data
->port
= port
;
832 conn_data
->addr_list
= NULL
;
833 conn_data
->cur_addr
= NULL
;
834 conn_data
->io_tag
= 0;
835 conn_data
->func
= func
;
836 conn_data
->data
= data
;
838 conn_data
->lookup_data
= sock_get_address_info_async
839 (hostname
, port
, sock_connect_async_get_address_info_cb
,
842 if (conn_data
->lookup_data
== NULL
) {
843 g_free(conn_data
->hostname
);
848 sock_connect_data_list
= g_list_append(sock_connect_data_list
,
851 return conn_data
->id
;
854 gint
sock_connect_async_cancel(gint id
)
856 SockConnectData
*conn_data
= NULL
;
859 for (cur
= sock_connect_data_list
; cur
!= NULL
; cur
= cur
->next
) {
860 if (((SockConnectData
*)cur
->data
)->id
== id
) {
861 conn_data
= (SockConnectData
*)cur
->data
;
867 sock_connect_data_list
= g_list_remove(sock_connect_data_list
,
870 if (conn_data
->lookup_data
)
871 sock_get_address_info_async_cancel
872 (conn_data
->lookup_data
);
874 if (conn_data
->io_tag
> 0)
875 g_source_remove(conn_data
->io_tag
);
876 if (conn_data
->channel
) {
877 g_io_channel_close(conn_data
->channel
);
878 g_io_channel_unref(conn_data
->channel
);
881 sock_address_list_free(conn_data
->addr_list
);
882 g_free(conn_data
->canonical_name
);
883 g_free(conn_data
->hostname
);
886 g_warning("sock_connect_async_cancel: id %d not found.\n", id
);
893 static gint
sock_connect_address_list_async(SockConnectData
*conn_data
)
895 SockAddrData
*addr_data
;
898 for (; conn_data
->cur_addr
!= NULL
;
899 conn_data
->cur_addr
= conn_data
->cur_addr
->next
) {
900 addr_data
= (SockAddrData
*)conn_data
->cur_addr
->data
;
902 if ((sock
= socket(addr_data
->family
, addr_data
->socktype
,
903 addr_data
->protocol
)) < 0) {
908 set_nonblocking_mode(sock
, TRUE
);
910 if (connect(sock
, addr_data
->addr
, addr_data
->addr_len
) < 0) {
911 if (EINPROGRESS
== errno
) {
921 if (conn_data
->cur_addr
== NULL
) {
922 g_warning("sock_connect_address_list_async: "
923 "connection to %s:%d failed\n",
924 conn_data
->hostname
, conn_data
->port
);
925 conn_data
->func(NULL
, conn_data
->data
);
926 sock_connect_async_cancel(conn_data
->id
);
930 conn_data
->cur_addr
= conn_data
->cur_addr
->next
;
932 conn_data
->channel
= g_io_channel_unix_new(sock
);
933 conn_data
->io_tag
= g_io_add_watch(conn_data
->channel
, G_IO_IN
|G_IO_OUT
,
934 sock_connect_async_cb
, conn_data
);
939 /* asynchronous DNS lookup */
941 static gboolean
sock_get_address_info_async_cb(GIOChannel
*source
,
942 GIOCondition condition
,
945 SockLookupData
*lookup_data
= (SockLookupData
*)data
;
946 GList
*addr_list
= NULL
;
947 SockAddrData
*addr_data
;
950 struct sockaddr
*addr
;
951 gchar
*canonical_name
= NULL
;
954 if (g_io_channel_read(source
, &len
, sizeof(len
),
955 &bytes_read
) == G_IO_ERROR_NONE
) {
956 if (bytes_read
== sizeof(len
) && len
> 0) {
959 canonical_name
= g_malloc0(len
+ 1);
960 cur
= canonical_name
;
962 if (g_io_channel_read(source
, cur
, todo
,
963 &bytes_read
) != G_IO_ERROR_NONE
) {
964 g_warning("canonical name not read\n");
965 g_free(canonical_name
);
966 canonical_name
= NULL
;
972 if (bytes_read
== 0) {
973 g_warning("canonical name not read\n");
974 g_free(canonical_name
);
975 canonical_name
= NULL
;
982 if (g_io_channel_read(source
, (gchar
*)ai_member
,
983 sizeof(ai_member
), &bytes_read
)
984 != G_IO_ERROR_NONE
) {
985 g_warning("sock_get_address_info_async_cb: "
986 "address length read error\n");
990 if (bytes_read
== 0 || bytes_read
!= sizeof(ai_member
))
993 if (ai_member
[0] == AF_UNSPEC
) {
994 g_warning("DNS lookup failed\n");
998 addr
= g_malloc(ai_member
[3]);
999 if (g_io_channel_read(source
, (gchar
*)addr
, ai_member
[3],
1001 != G_IO_ERROR_NONE
) {
1002 g_warning("sock_get_address_info_async_cb: "
1003 "address data read error\n");
1008 if (bytes_read
!= ai_member
[3]) {
1009 g_warning("sock_get_address_info_async_cb: "
1010 "incomplete address data\n");
1015 addr_data
= g_new0(SockAddrData
, 1);
1016 addr_data
->family
= ai_member
[0];
1017 addr_data
->socktype
= ai_member
[1];
1018 addr_data
->protocol
= ai_member
[2];
1019 addr_data
->addr_len
= ai_member
[3];
1020 addr_data
->addr
= addr
;
1022 addr_list
= g_list_append(addr_list
, addr_data
);
1025 g_io_channel_close(source
);
1026 g_io_channel_unref(source
);
1029 /* FIXME: We would need to cancel the thread. */
1031 kill(lookup_data
->child_pid
, SIGKILL
);
1032 waitpid(lookup_data
->child_pid
, NULL
, 0);
1034 lookup_data
->canonical_name
= canonical_name
;
1036 lookup_data
->func(addr_list
, lookup_data
->data
);
1038 g_free(lookup_data
->canonical_name
);
1039 g_free(lookup_data
->hostname
);
1040 g_free(lookup_data
);
1046 /* For better readability we use a separate function to implement the
1047 child code of sock_get_address_info_async. Note, that under W32
1048 this is actually not a child but a thread and this is the reason
1049 why we pass only a void pointer. */
1050 static void address_info_async_child(void *opaque
)
1052 SockLookupData
*parm
= opaque
;
1055 struct addrinfo hints
, *res
, *ai
;
1059 gchar
**addr_list_p
;
1060 struct sockaddr_in ad
;
1062 gint ai_member
[4] = {AF_UNSPEC
, 0, 0, 0};
1065 close(parm
->pipe_fds
[0]);
1066 parm
->pipe_fds
[0] = -1;
1070 memset(&hints
, 0, sizeof(hints
));
1071 hints
.ai_flags
= AI_CANONNAME
;
1072 hints
.ai_family
= AF_UNSPEC
;
1073 hints
.ai_socktype
= SOCK_STREAM
;
1074 hints
.ai_protocol
= IPPROTO_TCP
;
1076 g_snprintf(port_str
, sizeof(port_str
), "%d", parm
->port
);
1078 gai_err
= getaddrinfo(parm
->hostname
, port_str
, &hints
, &res
);
1081 g_warning("getaddrinfo for %s:%s failed: %s\n",
1082 parm
->hostname
, port_str
, gai_strerror(gai_err
));
1083 fd_write_all(parm
->pipe_fds
[1], &len
,
1085 fd_write_all(parm
->pipe_fds
[1], (gchar
*)ai_member
,
1087 close(parm
->pipe_fds
[1]);
1088 parm
->pipe_fds
[1] = -1;
1097 if (res
->ai_canonname
&& strlen(res
->ai_canonname
) < 255) {
1098 gchar len
= strlen(res
->ai_canonname
);
1099 fd_write_all(parm
->pipe_fds
[1], &len
,
1101 fd_write_all(parm
->pipe_fds
[1], res
->ai_canonname
,
1105 fd_write_all(parm
->pipe_fds
[1], &len
,
1110 fd_write_all(parm
->pipe_fds
[1], &len
,
1114 for (ai
= res
; ai
!= NULL
; ai
= ai
->ai_next
) {
1115 ai_member
[0] = ai
->ai_family
;
1116 ai_member
[1] = ai
->ai_socktype
;
1117 ai_member
[2] = ai
->ai_protocol
;
1118 ai_member
[3] = ai
->ai_addrlen
;
1120 fd_write_all(parm
->pipe_fds
[1], (gchar
*)ai_member
,
1122 fd_write_all(parm
->pipe_fds
[1], (gchar
*)ai
->ai_addr
,
1129 hp
= my_gethostbyname(parm
->hostname
);
1130 if (hp
== NULL
|| hp
->h_addrtype
!= AF_INET
) {
1132 fd_write_all(parm
->pipe_fds
[1], &len
,
1134 fd_write_all(parm
->pipe_fds
[1], (gchar
*)ai_member
,
1136 close(parm
->pipe_fds
[1]);
1137 parm
->pipe_fds
[1] = -1;
1145 ai_member
[0] = AF_INET
;
1146 ai_member
[1] = SOCK_STREAM
;
1147 ai_member
[2] = IPPROTO_TCP
;
1148 ai_member
[3] = sizeof(ad
);
1150 memset(&ad
, 0, sizeof(ad
));
1151 ad
.sin_family
= AF_INET
;
1152 ad
.sin_port
= htons(parm
->port
);
1154 if (hp
->h_name
&& strlen(hp
->h_name
) < 255) {
1155 gchar len
= strlen(hp
->h_name
);
1156 fd_write_all(parm
->pipe_fds
[1], &len
,
1158 fd_write_all(parm
->pipe_fds
[1], hp
->h_name
,
1162 fd_write_all(parm
->pipe_fds
[1], &len
,
1165 for (addr_list_p
= hp
->h_addr_list
; *addr_list_p
!= NULL
;
1167 memcpy(&ad
.sin_addr
, *addr_list_p
, hp
->h_length
);
1168 fd_write_all(parm
->pipe_fds
[1], (gchar
*)ai_member
,
1170 fd_write_all(parm
->pipe_fds
[1], (gchar
*)&ad
, sizeof(ad
));
1174 close(parm
->pipe_fds
[1]);
1175 parm
->pipe_fds
[1] = -1;
1184 static SockLookupData
*sock_get_address_info_async(const gchar
*hostname
,
1189 SockLookupData
*lookup_data
= NULL
;
1191 refresh_resolvers();
1193 lookup_data
= g_new0(SockLookupData
, 1);
1194 lookup_data
->hostname
= g_strdup(hostname
);
1195 lookup_data
->func
= func
;
1196 lookup_data
->data
= data
;
1197 lookup_data
->port
= port
;
1198 lookup_data
->child_pid
= (pid_t
)(-1);
1199 lookup_data
->pipe_fds
[0] = -1;
1200 lookup_data
->pipe_fds
[1] = -1;
1202 if (pipe(lookup_data
->pipe_fds
) < 0) {
1205 g_free (lookup_data
->hostname
);
1206 g_free (lookup_data
);
1211 if ((lookup_data
->child_pid
= fork()) < 0) {
1214 g_free (lookup_data
->hostname
);
1215 g_free (lookup_data
);
1219 if (lookup_data
->child_pid
== 0) {
1220 /* Child process. */
1221 address_info_async_child (lookup_data
);
1222 g_assert_not_reached ();
1224 /* Parent process. */
1225 close(lookup_data
->pipe_fds
[1]);
1226 lookup_data
->pipe_fds
[1] = -1;
1227 #endif /*!G_OS_WIN32 */
1229 lookup_data
->channel
= g_io_channel_unix_new(lookup_data
->pipe_fds
[0]);
1230 lookup_data
->io_tag
= g_io_add_watch(lookup_data
->channel
, G_IO_IN
,
1231 sock_get_address_info_async_cb
,
1234 lookup_data
->child_pid
= _beginthread(
1235 address_info_async_child
, 0, lookup_data
);
1241 static gint
sock_get_address_info_async_cancel(SockLookupData
*lookup_data
)
1243 if (lookup_data
->io_tag
> 0)
1244 g_source_remove(lookup_data
->io_tag
);
1245 if (lookup_data
->channel
) {
1246 g_io_channel_close(lookup_data
->channel
);
1247 g_io_channel_unref(lookup_data
->channel
);
1250 if (lookup_data
->child_pid
> 0) {
1252 /* FIXME: Need a way to cancel the thread. */
1254 kill(lookup_data
->child_pid
, SIGKILL
);
1255 waitpid(lookup_data
->child_pid
, NULL
, 0);
1259 g_free(lookup_data
->canonical_name
);
1260 g_free(lookup_data
->hostname
);
1261 g_free(lookup_data
);
1267 static SockInfo
*sockinfo_from_fd(const gchar
*hostname
,
1273 sockinfo
= g_new0(SockInfo
, 1);
1274 sockinfo
->sock
= sock
;
1275 sockinfo
->sock_ch
= g_io_channel_unix_new(sock
);
1276 sockinfo
->hostname
= g_strdup(hostname
);
1277 sockinfo
->port
= port
;
1278 sockinfo
->state
= CONN_ESTABLISHED
;
1283 static gint
fd_read(gint fd
, gchar
*buf
, gint len
)
1285 if (fd_check_io(fd
, G_IO_IN
) < 0)
1288 if (fd_is_w32_socket(fd
))
1289 return recv(fd
, buf
, len
, 0);
1290 return read(fd
, buf
, len
);
1294 static gint
ssl_read(SSL
*ssl
, gchar
*buf
, gint len
)
1298 if (SSL_pending(ssl
) == 0) {
1299 if (fd_check_io(SSL_get_rfd(ssl
), G_IO_IN
) < 0)
1303 ret
= SSL_read(ssl
, buf
, len
);
1305 switch ((err
= SSL_get_error(ssl
, ret
))) {
1306 case SSL_ERROR_NONE
:
1308 case SSL_ERROR_WANT_READ
:
1309 case SSL_ERROR_WANT_WRITE
:
1312 case SSL_ERROR_ZERO_RETURN
:
1315 g_warning("SSL_read() returned error %d, ret = %d\n", err
, ret
);
1323 gint
sock_read(SockInfo
*sock
, gchar
*buf
, gint len
)
1327 g_return_val_if_fail(sock
!= NULL
, -1);
1331 ret
= ssl_read(sock
->ssl
, buf
, len
);
1334 ret
= fd_read(sock
->sock
, buf
, len
);
1337 sock
->state
= CONN_DISCONNECTED
;
1341 gint
fd_write(gint fd
, const gchar
*buf
, gint len
)
1343 if (fd_check_io(fd
, G_IO_OUT
) < 0)
1346 if (fd_is_w32_socket (fd
))
1347 return send(fd
, buf
, len
, 0);
1348 return write(fd
, buf
, len
);
1352 static gint
ssl_write(SSL
*ssl
, const gchar
*buf
, gint len
)
1356 ret
= SSL_write(ssl
, buf
, len
);
1358 switch (SSL_get_error(ssl
, ret
)) {
1359 case SSL_ERROR_NONE
:
1361 case SSL_ERROR_WANT_READ
:
1362 case SSL_ERROR_WANT_WRITE
:
1371 gint
sock_write(SockInfo
*sock
, const gchar
*buf
, gint len
)
1375 g_return_val_if_fail(sock
!= NULL
, -1);
1379 ret
= ssl_write(sock
->ssl
, buf
, len
);
1382 ret
= fd_write(sock
->sock
, buf
, len
);
1385 sock
->state
= CONN_DISCONNECTED
;
1389 gint
fd_write_all(gint fd
, const gchar
*buf
, gint len
)
1394 if (fd_check_io(fd
, G_IO_OUT
) < 0)
1397 signal(SIGPIPE
, SIG_IGN
);
1399 if (fd_is_w32_socket(fd
))
1400 n
= send(fd
, buf
, len
, 0);
1402 n
= write(fd
, buf
, len
);
1405 log_error(LOG_PROTOCOL
, _("write on fd%d: %s\n"), fd
, strerror(errno
));
1417 static gint
ssl_write_all(SSL
*ssl
, const gchar
*buf
, gint len
)
1422 n
= ssl_write(ssl
, buf
, len
);
1434 gint
sock_write_all(SockInfo
*sock
, const gchar
*buf
, gint len
)
1438 g_return_val_if_fail(sock
!= NULL
, -1);
1442 ret
= ssl_write_all(sock
->ssl
, buf
, len
);
1445 ret
= fd_write_all(sock
->sock
, buf
, len
);
1448 sock
->state
= CONN_DISCONNECTED
;
1452 static gint
fd_recv(gint fd
, gchar
*buf
, gint len
, gint flags
)
1454 if (fd_check_io(fd
, G_IO_IN
) < 0)
1457 return recv(fd
, buf
, len
, flags
);
1460 gint
fd_gets(gint fd
, gchar
*buf
, gint len
)
1462 gchar
*newline
, *bp
= buf
;
1472 MSKB Article ID: Q147714
1473 Windows Sockets 2 Service Provider Interface Limitations
1474 Polling with recv(MSG_PEEK) to determine when a complete message
1476 Reason and Workaround not available.
1478 Single-byte send() and recv().
1479 Reason: Couple one-byte sends with Nagle disabled.
1480 Workaround: Send modest amounts and receive as much as possible.
1483 if (recv(fd
, bp
, 1, 0) <= 0)
1490 #else /*!G_OS_WIN32*/
1492 if ((n
= fd_recv(fd
, bp
, len
, MSG_PEEK
)) <= 0)
1494 if ((newline
= memchr(bp
, '\n', n
)) != NULL
)
1495 n
= newline
- bp
+ 1;
1496 if ((n
= fd_read(fd
, bp
, n
)) < 0)
1500 } while (!newline
&& len
);
1501 #endif /*!G_OS_WIN32*/
1508 static gint
ssl_peek (SSL
*ssl
, gchar
*buf
, gint len
);
1510 static gint
ssl_gets(SSL
*ssl
, gchar
*buf
, gint len
)
1512 gchar
*newline
, *bp
= buf
;
1518 if ((n
= ssl_peek(ssl
, bp
, len
)) <= 0)
1520 if ((newline
= memchr(bp
, '\n', n
)) != NULL
)
1521 n
= newline
- bp
+ 1;
1522 if ((n
= ssl_read(ssl
, bp
, n
)) < 0)
1526 } while (!newline
&& len
);
1533 gint
sock_gets(SockInfo
*sock
, gchar
*buf
, gint len
)
1537 g_return_val_if_fail(sock
!= NULL
, -1);
1541 return ssl_gets(sock
->ssl
, buf
, len
);
1544 return fd_gets(sock
->sock
, buf
, len
);
1547 sock
->state
= CONN_DISCONNECTED
;
1551 /* peek at the socket data without actually reading it */
1553 static gint
ssl_peek(SSL
*ssl
, gchar
*buf
, gint len
)
1557 if (SSL_pending(ssl
) == 0) {
1558 if (fd_check_io(SSL_get_rfd(ssl
), G_IO_IN
) < 0)
1562 ret
= SSL_peek(ssl
, buf
, len
);
1564 switch ((err
= SSL_get_error(ssl
, ret
))) {
1565 case SSL_ERROR_NONE
:
1567 case SSL_ERROR_WANT_READ
:
1568 case SSL_ERROR_WANT_WRITE
:
1571 case SSL_ERROR_ZERO_RETURN
:
1573 case SSL_ERROR_SYSCALL
:
1574 g_warning("SSL_peek() returned syscall error. errno=%d\n", errno
);
1577 g_warning("SSL_peek() returned error %d, ret = %d\n", err
, ret
);
1585 gint
sock_close(SockInfo
*sock
)
1593 g_io_channel_unref(sock
->sock_ch
);
1597 ssl_done_socket(sock
);
1598 if (sock
->g_source
!= 0)
1599 g_source_remove(sock
->g_source
);
1603 shutdown(sock
->sock
, 1); /* complete transfer before close */
1604 ret
= closesocket(sock
->sock
);
1606 ret
= fd_close(sock
->sock
);
1609 g_free(sock
->canonical_name
);
1610 g_free(sock
->hostname
);
1616 gint
fd_close(gint fd
)