aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--libsylph/imap.c1
-rw-r--r--libsylph/nntp.c1
-rw-r--r--libsylph/session.c122
-rw-r--r--libsylph/session.h12
-rw-r--r--libsylph/socket.c222
-rw-r--r--libsylph/socket.h12
-rw-r--r--src/inc.c14
-rw-r--r--src/inc.h3
-rw-r--r--src/send_message.c6
10 files changed, 327 insertions, 76 deletions
diff --git a/ChangeLog b/ChangeLog
index ceca52d6..e683e60e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2012-05-31
+
+ * libsylph/session.[ch]
+ libsylph/socket.[ch]
+ src/inc.[ch]
+ src/send_message.c: differentiate DNS lookup error from connection
+ errors.
+ * libsylph/imap.c
+ libsylph/nntp.c: fixed resource leak on SOCKS connection failure.
+
2012-05-30
* nsis/sylpheed.nsi: reserve nsProcess.dll file to speed up the launch
diff --git a/libsylph/imap.c b/libsylph/imap.c
index fee09646..d9c98857 100644
--- a/libsylph/imap.c
+++ b/libsylph/imap.c
@@ -2960,6 +2960,7 @@ static SockInfo *imap_open(const gchar *server, gushort port,
if (socks_connect(sock, server, port, socks_info) < 0) {
log_warning("Can't establish SOCKS connection: %s:%d\n",
server, port);
+ sock_close(sock);
return NULL;
}
}
diff --git a/libsylph/nntp.c b/libsylph/nntp.c
index daed4ff1..64c9da12 100644
--- a/libsylph/nntp.c
+++ b/libsylph/nntp.c
@@ -87,6 +87,7 @@ Session *nntp_session_new_full(const gchar *server, gushort port,
if (socks_connect(sock, server, port, socks_info) < 0) {
log_warning("Can't establish SOCKS connection: %s:%d\n",
server, port);
+ sock_close(sock);
return NULL;
}
}
diff --git a/libsylph/session.c b/libsylph/session.c
index 31525d8b..9f150230 100644
--- a/libsylph/session.c
+++ b/libsylph/session.c
@@ -40,6 +40,7 @@ typedef struct _SessionPrivData SessionPrivData;
struct _SessionPrivData {
Session *session;
SocksInfo *socks_info;
+ SessionErrorValue error_val;
gpointer data;
};
@@ -83,6 +84,8 @@ static gboolean session_write_data_cb (SockInfo *source,
void session_init(Session *session)
{
+ SessionPrivData *priv;
+
session->type = SESSION_UNKNOWN;
session->sock = NULL;
session->server = NULL;
@@ -127,6 +130,12 @@ void session_init(Session *session)
session->ping_tag = 0;
session->data = NULL;
+
+ priv = g_new0(SessionPrivData, 1);
+ priv->session = session;
+ priv->socks_info = NULL;
+ priv->error_val = SESSION_ERROR_OK;
+ priv_list = g_list_prepend(priv_list, priv);
}
static SessionPrivData *session_get_priv(Session *session)
@@ -153,6 +162,7 @@ gint session_connect(Session *session, const gchar *server, gushort port)
gint session_connect_full(Session *session, const gchar *server, gushort port,
SocksInfo *socks_info)
{
+ SessionPrivData *priv;
#ifndef G_OS_UNIX
SockInfo *sock = NULL;
#endif
@@ -160,6 +170,10 @@ gint session_connect_full(Session *session, const gchar *server, gushort port,
g_return_val_if_fail(server != NULL, -1);
g_return_val_if_fail(port > 0, -1);
+ priv = session_get_priv(session);
+ g_return_val_if_fail(priv != NULL, -1);
+ priv->socks_info = socks_info;
+
if (session->server != server) {
g_free(session->server);
session->server = g_strdup(server);
@@ -178,6 +192,7 @@ gint session_connect_full(Session *session, const gchar *server, gushort port,
if (session->conn_id < 0) {
g_warning("can't connect to server.");
session->state = SESSION_ERROR;
+ priv->error_val = SESSION_ERROR_CONNFAIL;
return -1;
}
#elif USE_THREADS
@@ -185,31 +200,24 @@ gint session_connect_full(Session *session, const gchar *server, gushort port,
if (session->conn_id < 0) {
g_warning("can't connect to server.");
session->state = SESSION_ERROR;
+ priv->error_val = SESSION_ERROR_CONNFAIL;
return -1;
}
- if (sock_connect_async_thread_wait(session->conn_id, &sock) < 0) {
- g_warning("can't connect to server.");
- session->state = SESSION_ERROR;
+ if (sock_info_connect_async_thread_wait(session->conn_id, &sock) < 0) {
+ session_connect_cb(sock, session);
+ if (sock)
+ sock_close(sock);
return -1;
}
#else /* !USE_THREADS */
- sock = sock_connect(server, port);
- if (sock == NULL) {
- g_warning("can't connect to server.");
- session->state = SESSION_ERROR;
+ sock = sock_new(server, port);
+ if (sock_info_connect(sock) < 0) {
+ session_connect_cb(sock, session);
+ sock_close(sock);
return -1;
}
#endif
- if (socks_info) {
- SessionPrivData *priv;
-
- priv = g_new0(SessionPrivData, 1);
- priv->session = session;
- priv->socks_info = socks_info;
- priv_list = g_list_prepend(priv_list, priv);
- }
-
#ifdef G_OS_UNIX
return 0;
#else
@@ -222,23 +230,37 @@ static gint session_connect_cb(SockInfo *sock, gpointer data)
Session *session = SESSION(data);
SessionPrivData *priv;
+ priv = session_get_priv(session);
session->conn_id = 0;
if (!sock) {
g_warning("can't connect to server.");
session->state = SESSION_ERROR;
+ priv->error_val = SESSION_ERROR_CONNFAIL;
+ return -1;
+ }
+ if (sock->state == CONN_LOOKUPFAILED) {
+ g_warning("DNS lookup failed.");
+ session->state = SESSION_ERROR;
+ priv->error_val = SESSION_ERROR_LOOKUP;
+ return -1;
+ } else if (sock->state != CONN_ESTABLISHED) {
+ g_warning("can't connect to server (ConnectionState: %d).",
+ sock->state);
+ session->state = SESSION_ERROR;
+ priv->error_val = SESSION_ERROR_CONNFAIL;
return -1;
}
session->sock = sock;
- priv = session_get_priv(session);
- if (priv && priv->socks_info) {
+ if (priv->socks_info) {
sock_set_nonblocking_mode(sock, FALSE);
if (socks_connect(sock, session->server, session->port,
priv->socks_info) < 0) {
g_warning("can't establish SOCKS connection.");
session->state = SESSION_ERROR;
+ priv->error_val = SESSION_ERROR_CONNFAIL;
return -1;
}
}
@@ -249,6 +271,7 @@ static gint session_connect_cb(SockInfo *sock, gpointer data)
if (!ssl_init_socket(sock)) {
g_warning("can't initialize SSL.");
session->state = SESSION_ERROR;
+ priv->error_val = SESSION_ERROR_SOCKET;
return -1;
}
}
@@ -259,6 +282,7 @@ static gint session_connect_cb(SockInfo *sock, gpointer data)
sock_set_nonblocking_mode(sock, session->nonblocking);
session->state = SESSION_RECV;
+ priv->error_val = SESSION_ERROR_OK;
session->io_tag = sock_add_watch(session->sock, G_IO_IN,
session_read_msg_cb,
session);
@@ -312,6 +336,17 @@ gboolean session_is_connected(Session *session)
session->state == SESSION_RECV);
}
+SessionErrorValue session_get_error(Session *session)
+{
+ SessionPrivData *priv;
+
+ priv = session_get_priv(session);
+ if (priv)
+ return priv->error_val;
+ else
+ return SESSION_ERROR_ERROR;
+}
+
void session_set_access_time(Session *session)
{
session->last_access_time = time(NULL);
@@ -333,6 +368,7 @@ void session_set_timeout(Session *session, guint interval)
static gboolean session_timeout_cb(gpointer data)
{
Session *session = SESSION(data);
+ SessionPrivData *priv;
g_warning("session timeout.\n");
@@ -343,6 +379,8 @@ static gboolean session_timeout_cb(gpointer data)
session->timeout_tag = 0;
session->state = SESSION_TIMEOUT;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_TIMEOUT;
return FALSE;
}
@@ -681,6 +719,7 @@ static gboolean session_read_msg_cb(SockInfo *source, GIOCondition condition,
gpointer data)
{
Session *session = SESSION(data);
+ SessionPrivData *priv;
gchar buf[SESSION_BUFFSIZE];
gint line_len;
gchar *newline;
@@ -708,6 +747,8 @@ static gboolean session_read_msg_cb(SockInfo *source, GIOCondition condition,
default:
g_warning("%s: sock_read: %s\n", G_STRFUNC, g_strerror(errno));
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_SOCKET;
return FALSE;
}
}
@@ -759,8 +800,11 @@ static gboolean session_read_msg_cb(SockInfo *source, GIOCondition condition,
g_free(msg);
- if (ret < 0)
+ if (ret < 0) {
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_SOCKET;
+ }
return FALSE;
}
@@ -769,6 +813,7 @@ static gboolean session_read_data_cb(SockInfo *source, GIOCondition condition,
gpointer data)
{
Session *session = SESSION(data);
+ SessionPrivData *priv;
GByteArray *data_buf;
gint terminator_len;
gboolean complete = FALSE;
@@ -796,6 +841,8 @@ static gboolean session_read_data_cb(SockInfo *source, GIOCondition condition,
default:
g_warning("%s: sock_read: %s\n", G_STRFUNC, g_strerror(errno));
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_SOCKET;
return FALSE;
}
}
@@ -866,8 +913,11 @@ static gboolean session_read_data_cb(SockInfo *source, GIOCondition condition,
session->recv_data_notify(session, data_len,
session->recv_data_notify_data);
- if (ret < 0)
+ if (ret < 0) {
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_SOCKET;
+ }
return FALSE;
}
@@ -882,6 +932,7 @@ static gboolean session_read_data_as_file_cb(SockInfo *source,
gpointer data)
{
Session *session = SESSION(data);
+ SessionPrivData *priv;
gint terminator_len;
gchar *data_begin_p;
gint buf_data_len;
@@ -909,6 +960,8 @@ static gboolean session_read_data_as_file_cb(SockInfo *source,
default:
g_warning("%s: sock_read: %s\n", G_STRFUNC, g_strerror(errno));
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_SOCKET;
return FALSE;
}
}
@@ -980,6 +1033,8 @@ static gboolean session_read_data_as_file_cb(SockInfo *source,
g_warning("session_read_data_as_file_cb: "
"writing data to file failed\n");
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_IO;
return FALSE;
}
session->read_data_pos += write_len;
@@ -1016,6 +1071,8 @@ static gboolean session_read_data_as_file_cb(SockInfo *source,
g_warning("session_read_data_as_file_cb: "
"writing data to file failed\n");
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_IO;
return FALSE;
}
session->read_data_pos += write_len;
@@ -1025,6 +1082,8 @@ static gboolean session_read_data_as_file_cb(SockInfo *source,
g_warning("session_read_data_as_file_cb: "
"writing data to file failed\n");
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_IO;
return FALSE;
}
rewind(session->read_data_fp);
@@ -1046,8 +1105,11 @@ static gboolean session_read_data_as_file_cb(SockInfo *source,
session->read_data_pos = 0;
- if (ret < 0)
+ if (ret < 0) {
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_IO;
+ }
return FALSE;
}
@@ -1056,6 +1118,7 @@ static gint session_write_buf(Session *session)
{
gint write_len;
gint to_write_len;
+ SessionPrivData *priv;
g_return_val_if_fail(session->write_buf != NULL, -1);
g_return_val_if_fail(session->write_buf_p != NULL, -1);
@@ -1076,6 +1139,8 @@ static gint session_write_buf(Session *session)
default:
g_warning("sock_write: %s\n", g_strerror(errno));
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_SOCKET;
return -1;
}
}
@@ -1102,6 +1167,7 @@ static gint session_write_data(Session *session, gint *nwritten)
gchar buf[WRITE_DATA_BUFFSIZE];
gint write_len;
gint to_write_len;
+ SessionPrivData *priv;
g_return_val_if_fail(session->write_data_fp != NULL, -1);
g_return_val_if_fail(session->write_data_pos >= 0, -1);
@@ -1112,6 +1178,8 @@ static gint session_write_data(Session *session, gint *nwritten)
if (fread(buf, to_write_len, 1, session->write_data_fp) < 1) {
g_warning("session_write_data: reading data from file failed\n");
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_IO;
return -1;
}
@@ -1125,6 +1193,8 @@ static gint session_write_data(Session *session, gint *nwritten)
default:
g_warning("sock_write: %s\n", g_strerror(errno));
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_SOCKET;
*nwritten = write_len;
return -1;
}
@@ -1140,6 +1210,8 @@ static gint session_write_data(Session *session, gint *nwritten)
session->write_data_pos, SEEK_SET) < 0) {
g_warning("session_write_data: file seek failed\n");
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ priv->error_val = SESSION_ERROR_IO;
return -1;
}
}
@@ -1157,6 +1229,7 @@ static gboolean session_write_msg_cb(SockInfo *source, GIOCondition condition,
gpointer data)
{
Session *session = SESSION(data);
+ SessionPrivData *priv;
gint ret;
g_return_val_if_fail(condition == G_IO_OUT, FALSE);
@@ -1168,6 +1241,9 @@ static gboolean session_write_msg_cb(SockInfo *source, GIOCondition condition,
if (ret < 0) {
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ if (priv->error_val == SESSION_ERROR_OK)
+ priv->error_val = SESSION_ERROR_IO;
return FALSE;
} else if (ret > 0)
return TRUE;
@@ -1186,6 +1262,7 @@ static gboolean session_write_data_cb(SockInfo *source,
GIOCondition condition, gpointer data)
{
Session *session = SESSION(data);
+ SessionPrivData *priv;
guint write_data_len;
gint write_len;
gint ret;
@@ -1201,6 +1278,9 @@ static gboolean session_write_data_cb(SockInfo *source,
if (ret < 0) {
session->state = SESSION_ERROR;
+ priv = session_get_priv(session);
+ if (priv->error_val == SESSION_ERROR_OK)
+ priv->error_val = SESSION_ERROR_IO;
return FALSE;
} else if (ret > 0) {
GTimeVal tv_cur;
diff --git a/libsylph/session.h b/libsylph/session.h
index a807a4ae..d41d169c 100644
--- a/libsylph/session.h
+++ b/libsylph/session.h
@@ -73,6 +73,16 @@ typedef enum
} SSLType;
#endif
+typedef enum {
+ SESSION_ERROR_OK,
+ SESSION_ERROR_LOOKUP,
+ SESSION_ERROR_CONNFAIL,
+ SESSION_ERROR_IO,
+ SESSION_ERROR_SOCKET,
+ SESSION_ERROR_TIMEOUT,
+ SESSION_ERROR_ERROR
+} SessionErrorValue;
+
typedef gint (*RecvMsgNotify) (Session *session,
const gchar *msg,
gpointer user_data);
@@ -190,6 +200,8 @@ gint session_disconnect (Session *session);
void session_destroy (Session *session);
gboolean session_is_connected (Session *session);
+SessionErrorValue session_get_error (Session *session);
+
void session_set_access_time (Session *session);
void session_set_timeout (Session *session,
diff --git a/libsylph/socket.c b/libsylph/socket.c
index 6005f3cf..52a3fb63 100644
--- a/libsylph/socket.c
+++ b/libsylph/socket.c
@@ -91,8 +91,8 @@ struct _SockConnectData {
#if USE_THREADS
gint flag;
GThread *thread;
- SockInfo *sock;
#endif /* G_OS_UNIX */
+ SockInfo *sock;
SockConnectFunc func;
gpointer data;
};
@@ -146,9 +146,8 @@ static gint sock_connect_with_timeout (gint sock,
guint timeout_secs);
#ifndef INET6
-static gint sock_connect_by_hostname (gint sock,
- const gchar *hostname,
- gushort port);
+static gint sock_info_connect_by_hostname
+ (SockInfo *sock);
#else
#ifdef G_OS_WIN32
typedef int (*GetAddrInfoFunc) (const char *node,
@@ -166,8 +165,7 @@ static FreeAddrInfoFunc freeaddrinfo_func = NULL;
#define freeaddrinfo my_freeaddrinfo
#endif
-static SockDesc sock_connect_by_getaddrinfo (const gchar *hostname,
- gushort port);
+static SockDesc sock_info_connect_by_getaddrinfo(SockInfo *sock);
#endif
#ifdef G_OS_UNIX
@@ -377,6 +375,22 @@ gint fd_accept(gint sock)
}
+SockInfo *sock_new(const gchar *hostname, gushort port)
+{
+ SockInfo *sockinfo;
+
+ sockinfo = g_new0(SockInfo, 1);
+ sockinfo->sock = INVALID_SOCKET;
+ sockinfo->sock_ch = NULL;
+ sockinfo->hostname = g_strdup(hostname);
+ sockinfo->port = port;
+ sockinfo->state = CONN_READY;
+ sockinfo->flags = 0;
+ sockinfo->data = NULL;
+
+ return sockinfo;
+}
+
static SockInfo *sock_find_from_fd(gint fd)
{
GList *cur;
@@ -816,11 +830,14 @@ static gint my_inet_aton(const gchar *hostname, struct in_addr *inp)
#endif /* !defined(INET6) || defined(G_OS_WIN32) */
#ifndef INET6
-static gint sock_connect_by_hostname(gint sock, const gchar *hostname,
- gushort port)
+static gint sock_info_connect_by_hostname(SockInfo *sock)
{
struct hostent *hp;
struct sockaddr_in ad;
+ gint ret;
+
+ g_return_val_if_fail(sock != NULL, -1);
+ g_return_val_if_fail(sock->hostname != NULL && sock->port > 0, -1);
resolver_init();
@@ -828,24 +845,32 @@ static gint sock_connect_by_hostname(gint sock, const gchar *hostname,
ad.sin_family = AF_INET;
ad.sin_port = htons(port);
- if (!my_inet_aton(hostname, &ad.sin_addr)) {
- if ((hp = my_gethostbyname(hostname)) == NULL) {
- fprintf(stderr, "%s: unknown host.\n", hostname);
+ if (!my_inet_aton(sock->hostname, &ad.sin_addr)) {
+ if ((hp = my_gethostbyname(sock->hostname)) == NULL) {
+ fprintf(stderr, "%s: unknown host.\n", sock->hostname);
errno = 0;
+ sock->state = CONN_LOOKUPFAILED;
return -1;
}
if (hp->h_length != 4 && hp->h_length != 8) {
- fprintf(stderr, "illegal address length received for host %s\n", hostname);
+ fprintf(stderr, "illegal address length received for host %s\n", sock->hostname);
errno = 0;
+ sock->state = CONN_LOOKUPFAILED;
return -1;
}
memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
}
- return sock_connect_with_timeout(sock, (struct sockaddr *)&ad,
- sizeof(ad), io_timeout);
+ sock->state = CONN_LOOKUPSUCCESS;
+
+ ret = sock_connect_with_timeout(sock->sock, (struct sockaddr *)&ad,
+ sizeof(ad), io_timeout);
+ if (ret < 0)
+ sock->state = CONN_FAILED;
+ else
+ sock->state = CONN_ESTABLISHED;
}
#else /* INET6 */
@@ -982,13 +1007,16 @@ const gchar *gai_strerror(gint errcode)
}
#endif
-static SockDesc sock_connect_by_getaddrinfo(const gchar *hostname, gushort port)
+static SockDesc sock_info_connect_by_getaddrinfo(SockInfo *sockinfo)
{
SockDesc sock = INVALID_SOCKET;
gint gai_error;
struct addrinfo hints, *res, *ai;
gchar port_str[6];
+ g_return_val_if_fail(sockinfo != NULL, INVALID_SOCKET);
+ g_return_val_if_fail(sockinfo->hostname != NULL && sockinfo->port > 0, INVALID_SOCKET);
+
resolver_init();
memset(&hints, 0, sizeof(hints));
@@ -998,11 +1026,12 @@ static SockDesc sock_connect_by_getaddrinfo(const gchar *hostname, gushort port)
hints.ai_protocol = IPPROTO_TCP;
/* convert port from integer to string. */
- g_snprintf(port_str, sizeof(port_str), "%d", port);
+ g_snprintf(port_str, sizeof(port_str), "%d", sockinfo->port);
- if ((gai_error = getaddrinfo(hostname, port_str, &hints, &res)) != 0) {
+ if ((gai_error = getaddrinfo(sockinfo->hostname, port_str, &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo for %s:%s failed: %s\n",
- hostname, port_str, gai_strerror(gai_error));
+ sockinfo->hostname, port_str, gai_strerror(gai_error));
+ sockinfo->state = CONN_LOOKUPFAILED;
return INVALID_SOCKET;
}
@@ -1022,22 +1051,45 @@ static SockDesc sock_connect_by_getaddrinfo(const gchar *hostname, gushort port)
if (res != NULL)
freeaddrinfo(res);
- if (ai == NULL)
+ if (ai == NULL) {
+ sockinfo->state = CONN_FAILED;
return INVALID_SOCKET;
+ }
+ sockinfo->state = CONN_ESTABLISHED;
return sock;
}
#endif /* !INET6 */
SockInfo *sock_connect(const gchar *hostname, gushort port)
{
- SockDesc sock;
SockInfo *sockinfo;
-#ifdef INET6
- sock = sock_connect_by_getaddrinfo(hostname, port);
- if (!SOCKET_IS_VALID(sock))
+ sockinfo = sock_new(hostname, port);
+ if (sock_info_connect(sockinfo) < 0) {
+ sock_close(sockinfo);
return NULL;
+ }
+
+ return sockinfo;
+}
+
+gint sock_info_connect(SockInfo *sockinfo)
+{
+ SockDesc sock;
+#ifndef INET6
+ gint ret;
+#endif
+
+ g_return_val_if_fail(sockinfo != NULL, -1);
+ g_return_val_if_fail(sockinfo->hostname != NULL && sockinfo->port > 0,
+ -1);
+
+#ifdef INET6
+ sock = sock_info_connect_by_getaddrinfo(sockinfo);
+ if (!SOCKET_IS_VALID(sock)) {
+ return -1;
+ }
#else
sock = socket(AF_INET, SOCK_STREAM, 0);
if (!SOCKET_IS_VALID(sock)) {
@@ -1046,30 +1098,29 @@ SockInfo *sock_connect(const gchar *hostname, gushort port)
#else
perror("socket");
#endif /* G_OS_WIN32 */
- return NULL;
+ sockinfo->state = CONN_FAILED;
+ return -1;
}
sock_set_buffer_size(sock);
- if (sock_connect_by_hostname(sock, hostname, port) < 0) {
+ sockinfo->sock = sock;
+ if ((ret = sock_info_connect_by_hostname(sockinfo)) < 0) {
if (errno != 0) perror("connect");
fd_close(sock);
- return NULL;
+ sockinfo->sock = INVALID_SOCKET;
+ return ret;
}
#endif /* INET6 */
- sockinfo = g_new0(SockInfo, 1);
sockinfo->sock = sock;
sockinfo->sock_ch = g_io_channel_unix_new(sock);
- sockinfo->hostname = g_strdup(hostname);
- sockinfo->port = port;
- sockinfo->state = CONN_ESTABLISHED;
sockinfo->flags = SYL_SOCK_CHECK_IO;
sock_list = g_list_prepend(sock_list, sockinfo);
g_usleep(100000);
- return sockinfo;
+ return 0;
}
#ifdef G_OS_UNIX
@@ -1126,11 +1177,9 @@ static gboolean sock_connect_async_cb(GIOChannel *source,
return FALSE;
}
- sockinfo = g_new0(SockInfo, 1);
+ sockinfo = conn_data->sock;
sockinfo->sock = fd;
sockinfo->sock_ch = g_io_channel_unix_new(fd);
- sockinfo->hostname = g_strdup(conn_data->hostname);
- sockinfo->port = conn_data->port;
sockinfo->state = CONN_ESTABLISHED;
sockinfo->flags = SYL_SOCK_NONBLOCK;
@@ -1138,6 +1187,7 @@ static gboolean sock_connect_async_cb(GIOChannel *source,
conn_data->func(sockinfo, conn_data->data);
+ conn_data->sock = NULL;
sock_connect_async_cancel(conn_data->id);
return FALSE;
@@ -1158,22 +1208,40 @@ static gint sock_connect_async_get_address_info_cb(GList *addr_list,
gint sock_connect_async(const gchar *hostname, gushort port,
SockConnectFunc func, gpointer data)
{
+ SockInfo *sock;
+ gint ret;
+
+ sock = sock_new(hostname, port);
+ ret = sock_info_connect_async(sock, func, data);
+ if (ret < 0)
+ sock_close(sock);
+
+ return ret;
+}
+
+gint sock_info_connect_async(SockInfo *sock, SockConnectFunc func,
+ gpointer data)
+{
static gint id = 1;
SockConnectData *conn_data;
+ g_return_val_if_fail(sock != NULL, -1);
+ g_return_val_if_fail(sock->hostname != NULL && sock->port > 0, -1);
+
conn_data = g_new0(SockConnectData, 1);
conn_data->id = id++;
- conn_data->hostname = g_strdup(hostname);
- conn_data->port = port;
+ conn_data->hostname = g_strdup(sock->hostname);
+ conn_data->port = sock->port;
conn_data->addr_list = NULL;
conn_data->cur_addr = NULL;
conn_data->io_tag = 0;
+ conn_data->sock = sock;
conn_data->func = func;
conn_data->data = data;
conn_data->lookup_data = sock_get_address_info_async
- (hostname, port, sock_connect_async_get_address_info_cb,
- conn_data);
+ (sock->hostname, sock->port,
+ sock_connect_async_get_address_info_cb, conn_data);
if (conn_data->lookup_data == NULL) {
g_free(conn_data->hostname);
@@ -1213,6 +1281,8 @@ gint sock_connect_async_cancel(gint id)
g_io_channel_shutdown(conn_data->channel, FALSE, NULL);
g_io_channel_unref(conn_data->channel);
}
+ if (conn_data->sock)
+ sock_close(conn_data->sock);
sock_address_list_free(conn_data->addr_list);
g_free(conn_data->hostname);
@@ -1230,6 +1300,15 @@ static gint sock_connect_address_list_async(SockConnectData *conn_data)
SockAddrData *addr_data;
gint sock = -1;
+ if (conn_data->addr_list == NULL) {
+ g_warning("sock_connect_address_list_async: "
+ "DNS lookup for %s failed", conn_data->hostname);
+ conn_data->sock->state = CONN_LOOKUPFAILED;
+ conn_data->func(conn_data->sock, conn_data->data);
+ sock_connect_async_cancel(conn_data->id);
+ return -1;
+ }
+
for (; conn_data->cur_addr != NULL;
conn_data->cur_addr = conn_data->cur_addr->next) {
addr_data = (SockAddrData *)conn_data->cur_addr->data;
@@ -1256,9 +1335,10 @@ static gint sock_connect_address_list_async(SockConnectData *conn_data)
if (conn_data->cur_addr == NULL) {
g_warning("sock_connect_address_list_async: "
- "connection to %s:%d failed\n",
+ "connection to %s:%d failed",
conn_data->hostname, conn_data->port);
- conn_data->func(NULL, conn_data->data);
+ conn_data->sock->state = CONN_FAILED;
+ conn_data->func(conn_data->sock, conn_data->data);
sock_connect_async_cancel(conn_data->id);
return -1;
}
@@ -1319,7 +1399,7 @@ static gboolean sock_get_address_info_async_cb(GIOChannel *source,
break;
if (ai_member[0] == AF_UNSPEC) {
- g_warning("DNS lookup failed\n");
+ g_warning("DNS lookup failed");
break;
}
@@ -1412,7 +1492,7 @@ static SockLookupData *sock_get_address_info_async(const gchar *hostname,
gai_err = getaddrinfo(hostname, port_str, &hints, &res);
if (gai_err != 0) {
- g_warning("getaddrinfo for %s:%s failed: %s\n",
+ g_warning("getaddrinfo for %s:%s failed: %s",
hostname, port_str, gai_strerror(gai_err));
fd_write_all(pipe_fds[1], (gchar *)ai_member,
sizeof(ai_member));
@@ -1507,14 +1587,15 @@ static gpointer sock_connect_async_func(gpointer data)
SockConnectData *conn_data = (SockConnectData *)data;
gint ret;
- conn_data->sock = sock_connect(conn_data->hostname, conn_data->port);
+ ret = sock_info_connect(conn_data->sock);
- if (conn_data->sock) {
+ if (ret == 0) {
debug_print("sock_connect_async_func: connected\n");
- ret = 0;
} else {
- debug_print("sock_connect_async_func: connection failed\n");
- ret = -1;
+ if (conn_data->sock->state == CONN_LOOKUPFAILED)
+ debug_print("sock_connect_async_func: DNS lookup failed\n");
+ else
+ debug_print("sock_connect_async_func: connection failed\n");
}
g_atomic_int_set(&conn_data->flag, 1);
@@ -1526,15 +1607,31 @@ static gpointer sock_connect_async_func(gpointer data)
gint sock_connect_async_thread(const gchar *hostname, gushort port)
{
+ SockInfo *sock;
+ gint ret;
+
+ sock = sock_new(hostname, port);
+ ret = sock_info_connect_async_thread(sock);
+ if (ret < 0)
+ sock_close(sock);
+
+ return ret;
+}
+
+gint sock_info_connect_async_thread(SockInfo *sock)
+{
static gint id = 1;
SockConnectData *data;
+ g_return_val_if_fail(sock != NULL, -1);
+ g_return_val_if_fail(sock->hostname != NULL && sock->port > 0, -1);
+
data = g_new0(SockConnectData, 1);
data->id = id++;
- data->hostname = g_strdup(hostname);
- data->port = port;
+ data->hostname = g_strdup(sock->hostname);
+ data->port = sock->port;
data->flag = 0;
- data->sock = NULL;
+ data->sock = sock;
data->thread = g_thread_create(sock_connect_async_func, data, TRUE,
NULL);
@@ -1551,6 +1648,22 @@ gint sock_connect_async_thread(const gchar *hostname, gushort port)
gint sock_connect_async_thread_wait(gint id, SockInfo **sock)
{
+ gint ret;
+
+ *sock = NULL;
+ ret = sock_info_connect_async_thread_wait(id, sock);
+ if (ret < 0) {
+ if (*sock) {
+ sock_close(*sock);
+ *sock = NULL;
+ }
+ }
+
+ return ret;
+}
+
+gint sock_info_connect_async_thread_wait(gint id, SockInfo **sock)
+{
SockConnectData *conn_data = NULL;
GList *cur;
gint ret;
@@ -1563,7 +1676,7 @@ gint sock_connect_async_thread_wait(gint id, SockInfo **sock)
}
if (!conn_data) {
- g_warning("sock_connect_async_thread_wait: id %d not found.", id);
+ g_warning("sock_info_connect_async_thread_wait: id %d not found.", id);
return -1;
}
@@ -1572,9 +1685,10 @@ gint sock_connect_async_thread_wait(gint id, SockInfo **sock)
event_loop_iterate();
ret = GPOINTER_TO_INT(g_thread_join(conn_data->thread));
- debug_print("sock_connect_async_thread_wait: thread exited with status %d\n", ret);
+ debug_print("sock_info_connect_async_thread_wait: thread exited with status %d\n", ret);
- *sock = conn_data->sock;
+ if (sock)
+ *sock = conn_data->sock;
sock_connect_data_list = g_list_remove(sock_connect_data_list,
conn_data);
@@ -1973,6 +2087,8 @@ gint sock_close(SockInfo *sock)
if (!sock)
return 0;
+ debug_print("sock_close: %s:%u (%p)\n", sock->hostname ? sock->hostname : "(none)", sock->port, sock);
+
#if USE_SSL
if (sock->ssl)
ssl_done_socket(sock);
diff --git a/libsylph/socket.h b/libsylph/socket.h
index 64d2d6a1..9c761305 100644
--- a/libsylph/socket.h
+++ b/libsylph/socket.h
@@ -86,6 +86,8 @@ gint sock_cleanup (void);
gint sock_set_io_timeout (guint sec);
+SockInfo *sock_new (const gchar *hostname, gushort port);
+
gint sock_set_nonblocking_mode (SockInfo *sock, gboolean nonblock);
gboolean sock_is_nonblocking_mode (SockInfo *sock);
@@ -109,6 +111,16 @@ gint sock_connect_async_thread (const gchar *hostname, gushort port);
gint sock_connect_async_thread_wait (gint id, SockInfo **sock);
#endif
+gint sock_info_connect (SockInfo *sock);
+#ifdef G_OS_UNIX
+gint sock_info_connect_async (SockInfo *sock,
+ SockConnectFunc func, gpointer data);
+#endif
+#if USE_THREADS
+gint sock_info_connect_async_thread (SockInfo *sock);
+gint sock_info_connect_async_thread_wait(gint id, SockInfo **sock);
+#endif
+
/* Basic I/O functions */
gint sock_printf (SockInfo *sock, const gchar *format, ...)
G_GNUC_PRINTF(2, 3);
diff --git a/src/inc.c b/src/inc.c
index bd86daf8..f464926e 100644
--- a/src/inc.c
+++ b/src/inc.c
@@ -867,6 +867,10 @@ static gint inc_start(IncProgressDialog *inc_dialog, GSList **count_list)
SET_PIXMAP_AND_TEXT(ok_pixbuf, _("Done"), msg);
g_free(msg);
break;
+ case INC_LOOKUP_ERROR:
+ SET_PIXMAP_AND_TEXT(error_pixbuf,
+ _("Server not found"), NULL);
+ break;
case INC_CONNECT_ERROR:
SET_PIXMAP_AND_TEXT(error_pixbuf,
_("Connection failed"), NULL);
@@ -1017,6 +1021,8 @@ static IncState inc_pop3_session_do(IncSession *session)
SESSION(pop3_session)->server,
SESSION(pop3_session)->port);
session->inc_state = INC_CONNECT_ERROR;
+ if (session_get_error(SESSION(pop3_session)) == SESSION_ERROR_LOOKUP)
+ session->inc_state = INC_LOOKUP_ERROR;
statusbar_pop_all();
return INC_CONNECT_ERROR;
}
@@ -1036,6 +1042,8 @@ static IncState inc_pop3_session_do(IncSession *session)
session->inc_state = INC_CONNECT_ERROR;
else
session->inc_state = INC_ERROR;
+ if (session_get_error(SESSION(pop3_session)) == SESSION_ERROR_LOOKUP)
+ session->inc_state = INC_LOOKUP_ERROR;
break;
case SESSION_EOF:
session->inc_state = INC_EOF;
@@ -1522,6 +1530,12 @@ static void inc_put_error(IncState istate, const gchar *msg)
gboolean fatal_error = FALSE;
switch (istate) {
+ case INC_LOOKUP_ERROR:
+ log_msg = _("Server not found.");
+ if (prefs_common.no_recv_err_panel)
+ break;
+ err_msg = g_strdup(log_msg);
+ break;
case INC_CONNECT_ERROR:
log_msg = _("Connection failed.");
if (prefs_common.no_recv_err_panel)
diff --git a/src/inc.h b/src/inc.h
index 5f30c076..f971e1ea 100644
--- a/src/inc.h
+++ b/src/inc.h
@@ -47,7 +47,8 @@ typedef enum
INC_SOCKET_ERROR,
INC_EOF,
INC_TIMEOUT,
- INC_CANCEL
+ INC_CANCEL,
+ INC_LOOKUP_ERROR
} IncState;
struct _IncProgressDialog
diff --git a/src/send_message.c b/src/send_message.c
index b7abd141..2c910069 100644
--- a/src/send_message.c
+++ b/src/send_message.c
@@ -997,7 +997,11 @@ static void send_put_error(Session *session)
default:
switch (session->state) {
case SESSION_ERROR:
- if (SMTP_SESSION(session)->state == SMTP_READY) {
+ if (session_get_error(session) == SESSION_ERROR_LOOKUP) {
+ log_msg = _("Server not found.");
+ err_msg = g_strdup_printf
+ (_("SMTP server not found: %s:%d"), session->server, session->port);
+ } else if (SMTP_SESSION(session)->state == SMTP_READY) {
log_msg = _("Can't connect to SMTP server.");
err_msg = g_strdup_printf
(_("Can't connect to SMTP server: %s:%d"), session->server, session->port);