summaryrefslogtreecommitdiffstats
path: root/common/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/socket.c')
-rw-r--r--common/socket.c113
1 files changed, 82 insertions, 31 deletions
diff --git a/common/socket.c b/common/socket.c
index 0fb4ba8..a2f8eec 100644
--- a/common/socket.c
+++ b/common/socket.c
@@ -1,8 +1,8 @@
/*
* socket.c
*
+ * Copyright (C) 2012-2018 Nikias Bassen <nikias@gmx.li>
* Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org>
- * Copyright (C) 2012 Nikias Bassen <nikias@gmx.li>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
@@ -29,6 +32,7 @@
#include <sys/stat.h>
#ifdef WIN32
#include <winsock2.h>
+#include <ws2tcpip.h>
#include <windows.h>
static int wsa_init = 0;
#else
@@ -38,10 +42,12 @@ static int wsa_init = 0;
#include <netinet/tcp.h>
#include <netdb.h>
#include <arpa/inet.h>
+#include <fcntl.h>
#endif
#include "socket.h"
#define RECV_TIMEOUT 20000
+#define CONNECT_TIMEOUT 5000
static int verbose = 0;
@@ -82,7 +88,7 @@ int socket_create_unix(const char *filename)
strncpy(name.sun_path, filename, sizeof(name.sun_path));
name.sun_path[sizeof(name.sun_path) - 1] = '\0';
- if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) {
+ if (bind(sock, (struct sockaddr*)&name, sizeof(name)) < 0) {
perror("bind");
socket_close(sock);
return -1;
@@ -143,7 +149,6 @@ int socket_connect_unix(const char *filename)
return -1;
}
#endif
-
// and connect to 'filename'
name.sun_family = AF_UNIX;
strncpy(name.sun_path, filename, sizeof(name.sun_path));
@@ -221,9 +226,13 @@ int socket_connect(const char *addr, uint16_t port)
int sfd = -1;
int yes = 1;
int bufsize = 0x20000;
- struct hostent *hp;
- struct sockaddr_in saddr;
+ struct addrinfo hints;
+ struct addrinfo *result, *rp;
+ char portstr[8];
+ int res;
#ifdef WIN32
+ u_long l_yes = 1;
+ u_long l_no = 0;
WSADATA wsa_data;
if (!wsa_init) {
if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
@@ -232,6 +241,8 @@ int socket_connect(const char *addr, uint16_t port)
}
wsa_init = 1;
}
+#else
+ int flags = 0;
#endif
if (!addr) {
@@ -239,30 +250,81 @@ int socket_connect(const char *addr, uint16_t port)
return -1;
}
- if ((hp = gethostbyname(addr)) == NULL) {
- if (verbose >= 2)
- fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr);
- return -1;
- }
+ memset(&hints, '\0', sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
+ hints.ai_protocol = IPPROTO_TCP;
- if (!hp->h_addr) {
- if (verbose >= 2)
- fprintf(stderr, "%s: gethostbyname returned NULL address!\n",
- __func__);
+ sprintf(portstr, "%d", port);
+
+ res = getaddrinfo(addr, portstr, &hints, &result);
+ if (res != 0) {
+ fprintf(stderr, "%s: getaddrinfo: %s\n", __func__, gai_strerror(res));
return -1;
}
- if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
- perror("socket()");
- return -1;
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if (sfd == -1) {
+ continue;
+ }
+
+ if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
+ perror("setsockopt()");
+ close(sfd);
+ continue;
+ }
+
+#ifdef WIN32
+ ioctlsocket(sfd, FIONBIO, &l_yes);
+#else
+ fcntl(sfd, F_SETFL, O_NONBLOCK);
+#endif
+
+ if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) {
+ break;
+ }
+#ifdef WIN32
+ if (WSAGetLastError() == WSAEWOULDBLOCK)
+#else
+ if (errno == EINPROGRESS)
+#endif
+ {
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(sfd, &fds);
+
+ struct timeval timeout;
+ timeout.tv_sec = CONNECT_TIMEOUT / 1000;
+ timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
+ if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
+ int so_error;
+ socklen_t len = sizeof(so_error);
+ getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
+ if (so_error == 0) {
+ break;
+ }
+ }
+ }
+ close(sfd);
}
- if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
- perror("setsockopt()");
- socket_close(sfd);
+ freeaddrinfo(result);
+
+ if (rp == NULL) {
+ if (verbose >= 2)
+ fprintf(stderr, "%s: Could not connect to %s:%d\n", __func__, addr, port);
return -1;
}
+#ifdef WIN32
+ ioctlsocket(sfd, FIONBIO, &l_no);
+#else
+ flags = fcntl(sfd, F_GETFL, 0);
+ fcntl(sfd, F_SETFL, flags & (~O_NONBLOCK));
+#endif
+
#ifdef SO_NOSIGPIPE
if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
perror("setsockopt()");
@@ -283,17 +345,6 @@ int socket_connect(const char *addr, uint16_t port)
perror("Could not set receive buffer for socket");
}
- memset((void *) &saddr, 0, sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = *(uint32_t *) hp->h_addr;
- saddr.sin_port = htons(port);
-
- if (connect(sfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
- perror("connect");
- socket_close(sfd);
- return -2;
- }
-
return sfd;
}