summaryrefslogtreecommitdiffstats
path: root/common/socket.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2018-10-14 03:11:38 +0200
committerGravatar Nikias Bassen2018-10-14 03:11:38 +0200
commit80fe6e859302cb771bb6b6f10feb1766d765778b (patch)
treed8a0c4408dc312f0b137d60fed9ff0b77fdca684 /common/socket.c
parentf5a7387a54ae08c9cd1d83a415393e0e909dc6e6 (diff)
downloadlibusbmuxd-80fe6e859302cb771bb6b6f10feb1766d765778b.tar.gz
libusbmuxd-80fe6e859302cb771bb6b6f10feb1766d765778b.tar.bz2
Allow using non-standard usbmuxd socket address via environment variable
By using USBMUXD_SOCKET_ADDRESS environment variable, it is possible to make libusbmuxd connect to the specified address. The value needs to be in format ADDRESS:PORT (or UNIX:PATH on unix systems). If no port number is specified or parsing fails, the standard socket address (or unix domain socket file path) will be used silently.
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;
}