diff options
| -rw-r--r-- | common/socket.c | 193 | ||||
| -rw-r--r-- | common/socket.h | 5 | 
2 files changed, 187 insertions, 11 deletions
| diff --git a/common/socket.c b/common/socket.c index 7111749..cf6e9eb 100644 --- a/common/socket.c +++ b/common/socket.c @@ -1,7 +1,7 @@  /*   * socket.c   * - * Copyright (C) 2012-2018 Nikias Bassen <nikias@gmx.li> + * Copyright (C) 2012-2020 Nikias Bassen <nikias@gmx.li>   * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org>   *   * This library is free software; you can redistribute it and/or @@ -49,6 +49,9 @@ static int wsa_init = 0;  #define RECV_TIMEOUT 20000  #define CONNECT_TIMEOUT 5000 +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT 102 +#endif  #ifndef ECONNRESET  #define ECONNRESET 108  #endif @@ -63,6 +66,59 @@ void socket_set_verbose(int level)  	verbose = level;  } +const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size) +{ +#ifdef WIN32 +	WSADATA wsa_data; +	if (!wsa_init) { +		if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { +			fprintf(stderr, "WSAStartup failed!\n"); +			ExitProcess(-1); +		} +		wsa_init = 1; +	} +	DWORD addr_out_len = addr_out_size; +	DWORD addrlen = 0; + +	if (addr->sa_family == AF_INET) { +		addrlen = sizeof(struct sockaddr_in); +	} +#ifdef AF_INET6 +	else if (addr->sa_family == AF_INET6) { +		addrlen = sizeof(struct sockaddr_in6); +	} +#endif +	else { +		errno = EAFNOSUPPORT; +		return NULL; +	} + +	if (WSAAddressToString(addr, addrlen, NULL, addr_out, &addr_out_len) == 0) { +		return addr_out; +	} +#else +	const void *addrdata = NULL; + +	if (addr->sa_family == AF_INET) { +		addrdata = &((struct sockaddr_in*)addr)->sin_addr; +	} +#ifdef AF_INET6 +	else if (addr->sa_family == AF_INET6) { +		addrdata = &((struct sockaddr_in6*)addr)->sin6_addr; +	} +#endif +	else { +		errno = EAFNOSUPPORT; +		return NULL; +	} + +	if (inet_ntop(addr->sa_family, addrdata, addr_out, addr_out_size)) { +		return addr_out; +	} +#endif +	return NULL; +} +  #ifndef WIN32  int socket_create_unix(const char *filename)  { @@ -254,6 +310,124 @@ int socket_create(uint16_t port)  	return sfd;  } +int socket_connect_addr(struct sockaddr* addr, uint16_t port) +{ +	int sfd = -1; +	int yes = 1; +	int bufsize = 0x20000; +	int addrlen = 0; +#ifdef WIN32 +	u_long l_yes = 1; +	WSADATA wsa_data; +	if (!wsa_init) { +		if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { +			fprintf(stderr, "WSAStartup failed!\n"); +			ExitProcess(-1); +		} +		wsa_init = 1; +	} +#endif + +	if (addr->sa_family == AF_INET) { +		struct sockaddr_in* addr_in = (struct sockaddr_in*)addr; +		addr_in->sin_port = htons(port); +		addrlen = sizeof(struct sockaddr_in); +	} +#ifdef AF_INET6 +	else if (addr->sa_family == AF_INET6) { +		struct sockaddr_in6* addr_in = (struct sockaddr_in6*)addr; +		addr_in->sin6_port = htons(port); +		addrlen = sizeof(struct sockaddr_in6); +	} +#endif +	else { +		fprintf(stderr, "ERROR: Unsupported address family"); +		return -1; +	} + +	sfd = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); +	if (sfd == -1) { +		perror("socket()"); +		return -1; +	} + +#ifdef SO_NOSIGPIPE +	if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { +		perror("setsockopt()"); +		socket_close(sfd); +		return -1; +	} +#endif + +	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { +		perror("setsockopt()"); +		socket_close(sfd); +		return -1; +	} + +#ifdef WIN32 +	ioctlsocket(sfd, FIONBIO, &l_yes); +#else +	int flags = fcntl(sfd, F_GETFL, 0); +	fcntl(sfd, F_SETFL, flags | O_NONBLOCK); +#endif + +	do { +		if (connect(sfd, addr, 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) { +					errno = 0; +					break; +				} +				errno = so_error; +			} +		} +		socket_close(sfd); +		sfd = -1; +	} while (0); + +	if (sfd < 0) { +		if (verbose >= 2) { +			char addrtxt[48]; +			socket_addr_to_string(addr, addrtxt, sizeof(addrtxt)); +			fprintf(stderr, "%s: Could not connect to %s port %d\n", __func__, addrtxt, port); +		} +		return -1; +	} + +	if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) { +		perror("Could not set TCP_NODELAY on socket"); +	} + +	if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) { +		perror("Could not set send buffer for socket"); +	} + +	if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) { +		perror("Could not set receive buffer for socket"); +	} + +	return sfd; +} +  int socket_connect(const char *addr, uint16_t port)  {  	int sfd = -1; @@ -265,7 +439,6 @@ int socket_connect(const char *addr, uint16_t port)  	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) { @@ -303,6 +476,14 @@ int socket_connect(const char *addr, uint16_t port)  			continue;  		} +#ifdef SO_NOSIGPIPE +		if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { +			perror("setsockopt()"); +			socket_close(sfd); +			return -1; +		} +#endif +  		if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {  			perror("setsockopt()");  			socket_close(sfd); @@ -352,14 +533,6 @@ int socket_connect(const char *addr, uint16_t port)  		return -1;  	} -#ifdef SO_NOSIGPIPE -	if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { -		perror("setsockopt()"); -		socket_close(sfd); -		return -1; -	} -#endif -  	if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) {  		perror("Could not set TCP_NODELAY on socket");  	} diff --git a/common/socket.h b/common/socket.h index e31de6b..38eeddf 100644 --- a/common/socket.h +++ b/common/socket.h @@ -1,8 +1,8 @@  /*   * socket.h   * + * Copyright (C) 2012-2020 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 @@ -46,6 +46,7 @@ int socket_create_unix(const char *filename);  int socket_connect_unix(const char *filename);  #endif  int socket_create(uint16_t port); +int socket_connect_addr(struct sockaddr *addr, uint16_t port);  int socket_connect(const char *addr, uint16_t port);  int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout);  int socket_accept(int fd, uint16_t port); @@ -62,4 +63,6 @@ int socket_send(int fd, void *data, size_t size);  void socket_set_verbose(int level); +const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size); +  #endif	/* SOCKET_SOCKET_H */ | 
