diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | ChangeLog.ja | 8 | ||||
-rw-r--r-- | libsylph/session.c | 5 | ||||
-rw-r--r-- | libsylph/socket.c | 51 | ||||
-rw-r--r-- | libsylph/socket.h | 15 |
5 files changed, 71 insertions, 15 deletions
@@ -1,3 +1,10 @@ +2007-01-22 + + * libsylph/session.c: session_ping_cb(): prohibit blocking here. + libsylph/socket.[ch]: added SockFlags as a member of SockInfo. + fd_check_io(): select() sockets if SOCK_CHECK_IO flag is up even if + in non-blocking mode (prevents WSAEWOULDBLOCK in Win32). + 2007-01-19 * libsylph/session.c diff --git a/ChangeLog.ja b/ChangeLog.ja index ce70fc60..216a73aa 100644 --- a/ChangeLog.ja +++ b/ChangeLog.ja @@ -1,3 +1,11 @@ +2007-01-22 + + * libsylph/session.c: session_ping_cb(): ここではブロッキングを回避。 + libsylph/socket.[ch]: SockInfo のメンバに SockFlags を追加。 + fd_check_io(): 非ブロッキングモードでも SOCK_CHECK_IO フラグが立って + いたらソケットを select() するようにした(Win32 で WSAEWOULDBLOCK + を回避)。 + 2007-01-19 * libsylph/session.c diff --git a/libsylph/session.c b/libsylph/session.c index 73691dca..5ebb564d 100644 --- a/libsylph/session.c +++ b/libsylph/session.c @@ -276,8 +276,13 @@ static gboolean session_ping_cb(gpointer data) } if (tv_result.tv_sec * G_USEC_PER_SEC + tv_result.tv_usec > G_USEC_PER_SEC) { + SockFlags save_flags; + debug_print("state machine freeze for 1 second detected, forcing dispatch.\n"); + save_flags = sock->flags; + SOCK_UNSET_FLAGS(sock->flags, SOCK_CHECK_IO); sock->callback(sock, sock->condition, sock->data); + sock->flags = save_flags; } } diff --git a/libsylph/socket.c b/libsylph/socket.c index 189c1b77..3409b0e9 100644 --- a/libsylph/socket.c +++ b/libsylph/socket.c @@ -380,8 +380,13 @@ static gint set_nonblocking_mode(gint fd, gboolean nonblock) } sock = sock_find_from_fd(fd); - if (sock) - sock->nonblock = nonblock; + if (sock) { + if (nonblock) { + SOCK_SET_FLAGS(sock->flags, SOCK_NONBLOCK); + } else { + SOCK_UNSET_FLAGS(sock->flags, SOCK_NONBLOCK); + } + } debug_print("set nonblocking mode to %d\n", nonblock); return 0; @@ -410,8 +415,13 @@ gint sock_set_nonblocking_mode(SockInfo *sock, gboolean nonblock) g_return_val_if_fail(sock != NULL, -1); ret = set_nonblocking_mode(sock->sock, nonblock); - if (ret == 0) - sock->nonblock = nonblock; + if (ret == 0) { + if (nonblock) { + SOCK_SET_FLAGS(sock->flags, SOCK_NONBLOCK); + } else { + SOCK_UNSET_FLAGS(sock->flags, SOCK_NONBLOCK); + } + } return ret; } @@ -422,8 +432,9 @@ static gboolean is_nonblocking_mode(gint fd) SockInfo *sock; sock = sock_find_from_fd(fd); - if (sock) - return sock->nonblock; + if (sock) { + return SOCK_IS_NONBLOCK(sock->flags); + } return FALSE; #else @@ -444,7 +455,7 @@ gboolean sock_is_nonblocking_mode(SockInfo *sock) g_return_val_if_fail(sock != NULL, FALSE); #ifdef G_OS_WIN32 - return sock->nonblock; + return SOCK_IS_NONBLOCK(sock->flags); #else return is_nonblocking_mode(sock->sock); #endif @@ -560,8 +571,10 @@ static gint fd_check_io(gint fd, GIOCondition cond) { struct timeval timeout; fd_set fds; + SockInfo *sock; - if (is_nonblocking_mode(fd)) + sock = sock_find_from_fd(fd); + if (sock && !SOCK_IS_CHECK_IO(sock->flags)) return 0; timeout.tv_sec = io_timeout; @@ -679,15 +692,27 @@ struct hostent *my_gethostbyname(const gchar *hostname) static void sock_set_buffer_size(gint sock) { #ifdef G_OS_WIN32 - gint val = 32768; + gint val; guint len = sizeof(val); - setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&val, len); - setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&val, len); +#define SOCK_BUFFSIZE 32768 + + getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&val, &len); + if (val < SOCK_BUFFSIZE) { + val = SOCK_BUFFSIZE; + setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&val, len); + } + getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&val, &len); + if (val < SOCK_BUFFSIZE) { + val = SOCK_BUFFSIZE; + setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&val, len); + } getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&val, &len); debug_print("SO_SNDBUF = %d\n", val); getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&val, &len); debug_print("SO_RCVBUF = %d\n", val); + +#undef SOCK_BUFFSIZE #endif } @@ -839,7 +864,7 @@ SockInfo *sock_connect(const gchar *hostname, gushort port) sockinfo->hostname = g_strdup(hostname); sockinfo->port = port; sockinfo->state = CONN_ESTABLISHED; - sockinfo->nonblock = FALSE; + sockinfo->flags = SOCK_CHECK_IO; sock_list = g_list_prepend(sock_list, sockinfo); @@ -899,7 +924,7 @@ static gboolean sock_connect_async_cb(GIOChannel *source, sockinfo->hostname = g_strdup(conn_data->hostname); sockinfo->port = conn_data->port; sockinfo->state = CONN_ESTABLISHED; - sockinfo->nonblock = TRUE; + sockinfo->flags = SOCK_NONBLOCK; sock_list = g_list_prepend(sock_list, sockinfo); diff --git a/libsylph/socket.h b/libsylph/socket.h index aaa6b895..384f61a4 100644 --- a/libsylph/socket.h +++ b/libsylph/socket.h @@ -1,6 +1,6 @@ /* * LibSylph -- E-Mail client library - * Copyright (C) 1999-2006 Hiroyuki Yamamoto + * Copyright (C) 1999-2007 Hiroyuki Yamamoto * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -44,6 +44,17 @@ typedef enum CONN_FAILED } ConnectionState; +typedef enum +{ + SOCK_NONBLOCK = 1 << 0, + SOCK_CHECK_IO = 1 << 1 +} SockFlags; + +#define SOCK_SET_FLAGS(flags, set) { (flags) |= (set); } +#define SOCK_UNSET_FLAGS(flags, set) { (flags) &= ~(set); } +#define SOCK_IS_NONBLOCK(flags) ((flags & SOCK_NONBLOCK) != 0) +#define SOCK_IS_CHECK_IO(flags) ((flags & SOCK_CHECK_IO) != 0) + typedef gint (*SockConnectFunc) (SockInfo *sock, gpointer data); typedef gboolean (*SockFunc) (SockInfo *sock, @@ -63,7 +74,7 @@ struct _SockInfo gchar *hostname; gushort port; ConnectionState state; - gboolean nonblock; + SockFlags flags; gpointer data; SockFunc callback; |