Skip to content

Commit

Permalink
Allow using non-standard usbmuxd socket address via environment variable
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nikias committed Oct 14, 2018
1 parent f5a7387 commit 80fe6e8
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 31 deletions.
113 changes: 82 additions & 31 deletions common/socket.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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>
Expand All @@ -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
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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) {
Expand All @@ -232,37 +241,90 @@ int socket_connect(const char *addr, uint16_t port)
}
wsa_init = 1;
}
#else
int flags = 0;
#endif

if (!addr) {
errno = EINVAL;
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()");
Expand All @@ -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;
}

Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ case ${host_os} in
*mingw32*|*cygwin*)
AC_MSG_RESULT([yes])
win32=true
AC_DEFINE(WINVER, 0x0501, [minimum Windows version])
;;
darwin*)
AC_MSG_RESULT([no])
Expand Down
44 changes: 44 additions & 0 deletions src/libusbmuxd.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,50 @@ static usbmuxd_device_info_t *devices_find(uint32_t handle)
*/
static int connect_usbmuxd_socket()
{
char *usbmuxd_socket_addr = getenv("USBMUXD_SOCKET_ADDRESS");
if (usbmuxd_socket_addr) {
if (strncmp(usbmuxd_socket_addr, "UNIX:", 5) == 0) {
#if defined(WIN32) || defined(__CYGWIN__)
/* not supported, ignore */
#else
if (usbmuxd_socket_addr[5] != '\0') {
return socket_connect_unix(usbmuxd_socket_addr+5);
}
#endif
} else {
uint16_t port = 0;
char *p = strrchr(usbmuxd_socket_addr, ':');
if (p) {
char *endp = NULL;
long l_port = strtol(p+1, &endp, 10);
if (endp && *endp == '\0') {
if (l_port > 0 && l_port < 65536) {
port = (uint16_t)l_port;
}
}
}
if (p && port > 0) {
char *connect_addr = NULL;
if (usbmuxd_socket_addr[0] == '[') {
connect_addr = strdup(usbmuxd_socket_addr+1);
connect_addr[p - usbmuxd_socket_addr - 1] = '\0';
p = strrchr(connect_addr, ']');
if (p) {
*p = '\0';
}
} else {
connect_addr = strdup(usbmuxd_socket_addr);
connect_addr[p - usbmuxd_socket_addr] = '\0';
}
if (connect_addr && *connect_addr != '\0') {
int res = socket_connect(connect_addr, port);
free(connect_addr);
return res;
}
free(connect_addr);
}
}
}
#if defined(WIN32) || defined(__CYGWIN__)
return socket_connect("127.0.0.1", USBMUXD_SOCKET_PORT);
#else
Expand Down

0 comments on commit 80fe6e8

Please sign in to comment.