Blame common/socket.c

Packit f228a3
/*
Packit f228a3
 * socket.c
Packit f228a3
 *
Packit f228a3
 * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org>
Packit f228a3
 * Copyright (C) 2012 Nikias Bassen <nikias@gmx.li>
Packit f228a3
 *
Packit f228a3
 * This library is free software; you can redistribute it and/or
Packit f228a3
 * modify it under the terms of the GNU Lesser General Public
Packit f228a3
 * License as published by the Free Software Foundation; either
Packit f228a3
 * version 2.1 of the License, or (at your option) any later version.
Packit f228a3
 *
Packit f228a3
 * This library is distributed in the hope that it will be useful,
Packit f228a3
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit f228a3
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit f228a3
 * Lesser General Public License for more details.
Packit f228a3
 *
Packit f228a3
 * You should have received a copy of the GNU Lesser General Public
Packit f228a3
 * License along with this library; if not, write to the Free Software
Packit f228a3
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit f228a3
 */
Packit f228a3
Packit f228a3
#include <stdio.h>
Packit f228a3
#include <stddef.h>
Packit f228a3
#include <stdlib.h>
Packit f228a3
#include <string.h>
Packit f228a3
#include <unistd.h>
Packit f228a3
#include <errno.h>
Packit f228a3
#include <sys/time.h>
Packit f228a3
#include <sys/stat.h>
Packit f228a3
#ifdef WIN32
Packit f228a3
#include <winsock2.h>
Packit f228a3
#include <windows.h>
Packit f228a3
static int wsa_init = 0;
Packit f228a3
#else
Packit f228a3
#include <sys/socket.h>
Packit f228a3
#include <sys/un.h>
Packit f228a3
#include <netinet/in.h>
Packit f228a3
#include <netdb.h>
Packit f228a3
#include <arpa/inet.h>
Packit f228a3
#endif
Packit f228a3
#include "socket.h"
Packit f228a3
Packit f228a3
#define RECV_TIMEOUT 20000
Packit f228a3
Packit f228a3
static int verbose = 0;
Packit f228a3
Packit f228a3
void socket_set_verbose(int level)
Packit f228a3
{
Packit f228a3
	verbose = level;
Packit f228a3
}
Packit f228a3
Packit f228a3
#ifndef WIN32
Packit f228a3
int socket_create_unix(const char *filename)
Packit f228a3
{
Packit f228a3
	struct sockaddr_un name;
Packit f228a3
	int sock;
Packit f228a3
	size_t size;
Packit f228a3
#ifdef SO_NOSIGPIPE
Packit f228a3
	int yes = 1;
Packit f228a3
#endif
Packit f228a3
Packit f228a3
	// remove if still present
Packit f228a3
	unlink(filename);
Packit f228a3
Packit f228a3
	/* Create the socket. */
Packit f228a3
	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
Packit f228a3
	if (sock < 0) {
Packit f228a3
		perror("socket");
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
#ifdef SO_NOSIGPIPE
Packit f228a3
	if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
Packit f228a3
		perror("setsockopt()");
Packit f228a3
		socket_close(sock);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
#endif
Packit f228a3
Packit f228a3
	/* Bind a name to the socket. */
Packit f228a3
	name.sun_family = AF_LOCAL;
Packit f228a3
	strncpy(name.sun_path, filename, sizeof(name.sun_path));
Packit f228a3
	name.sun_path[sizeof(name.sun_path) - 1] = '\0';
Packit f228a3
Packit f228a3
	/* The size of the address is
Packit f228a3
	   the offset of the start of the filename,
Packit f228a3
	   plus its length,
Packit f228a3
	   plus one for the terminating null byte.
Packit f228a3
	   Alternatively you can just do:
Packit f228a3
	   size = SUN_LEN (&name);
Packit f228a3
	 */
Packit f228a3
	size = (offsetof(struct sockaddr_un, sun_path)
Packit f228a3
			+ strlen(name.sun_path) + 1);
Packit f228a3
Packit f228a3
	if (bind(sock, (struct sockaddr *) &name, size) < 0) {
Packit f228a3
		perror("bind");
Packit f228a3
		socket_close(sock);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	if (listen(sock, 10) < 0) {
Packit f228a3
		perror("listen");
Packit f228a3
		socket_close(sock);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	return sock;
Packit f228a3
}
Packit f228a3
Packit f228a3
int socket_connect_unix(const char *filename)
Packit f228a3
{
Packit f228a3
	struct sockaddr_un name;
Packit f228a3
	int sfd = -1;
Packit f228a3
	size_t size;
Packit f228a3
	struct stat fst;
Packit f228a3
#ifdef SO_NOSIGPIPE
Packit f228a3
	int yes = 1;
Packit f228a3
#endif
Packit f228a3
Packit f228a3
	// check if socket file exists...
Packit f228a3
	if (stat(filename, &fst) != 0) {
Packit f228a3
		if (verbose >= 2)
Packit f228a3
			fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename,
Packit f228a3
					strerror(errno));
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
	// ... and if it is a unix domain socket
Packit f228a3
	if (!S_ISSOCK(fst.st_mode)) {
Packit f228a3
		if (verbose >= 2)
Packit f228a3
			fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__,
Packit f228a3
					filename);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
	// make a new socket
Packit f228a3
	if ((sfd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
Packit f228a3
		if (verbose >= 2)
Packit f228a3
			fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno));
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
#ifdef SO_NOSIGPIPE
Packit f228a3
	if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
Packit f228a3
		perror("setsockopt()");
Packit f228a3
		socket_close(sfd);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
#endif
Packit f228a3
Packit f228a3
	// and connect to 'filename'
Packit f228a3
	name.sun_family = AF_LOCAL;
Packit f228a3
	strncpy(name.sun_path, filename, sizeof(name.sun_path));
Packit f228a3
	name.sun_path[sizeof(name.sun_path) - 1] = 0;
Packit f228a3
Packit f228a3
	size = (offsetof(struct sockaddr_un, sun_path)
Packit f228a3
			+ strlen(name.sun_path) + 1);
Packit f228a3
Packit f228a3
	if (connect(sfd, (struct sockaddr *) &name, size) < 0) {
Packit f228a3
		socket_close(sfd);
Packit f228a3
		if (verbose >= 2)
Packit f228a3
			fprintf(stderr, "%s: connect: %s\n", __func__,
Packit f228a3
					strerror(errno));
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	return sfd;
Packit f228a3
}
Packit f228a3
#endif
Packit f228a3
Packit f228a3
int socket_create(uint16_t port)
Packit f228a3
{
Packit f228a3
	int sfd = -1;
Packit f228a3
	int yes = 1;
Packit f228a3
#ifdef WIN32
Packit f228a3
	WSADATA wsa_data;
Packit f228a3
	if (!wsa_init) {
Packit f228a3
		if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
Packit f228a3
			fprintf(stderr, "WSAStartup failed!\n");
Packit f228a3
			ExitProcess(-1);
Packit f228a3
		}
Packit f228a3
		wsa_init = 1;
Packit f228a3
	}
Packit f228a3
#endif
Packit f228a3
	struct sockaddr_in saddr;
Packit f228a3
Packit f228a3
	if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
Packit f228a3
		perror("socket()");
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
Packit f228a3
		perror("setsockopt()");
Packit f228a3
		socket_close(sfd);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
#ifdef SO_NOSIGPIPE
Packit f228a3
	if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
Packit f228a3
		perror("setsockopt()");
Packit f228a3
		socket_close(sfd);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
#endif
Packit f228a3
Packit f228a3
	memset((void *) &saddr, 0, sizeof(saddr));
Packit f228a3
	saddr.sin_family = AF_INET;
Packit Service 60b028
	saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
Packit f228a3
	saddr.sin_port = htons(port);
Packit f228a3
Packit f228a3
	if (0 > bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr))) {
Packit f228a3
		perror("bind()");
Packit f228a3
		socket_close(sfd);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	if (listen(sfd, 1) == -1) {
Packit f228a3
		perror("listen()");
Packit f228a3
		socket_close(sfd);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	return sfd;
Packit f228a3
}
Packit f228a3
Packit f228a3
int socket_connect(const char *addr, uint16_t port)
Packit f228a3
{
Packit f228a3
	int sfd = -1;
Packit f228a3
	int yes = 1;
Packit f228a3
	struct hostent *hp;
Packit f228a3
	struct sockaddr_in saddr;
Packit f228a3
#ifdef WIN32
Packit f228a3
	WSADATA wsa_data;
Packit f228a3
	if (!wsa_init) {
Packit f228a3
		if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
Packit f228a3
			fprintf(stderr, "WSAStartup failed!\n");
Packit f228a3
			ExitProcess(-1);
Packit f228a3
		}
Packit f228a3
		wsa_init = 1;
Packit f228a3
	}
Packit f228a3
#endif
Packit f228a3
Packit f228a3
	if (!addr) {
Packit f228a3
		errno = EINVAL;
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	if ((hp = gethostbyname(addr)) == NULL) {
Packit f228a3
		if (verbose >= 2)
Packit f228a3
			fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	if (!hp->h_addr) {
Packit f228a3
		if (verbose >= 2)
Packit f228a3
			fprintf(stderr, "%s: gethostbyname returned NULL address!\n",
Packit f228a3
					__func__);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
Packit f228a3
		perror("socket()");
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
Packit f228a3
		perror("setsockopt()");
Packit f228a3
		socket_close(sfd);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
#ifdef SO_NOSIGPIPE
Packit f228a3
	if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
Packit f228a3
		perror("setsockopt()");
Packit f228a3
		socket_close(sfd);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
#endif
Packit f228a3
Packit f228a3
	memset((void *) &saddr, 0, sizeof(saddr));
Packit f228a3
	saddr.sin_family = AF_INET;
Packit f228a3
	saddr.sin_addr.s_addr = *(uint32_t *) hp->h_addr;
Packit f228a3
	saddr.sin_port = htons(port);
Packit f228a3
Packit f228a3
	if (connect(sfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
Packit f228a3
		perror("connect");
Packit f228a3
		socket_close(sfd);
Packit f228a3
		return -2;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	return sfd;
Packit f228a3
}
Packit f228a3
Packit f228a3
int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout)
Packit f228a3
{
Packit f228a3
	fd_set fds;
Packit f228a3
	int sret;
Packit f228a3
	int eagain;
Packit f228a3
	struct timeval to;
Packit f228a3
	struct timeval *pto;
Packit f228a3
Packit f228a3
	if (fd < 0) {
Packit f228a3
		if (verbose >= 2)
Packit f228a3
			fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd);
Packit f228a3
		return -1;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	FD_ZERO(&fds);
Packit f228a3
	FD_SET(fd, &fds);
Packit f228a3
Packit f228a3
	if (timeout > 0) {
Packit f228a3
		to.tv_sec = (time_t) (timeout / 1000);
Packit f228a3
		to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
Packit f228a3
		pto = &to;
Packit f228a3
	} else {
Packit f228a3
		pto = NULL;
Packit f228a3
	}
Packit f228a3
Packit f228a3
	sret = -1;
Packit f228a3
Packit f228a3
	do {
Packit f228a3
		eagain = 0;
Packit f228a3
		switch (fdm) {
Packit f228a3
		case FDM_READ:
Packit f228a3
			sret = select(fd + 1, &fds, NULL, NULL, pto);
Packit f228a3
			break;
Packit f228a3
		case FDM_WRITE:
Packit f228a3
			sret = select(fd + 1, NULL, &fds, NULL, pto);
Packit f228a3
			break;
Packit f228a3
		case FDM_EXCEPT:
Packit f228a3
			sret = select(fd + 1, NULL, NULL, &fds, pto);
Packit f228a3
			break;
Packit f228a3
		default:
Packit f228a3
			return -1;
Packit f228a3
		}
Packit f228a3
Packit f228a3
		if (sret < 0) {
Packit f228a3
			switch (errno) {
Packit f228a3
			case EINTR:
Packit f228a3
				// interrupt signal in select
Packit f228a3
				if (verbose >= 2)
Packit f228a3
					fprintf(stderr, "%s: EINTR\n", __func__);
Packit f228a3
				eagain = 1;
Packit f228a3
				break;
Packit f228a3
			case EAGAIN:
Packit f228a3
				if (verbose >= 2)
Packit f228a3
					fprintf(stderr, "%s: EAGAIN\n", __func__);
Packit f228a3
				break;
Packit f228a3
			default:
Packit f228a3
				if (verbose >= 2)
Packit f228a3
					fprintf(stderr, "%s: select failed: %s\n", __func__,
Packit f228a3
							strerror(errno));
Packit f228a3
				return -1;
Packit f228a3
			}
Packit f228a3
		}
Packit f228a3
	} while (eagain);
Packit f228a3
Packit f228a3
	return sret;
Packit f228a3
}
Packit f228a3
Packit f228a3
int socket_accept(int fd, uint16_t port)
Packit f228a3
{
Packit f228a3
#ifdef WIN32
Packit f228a3
	int addr_len;
Packit f228a3
#else
Packit f228a3
	socklen_t addr_len;
Packit f228a3
#endif
Packit f228a3
	int result;
Packit f228a3
	struct sockaddr_in addr;
Packit f228a3
Packit f228a3
	memset(&addr, 0, sizeof(addr));
Packit f228a3
	addr.sin_family = AF_INET;
Packit Service 60b028
	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
Packit f228a3
	addr.sin_port = htons(port);
Packit f228a3
Packit f228a3
	addr_len = sizeof(addr);
Packit f228a3
	result = accept(fd, (struct sockaddr*)&addr, &addr_len);
Packit f228a3
Packit f228a3
	return result;
Packit f228a3
}
Packit f228a3
Packit f228a3
int socket_shutdown(int fd, int how)
Packit f228a3
{
Packit f228a3
	return shutdown(fd, how);
Packit f228a3
}
Packit f228a3
Packit f228a3
int socket_close(int fd) {
Packit f228a3
#ifdef WIN32
Packit f228a3
	return closesocket(fd);
Packit f228a3
#else
Packit f228a3
	return close(fd);
Packit f228a3
#endif
Packit f228a3
}
Packit f228a3
Packit f228a3
int socket_receive(int fd, void *data, size_t length)
Packit f228a3
{
Packit f228a3
	return socket_receive_timeout(fd, data, length, 0, RECV_TIMEOUT);
Packit f228a3
}
Packit f228a3
Packit f228a3
int socket_peek(int fd, void *data, size_t length)
Packit f228a3
{
Packit f228a3
	return socket_receive_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT);
Packit f228a3
}
Packit f228a3
Packit f228a3
int socket_receive_timeout(int fd, void *data, size_t length, int flags,
Packit f228a3
					 unsigned int timeout)
Packit f228a3
{
Packit f228a3
	int res;
Packit f228a3
	int result;
Packit f228a3
Packit f228a3
	// check if data is available
Packit f228a3
	res = socket_check_fd(fd, FDM_READ, timeout);
Packit f228a3
	if (res <= 0) {
Packit f228a3
		return res;
Packit f228a3
	}
Packit f228a3
	// if we get here, there _is_ data available
Packit f228a3
	result = recv(fd, data, length, flags);
Packit f228a3
	if (res > 0 && result == 0) {
Packit f228a3
		// but this is an error condition
Packit f228a3
		if (verbose >= 3)
Packit f228a3
			fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
Packit f228a3
		return -EAGAIN;
Packit f228a3
	}
Packit f228a3
	if (result < 0) {
Packit f228a3
		return -errno;
Packit f228a3
	}
Packit f228a3
	return result;
Packit f228a3
}
Packit f228a3
Packit f228a3
int socket_send(int fd, void *data, size_t length)
Packit f228a3
{
Packit f228a3
	int flags = 0;
Packit f228a3
#ifdef MSG_NOSIGNAL
Packit f228a3
	flags |= MSG_NOSIGNAL;
Packit f228a3
#endif
Packit f228a3
	return send(fd, data, length, flags);
Packit f228a3
}