summaryrefslogtreecommitdiffstats
path: root/src/util.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2013-05-31 17:45:18 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2013-05-31 17:45:18 +0100
commit8cc2aee8859731ee2fe280070423f79e7d009ca3 (patch)
tree76951e59a1285c02ae50a89cbf69fcbb11f89b6b /src/util.c
parent7b3682ce3c78d26dd75782f931611bd09bcc76a5 (diff)
downloadrspamd-8cc2aee8859731ee2fe280070423f79e7d009ca3.tar.gz
rspamd-8cc2aee8859731ee2fe280070423f79e7d009ca3.zip
Use getaddrinfo when opening sockets.
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c167
1 files changed, 82 insertions, 85 deletions
diff --git a/src/util.c b/src/util.c
index 9c4d8bf4c..8d7bf69ad 100644
--- a/src/util.c
+++ b/src/util.c
@@ -87,94 +87,88 @@ poll_sync_socket (gint fd, gint timeout, short events)
}
static gint
-make_inet_socket (gint family, struct in_addr *addr, u_short port, gboolean is_server, gboolean async)
+make_inet_socket (gint family, struct addrinfo *addr, gboolean is_server, gboolean async)
{
gint fd, r, optlen, on = 1, s_error;
- gint serrno;
- struct sockaddr_in sin;
-
- /* Create socket */
- fd = socket (AF_INET, family, 0);
- if (fd == -1) {
- msg_warn ("socket failed: %d, '%s'", errno, strerror (errno));
- return -1;
- }
-
- if (make_socket_nonblocking (fd) < 0) {
- goto out;
- }
-
- /* Set close on exec */
- if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) {
- msg_warn ("fcntl failed: %d, '%s'", errno, strerror (errno));
- goto out;
- }
-
- memset (&sin, 0, sizeof (sin));
-
- /* Bind options */
- sin.sin_family = AF_INET;
- sin.sin_port = htons (port);
- sin.sin_addr.s_addr = addr->s_addr;
+ struct addrinfo *cur;
+
+ cur = addr;
+ while (cur) {
+ /* Create socket */
+ fd = socket (cur->ai_protocol, family, 0);
+ if (fd == -1) {
+ msg_warn ("socket failed: %d, '%s'", errno, strerror (errno));
+ goto out;
+ }
- if (is_server) {
- setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
- r = bind (fd, (struct sockaddr *)&sin, sizeof (struct sockaddr_in));
- }
- else {
- r = connect (fd, (struct sockaddr *)&sin, sizeof (struct sockaddr_in));
- }
+ if (make_socket_nonblocking (fd) < 0) {
+ goto out;
+ }
- if (r == -1) {
- if (errno != EINPROGRESS) {
- msg_warn ("bind/connect failed: %d, '%s'", errno, strerror (errno));
+ /* Set close on exec */
+ if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) {
+ msg_warn ("fcntl 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");
+
+ if (is_server) {
+ setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
+ r = bind (fd, cur->ai_addr, cur->ai_addrlen);
+ }
+ else {
+ r = connect (fd, cur->ai_addr, cur->ai_addrlen);
+ }
+
+ if (r == -1) {
+ if (errno != EINPROGRESS) {
+ msg_warn ("bind/connect failed: %d, '%s'", errno, strerror (errno));
goto out;
}
- else {
- /* Make synced again */
- if (make_socket_blocking (fd) < 0) {
+ 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 */
- optlen = sizeof (s_error);
- getsockopt (fd, SOL_SOCKET, SO_ERROR, (void *)&s_error, &optlen);
- if (s_error) {
- errno = s_error;
- goto out;
+ else {
+ /* Still need to check SO_ERROR on socket */
+ optlen = sizeof (s_error);
+ getsockopt (fd, SOL_SOCKET, SO_ERROR, (void *)&s_error, &optlen);
+ if (s_error) {
+ errno = s_error;
+ goto out;
+ }
+ }
+ break;
+out:
+ if (fd != -1) {
+ close (fd);
}
+ fd = -1;
+ cur = cur->ai_next;
}
-
-
return (fd);
-
- out:
- serrno = errno;
- close (fd);
- errno = serrno;
- return (-1);
}
gint
-make_tcp_socket (struct in_addr *addr, u_short port, gboolean is_server, gboolean async)
+make_tcp_socket (struct addrinfo *addr, gboolean is_server, gboolean async)
{
- return make_inet_socket (SOCK_STREAM, addr, port, is_server, async);
+ return make_inet_socket (SOCK_STREAM, addr, is_server, async);
}
gint
-make_udp_socket (struct in_addr *addr, u_short port, gboolean is_server, gboolean async)
+make_udp_socket (struct addrinfo *addr, gboolean is_server, gboolean async)
{
- return make_inet_socket (SOCK_DGRAM, addr, port, is_server, async);
+ return make_inet_socket (SOCK_DGRAM, addr, is_server, async);
}
gint
@@ -304,9 +298,9 @@ make_universal_stream_socket (const gchar *credits, guint16 port, gboolean async
{
struct sockaddr_un un;
struct stat st;
- struct in_addr in;
- struct hostent *he;
- gint r;
+ struct addrinfo hints, *res;
+ gint r;
+ gchar portbuf[8];
if (*credits == '/') {
r = stat (credits, &st);
@@ -340,25 +334,28 @@ make_universal_stream_socket (const gchar *credits, guint16 port, gboolean 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;
- }
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
+ hints.ai_socktype = SOCK_STREAM; /* Stream socket */
+ hints.ai_flags = is_server ? AI_PASSIVE : 0;
+ hints.ai_protocol = 0; /* Any protocol */
+ hints.ai_canonname = NULL;
+ hints.ai_addr = NULL;
+ hints.ai_next = NULL;
+
+ if (!try_resolve) {
+ hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
+ }
+
+ rspamd_snprintf (portbuf, sizeof (portbuf), "%d", (int)port);
+ if ((r = getaddrinfo (credits, portbuf, &hints, &res)) == 0) {
+ r = make_tcp_socket (res, is_server, async);
+ freeaddrinfo (res);
+ return r;
}
else {
- return make_tcp_socket (&in, port, is_server, async);
+ msg_err ("address resolution for %s failed: %s", credits, gai_strerror (r));
+ return FALSE;
}
}
}