From: Vsevolod Stakhov Date: Tue, 18 Oct 2011 14:56:51 +0000 (+0300) Subject: Add universal utility function for creating stream sockets. X-Git-Tag: 0.4.5~47 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=89c8b90f8e52f9274996ffb6a2b0dc1214ea1010;p=rspamd.git Add universal utility function for creating stream sockets. --- diff --git a/src/lmtp_proto.c b/src/lmtp_proto.c index a8c462b03..1ea64ddf4 100644 --- a/src/lmtp_proto.c +++ b/src/lmtp_proto.c @@ -452,7 +452,7 @@ lmtp_deliver_mta (struct worker_task *task) if (task->cfg->deliver_family == AF_UNIX) { un = alloca (sizeof (struct sockaddr_un)); - sock = make_unix_socket (task->cfg->deliver_host, un, FALSE); + sock = make_unix_socket (task->cfg->deliver_host, un, FALSE, TRUE); } else { sock = make_tcp_socket (&task->cfg->deliver_addr, task->cfg->deliver_port, FALSE, TRUE); diff --git a/src/main.c b/src/main.c index 25e9dd562..e470a1e8b 100644 --- a/src/main.c +++ b/src/main.c @@ -473,7 +473,7 @@ create_listen_socket (struct in_addr *addr, gint port, gint family, gchar *path) } else { un_addr = (struct sockaddr_un *)alloca (sizeof (struct sockaddr_un)); - if (!un_addr || (listen_sock = make_unix_socket (path, un_addr, TRUE)) == -1) { + if (!un_addr || (listen_sock = make_unix_socket (path, un_addr, TRUE, TRUE)) == -1) { msg_err ("cannot create unix listen socket. %s", strerror (errno)); } } diff --git a/src/smtp_utils.c b/src/smtp_utils.c index 27dffd275..1ed92ead6 100644 --- a/src/smtp_utils.c +++ b/src/smtp_utils.c @@ -78,7 +78,7 @@ create_smtp_upstream_connection (struct smtp_session *session) /* Now try to create socket */ if (selected->is_unix) { un = alloca (sizeof (struct sockaddr_un)); - session->upstream_sock = make_unix_socket (selected->name, un, FALSE); + session->upstream_sock = make_unix_socket (selected->name, un, FALSE, TRUE); } else { session->upstream_sock = make_tcp_socket (&selected->addr, selected->port, FALSE, TRUE); diff --git a/src/util.c b/src/util.c index 01936474e..3ddfe3b61 100644 --- a/src/util.c +++ b/src/util.c @@ -215,7 +215,7 @@ accept_from_socket (gint listen_sock, struct sockaddr *addr, socklen_t * len) } gint -make_unix_socket (const gchar *path, struct sockaddr_un *addr, gboolean is_server) +make_unix_socket (const gchar *path, struct sockaddr_un *addr, gboolean is_server, gboolean async) { gint fd, s_error, r, optlen, serrno, on = 1; @@ -258,6 +258,20 @@ make_unix_socket (const gchar *path, struct sockaddr_un *addr, gboolean is_serve msg_warn ("bind/connect failed: %d, '%s'", errno, strerror (errno)); goto out; } + if (!async) { + /* Try to poll */ + if (poll_sync_socket (fd, CONNECT_TIMEOUT * 1000, POLLOUT) <= 0) { + errno = ETIMEDOUT; + msg_warn ("bind/connect failed: timeout"); + goto out; + } + else { + /* Make synced again */ + if (make_socket_blocking (fd) < 0) { + goto out; + } + } + } } else { /* Still need to check SO_ERROR on socket */ @@ -279,6 +293,78 @@ make_unix_socket (const gchar *path, struct sockaddr_un *addr, gboolean is_serve return (-1); } +/** + * Make universal stream socket + * @param credits host, ip or path to unix socket + * @param port port (used for network sockets) + * @param async make this socket asynced + * @param is_server make this socket as server socket + * @param try_resolve try name resolution for a socket (BLOCKING) + */ +gint +make_universal_stream_socket (const gchar *credits, guint16 port, gboolean async, gboolean is_server, gboolean try_resolve) +{ + struct sockaddr_un un; + struct stat st; + struct in_addr in; + struct hostent *he; + gint r; + + if (*credits == '/') { + r = stat (credits, &st); + if (is_server) { + if (r == -1) { + return make_unix_socket (credits, &un, is_server, async); + } + else { + /* Unix socket exists, it must be unlinked first */ + errno = EEXIST; + return -1; + } + } + else { + if (r == -1) { + /* Unix socket doesn't exists it must be created first */ + errno = ENOENT; + return -1; + } + else { + if ((st.st_mode & S_IFSOCK) == 0) { + /* Path is not valid socket */ + errno = EINVAL; + return -1; + } + else { + return make_unix_socket (credits, &un, is_server, async); + } + } + } + } + else { + /* TCP related part */ + if (inet_aton (credits, &in) == 0) { + /* Try to resolve */ + if (try_resolve) { + if ((he = gethostbyname (credits)) == NULL) { + errno = ENOENT; + return -1; + } + else { + memcpy (&in, he->h_addr, sizeof (struct in_addr)); + return make_tcp_socket (&in, port, is_server, async); + } + } + else { + errno = ENOENT; + return -1; + } + } + else { + return make_tcp_socket (&in, port, is_server, async); + } + } +} + gint make_socketpair (gint pair[2]) { diff --git a/src/util.h b/src/util.h index 7a5a00915..7bdf3bdc4 100644 --- a/src/util.h +++ b/src/util.h @@ -44,7 +44,18 @@ gint accept_from_socket (gint listen_sock, struct sockaddr *addr, socklen_t *len /* * Create and bind or connect unix socket */ -gint make_unix_socket (const gchar *, struct sockaddr_un *, gboolean is_server); +gint make_unix_socket (const gchar *, struct sockaddr_un *, gboolean is_server, gboolean async); + +/** + * Make universal stream socket + * @param credits host, ip or path to unix socket + * @param port port (used for network sockets) + * @param async make this socket asynced + * @param is_server make this socket as server socket + * @param try_resolve try name resolution for a socket (BLOCKING) + */ +gint make_universal_stream_socket (const gchar *credits, guint16 port, + gboolean async, gboolean is_server, gboolean try_resolve); /* * Create socketpair