diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 31 | ||||
| -rw-r--r-- | src/libusbmuxd.c | 248 | ||||
| -rw-r--r-- | src/main.c | 1447 | ||||
| -rw-r--r-- | src/sock_stuff.c | 301 | ||||
| -rw-r--r-- | src/sock_stuff.h | 28 | ||||
| -rw-r--r-- | src/usbmux.c | 1264 | ||||
| -rw-r--r-- | src/usbmux.h | 53 | ||||
| -rw-r--r-- | src/usbmuxd-proto.h | 52 | ||||
| -rw-r--r-- | src/usbmuxd.h | 91 | 
9 files changed, 0 insertions, 3515 deletions
| diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index 547870e..0000000 --- a/src/Makefile.am +++ /dev/null @@ -1,31 +0,0 @@ -AM_CFLAGS = $(GLOBAL_CFLAGS) $(libusb_CFLAGS) -AM_LDFLAGS = $(libusb_LIBS) -lpthread -lrt - -# Libraries - -noinst_LTLIBRARIES = libusbmux.la libsock_stuff.la -libsock_stuff_la_SOURCES = sock_stuff.c \ -			   sock_stuff.h - -libusbmux_la_SOURCES = usbmux.c \ -		       usbmux.h -libusbmux_la_CFLAGS = $(AM_CFLAGS) -libusbmux_la_LDFLAGS = $(AM_LDFLAGS) - -lib_LTLIBRARIES = libusbmuxd.la -libusbmuxd_la_SOURCES = libusbmuxd.c \ -		        usbmuxd.h \ -		        usbmuxd-proto.h -libusbmuxd_la_LIBADD = libsock_stuff.la - -include_HEADERS = usbmuxd.h \ -		  usbmuxd-proto.h - -# Programs - -sbin_PROGRAMS = usbmuxd - -usbmuxd_SOURCES = main.c -usbmuxd_LDADD = libusbmux.la \ -	        libsock_stuff.la - diff --git a/src/libusbmuxd.c b/src/libusbmuxd.c deleted file mode 100644 index 4cd0a6d..0000000 --- a/src/libusbmuxd.c +++ /dev/null @@ -1,248 +0,0 @@ -#include <stdint.h> -#include <stdlib.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <unistd.h> - -// usbmuxd public interface -#include <usbmuxd.h> -// usbmuxd protocol  -#include <usbmuxd-proto.h> -// socket utility functions -#include "sock_stuff.h" - -static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t * result) -{ -	struct usbmuxd_result res; -	int recv_len; - -	if (!result) { -		return -EINVAL; -	} - -	if ((recv_len = recv_buf(sfd, &res, sizeof(res))) <= 0) { -		perror("recv"); -		return -errno; -	} else { -		if ((recv_len == sizeof(res)) -			&& (res.header.length == (uint32_t) recv_len) -			&& (res.header.reserved == 0) -			&& (res.header.type == USBMUXD_RESULT) -			) { -			*result = res.result; -			if (res.header.tag == tag) { -				return 1; -			} else { -				return 0; -			} -		} -	} - -	return -1; -} - -int usbmuxd_scan(usbmuxd_scan_result ** available_devices) -{ -	struct usbmuxd_scan_request s_req; -	int sfd; -	int scan_success = 0; -	uint32_t res; -	uint32_t pktlen; -	int recv_len; -	usbmuxd_scan_result *newlist = NULL; -	struct usbmuxd_device_info_record dev_info_pkt; -	int dev_cnt = 0; - -	sfd = connect_unix_socket(USBMUXD_SOCKET_FILE); -	if (sfd < 0) { -		fprintf(stderr, "%s: error opening socket!\n", __func__); -		return sfd; -	} - -	s_req.header.length = sizeof(struct usbmuxd_scan_request); -	s_req.header.reserved = 0; -	s_req.header.type = USBMUXD_SCAN; -	s_req.header.tag = 2; - -	// send scan request packet -	if (send_buf(sfd, &s_req, s_req.header.length) == -		(int) s_req.header.length) { -		res = -1; -		// get response -		if (usbmuxd_get_result(sfd, s_req.header.tag, &res) && (res == 0)) { -			scan_success = 1; -		} else { -			fprintf(stderr, -					"%s: Did not get response to scan request (with result=0)...\n", -					__func__); -			close(sfd); -			return res; -		} -	} - -	if (!scan_success) { -		fprintf(stderr, "%s: Could not send scan request!\n", __func__); -		return -1; -	} - -	*available_devices = NULL; -	// receive device list -	while (1) { -		if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) { -			if (pktlen != sizeof(dev_info_pkt)) { -				// invalid packet size received! -				fprintf(stderr, -						"%s: Invalid packet size (%d) received when expecting a device info record.\n", -						__func__, pktlen); -				break; -			} - -			recv_len = recv_buf(sfd, &dev_info_pkt, pktlen); -			if (recv_len <= 0) { -				fprintf(stderr, -						"%s: Error when receiving device info record\n", -						__func__); -				break; -			} else if ((uint32_t) recv_len < pktlen) { -				fprintf(stderr, -						"%s: received less data than specified in header!\n", -						__func__); -			} else { -				//fprintf(stderr, "%s: got device record with id %d, UUID=%s\n", __func__, dev_info_pkt.device_info.device_id, dev_info_pkt.device_info.serial_number); -				newlist = -					(usbmuxd_scan_result *) realloc(*available_devices, -													sizeof -													(usbmuxd_scan_result) * -													(dev_cnt + 1)); -				if (newlist) { -					newlist[dev_cnt].handle = -						(int) dev_info_pkt.device.device_id; -					newlist[dev_cnt].product_id = -						dev_info_pkt.device.product_id; -					memset(newlist[dev_cnt].serial_number, '\0', -						   sizeof(newlist[dev_cnt].serial_number)); -					memcpy(newlist[dev_cnt].serial_number, -						   dev_info_pkt.device.serial_number, -						   sizeof(dev_info_pkt.device.serial_number)); -					*available_devices = newlist; -					dev_cnt++; -				} else { -					fprintf(stderr, -							"%s: ERROR: out of memory when trying to realloc!\n", -							__func__); -					break; -				} -			} -		} else { -			// we _should_ have all of them now. -			// or perhaps an error occured. -			break; -		} -	} - -	// terminating zero record -	newlist = -		(usbmuxd_scan_result *) realloc(*available_devices, -										sizeof(usbmuxd_scan_result) * -										(dev_cnt + 1)); -	memset(newlist + dev_cnt, 0, sizeof(usbmuxd_scan_result)); -	*available_devices = newlist; - -	return dev_cnt; -} - -int usbmuxd_connect(const int handle, const unsigned short tcp_port) -{ -	int sfd; -	struct usbmuxd_connect_request c_req; -	int connected = 0; -	uint32_t res = -1; - -	sfd = connect_unix_socket(USBMUXD_SOCKET_FILE); -	if (sfd < 0) { -		fprintf(stderr, "%s: Error: Connection to usbmuxd failed: %s\n", -				__func__, strerror(errno)); -		return sfd; -	} - -	c_req.header.length = sizeof(c_req); -	c_req.header.reserved = 0; -	c_req.header.type = USBMUXD_CONNECT; -	c_req.header.tag = 3; -	c_req.device_id = (uint32_t) handle; -	c_req.tcp_dport = htons(tcp_port); -	c_req.reserved = 0; - -	if (send_buf(sfd, &c_req, sizeof(c_req)) < 0) { -		perror("send"); -	} else { -		// read ACK -		//fprintf(stderr, "%s: Reading connect result...\n", __func__); -		if (usbmuxd_get_result(sfd, c_req.header.tag, &res)) { -			if (res == 0) { -				//fprintf(stderr, "%s: Connect success!\n", __func__); -				connected = 1; -			} else { -				fprintf(stderr, "%s: Connect failed, Error code=%d\n", -						__func__, res); -			} -		} -	} - -	if (connected) { -		return sfd; -	} - -	close(sfd); - -	return -1; -} - -int usbmuxd_disconnect(int sfd) -{ -	return close(sfd); -} - -int usbmuxd_send(int sfd, const char *data, uint32_t len, uint32_t *sent_bytes) -{ -	int num_sent; - -	if (sfd < 0) { -		return -EINVAL; -	} -	 -	num_sent = send(sfd, (void*)data, len, 0); -	if (num_sent < 0) { -		*sent_bytes = 0; -		fprintf(stderr, "%s: Error %d when sending: %s\n", __func__, num_sent, strerror(errno)); -		return num_sent; -	} else if ((uint32_t)num_sent < len) { -		fprintf(stderr, "%s: Warning: Did not send enough (only %d of %d)\n", __func__, num_sent, len); -	} - -	*sent_bytes = num_sent; - -	return 0; -} - -int usbmuxd_recv_timeout(int sfd, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) -{ -	int num_recv = recv_buf_timeout(sfd, (void*)data, len, 0, timeout); -	if (num_recv < 0) { -		*recv_bytes = 0; -		return num_recv; -	} - -	*recv_bytes = num_recv; - -	return 0; -} - -int usbmuxd_recv(int sfd, char *data, uint32_t len, uint32_t *recv_bytes) -{ -	return usbmuxd_recv_timeout(sfd, data, len, recv_bytes, 5000); -} - diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 19649b1..0000000 --- a/src/main.c +++ /dev/null @@ -1,1447 +0,0 @@ -/* - * usbmuxd -- daemon for communication with iPhone/iPod via USB - *  - * Copyright (c) 2009 Nikias Bassen. All Rights Reserved. - * Based upon iTunnel source code, Copyright (c) 2008 Jing Su. - *  http://www.cs.toronto.edu/~jingsu/itunnel/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  - */ -#include <stddef.h> -#include <stdio.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <getopt.h> -#include <stdarg.h> -#include <syslog.h> -#include <fcntl.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <sys/stat.h> -#include <arpa/inet.h> -#include <unistd.h> -#include <signal.h> -#include <pthread.h> -#include <stdint.h> -#include <usb.h> -#include <pwd.h> - -#include "usbmuxd-proto.h" -#include "sock_stuff.h" - -#include "usbmux.h" - -#define DEFAULT_TIMEOUT 4000 -#define DEFAULT_CHILDREN_CAPACITY 10 -#define DEBUG_LEVEL 0 - -#define LOCKFILE "/var/run/usbmuxd.lock" - -#define THREAD (unsigned int)pthread_self() - -static int quit_flag = 0; -static int fsock = -1; -static int verbose = DEBUG_LEVEL; -static int foreground = 0; -static int exit_on_no_devices = 0; -static int drop_privileges = 0; -static int opt_udev = 0; -static int opt_exit = 0; -static int exit_signal = 0; - -struct device_info { -	uint32_t device_id; -	usbmux_device_t phone; -	int use_count; -	pthread_t bulk_reader; -	pthread_mutex_t mutex; -	/* mutex for mutual exclusion of calling the usbmux_send function -	 * TODO: I don't know if we need really need this? */ -	pthread_mutex_t writer_mutex; -}; - -struct client_data { -	volatile int dead; -	int socket; -	int tag; -	pthread_t thread; -	pthread_t handler; -	pthread_t reader; -	int reader_quit; -	int reader_dead; -	int handler_dead; -	int connected; -	usbmux_client_t muxclient; -	struct device_info *dev; -}; - -static struct device_info **devices = NULL; -static int device_count = 0; -static pthread_mutex_t usbmux_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t usb_mutex = PTHREAD_MUTEX_INITIALIZER; - -/** - * logs a message to syslog when running as daemon or to stdout/stderr when - * running in foreground. - * @param prio The logging priority. - * @param format The message to be printed. - */ -static void logmsg(int prio, const char *format, ...) -{ -	va_list args; -	va_start(args, format); - -	if (!foreground) { -		// daemon. log using syslog. -		vsyslog(prio, format, args); -	} else { -		// running in foreground. log to stdout/stderr. -		char msgbuf[256]; -		FILE *lfp = stdout; -		switch (prio) { -		case LOG_EMERG: -		case LOG_ALERT: -		case LOG_CRIT: -		case LOG_ERR: -		case LOG_WARNING: -			lfp = stderr; -			break; -		default: -			lfp = stdout; -		} -		strcpy(msgbuf, "usbmuxd: "); -		vsnprintf(msgbuf + 9, 244, format, args); -		strcat(msgbuf, "\n"); -		fputs(msgbuf, lfp); -	} - -	va_end(args); -} - -#ifdef DEBUG -/** - * for debugging purposes. - */ -static void print_buffer(FILE * fp, const char *data, const int length) -{ -	int i; -	int j; -	unsigned char c; - -	for (i = 0; i < length; i += 16) { -		if (verbose >= 4) -			fprintf(fp, "%04x: ", i); -		for (j = 0; j < 16; j++) { -			if (i + j >= length) { -				if (verbose >= 4) -					fprintf(fp, "   "); -				continue; -			} -			if (verbose >= 4) -				fprintf(fp, "%02hhx ", *(data + i + j)); -		} -		if (verbose >= 4) -			fprintf(fp, "  | "); -		for (j = 0; j < 16; j++) { -			if (i + j >= length) -				break; -			c = *(data + i + j); -			if ((c < 32) || (c > 127)) { -				if (verbose >= 4) -					fprintf(fp, "."); -				continue; -			} -			if (verbose >= 4) -				fprintf(fp, "%c", c); -		} -		if (verbose >= 4) -			fprintf(fp, "\n"); -	} -	if (verbose >= 4) -		fprintf(fp, "\n"); -} -#endif - -/** - * Read incoming usbmuxd packet. If the packet is larger than - * the size specified by len, the data will be truncated. - * - * @param fd the file descriptor to read from. - * @param data pointer to a buffer to store the read data to. - * @param len the length of the data to be read. The buffer - *        pointed to by data should be at least len bytes in size. - * - * @return  - */ -static int usbmuxd_get_request(int fd, void **data, size_t len) -{ -	uint32_t pktlen; -	int recv_len; - -	if (peek_buf(fd, &pktlen, sizeof(pktlen)) < (int) sizeof(pktlen)) { -		return -errno; -	} - -	if (len == 0) { -		// allocate buffer space -		*data = malloc(pktlen); -	} else if (len < pktlen) { -		// target buffer is to small to hold this packet! fix it! -		if (verbose >= 2) -			logmsg(LOG_WARNING, -				   "%s: WARNING -- packet (%d) is larger than target buffer (%d)! Truncating.", -				   __func__, pktlen, len); -		pktlen = len; -	} - -	recv_len = recv_buf(fd, *data, pktlen); -	if ((recv_len > 0) && ((uint32_t) recv_len < pktlen)) { -		if (verbose >= 2) -			logmsg(LOG_WARNING, -				   "%s: Uh-oh, we got less than the packet's size, %d instead of %d...", -				   __func__, recv_len, pktlen); -	} -#ifdef DEBUG -	if (*data && (recv_len > 0) && verbose >= 4) { -		fprintf(stderr, "%s: received:\n", __func__); -		print_buffer(stderr, *data, recv_len); -	} -#endif - -	return recv_len; -} - -/** - * Send a usbmuxd result packet with given tag and result_code. - * - * @param fd the file descriptor to write to. - * @param tag the tag value that identifies where this message belongs to. - * @param result_code the error value (0 = Success, most likely errno values otherwise) - * - * @return the return value returned by send_buf (normally the number of bytes sent) - */ -static int usbmuxd_send_result(int fd, uint32_t tag, uint32_t result_code) -{ -	struct usbmuxd_result res; -	int ret; - -	res.header.length = sizeof(res); -	res.header.reserved = 0; -	res.header.type = USBMUXD_RESULT; -	res.header.tag = tag; -	res.result = result_code; - -	if (verbose >= 4) -		logmsg(LOG_NOTICE, "%s: tag=%d result=%d", __func__, -			   res.header.tag, res.result); - -	ret = send_buf(fd, &res, sizeof(res)); -	fsync(fd);					// let's get it sent -	return ret; -} - -/** - * this thread reads from the usb connection and writes the  - * data to the connected client. - * - * @param arg pointer to a client_data structure. - * - * @return NULL in any case - */ -static void *usbmuxd_client_reader_thread(void *arg) -{ -	struct client_data *cdata; - -	char rbuffer[512]; -	uint32_t rbuffersize = 512; -	uint32_t rlen; -	int err; -	char *cursor; -	ssize_t len; -	int result; - -	if (!arg) { -		if (verbose >= 2) -			logmsg(LOG_ERR, "%s: invalid client_data supplied!", __func__); -		cdata->reader_dead = 1; -		return NULL; -	} - -	cdata = (struct client_data *) arg; - -	cdata->reader_dead = 0; - -	if (verbose >= 3) -		logmsg(LOG_NOTICE, "%s[%x]: started (device %d:%d, use_count=%d)", __func__, THREAD, -			   cdata->dev->device_id >> 16, cdata->dev->device_id & 0xFFFF, cdata->dev->use_count); - -	while (!quit_flag && !cdata->reader_quit) { -		result = check_fd(cdata->socket, FD_WRITE, DEFAULT_TIMEOUT); -		if (result <= 0) { -			if (result < 0) { -				if (verbose >= 2) -					logmsg(LOG_ERR, "%s: select error: %s", __func__, -						   strerror(errno)); -			} -			continue; -		} - -		rlen = 0; -		err = -			usbmux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, -								&rlen, DEFAULT_TIMEOUT); -		if (err != 0) { -			if (verbose >= 2) -				logmsg(LOG_ERR, -					   "%s[%x]: encountered USB read error: %d", -					   __func__, THREAD, err); -			break; -		} - -		cursor = rbuffer; -		while (rlen > 0) { -			len = send_buf(cdata->socket, cursor, rlen); -			if (len <= 0) { -				logmsg(LOG_ERR, "%s: Error: send returned %d", __func__, -					   len); -				err = 1; -				break; -			} -			// calculate remainder -			rlen -= len; -			// advance cursor -			cursor += len; -		} -		if (err != 0) { -			logmsg(LOG_ERR, "%s: Error when writing to client...", -				   __func__); -			break; -		} -		fsync(cdata->socket); -	} - -	if (verbose >= 3) -		logmsg(LOG_NOTICE, "%s[%x]: terminated", __func__, THREAD); - -	cdata->reader_dead = 1; - -	return NULL; -} - -/** - * This function handles the connecting procedure to a previously - * set up usbmux client. - * Sends a usbmuxd result packet denoting success or failure. - * A successful result is mandatory for later communication. - * - * @param cdata pointer to a previously initialized client_data structure - * - * @return - */ -static int usbmuxd_handleConnectResult(struct client_data *cdata) -{ -	int result; -	char buffer[512]; -	char err_type[64]; -	int err_code; -	ssize_t maxlen = 512; -	uint32_t rlen; -	int err; - -	if (!cdata) { -		if (verbose >= 2) -			logmsg(LOG_ERR, "%s: Invalid client_data provided!", __func__); -		return -EINVAL; -	} - -	result = check_fd(cdata->socket, FD_WRITE, DEFAULT_TIMEOUT); -	if (result <= 0) { -		if (result < 0) { -			if (verbose >= 2) -				logmsg(LOG_ERR, "%s: select error: %s", __func__, -					   strerror(errno)); -			return result; -		} -	} else { -		result = 0; -		err = -			usbmux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, -								100); -		if (err < 0) { -			if (verbose >= 2) -				logmsg(LOG_ERR, "%s: encountered USB read error: %d", -					   __func__, err); -			usbmuxd_send_result(cdata->socket, cdata->tag, -err); -			return err; -		} else { -			if (rlen > 0) { -				if ((buffer[0] == 1) && (rlen > 20) -					&& !memcmp(buffer + 1, "handleConnectResult:", 20)) { -					// hm... we got an error message! -					buffer[rlen] = 0; -					if (verbose >= 1) -						logmsg(LOG_ERR, "%s: %s\n", __func__, buffer + 22); - -					if (sscanf -						(buffer + 22, "%s - %d\n", err_type, &err_code) -						== 2) { -						usbmuxd_send_result(cdata->socket, cdata->tag, -											err_code); -						return -err_code; -					} else { -						usbmuxd_send_result(cdata->socket, cdata->tag, -											ENODATA); -						return -ENODATA; -					} -				} else { -					// send success result -					usbmuxd_send_result(cdata->socket, cdata->tag, 0); -					// and the server greeting message -					send_buf(cdata->socket, buffer, rlen); -				} -			} else { -				// no server greeting? this seems to be ok. send success. -				usbmuxd_send_result(cdata->socket, cdata->tag, 0); -			} -		} -		//fsync(cdata->socket); -	} -	return result; -} - -/** - * This thread handles the communication between the connected iPhone/iPod - * and the client that created the connection. - */ -static void *usbmuxd_client_handler_thread(void *arg) -{ -	struct client_data *cdata; -	int result; -	char *cursor; -	char buffer[32740]; -	ssize_t len; -	ssize_t maxlen = sizeof(buffer); -	uint32_t wlen; -	int err; - -	if (!arg) { -		if (verbose >= 2) -			logmsg(LOG_ERR, "%s: invalid client_data provided!", __func__); -		return NULL; -	} - -	cdata = (struct client_data *) arg; - -	if (verbose >= 3) -		logmsg(LOG_NOTICE, "%s[%x]: started (device %d:%d, use_count=%d)", __func__, THREAD, -			   cdata->dev->device_id >> 16, cdata->dev->device_id & 0xFFFF, cdata->dev->use_count); - -	if (usbmuxd_handleConnectResult(cdata)) { -		if (verbose >= 3) -			logmsg(LOG_ERR, "handleConnectResult: Error"); -		goto leave; -	} else { -		if (verbose >= 3) -			logmsg(LOG_NOTICE, "handleConnectResult: Success"); -	} - -	// starting mux reader thread -	cdata->reader_quit = 0; -	cdata->reader_dead = 0; -	if (pthread_create -		(&cdata->reader, NULL, usbmuxd_client_reader_thread, cdata) != 0) { -		if (verbose >= 2) -			logmsg(LOG_ERR, "%s: could not start client_reader thread", -				   __func__); -		cdata->reader = 0; -	} - -	while (!quit_flag && !cdata->reader_dead) { -		result = check_fd(cdata->socket, FD_READ, DEFAULT_TIMEOUT); -		if (result <= 0) { -			if (result < 0) { -				if (verbose >= 3) -					logmsg(LOG_ERR, "%s[%x]: Error: checkfd: %s", __func__, THREAD, strerror(errno)); -			} -			continue; -		} -		// check_fd told us there's data available, so read from client -		// and push to USB device. -		len = recv(cdata->socket, buffer, maxlen, 0); -		if (len == 0) { -			break; -		} -		if (len < 0) { -			if (verbose >= 2) -				logmsg(LOG_ERR, "%s[%x]: Error: recv: %s", __func__, THREAD, strerror(errno)); -			break; -		} - -		cursor = buffer; - -		pthread_mutex_lock(&cdata->dev->writer_mutex); -		do { -			wlen = 0; -			err = usbmux_send(cdata->muxclient, cursor, len, &wlen); -			if (err == -ETIMEDOUT) { -				// some kind of timeout... just be patient and retry. -			} else if (err < 0) { -				if (verbose >= 2) -					logmsg(LOG_ERR, "%s[%x]: USB write error: %d", __func__, THREAD, err); -				len = -1; -				break; -			} -			// calculate remainder. -			len -= wlen; -			// advance cursor appropiately. -			cursor += wlen; -		} -		while ((len > 0) && !quit_flag); -		pthread_mutex_unlock(&cdata->dev->writer_mutex); -		if (len < 0) { -			break; -		} -	} - -  leave: -	// cleanup -	if (verbose >= 3) -		logmsg(LOG_NOTICE, "%s[%x]: terminating", __func__, THREAD); -	if (cdata->reader != 0) { -		cdata->reader_quit = 1; -		pthread_join(cdata->reader, NULL); -	} - -	cdata->handler_dead = 1; - -	if (verbose >= 3) -		logmsg(LOG_NOTICE, "%s[%x]: terminated", __func__, THREAD); -	return NULL; -} - -/** - * Thread performing usb_bulk_read from the connected device. - * One thread per device. Lives as long as the device is in use. - */ -static void *usbmuxd_bulk_reader_thread(void *arg) -{ -	struct device_info *cur_dev; -	int err; - -	if (!arg) { -		if (verbose >= 2) -			logmsg(LOG_ERR, "%s: Invalid client_data provided", __func__); -		return NULL; -	} - -	cur_dev = (struct device_info *) arg; - -	if (verbose >= 3) -		logmsg(LOG_NOTICE, "%s: started", __func__); - -	while (!quit_flag && cur_dev) { - -		pthread_mutex_lock(&cur_dev->mutex); -		if (cur_dev->use_count <= 0) { -			pthread_mutex_unlock(&cur_dev->mutex); -			break; -		} -		pthread_mutex_unlock(&cur_dev->mutex); - -		if ((err = usbmux_pullbulk(cur_dev->phone)) < 0) { -			if (verbose >= 1) -				logmsg(LOG_ERR, "%s: error %d when reading from device", -					   __func__, err); -			break; -		} -	} - -	if (verbose >= 3) -		logmsg(LOG_NOTICE, "%s: terminated", __func__); - -	return NULL; -} - -/** - * This thread is started when a new connection is accepted. - * It performs the handshake, then waits for the connect packet and - * on success it starts the usbmuxd_client_handler thread. - */ -static void *usbmuxd_client_init_thread(void *arg) -{ -	struct client_data *cdata; -	struct usbmuxd_scan_request *s_req; -	struct usbmuxd_device_info_record dev_info_rec; -	struct usbmuxd_connect_request *c_req = NULL; - -	struct usb_bus *bus; -	struct usb_device *dev; - -	int recv_len; -	int found = 0; -	int res; -	int i; - -	usbmux_device_t phone = NULL; -	struct device_info *cur_dev = NULL; - -	if (!arg) { -		if (verbose >= 1) -			logmsg(LOG_ERR, "%s[%x]: invalid client_data provided!", -				   __func__, THREAD); -		return NULL; -	} - -	cdata = (struct client_data *) arg; -	cdata->dead = 0; - -	if (verbose >= 3) -		logmsg(LOG_NOTICE, "%s[%x]: started (fd=%d)", __func__, THREAD, -			   cdata->socket); - -	if ((recv_len = -		 usbmuxd_get_request(cdata->socket, (void **) &s_req, 0)) <= 0) { -		if (verbose >= 2) -			logmsg(LOG_ERR, "%s[%x]: No scan packet received, error %s", -				   __func__, THREAD, strerror(errno)); -		goto leave; -	} - -	if ((recv_len == sizeof(struct usbmuxd_scan_request)) -		&& (s_req->header.length == sizeof(struct usbmuxd_scan_request)) -		&& (s_req->header.reserved == 0) -		&& (s_req->header.type == USBMUXD_SCAN)) { -		// send success response -		if (verbose >= 3) -			logmsg(LOG_NOTICE, "%s[%x]: Got scan packet!", __func__, -				   THREAD); -		usbmuxd_send_result(cdata->socket, s_req->header.tag, 0); -	} else if ((recv_len == sizeof(struct usbmuxd_connect_request)) -			   && (s_req->header.type == USBMUXD_CONNECT)) { -		c_req = (struct usbmuxd_connect_request *) s_req; -		s_req = NULL; -		goto connect; -	} else { -		// send error response and exit -		if (verbose >= 2) -			logmsg(LOG_ERR, "%s[%x]: Invalid scan packet received.", -				   __func__, THREAD); -		// TODO is this required?! -		usbmuxd_send_result(cdata->socket, s_req->header.tag, EINVAL); -		goto leave; -	} - -	pthread_mutex_lock(&usb_mutex); -	// gather data about all iPhones/iPods attached - -	if (verbose >= 5) -		logmsg(LOG_DEBUG, "%s[%x]: usb init", __func__, THREAD); -	usb_init(); -	if (verbose >= 5) -		logmsg(LOG_DEBUG, "%s[%x]: usb find busses", __func__, THREAD); -	usb_find_busses(); -	if (verbose >= 5) -		logmsg(LOG_DEBUG, "%s[%x]: usb find devices", __func__, THREAD); -	usb_find_devices(); - -	if (verbose >= 2) -		logmsg(LOG_NOTICE, "%s[%x]: Looking for attached devices...", -			   __func__, THREAD); - -	for (bus = usb_get_busses(); bus; bus = bus->next) { -		for (dev = bus->devices; dev; dev = dev->next) { -			if (dev->descriptor.idVendor == 0x05ac -				&& dev->descriptor.idProduct >= 0x1290 -				&& dev->descriptor.idProduct <= 0x1294) { -				if (verbose >= 1) -					logmsg(LOG_NOTICE, -						   "%s[%x]: Found device on bus %s, id %s", -						   __func__, THREAD, bus->dirname, dev->filename); -				found++; - -				// construct packet -				memset(&dev_info_rec, 0, sizeof(dev_info_rec)); -				dev_info_rec.header.length = sizeof(dev_info_rec); -				dev_info_rec.header.type = USBMUXD_DEVICE_INFO; -				uint32_t dev_id = -					strtol(dev->filename, NULL, 10) -					+ (strtoul(bus->dirname, NULL, 10) << 16); -				dev_info_rec.device.device_id = dev_id; -				dev_info_rec.device.product_id = dev->descriptor.idProduct; -				if (dev->descriptor.iSerialNumber) { -					usb_dev_handle *udev; -					//pthread_mutex_lock(&usbmux_mutex); -					udev = usb_open(dev); -					if (udev) { -						usb_get_string_simple(udev, -							dev->descriptor.iSerialNumber, -							dev_info_rec.device.serial_number, -							sizeof(dev_info_rec.device.serial_number) + 1); -						usb_close(udev); -					} else { -						logmsg(LOG_ERR, "%s[%x]: Error: usb_open(): %s\n", __func__, THREAD, usb_strerror()); -					} -					//pthread_mutex_unlock(&usbmux_mutex); -				} -#ifdef DEBUG -				if (verbose >= 4) -					print_buffer(stderr, (char *) &dev_info_rec, -								 sizeof(dev_info_rec)); -#endif - -				// send it -				if (send_buf -					(cdata->socket, &dev_info_rec, -					 sizeof(dev_info_rec)) <= 0) { -					if (verbose >= 3) -						logmsg(LOG_ERR, -							   "%s[%x]: Error: Could not send device info: %s", -							   __func__, THREAD, strerror(errno)); -					found--; -				} -			} -		} -	} -	pthread_mutex_unlock(&usb_mutex); - -	if (found <= 0) { -		if (verbose >= 1) -			logmsg(LOG_NOTICE, -				   "%s[%x]: No attached iPhone/iPod devices found.", -				   __func__, THREAD); -		usbmuxd_send_result(cdata->socket, s_req->header.tag, -ENODEV); -		goto leave; -	} - -	goto leave; - -/*	if (verbose >= 3) -		logmsg(LOG_NOTICE, "%s[%x]: Waiting for connect request", __func__, -			   THREAD); - -	// now wait for connect request -	//memset(&c_req, 0, sizeof(c_req)); -	if ((recv_len = -		 usbmuxd_get_request(cdata->socket, (void **) &c_req, 0)) <= 0) { -		if (verbose >= 3) -			logmsg(LOG_NOTICE, -				   "%s[%x]: Did not receive any connect request.", -				   __func__, THREAD); -		goto leave; -	}*/ - -  connect: - -	if (c_req->header.type != USBMUXD_CONNECT) { -		if (verbose >= 2) -			logmsg(LOG_ERR, -				   "%s[%x]: Unexpected packet of type %d received.", -				   __func__, THREAD, c_req->header.type); -		goto leave; -	} - -	if (verbose >= 3) -		logmsg(LOG_NOTICE, -			   "%s[%x]: Setting up connection to usb device %d:%d on port %d", -			   __func__, THREAD, c_req->device_id >> 16, c_req->device_id & 0xFFFF, ntohs(c_req->tcp_dport)); - -	// find the device, and open usb connection -	pthread_mutex_lock(&usbmux_mutex); -	phone = NULL; -	cur_dev = NULL; -	// first check if we already have an open connection -	if (devices) { -		for (i = 0; i < device_count; i++) { -			if (devices[i]) { -				if (devices[i]->device_id == c_req->device_id) { -					devices[i]->use_count++; -					cur_dev = devices[i]; -					phone = cur_dev->phone; -					break; -				} -			} -		} -	} -	if (!phone) { -		// if not found, make a new connection -		if (verbose >= 2) -			logmsg(LOG_NOTICE, -				   "%s[%x]: creating new usb connection, device %d:%d", -				   __func__, THREAD, c_req->device_id >> 16, c_req->device_id & 0xFFFF); - -		pthread_mutex_lock(&usb_mutex); -		if (usbmux_get_specific_device(c_req->device_id >> 16, c_req->device_id & 0xFFFF, &phone) < 0) { -			pthread_mutex_unlock(&usb_mutex); -			pthread_mutex_unlock(&usbmux_mutex); -			if (verbose >= 1) -				logmsg(LOG_ERR, "%s[%x]: device %d:%d could not be opened", -					   __func__, THREAD, c_req->device_id >> 16, c_req->device_id & 0xFFFF); -			usbmuxd_send_result(cdata->socket, c_req->header.tag, ENODEV); -			goto leave; -		} -		pthread_mutex_unlock(&usb_mutex); - -		// create device object -		if (verbose >= 3) -			logmsg(LOG_DEBUG, "%s[%x]: add to device list", __func__, -				   THREAD); -		cur_dev = -			(struct device_info *) malloc(sizeof(struct device_info)); -		memset(cur_dev, 0, sizeof(struct device_info)); -		cur_dev->use_count = 1; -		cur_dev->device_id = c_req->device_id; -		cur_dev->phone = phone; -		cur_dev->bulk_reader = 0; -		pthread_mutex_init(&cur_dev->mutex, NULL); -		pthread_mutex_init(&cur_dev->writer_mutex, NULL); - -		if (verbose >= 3) -			logmsg(LOG_DEBUG, "%s[%x]: device_count = %d", __func__, -				   THREAD, device_count); - -		// add to list of devices -		devices = -			(struct device_info **) realloc(devices, -											sizeof(struct device_info *) * -											(device_count + 1)); -		if (devices) { -			devices[device_count] = cur_dev; -			device_count++; -		} -	} else { -		if (verbose >= 2) -			logmsg(LOG_NOTICE, -				   "%s[%x]: reusing usb connection, device %d:%d", -				   __func__, THREAD, c_req->device_id >> 16, c_req->device_id & 0xFFFF); -	} -	pthread_mutex_unlock(&usbmux_mutex); - -	// setup connection to iPhone/iPod -	pthread_mutex_lock(&cur_dev->writer_mutex); -	res = -		usbmux_new_client(cur_dev->phone, 0, ntohs(c_req->tcp_dport), -						  &(cdata->muxclient)); -	pthread_mutex_unlock(&cur_dev->writer_mutex); - -	if (res != 0) { -		usbmuxd_send_result(cdata->socket, c_req->header.tag, res); -		if (verbose >= 1) -			logmsg(LOG_ERR, -				   "%s[%x]: mux_new_client returned %d, aborting.", -				   __func__, THREAD, res); -		goto leave; -	} -	// start bulk reader thread (once per device) -	pthread_mutex_lock(&cur_dev->mutex); -	if (cur_dev->bulk_reader == 0) { -		pthread_create(&cur_dev->bulk_reader, NULL, -					   usbmuxd_bulk_reader_thread, cur_dev); -	} -	pthread_mutex_unlock(&cur_dev->mutex); - -	// wait for the initial handshake (SYN->SYN+ACK->ACK) to complete) -	struct timespec ts; -	ts.tv_sec = 0; -	ts.tv_nsec = 100000000; - -	i = 0; -	while (i < 10000) { -		if (usbmux_is_connected(cdata->muxclient)) { -			break; -		} -		nanosleep(&ts, NULL); -		i+=100; -	} -	if (!usbmux_is_connected(cdata->muxclient)) { -		usbmuxd_send_result(cdata->socket, c_req->header.tag, -ENOTCONN); -		goto leave; -	} - -	// start connection handler thread -	cdata->handler_dead = 0; -	cdata->tag = c_req->header.tag; -	cdata->dev = cur_dev; -	if (pthread_create -		(&cdata->handler, NULL, usbmuxd_client_handler_thread, cdata) != 0) -	{ -		if (verbose >= 1) -			logmsg(LOG_ERR, -				   "%s[%x]: could not create usbmuxd_client_handler_thread!", -				   __func__, THREAD); -		cdata->handler = 0; -		goto leave; -	} -	// wait for handler thread to finish its work -	if (cdata->handler != 0) { -		pthread_join(cdata->handler, NULL); -	} - -	if (verbose >= 2) -		logmsg(LOG_NOTICE, "%s[%x]: closing connection", __func__, THREAD); - -	// time to clean up -	if (cdata && cdata->muxclient) {	// should be non-NULL -		pthread_mutex_lock(&cdata->dev->writer_mutex); -		usbmux_free_client(cdata->muxclient); -		pthread_mutex_unlock(&cdata->dev->writer_mutex); -	} - -  leave: -	if (verbose >= 3) -		logmsg(LOG_NOTICE, "%s[%x]: terminating", __func__, THREAD); - -	if (s_req) { -		free(s_req); -	} -	if (c_req) { -		free(c_req); -	} -	// this has to be freed only if it's not in use anymore as it closes -	// the USB connection -	pthread_mutex_lock(&usbmux_mutex); -	if (cur_dev) { -		pthread_mutex_lock(&cur_dev->mutex); -		if (cur_dev->use_count > 1) { -			if (verbose >= 2) -				logmsg(LOG_NOTICE, -					   "%s[%x]: decreasing device use count (from %d to %d)", -					   __func__, THREAD, cur_dev->use_count, -					   cur_dev->use_count - 1); -			cur_dev->use_count--; -			pthread_mutex_unlock(&cur_dev->mutex); -		} else { -			if (verbose >= 2) -				logmsg(LOG_NOTICE, -					   "%s[%x]: last client disconnected, cleaning up", -					   __func__, THREAD); -			cur_dev->use_count = 0; -			pthread_mutex_unlock(&cur_dev->mutex); -			if (cur_dev->bulk_reader != 0) { -				if (verbose >= 3) -					logmsg(LOG_NOTICE, "%s[%x]: joining bulk_reader...", -						   __func__, THREAD); -				pthread_join(cur_dev->bulk_reader, NULL); -			} -			pthread_mutex_lock(&usb_mutex); -			usbmux_free_device(cur_dev->phone); -			pthread_mutex_unlock(&usb_mutex); -			pthread_mutex_destroy(&cur_dev->writer_mutex); -			pthread_mutex_destroy(&cur_dev->mutex); -			free(cur_dev); -			cur_dev = NULL; -			if (device_count > 1) { -				struct device_info **newlist; -				int j = 0; - -				newlist = -					(struct device_info **) -					malloc(sizeof(struct device_info *) -						   * device_count - 1); -				for (i = 0; i < device_count; i++) { -					if (devices[i] != NULL) { -						newlist[j++] = devices[i]; -					} -				} -				free(devices); -				devices = newlist; -				device_count--; -			} else { -				free(devices); -				devices = NULL; -				device_count = 0; -			} -		} -	} -	pthread_mutex_unlock(&usbmux_mutex); - -	cdata->dead = 1; -	close(cdata->socket); - -	if (verbose >= 3) -		logmsg(LOG_NOTICE, "%s[%x]: terminated", __func__, THREAD); - -	return NULL; -} - -/** - * make this program run detached from the current console - */ -static int daemonize() -{ -	pid_t pid; -	pid_t sid; - -	// already a daemon -	if (getppid() == 1) -		return 0; - -	pid = fork(); -	if (pid < 0) { -		exit(EXIT_FAILURE); -	} - -	if (pid > 0) { -		// exit parent process -		exit(EXIT_SUCCESS); -	} -	// At this point we are executing as the child process - -	// Change the file mode mask -	umask(0); - -	// Create a new SID for the child process -	sid = setsid(); -	if (sid < 0) { -		return -1; -	} -	// Change the current working directory. -	if ((chdir("/")) < 0) { -		return -2; -	} -	// Redirect standard files to /dev/null -	if (!freopen("/dev/null", "r", stdin)) { -		logmsg(LOG_ERR, "ERROR: redirection of stdin failed.\n"); -	} -	if (!freopen("/dev/null", "w", stdout)) { -		logmsg(LOG_ERR, "ERROR: redirection of stdout failed.\n"); -	} -	if (!freopen("/dev/null", "w", stderr)) { -		logmsg(LOG_ERR, "ERROR: redirection of stderr failed.\n"); -	} - -	return 0; -} - -static void usage() -{ -	printf("usage: usbmuxd [options]\n"); -	printf("\t-h|--help                 print this message\n"); -	printf("\t-v|--verbose              be verbose (use twice or more to increase)\n"); -	printf("\t-f|--foreground           do not daemonize\n"); -	printf("\t-e|--exit-on-no-devices   exit if no device is attached\n"); -	printf("\t-d|--drop-privileges      drop privileges after startup\n"); -	printf("\t-u|--udev                 udev operation mode\n"); -	printf("\t-x|--exit                 tell a running instance to exit\n"); -	printf("\t-X|--force-exit           tell a running instance to exit, even if\n"); -	printf("\t                          there are still devices connected\n"); -	printf("\n"); -} - -static void parse_opts(int argc, char **argv) -{ -	static struct option longopts[] = { -		{"help", 0, NULL, 'h'}, -		{"foreground", 0, NULL, 'f'}, -		{"verbose", 0, NULL, 'v'}, -		{"exit-on-no-devices", 0, NULL, 'e'}, -		{"drop-privileges", 0, NULL, 'd'}, -		{"udev", 0, NULL, 'u'}, -		{"exit", 0, NULL, 'x'}, -		{"force-exit", 0, NULL, 'X'}, -		{NULL, 0, NULL, 0} -	}; -	int c; - -	while (1) { -		c = getopt_long(argc, argv, "hfveduxX", longopts, (int *) 0); -		if (c == -1) { -			break; -		} - -		switch (c) { -		case 'h': -			usage(); -			exit(0); -		case 'f': -			foreground = 1; -			break; -		case 'v': -			sock_stuff_set_verbose(++verbose); -			break; -		case 'e': -			exit_on_no_devices = 1; -			break; -		case 'd': -			drop_privileges = 1; -			break; -		case 'u': -			opt_udev = 1; -			break; -		case 'x': -			opt_exit = 1; -			exit_signal = SIGQUIT; -			break; -		case 'X': -			opt_exit = 1; -			exit_signal = SIGTERM; -			break; -		default: -			usage(); -			exit(2); -		} -	} -	if (opt_udev) -		foreground = 0; -} - -/** - * checks for attached devices - * - * @return number of devices found - */ -static int devices_attached() -{ -	struct usb_bus *bus; -	struct usb_device *dev; -	int res = 0; - -	usb_init(); -	usb_find_busses(); -	usb_find_devices(); - -	for (bus = usb_get_busses(); bus; bus = bus->next) { -		for (dev = bus->devices; dev; dev = dev->next) { -			if (dev->descriptor.idVendor == 0x05ac -				&& dev->descriptor.idProduct >= 0x1290 -				&& dev->descriptor.idProduct <= 0x1294) { -				res++; -			} -		} -	} - -	return res; -} - -/** - * signal handler function for cleaning up properly - */ -static void handle_signal(int sig) -{ -	if (sig == SIGTERM) { -		quit_flag = 1; -	} else { -		if (sig == SIGINT) { -			if (verbose >= 1) -				fprintf(stderr, "CTRL+C pressed\n"); -		} - -		if (verbose >= 1) -			fprintf(stderr, "Checking if we can terminate (no more devices attached)...\n"); - -		if (devices_attached() > 0) { -			// we can't quit, there are still devices attached. -			if (verbose >= 1) -				fprintf(stderr, "Refusing to terminate, there are still devices attached. Kill me with signal 15 (TERM) to force quit.\n"); -		} else { -			// it's safe to quit -			quit_flag = 1; -		} -	} -} - -/** - * main function. Initializes all stuff and then loops waiting in accept. - */ -int main(int argc, char **argv) -{ -	struct sockaddr_un c_addr; -	socklen_t len = sizeof(struct sockaddr_un); -	struct client_data *cdata = NULL; -	struct client_data **children = NULL; -	int children_capacity = DEFAULT_CHILDREN_CAPACITY; -	int i; -	int result = 0; -	int exit_val = 0; -	int cnt = 0; -	FILE *lfd = NULL; -	struct flock lock; - -	parse_opts(argc, argv); - -	argc -= optind; -	argv += optind; - -	if (!foreground) { -		openlog("usbmuxd", LOG_PID, 0); -	} - -	if (verbose >= 1) -		logmsg(LOG_NOTICE, "starting"); - -	// signal(SIGHUP, reload_conf); // none yet -	signal(SIGINT, handle_signal); -	signal(SIGQUIT, handle_signal); -	signal(SIGTERM, handle_signal); -	signal(SIGPIPE, SIG_IGN); - -	// check for other running instance -	lfd = fopen(LOCKFILE, "r"); -	if (lfd) { -		lock.l_type = 0; -		lock.l_whence = SEEK_SET; -		lock.l_start = 0; -		lock.l_len = 0; -		fcntl(fileno(lfd), F_GETLK, &lock); -		fclose(lfd); -		if (lock.l_type != F_UNLCK) { -			if (opt_exit) { -				if (lock.l_pid && !kill(lock.l_pid, 0)) { -					logmsg(LOG_NOTICE, "sending signal %d to instance with pid %d", exit_signal, lock.l_pid); -					if (kill(lock.l_pid, exit_signal) < 0) { -						logmsg(LOG_ERR, "Error: could not deliver signal %d to pid %d", exit_signal, lock.l_pid); -					} -					exit_val = 0; -					goto terminate; -				} else { -					logmsg(LOG_ERR, "Error: could not determine pid of the other running instance!"); -					exit_val = -1; -					goto terminate; -				} -			} else { -				logmsg(LOG_NOTICE, -					   "another instance is already running (pid %d). exiting.", lock.l_pid); -				if (!opt_udev) { -					exit_val = -1; -				} -				goto terminate; -			} -		} -	} - -	if (opt_exit) { -		logmsg(LOG_NOTICE, "no running instance found, none killed. exiting."); -		goto terminate; -	} - -	if (exit_on_no_devices) { -		if (devices_attached() <= 0) { -			logmsg(LOG_NOTICE, "no devices attached. exiting."); -			return 0; -		} -	} - -	fsock = create_unix_socket(USBMUXD_SOCKET_FILE); -	if (fsock < 0) { -		logmsg(LOG_ERR, "Could not create socket, exiting"); -		if (!foreground) { -			closelog(); -		} -		return -1; -	} - -	chmod(USBMUXD_SOCKET_FILE, 0666); - -	if (verbose >= 2) -		usb_set_debug(verbose); - -	if (verbose >= 4) -		usbmux_set_debug(1); - -	if (!foreground) { -		if (daemonize() < 0) { -			fprintf(stderr, "usbmuxd: FATAL: Could not daemonize!\n"); -			syslog(LOG_ERR, "FATAL: Could not daemonize!"); -			closelog(); -			exit(EXIT_FAILURE); -		} -	} -	// now open the lockfile and place the lock -	lfd = fopen(LOCKFILE, "w"); -	if (lfd) { -		lock.l_type = F_WRLCK; -		lock.l_whence = SEEK_SET; -		lock.l_start = 0; -		lock.l_len = 0; -		if (fcntl(fileno(lfd), F_SETLK, &lock) == -1) { -			logmsg(LOG_ERR, "ERROR: lockfile locking failed!"); -			exit(EXIT_FAILURE); -		} -	} -	// drop elevated privileges -	if (drop_privileges && (getuid() == 0 || geteuid() == 0)) { -		struct passwd *pw = getpwnam("nobody"); -		if (pw) { -			setuid(pw->pw_uid); -		} else { -			logmsg(LOG_ERR, -				   "ERROR: Dropping privileges failed, check if user 'nobody' exists! Will now terminate."); -			exit(EXIT_FAILURE); -		} - -		// security check -		if (setuid(0) != -1) { -			logmsg(LOG_ERR, "ERROR: Failed to drop privileges properly!"); -			exit(EXIT_FAILURE); -		} -		if (verbose >= 2) -			logmsg(LOG_NOTICE, "Successfully dropped privileges"); -	} -	// Reserve space for 10 clients which should be enough. If not, the -	// buffer gets enlarged later. -	children = -		(struct client_data **) malloc(sizeof(struct client_data *) * -									   children_capacity); -	if (!children) { -		logmsg(LOG_ERR, -			   "Out of memory when allocating memory for child threads. Terminating."); -		if (!foreground) { -			closelog(); -		} -		exit(EXIT_FAILURE); -	} -	memset(children, 0, sizeof(struct client_data *) * children_capacity); - -	if (verbose >= 2) -		logmsg(LOG_NOTICE, "waiting for connection"); -	while (!quit_flag) { -		// Check the file descriptor before accepting a connection. -		// If no connection attempt is made, just repeat... -		result = check_fd(fsock, FD_READ, 1000); -		if (result <= 0) { -			if (result == 0) { -				// cleanup -				for (i = 0; i < children_capacity; i++) { -					if (children[i]) { -						if (children[i]->dead != 0) { -							pthread_join(children[i]->thread, NULL); -							if (verbose >= 3) -								logmsg(LOG_NOTICE, -									   "reclaimed client thread (fd=%d)", -									   children[i]->socket); -							free(children[i]); -							children[i] = NULL; -							cnt++; -						} else { -							cnt = 0; -						} -					} else { -						cnt++; -					} -				} - -				if ((children_capacity > DEFAULT_CHILDREN_CAPACITY) -					&& ((children_capacity - cnt) <= -						DEFAULT_CHILDREN_CAPACITY)) { -					children_capacity = DEFAULT_CHILDREN_CAPACITY; -					children = -						realloc(children, -								sizeof(struct client_data *) * -								children_capacity); -				} -				continue; -			} else { -				if (verbose >= 3) -					logmsg(LOG_ERR, "usbmuxd: select error: %s", -						   strerror(errno)); -				continue; -			} -		} - -		cdata = (struct client_data *) malloc(sizeof(struct client_data)); -		memset(cdata, 0, sizeof(struct client_data)); -		if (!cdata) { -			quit_flag = 1; -			logmsg(LOG_ERR, "Error: Out of memory! Terminating."); -			break; -		} - -		cdata->socket = accept(fsock, (struct sockaddr *) &c_addr, &len); -		if (cdata->socket < 0) { -			free(cdata); -			if (errno == EINTR) { -				continue; -			} else { -				if (verbose >= 3) -					logmsg(LOG_ERR, "Error in accept: %s", -						   strerror(errno)); -				continue; -			} -		} - -		if (verbose >= 1) -			logmsg(LOG_NOTICE, "new client connected (fd=%d)", -				   cdata->socket); - -		// create client thread: -		if (pthread_create -			(&cdata->thread, NULL, usbmuxd_client_init_thread, cdata) == 0) -		{ -			for (i = 0; i < children_capacity; i++) { -				if (children[i] == NULL) -					break; -			} -			if (i == children_capacity) { -				// enlarge buffer -				children_capacity++; -				children = -					realloc(children, -							sizeof(struct client_data *) * -							children_capacity); -				if (!children) { -					logmsg(LOG_ERR, -						   "Out of memory when enlarging child thread buffer"); -				} -			} -			children[i] = cdata; -		} else { -			logmsg(LOG_ERR, "Failed to create client_init_thread."); -			close(cdata->socket); -			free(cdata); -			cdata = NULL; -		} -	} - -	if (verbose >= 3) -		logmsg(LOG_NOTICE, "terminating"); - -	// preparing for shutdown: wait for child threads to terminate (if any) -	if (verbose >= 2) -		logmsg(LOG_NOTICE, "waiting for child threads to terminate..."); -	for (i = 0; i < children_capacity; i++) { -		if (children[i] != NULL) { -			pthread_join(children[i]->thread, NULL); -			free(children[i]); -			children[i] = NULL; -		} -	} - -	// delete the children set. -	free(children); -	children = NULL; - - -	if (fsock >= 0) { -		close(fsock); -	} - -	unlink(USBMUXD_SOCKET_FILE); - -	// unlock lock file and close it. -	if (lfd) { -		lock.l_type = F_UNLCK; -		fcntl(fileno(lfd), F_SETLK, &lock); -		fclose(lfd); -	} - -terminate: -	if (verbose >= 1) -		logmsg(LOG_NOTICE, "terminated"); -	if (!foreground) { -		closelog(); -	} - -	return 0; -} diff --git a/src/sock_stuff.c b/src/sock_stuff.c deleted file mode 100644 index 137375d..0000000 --- a/src/sock_stuff.c +++ /dev/null @@ -1,301 +0,0 @@ -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> -#include <errno.h> -#include <sys/time.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <netinet/in.h> -#include <netdb.h> -#include <arpa/inet.h> -#include "sock_stuff.h" - -#define RECV_TIMEOUT 20000 - -static int verbose = 0; - -void sock_stuff_set_verbose(int level) -{ -	verbose = level; -} - -int create_unix_socket(const char *filename) -{ -	struct sockaddr_un name; -	int sock; -	size_t size; - -	// remove if still present -	unlink(filename); - -	/* Create the socket. */ -	sock = socket(PF_LOCAL, SOCK_STREAM, 0); -	if (sock < 0) { -		perror("socket"); -		return -1; -	} - -	/* Bind a name to the socket. */ -	name.sun_family = AF_LOCAL; -	strncpy(name.sun_path, filename, sizeof(name.sun_path)); -	name.sun_path[sizeof(name.sun_path) - 1] = '\0'; - -	/* The size of the address is -	   the offset of the start of the filename, -	   plus its length, -	   plus one for the terminating null byte. -	   Alternatively you can just do: -	   size = SUN_LEN (&name); -	 */ -	size = (offsetof(struct sockaddr_un, sun_path) -			+ strlen(name.sun_path) + 1); - -	if (bind(sock, (struct sockaddr *) &name, size) < 0) { -		perror("bind"); -		close(sock); -		return -1; -	} - -	if (listen(sock, 10) < 0) { -		perror("listen"); -		close(sock); -		return -1; -	} - -	return sock; -} - -int connect_unix_socket(const char *filename) -{ -	struct sockaddr_un name; -	int sfd = -1; -	size_t size; -	struct stat fst; - -	// check if socket file exists... -	if (stat(filename, &fst) != 0) { -		if (verbose >= 2) -			fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename, -					strerror(errno)); -		return -1; -	} -	// ... and if it is a unix domain socket -	if (!S_ISSOCK(fst.st_mode)) { -		if (verbose >= 2) -			fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__, -					filename); -		return -1; -	} -	// make a new socket -	if ((sfd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { -		if (verbose >= 2) -			fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno)); -		return -1; -	} -	// and connect to 'filename' -	name.sun_family = AF_LOCAL; -	strncpy(name.sun_path, filename, sizeof(name.sun_path)); -	name.sun_path[sizeof(name.sun_path) - 1] = 0; - -	size = (offsetof(struct sockaddr_un, sun_path) -			+ strlen(name.sun_path) + 1); - -	if (connect(sfd, (struct sockaddr *) &name, size) < 0) { -		close(sfd); -		if (verbose >= 2) -			fprintf(stderr, "%s: connect: %s\n", __func__, -					strerror(errno)); -		return -1; -	} - -	return sfd; -} - -int create_socket(uint16_t port) -{ -	int sfd = -1; -	int yes = 1; -	struct sockaddr_in saddr; - -	if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) { -		perror("socket()"); -		return -1; -	} - -	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { -		perror("setsockopt()"); -		close(sfd); -		return -1; -	} - -	memset((void *) &saddr, 0, sizeof(saddr)); -	saddr.sin_family = AF_INET; -	saddr.sin_addr.s_addr = htonl(INADDR_ANY); -	saddr.sin_port = htons(port); - -	if (0 > bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr))) { -		perror("bind()"); -		close(sfd); -		return -1; -	} - -	if (listen(sfd, 1) == -1) { -		perror("listen()"); -		close(sfd); -		return -1; -	} - -	return sfd; -} - -int connect_socket(const char *addr, uint16_t port) -{ -	int sfd = -1; -	int yes = 1; -	struct hostent *hp; -	struct sockaddr_in saddr; - -	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; -	} - -	if (!hp->h_addr) { -		if (verbose >= 2) -			fprintf(stderr, "%s: gethostbyname returned NULL address!\n", -					__func__); -		return -1; -	} - -	if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) { -		perror("socket()"); -		return -1; -	} - -	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { -		perror("setsockopt()"); -		close(sfd); -		return -1; -	} - -	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"); -		close(sfd); -		return -2; -	} - -	return sfd; -} - -int check_fd(int fd, fd_mode fdm, unsigned int timeout) -{ -	fd_set fds; -	int sret; -	int eagain; -	struct timeval to; - -	if (fd <= 0) { -		if (verbose >= 2) -			fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd); -		return -1; -	} - -	FD_ZERO(&fds); -	FD_SET(fd, &fds); - -	to.tv_sec = (time_t) (timeout / 1000); -	to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000); - -	sret = -1; - -	do { -		eagain = 0; -		switch (fdm) { -		case FD_READ: -			sret = select(fd + 1, &fds, NULL, NULL, &to); -			break; -		case FD_WRITE: -			sret = select(fd + 1, NULL, &fds, NULL, &to); -			break; -		case FD_EXCEPT: -			sret = select(fd + 1, NULL, NULL, &fds, &to); -			break; -		default: -			return -1; -		} - -		if (sret < 0) { -			switch (errno) { -			case EINTR: -				// interrupt signal in select -				if (verbose >= 2) -					fprintf(stderr, "%s: EINTR\n", __func__); -				eagain = 1; -				break; -			case EAGAIN: -				if (verbose >= 2) -					fprintf(stderr, "%s: EAGAIN\n", __func__); -				break; -			default: -				if (verbose >= 2) -					fprintf(stderr, "%s: select failed: %s\n", __func__, -							strerror(errno)); -				return -1; -			} -		} -	} while (eagain); - -	return sret; -} - -int recv_buf(int fd, void *data, size_t length) -{ -	return recv_buf_timeout(fd, data, length, 0, RECV_TIMEOUT); -} - -int peek_buf(int fd, void *data, size_t length) -{ -	return recv_buf_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT); -} - -int recv_buf_timeout(int fd, void *data, size_t length, int flags, -					 unsigned int timeout) -{ -	int res; -	int result; - -	// check if data is available -	res = check_fd(fd, FD_READ, timeout); -	if (res <= 0) { -		return res; -	} -	// if we get here, there _is_ data available -	result = recv(fd, data, length, flags); -	if (res > 0 && result == 0) { -		// but this is an error condition -		if (verbose >= 3) -			fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd); -		return -EAGAIN; -	} -	if (result < 0) { -		return -errno; -	} -	return result; -} - -int send_buf(int fd, void *data, size_t length) -{ -	return send(fd, data, length, 0); -} diff --git a/src/sock_stuff.h b/src/sock_stuff.h deleted file mode 100644 index 190f7e1..0000000 --- a/src/sock_stuff.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __SOCK_STUFF_H -#define __SOCK_STUFF_H - -#include <stdint.h> - -enum fd_mode { -	FD_READ, -	FD_WRITE, -	FD_EXCEPT -}; -typedef enum fd_mode fd_mode; - -int create_unix_socket(const char *filename); -int connect_unix_socket(const char *filename); -int create_socket(uint16_t port); -int connect_socket(const char *addr, uint16_t port); -int check_fd(int fd, fd_mode fdm, unsigned int timeout); - -int recv_buf(int fd, void *data, size_t size); -int peek_buf(int fd, void *data, size_t size); -int recv_buf_timeout(int fd, void *data, size_t size, int flags, -					 unsigned int timeout); - -int send_buf(int fd, void *data, size_t size); - -void sock_stuff_set_verbose(int level); - -#endif							/* __SOCK_STUFF_H */ diff --git a/src/usbmux.c b/src/usbmux.c deleted file mode 100644 index c5e38dd..0000000 --- a/src/usbmux.c +++ /dev/null @@ -1,1264 +0,0 @@ -/* - * Copyright (c) 2008 Jing Su. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  - */ -#include <stdint.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> -#include <usb.h> -#include <stdio.h> -#include <arpa/inet.h> -#include <errno.h> -#include <pthread.h> -#include "usbmux.h" - -#define BULKIN 0x85 -#define BULKOUT 0x04 - -static const uint8_t TCP_FIN = 1; -static const uint8_t TCP_SYN = 1 << 1; -static const uint8_t TCP_RST = 1 << 2; -static const uint8_t TCP_PSH = 1 << 3; -static const uint8_t TCP_ACK = 1 << 4; -static const uint8_t TCP_URG = 1 << 5; - -// I have trouble figuring out how to properly manage the windowing to -// the device. It keeps sending back 512 and seems to drop off a cliff -// when the device gets overwhelmed. In addition, the device likes to -// panic and send out RESETS before the window hits zero. Also, waiting -// for responses seems to not be a winning strategy. -// -// Since I'm not sure how in the hell to interpret the window sizes that -// the device is sending back to us, I've figured out some magic number -// constants which seem to work okay. -static const uint32_t WINDOW_MAX = 5 * 1024; -static const uint32_t WINDOW_INCREMENT = 512; - -typedef struct { -	char *buffer; -	int leftover; -	int capacity; -} receivebuf_t; - -struct usbmux_device_int { -	struct usb_dev_handle *usbdev; -	struct usb_device *__device; -	receivebuf_t usbReceive; -	int wMaxPacketSize; -}; - -typedef struct { -	uint32_t type, length, major, minor, allnull; -} usbmux_version_header; - -typedef struct { -	uint32_t type, length; -	uint16_t sport, dport; -	uint32_t scnt, ocnt; -	uint8_t offset, tcp_flags; -	uint16_t window, nullnull, length16; -} usbmux_tcp_header; - -struct usbmux_client_int { -	usbmux_tcp_header *header; -	usbmux_device_t device; - -	char *recv_buffer; -	int r_len; -	pthread_cond_t wait; - -	// this contains a conditional variable which usb-writers can wait -	// on while waiting for window updates from the device. -	pthread_cond_t wr_wait; -	// I'm going to do something really cheesy here. We are going to  -	// just record the most recent scnt that we are expecting to hear -	// back on. We will actually halt progress by limiting the number -	// of outstanding un-acked bulk sends that we have beamed out. -	uint32_t wr_pending_scnt; -	long wr_window; - -	pthread_mutex_t mutex; - -	// this variable is not protected by the mutex. This will always -	// be E_SUCCESS, unless an error of some kind breaks this stream. -	// this will then be set to the error that caused the broken stream. -	// no further operations other than free_client will be allowed. -	int error; - -	int cleanup; - -	int connected; -}; - - -static pthread_mutex_t usbmuxmutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t printmutex = PTHREAD_MUTEX_INITIALIZER; -static usbmux_client_t *connlist = NULL; -static int clients = 0; - - -/** - */ -int toto_debug = 0; - -void usbmux_set_debug(int e) -{ -	toto_debug = e; -} - -static void log_debug_msg(const char *format, ...) -{ -#ifndef STRIP_DEBUG_CODE -	va_list args; -	/* run the real fprintf */ -	va_start(args, format); - -	if (toto_debug) { -		pthread_mutex_lock(&printmutex); -		vfprintf(stderr, format, args); -		pthread_mutex_unlock(&printmutex); -	} - -	va_end(args); -#endif -} - -/** - * for debugging purposes. - */ -static void print_buffer(const char *data, const int length) -{ -	if (toto_debug <= 0) { -		return; -	} -	int i; -	int j; -	unsigned char c; - -	for (i = 0; i < length; i += 16) { -		printf("%04x: ", i); -		for (j = 0; j < 16; j++) { -			if (i + j >= length) { -				printf("   "); -				continue; -			} -			printf("%02hhx ", *(data + i + j)); -		} -		printf("  | "); -		for (j = 0; j < 16; j++) { -			if (i + j >= length) -				break; -			c = *(data + i + j); -			if ((c < 32) || (c > 127)) { -				printf("."); -				continue; -			} -			printf("%c", c); -		} -		printf("\n"); -	} -	printf("\n"); -} - -static void hton_header(usbmux_tcp_header * hdr) -{ -	if (hdr) { -		hdr->length = htonl(hdr->length); -		hdr->scnt = htonl(hdr->scnt); -		hdr->ocnt = htonl(hdr->ocnt); -		hdr->length16 = htons(hdr->length16); -	} -} - -static void ntoh_header(usbmux_tcp_header * hdr) -{ -	if (hdr) { -		hdr->length = ntohl(hdr->length); -		hdr->scnt = ntohl(hdr->scnt); -		hdr->ocnt = ntohl(hdr->ocnt); -		hdr->length16 = ntohs(hdr->length16); -	} -} - -/** Creates a USBMux header containing version information - *  - * @return A USBMux header - */ -static usbmux_version_header *version_header() -{ -	usbmux_version_header *version = -		(usbmux_version_header *) malloc(sizeof(usbmux_version_header)); -	version->type = 0; -	version->length = htonl(20); -	version->major = htonl(1); -	version->minor = 0; -	version->allnull = 0; -	return version; -} - -/** - * This function sets the configuration of the given device to 3 - * and claims the interface 1. If usb_set_configuration fails, it detaches - * the kernel driver that blocks the device, and retries configuration. - * - * @param device which device to configure - */ -static int usbmux_config_usb_device(usbmux_device_t device) -{ -	int ret; -	int bytes; -	char buf[512]; - -	log_debug_msg("claiming interface... "); -	ret = usb_claim_interface(device->usbdev, 1); -	if (ret != 0) { -		log_debug_msg("Error: usb_claim_interface returned %d: %s\n", ret, -					  strerror(-ret)); -		return -ENODEV; -	} else { -		log_debug_msg("done.\n"); -	} - -	// get the last configuration -	struct usb_config_descriptor *cfg = &device->__device->config[device->__device->descriptor.bNumConfigurations-1]; -	if (cfg && cfg->bNumInterfaces >= 2) { -		struct usb_interface *ifp = &cfg->interface[1]; -		if (ifp && ifp->num_altsetting >= 1) { -			struct usb_interface_descriptor *as = &ifp->altsetting[0]; -			int i; -			for (i = 0; i < as->bNumEndpoints; i++) { -				struct usb_endpoint_descriptor *ep=&as->endpoint[i]; -				if (ep->bEndpointAddress == BULKOUT) { -					device->wMaxPacketSize = ep->wMaxPacketSize; -				} -			} -		} -	} - -	log_debug_msg("Setting wMaxPacketSize to %d\n", device->wMaxPacketSize); - -	do { -		bytes = usb_bulk_read(device->usbdev, BULKIN, buf, 512, 800); -	} while (bytes > 0); - -	return 0; -} - -/** - * Given a USB bus and device number, returns a device handle to the device on - * that bus. To aid compatibility with future devices, this function does not - * check the vendor and device IDs! To do that, you should use - * usbmux_get_device() or a system-specific API (e.g. HAL). - * - * @param bus_n The USB bus number. - * @param dev_n The USB device number. - * @param device A pointer to a usbmux_device_t, which must be set to NULL upon - *      calling usbmux_get_specific_device, which will be filled with a device - *      descriptor on return.  - * @return 0 if ok, otherwise a negative errno value. - */ -int usbmux_get_specific_device(int bus_n, int dev_n, -							   usbmux_device_t * device) -{ -	struct usb_bus *bus; -	struct usb_device *dev; -	usbmux_version_header *version; -	int bytes = 0; - -	//check we can actually write in device -	if (!device || (device && *device)) -		return -EINVAL; - -	usbmux_device_t newdevice = -		(usbmux_device_t) malloc(sizeof(struct usbmux_device_int)); - -	// Initialize the struct -	newdevice->usbdev = NULL; -	newdevice->__device = NULL; - -	// don't forget these: -	newdevice->usbReceive.buffer = NULL; -	newdevice->usbReceive.leftover = 0; -	newdevice->usbReceive.capacity = 0; - -	// wMaxPacketSize -	newdevice->wMaxPacketSize = 64; - -	// Initialize libusb -	usb_init(); -	usb_find_busses(); -	usb_find_devices(); - -	// Set the device configuration -	for (bus = usb_get_busses(); bus; bus = bus->next) -		if (strtoul(bus->dirname, NULL, 10) == bus_n) -			for (dev = bus->devices; dev != NULL; dev = dev->next) -				if (strtol(dev->filename, NULL, 10) == dev_n) { -					newdevice->__device = dev; -					newdevice->usbdev = usb_open(newdevice->__device); - 					if (!newdevice->usbdev) { -						fprintf(stderr, "%s: Error: usb_open(): %s\n", __func__, usb_strerror()); -					} -					if (usbmux_config_usb_device(newdevice) == 0) { -						goto found; -					} -				} - -	usbmux_free_device(newdevice); - -	log_debug_msg("usbmux_get_specific_device: device not found\n"); -	return -ENODEV; - -  found: -	// Send the version command to the device -	version = version_header(); -	bytes = -		usb_bulk_write(newdevice->usbdev, BULKOUT, (char *) version, -					   sizeof(*version), 800); -	if (bytes < 20) { -		log_debug_msg("%s: libusb did NOT send enough!\n", __func__); -		if (bytes < 0) { -			log_debug_msg("%s: libusb gave me the error %d: %s (%s)\n", -						  __func__, bytes, usb_strerror(), -						  strerror(-bytes)); -		} -	} -	// Read the device's response -	bytes = -		usb_bulk_read(newdevice->usbdev, BULKIN, (char *) version, -					  sizeof(*version), 800); - -	// Check for bad response -	if (bytes < 20) { -		free(version); -		usbmux_free_device(newdevice); -		log_debug_msg("%s: Invalid version message -- header too short.\n", -					  __func__); -		if (bytes < 0) { -			log_debug_msg("%s: libusb error message %d: %s (%s)\n", -						  __func__, bytes, usb_strerror(), -						  strerror(-bytes)); -			return bytes; -		} -		return -EBADMSG; -	} -	// Check for correct version -	if (ntohl(version->major) == 1 && ntohl(version->minor) == 0) { -		// We're all ready to roll. -		log_debug_msg("%s: success\n", __func__); -		free(version); -		*device = newdevice; -		return 0; -	} else { -		// Bad header -		usbmux_free_device(newdevice); -		free(version); -		log_debug_msg("%s: Received a bad header/invalid version number.", -					  __func__); -		return -EBADMSG; -	} - -	// If it got to this point it's gotta be bad -	log_debug_msg("%s: Unknown error.\n", __func__); -	usbmux_free_device(newdevice); -	free(version); -	return -EBADMSG;			// if it got to this point it's gotta be bad -} - -/** Cleans up an usbmux_device_t structure, then frees the structure itself. - * This is a library-level function; deals directly with the device to tear - *  down relations, but otherwise is mostly internal. - *  - * @param device A pointer to an usbmux_device_t structure. - */ -int usbmux_free_device(usbmux_device_t device) -{ -	char buf[512]; -	int bytes = -1; - -	if (!device) -		return -EINVAL; -	int ret = 0; - -	if (device->usbdev) { -		do { -			bytes = usb_bulk_read(device->usbdev, BULKIN, buf, 512, 800); -		} while (bytes > 0); -	} - -	if (bytes < 0) { -		ret = bytes; -	} - -	if (device->usbReceive.buffer) { -		free(device->usbReceive.buffer); -	} -	if (device->usbdev) { -		usb_release_interface(device->usbdev, 1); -		usb_close(device->usbdev); -		ret = 0; -	} -	free(device); - -	return ret; -} - - - -/** Sends data to the device - * This is a low-level (i.e. directly to device) function. - *  - * @param device The device to send data to - * @param data The data to send - * @param datalen The length of the data - * @return The number of bytes sent, or -ERRNO on error - */ -static int send_to_device(usbmux_device_t device, char *data, int datalen) -{ -	if (!device) -		return -EINVAL; - -	int timeout = 1000; -	int retrycount = 0; -	int bytes = 0; - -if (toto_debug > 0) { -	pthread_mutex_lock(&printmutex); -	printf("===============================\n%s: trying to send\n", -		   __func__); -	print_buffer(data, datalen); -	printf("===============================\n"); -	pthread_mutex_unlock(&printmutex); -} - -	do { -		if (retrycount > 3) { -			log_debug_msg -				("EPIC FAIL! aborting on retry count overload.\n"); -			return -ECOMM; -		} - -		bytes = -			usb_bulk_write(device->usbdev, BULKOUT, data, datalen, -						   timeout); -		if (bytes == -ETIMEDOUT) { -			// timed out waiting for write. -			log_debug_msg("usb_bulk_write timeout error.\n"); -			return bytes; -		} else if (bytes < 0) { -			log_debug_msg -				("usb_bulk_write failed with error. err:%d (%s)(%s)\n", -				 bytes, usb_strerror(), strerror(-bytes)); -			return bytes; -		} else if (bytes == 0) { -			log_debug_msg("usb_bulk_write sent nothing. retrying.\n"); -			timeout = timeout * 4; -			retrycount++; -			continue; -		} else if (bytes < datalen) { -			log_debug_msg -				("usb_bulk_write failed to send full dataload. %d of %d\n", -				 bytes, datalen); -			timeout = timeout * 4; -			retrycount++; -			data += bytes; -			datalen -= bytes; -			continue; -		} -		if ((bytes % device->wMaxPacketSize) == 0) { -		 	log_debug_msg("NOTE: sending NULL packet\n"); -			char nullp = 0; -			int res = usb_bulk_write(device->usbdev, BULKOUT, -						&nullp, 0, timeout); -			if (res < 0) { -			    log_debug_msg("ERROR: NULL packet write returned %d\n", res); -			} -		} -	} while (0);				// fall out - -	if (bytes > 0) { -		if (toto_debug > 0) { -			pthread_mutex_lock(&printmutex); -			printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); -			printf("%s: sent to device\n", __func__); -			print_buffer(data, bytes); -			printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); -			pthread_mutex_unlock(&printmutex); -		} -	} -	return bytes; -} - -/** Receives data from the device - * This function is a low-level (i.e. direct from device) function. - *  - * @param device The device to receive data from - * @param data Where to put data read - * @param datalen How much data to read in - * @param timeout How many milliseconds to wait for data - *  - * @return How many bytes were read in, or -1 on error. - */ -static int recv_from_device_timeout(usbmux_device_t device, char *data, -							 int datalen, int timeoutmillis) -{ -	if (!device) -		return -EINVAL; -	//log_debug_msg("%s: attempting to receive %i bytes\n", __func__, datalen); - -	int bytes = -		usb_bulk_read(device->usbdev, BULKIN, data, datalen, -					  timeoutmillis); -	// There are some things which are errors, others which are no problem. -	// It's not documented in libUSB, but it seems that the error values -	// returned are just negated ERRNO values. -	if (bytes < 0) { -		if (bytes == -ETIMEDOUT) { -			// ignore this. it just means timeout reached before we -			//  picked up any data. no problem. -			return 0; -		} else { -			fprintf(stderr, "%s: libusb gave me the error %d: %s (%s)\n", -					__func__, bytes, usb_strerror(), strerror(-bytes)); -			log_debug_msg("%s: libusb gave me the error %d: %s (%s)\n", -						  __func__, bytes, usb_strerror(), -						  strerror(-bytes)); -		} -		return bytes; -	} -	if (bytes > 0) { -		if (toto_debug > 0) { -			pthread_mutex_lock(&printmutex); -			printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); -			printf("%s: received from device:\n", __func__); -			print_buffer(data, bytes); -			printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); -			pthread_mutex_unlock(&printmutex); -		} -	} - -	return bytes; -} - -/** Creates a USBMux packet for the given set of ports. - *  - * @param s_port The source port for the connection. - * @param d_port The destination port for the connection. - * - * @return A USBMux packet - */ -static usbmux_tcp_header *new_mux_packet(uint16_t s_port, uint16_t d_port) -{ -	usbmux_tcp_header *conn = -		(usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header)); -	conn->type = htonl(6); -	conn->length = sizeof(usbmux_tcp_header); -	conn->sport = htons(s_port); -	conn->dport = htons(d_port); -	conn->scnt = 0; -	conn->ocnt = 0; -	conn->offset = 0x50; -	conn->window = htons(0x0200); -	conn->nullnull = 0x0000; -	conn->length16 = sizeof(usbmux_tcp_header); -	return conn; -} - - -/** Removes a connection from the list of connections made. - * The list of connections is necessary for buffering. - *  - * @param connection The connection to delete from the tracking list. - */ -static void delete_connection(usbmux_client_t connection) -{ -	usbmux_client_t *newlist = NULL; - -	pthread_mutex_lock(&usbmuxmutex); - -	// update the global list of connections -	if (clients > 1) { -		newlist = -			(usbmux_client_t *) malloc(sizeof(usbmux_client_t) * -									   (clients - 1)); -		int i = 0, j = 0; -		for (i = 0; i < clients; i++) { -			if (connlist[i] == connection) -				continue; -			else { -				newlist[j] = connlist[i]; -				j++; -			} -		} -	} -	if (connlist) { -		free(connlist); -	} -	connlist = newlist; -	clients--; - -	// free up this connection -	pthread_mutex_lock(&connection->mutex); -	if (connection->recv_buffer) { -		free(connection->recv_buffer); -		connection->recv_buffer = NULL; -	} -	if (connection->header) { -		free(connection->header); -		connection->header = NULL; -	} -	connection->r_len = 0; -	pthread_mutex_unlock(&connection->mutex); -	pthread_mutex_destroy(&connection->mutex); -	free(connection); - -	pthread_mutex_unlock(&usbmuxmutex); -} - -/** Adds a connection to the list of connections made. - * The connection list is necessary for buffering. - * - * @param connection The connection to add to the global list of connections. - */ - -static void add_connection(usbmux_client_t connection) -{ -	pthread_mutex_lock(&usbmuxmutex); -	usbmux_client_t *newlist = -		(usbmux_client_t *) realloc(connlist, -									sizeof(usbmux_client_t) * (clients + -															   1)); -	newlist[clients] = connection; -	connlist = newlist; -	clients++; -	pthread_mutex_unlock(&usbmuxmutex); -} - -/** - * Get a source port number that is not used by one of our connections - * This is needed for us to make sure we are not sending on another - * connection. - */ -static uint16_t get_free_port() -{ -	int i; -	uint16_t newport = 30000; -	int cnt = 0; - -	pthread_mutex_lock(&usbmuxmutex); -	while (1) { -		cnt = 0; -		for (i = 0; i < clients; i++) { -			if (ntohs(connlist[i]->header->sport) == newport) { -				cnt++; -			} -		} -		if (cnt == 0) { -			// newport is not used in our list of connections! -			break; -		} else { -			newport++; -			if (newport < 30000) { -				// if all ports from 30000 to 65535 are in use, -				// the value wraps (16-bit overflow) -				// return 0, no port is available. -				// This should not happen, but just in case ;) -				newport = 0; -				break; -			} -		} -	} -	pthread_mutex_unlock(&usbmuxmutex); - -	return newport; -} - -/** Initializes a connection to 'device' with source port s_port and destination port d_port - * - * @param device The device to initialize a connection on. - * @param src_port The source port - * @param dst_port The destination port -- 0xf27e for lockdownd.  - * @param client A mux TCP header for the connection which is used for tracking and data transfer. - * @return 0 on success, a negative errno value otherwise. - */ -int usbmux_new_client(usbmux_device_t device, uint16_t src_port, -					  uint16_t dst_port, usbmux_client_t * client) -{ -	if (!device || !dst_port) -		return -EINVAL; - -	src_port = get_free_port(); - -	if (!src_port) { -		// this is a special case, if we get 0, this is not good, so -		return -EISCONN;		// TODO: error code suitable? -	} -	// Initialize connection stuff -	usbmux_client_t new_connection = -		(usbmux_client_t) malloc(sizeof(struct usbmux_client_int)); -	new_connection->header = new_mux_packet(src_port, dst_port); - -	// send TCP syn -	if (new_connection && new_connection->header) { -		int err = 0; -		new_connection->header->tcp_flags = TCP_SYN; -		new_connection->header->length = new_connection->header->length; -		new_connection->header->length16 = -			new_connection->header->length16; -		new_connection->header->scnt = 0; -		new_connection->header->ocnt = 0; -		new_connection->device = device; -		new_connection->recv_buffer = NULL; -		new_connection->r_len = 0; -		pthread_cond_init(&new_connection->wait, NULL); -		pthread_mutex_init(&new_connection->mutex, NULL); -		pthread_cond_init(&new_connection->wr_wait, NULL); -		new_connection->wr_pending_scnt = 0; -		new_connection->wr_window = 0; -		add_connection(new_connection); -		new_connection->error = 0; -		new_connection->cleanup = 0; -		new_connection->connected = 0; -		hton_header(new_connection->header); -		log_debug_msg("%s: send_to_device (%d --> %d)\n", __func__, -					  ntohs(new_connection->header->sport), -					  ntohs(new_connection->header->dport)); -		err = -			send_to_device(device, (char *) new_connection->header, -						   sizeof(usbmux_tcp_header)); -		if (err >= 0) { -			*client = new_connection; -			return 0; -		} else { -			delete_connection(new_connection); -			return err; -		} -	} -	// if we get to this point it's probably bad -	return -ENOMEM; -} - -/** Cleans up the given USBMux connection. - * @note Once a connection is closed it may not be used again. - *  - * @param connection The connection to close. - * - * @return 0 on success or a negative errno value on error. - */ -int usbmux_free_client(usbmux_client_t client) -{ -	if (!client || !client->device) -		return -EINVAL; - -	int err = 0; -	int result = 0; -	pthread_mutex_lock(&client->mutex); -	client->header->tcp_flags = TCP_RST; -	client->header->length = 0x1C; -	client->header->window = 0; -	client->header->length16 = 0x1C; -	hton_header(client->header); - -	err = -		send_to_device(client->device, (char *) client->header, -					   sizeof(usbmux_tcp_header)); -	if (err < 0) { -		log_debug_msg("%s: error sending TCP_FIN\n", __func__); -		result = err; -	} - -	client->cleanup = 1; - -	// make sure we don't have any last-minute laggards waiting on this. -	// I put it after the mutex unlock because we have cases where the -	// conditional wait is dependent on re-grabbing that mutex. -	pthread_cond_broadcast(&client->wait); -	pthread_cond_destroy(&client->wait); -	pthread_cond_broadcast(&client->wr_wait); -	pthread_cond_destroy(&client->wr_wait); - -	pthread_mutex_unlock(&client->mutex); - -	return result; -} - -/** Sends the given data over the selected connection. - * - * @param client The client we're sending data on. - * @param data A pointer to the data to send. - * @param datalen How much data we're sending. - * @param sent_bytes The number of bytes sent, minus the header (28) - * - * @return 0 on success or a negative errno value on error. - */ -int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, -				uint32_t * sent_bytes) -{ -	if (!client->device || !client || !sent_bytes) -		return -EINVAL; - -	if (client->error < 0) { -		return client->error; -	} - -	*sent_bytes = 0; -	pthread_mutex_lock(&client->mutex); - -	int sendresult = 0; -	uint32_t blocksize = 0; -	if (client->wr_window <= 0) { -		struct timespec ts; -		clock_gettime(CLOCK_REALTIME, &ts); -		//ts.tv_sec += 1; -		ts.tv_nsec += 750 * 1000; -		if (pthread_cond_timedwait(&client->wait, &client->mutex, &ts) == -			ETIMEDOUT) { -			// timed out. optimistically grow the window and try to make progress -			client->wr_window += WINDOW_INCREMENT; -		} -	} - -	blocksize = sizeof(usbmux_tcp_header) + datalen; - -	// client->scnt and client->ocnt should already be in host notation... -	// we don't need to change them juuuust yet.  -	char *buffer = (char *) malloc(blocksize + 2);	// allow 2 bytes of safety padding -	// Set the length -	client->header->length = blocksize; -	client->header->length16 = blocksize; - -	// Put header into big-endian notation -	hton_header(client->header); -	// Concatenation of stuff in the buffer. -	memcpy(buffer, client->header, sizeof(usbmux_tcp_header)); -	memcpy(buffer + sizeof(usbmux_tcp_header), data, datalen); - -	log_debug_msg("%s: send_to_device(%d --> %d)\n", __func__, -				  ntohs(client->header->sport), -				  ntohs(client->header->dport)); -	sendresult = send_to_device(client->device, buffer, blocksize); -	// Now that we've sent it off, we can clean up after our sloppy selves. -	if (buffer) -		free(buffer); - -	// revert header fields that have been swapped before trying to send -	ntoh_header(client->header); - -	// update counts ONLY if the send succeeded. -	if ((uint32_t) sendresult == blocksize) { -		// Re-calculate scnt -		client->header->scnt += datalen; -		client->wr_window -= blocksize; -	} - -	pthread_mutex_unlock(&client->mutex); - -	if (sendresult == -ETIMEDOUT || sendresult == 0) { -		// no problem for now... -		*sent_bytes = 0; -		return -ETIMEDOUT; -	} else if (sendresult < 0) { -		return sendresult; -	} else if ((uint32_t) sendresult == blocksize) { -		// actual number of data bytes sent. -		*sent_bytes = sendresult - sizeof(usbmux_tcp_header); -		return 0; -	} else { -		fprintf(stderr, -				"usbsend managed to dump a packet that is not full size. %d of %d\n", -				sendresult, blocksize); -		return -EBADMSG; -	} -} - -/** append the packet's DATA to the receive buffer for the client. - * - *  this has a few other corner-case functions: - *  1. this will properly handle the handshake syn+ack. - *  2. for all receives, this will appropriately update the ocnt. - *  - * @return number of bytes consumed (header + data) - */ -static uint32_t append_receive_buffer(usbmux_client_t client, char *packet) -{ -	if (client == NULL || packet == NULL) -		return 0; - -	usbmux_tcp_header *header = (usbmux_tcp_header *) packet; -	char *data = &packet[sizeof(usbmux_tcp_header)]; -	uint32_t packetlen = ntohl(header->length); -	uint32_t datalen = packetlen - sizeof(usbmux_tcp_header); - -	int dobroadcast = 0; - -	pthread_mutex_lock(&client->mutex); - -	// we need to handle a few corner case tasks and book-keeping which -	// falls on our responsibility because we are the ones reading in -	// feedback. -	if (client->header->scnt == 0 && client->header->ocnt == 0) { -		log_debug_msg("client is still waiting for handshake.\n"); -		if (header->tcp_flags == (TCP_SYN | TCP_ACK)) { -			log_debug_msg("yes, got syn+ack ; replying with ack.\n"); -			client->header->tcp_flags = TCP_ACK; -			client->header->length = sizeof(usbmux_tcp_header); -			client->header->length16 = sizeof(usbmux_tcp_header); -			client->header->scnt += 1; -			client->header->ocnt = header->ocnt; -			hton_header(client->header); -			// push it to USB -			// TODO: need to check for error in the send here.... :( -			log_debug_msg("%s: send_to_device (%d --> %d)\n", __func__, -						  ntohs(client->header->sport), -						  ntohs(client->header->dport)); -			if (send_to_device -				(client->device, (char *) client->header, -				 sizeof(usbmux_tcp_header)) <= 0) { -				log_debug_msg("%s: error when pushing to usb...\n", -							  __func__); -			} else { -				client->connected = 1; -			} -			// need to revert some of the fields back to host notation. -			ntoh_header(client->header); -		} else { -			client->error = -ECONNABORTED; -			// woah... this connection failed us. -			// TODO: somehow signal that this stream is a no-go. -			log_debug_msg("WOAH! client failed to get proper syn+ack.\n"); -		} -	} -	// update TCP counters and windows. -	// -	// save the window that we're getting from the USB device. -	// apparently the window is bigger than just the 512 that's typically -	// advertised. iTunes apparently shifts this value by 8 to get a much -	// larger number. -	if (header->tcp_flags & TCP_RST) { -		client->error = -ECONNRESET; - -		if (datalen > 0) { -			char e_msg[128]; -			e_msg[0] = 0; -			if (datalen > 1) { -				memcpy(e_msg, data + 1, datalen - 1); -				e_msg[datalen - 1] = 0; -			} -			// fetch the message -			switch (data[0]) { -			case 0: -				// this is not an error, it's just a status message. -				log_debug_msg("received status message: %s\n", e_msg); -				datalen = 0; -				break; -			case 1: -				log_debug_msg("received error message: %s\n", e_msg); -				datalen = 0; -				break; -			default: -				log_debug_msg -					("received unknown message (type 0x%02x): %s\n", -					 data[0], e_msg); -				//datalen = 0; // <-- we let this commented out for testing -				break; -			} -		} else { -			log_debug_msg -				("peer sent connection reset. setting error: %d\n", -				 client->error); -		} -	} -	// the packet's ocnt tells us how much of our data the device has received. -	if (header->tcp_flags & TCP_ACK) { -		// this is a hacky magic number condition. it seems that once -		// the window reported by the device starts to drop below this -		// number, we quickly fall into connection reset problems. -		// Once we see the reported window size start falling off, -		// ut off and wait for solid acks to come back. -		if (ntohs(header->window) < 256) -			client->wr_window = 0; - -		// check what just got acked. -		if (ntohl(header->ocnt) < client->header->scnt) { -			// we got some kind of ack, but it hasn't caught up -			// with the pending that have been sent. -			pthread_cond_broadcast(&client->wr_wait); -		} else if (ntohl(header->ocnt) > -				   /*client->wr_pending_scnt */ client->header->scnt) { -			fprintf(stderr, -					"WTF?! acks overtook pending outstanding.  %u,%u\n", -					ntohl(header->ocnt), client->wr_pending_scnt); -		} else { -			// reset the window -			client->wr_window = WINDOW_MAX; -			pthread_cond_broadcast(&client->wr_wait); -		} -	} -	// the packet's scnt will be our new ocnt. -	client->header->ocnt = ntohl(header->scnt); - -	// ensure there is enough space, either by first malloc or realloc -	if (datalen > 0) { -		log_debug_msg("%s: putting %d bytes into client's recv_buffer\n", -					  __func__, datalen); -		if (client->r_len == 0) -			dobroadcast = 1; - -		if (client->recv_buffer == NULL) { -			client->recv_buffer = malloc(datalen); -			client->r_len = 0; -		} else { -			client->recv_buffer = -				realloc(client->recv_buffer, client->r_len + datalen); -		} - -		memcpy(&client->recv_buffer[client->r_len], data, datalen); -		client->r_len += datalen; -	} - -	pthread_mutex_unlock(&client->mutex); - -	// I put this outside the mutex unlock just so that when the threads -	// wake, we don't have to do another round of unlock+try to grab. -	if (dobroadcast) -		pthread_cond_broadcast(&client->wait); - -	return packetlen; -} - -/** - * @note THERE IS NO MUTEX LOCK IN THIS FUNCTION! - * because we're only called from one location, pullbulk, where the lock - * is already held. - */ -static usbmux_client_t find_client(usbmux_tcp_header * recv_header) -{ -	// remember, as we're looking for the client, the receive header is -	// coming from the USB into our client. This means that when we check -	// the src/dst ports, we need to reverse them. -	usbmux_client_t retval = NULL; - -	// just for debugging check, I'm going to convert the numbers to host-endian. -	uint16_t hsport = ntohs(recv_header->sport); -	uint16_t hdport = ntohs(recv_header->dport); - -	pthread_mutex_lock(&usbmuxmutex); -	int i; -	for (i = 0; i < clients; i++) { -		uint16_t csport = ntohs(connlist[i]->header->sport); -		uint16_t cdport = ntohs(connlist[i]->header->dport); - -		if (hsport == cdport && hdport == csport) { -			retval = connlist[i]; -			break; -		} -	} -	pthread_mutex_unlock(&usbmuxmutex); - -	return retval; -} - -/** pull in a big USB bulk packet and distribute it to queues appropriately. - */ -int usbmux_pullbulk(usbmux_device_t device) -{ -	if (!device) -		return -EINVAL; - -	int res = 0; -	static const int DEFAULT_CAPACITY = 128 * 1024; -	if (device->usbReceive.buffer == NULL) { -		device->usbReceive.capacity = DEFAULT_CAPACITY; -		device->usbReceive.buffer = malloc(device->usbReceive.capacity); -		device->usbReceive.leftover = 0; -	} -	// start the cursor off just ahead of the leftover. -	char *cursor = &device->usbReceive.buffer[device->usbReceive.leftover]; -	// pull in content, note that the amount we can pull is capacity minus leftover -	int readlen = -		recv_from_device_timeout(device, cursor, -								 device->usbReceive.capacity - -								 device->usbReceive.leftover, 3000); -	if (readlen < 0) { -		res = readlen; -		//fprintf(stderr, "recv_from_device_timeout gave us an error.\n"); -		readlen = 0; -	} -	if (readlen > 0) { -		//fprintf(stdout, "recv_from_device_timeout pulled an extra %d bytes\n", readlen); -	} -	// the amount of content we have to work with is the remainder plus -	// what we managed to read -	device->usbReceive.leftover += readlen; - -	// reset the cursor to the front of that buffer and work through -	// trying to decode packets out of them. -	cursor = device->usbReceive.buffer; -	while (1) { -		// check if there's even sufficient data to decode a header -		if (device->usbReceive.leftover < sizeof(usbmux_tcp_header)) -			break; -		usbmux_tcp_header *header = (usbmux_tcp_header *) cursor; - -		log_debug_msg("%s: recv_from_device_timeout (%d --> %d)\n", -					  __func__, ntohs(header->sport), -					  ntohs(header->dport)); - -		// now that we have a header, check if there is sufficient data -		// to construct a full packet, including its data -		uint32_t packetlen = ntohl(header->length); -		if ((uint32_t) device->usbReceive.leftover < packetlen) { -			fprintf(stderr, -					"%s: not enough data to construct a full packet\n", -					__func__); -			break; -		} -		// ok... find the client this packet will get stuffed to. -		usbmux_client_t client = find_client(header); -		if (client == NULL) { -			log_debug_msg -				("WARNING: client for packet cannot be found. dropping packet.\n"); -		} else { -			// stuff the data -			log_debug_msg -				("%s: found client, calling append_receive_buffer\n", -				 __func__); -			append_receive_buffer(client, cursor); - -			// perhaps this is too general, == -ECONNRESET -			//  might be a better check here -			if (client->error < 0) { -				pthread_mutex_lock(&client->mutex); -				if (client->cleanup) { -					pthread_mutex_unlock(&client->mutex); -					log_debug_msg("freeing up connection (%d->%d)\n", -								  ntohs(client->header->sport), -								  ntohs(client->header->dport)); -					delete_connection(client); -				} else { -					pthread_mutex_unlock(&client->mutex); -				} -			} -		} - -		// move the cursor and account for the consumption -		cursor += packetlen; -		device->usbReceive.leftover -= packetlen; -	} - -	// now, we need to manage any leftovers. -	// I'm going to manage the leftovers by alloc'ing a new block and -	// copyingthe leftovers to it. This is just to prevent problems with -	// memory moves where there may be overlap. Besides, the leftovers -	// should be small enough that this copy is minimal in overhead. -	// -	// if there are no leftovers, we just leave the datastructure as is, -	// and re-use the block next time. -	if (device->usbReceive.leftover > 0 -		&& cursor != device->usbReceive.buffer) { -		log_debug_msg("%s: we got a leftover, so handle it\n", __func__); -		char *newbuff = malloc(DEFAULT_CAPACITY); -		memcpy(newbuff, cursor, device->usbReceive.leftover); -		free(device->usbReceive.buffer); -		device->usbReceive.buffer = newbuff; -		device->usbReceive.capacity = DEFAULT_CAPACITY; -	} - -	return res; -} - -/** - * return the error code stored in usbmux_client_t structure, - * e.g. non-zero when an usb read error occurs. - * - * @param client the usbmux client - * - * @return 0 or a negative errno value. - */ -int usbmux_get_error(usbmux_client_t client) -{ -	if (!client) { -		return 0; -	} -	return client->error; -} - -/** This function reads from the client's recv_buffer. - * - * @param client The client to receive data from. - * @param data Where to put the data we receive.  - * @param datalen How much data to read. - * @param timeout How many milliseconds to wait for data - * - * @return 0 on success or a negative errno value on failure. - */ -int usbmux_recv_timeout(usbmux_client_t client, char *data, -						uint32_t datalen, uint32_t * recv_bytes, -						int timeout) -{ - -	if (!client || !data || datalen == 0 || !recv_bytes) -		return -EINVAL; - -	if (client->error < 0) -		return client->error; - -	pthread_mutex_lock(&client->mutex); - -	if (timeout > 0 && (client->recv_buffer == NULL || client->r_len == 0)) { -		struct timespec ts; -		clock_gettime(CLOCK_REALTIME, &ts); -		ts.tv_sec += timeout / 1000; -		ts.tv_nsec += (timeout - ((int) (timeout / 1000)) * 1000) * 1000; -		pthread_cond_timedwait(&client->wait, &client->mutex, &ts); -	} - -	*recv_bytes = 0; -	if (client->recv_buffer != NULL && client->r_len > 0) { -		uint32_t foolen = datalen; -		if ((int) foolen > client->r_len) -			foolen = client->r_len; -		memcpy(data, client->recv_buffer, foolen); -		*recv_bytes = foolen; - -		// preserve any left-over unread amounts. -		int remainder = client->r_len - foolen; -		if (remainder > 0) { -			char *newbuf = malloc(remainder); -			memcpy(newbuf, client->recv_buffer + foolen, remainder); -			client->r_len = remainder; -			free(client->recv_buffer); -			client->recv_buffer = newbuf; -		} else { -			free(client->recv_buffer); -			client->recv_buffer = NULL; -			client->r_len = 0; -		} -	} - -	pthread_mutex_unlock(&client->mutex); - -	return 0; -} - -int usbmux_is_connected(usbmux_client_t client) -{ -	if (!client) { -		return 0; -	} -	return client->connected; -} diff --git a/src/usbmux.h b/src/usbmux.h deleted file mode 100644 index 155316a..0000000 --- a/src/usbmux.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2008 Jing Su. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  - */ - -#ifndef __USBMUX_H__ -#define __USBMUX_H__ - -#include <stdint.h> -#include <sys/types.h> -//#include <sys/stat.h> - - -void usbmux_set_debug(int e); - -struct usbmux_device_int; -typedef struct usbmux_device_int *usbmux_device_t; - -struct usbmux_client_int; -typedef struct usbmux_client_int *usbmux_client_t; - -int usbmux_get_device ( usbmux_device_t *device ); -int usbmux_get_specific_device(int bus_n, int dev_n, usbmux_device_t * device); -int usbmux_free_device ( usbmux_device_t device ); - - -int usbmux_new_client ( usbmux_device_t device, uint16_t src_port, uint16_t dst_port, usbmux_client_t *client ); -int usbmux_free_client ( usbmux_client_t client ); - -int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, uint32_t * sent_bytes); - -int usbmux_recv_timeout(usbmux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout); - -int usbmux_pullbulk(usbmux_device_t device); - -int usbmux_get_error(usbmux_client_t client); - -int usbmux_is_connected(usbmux_client_t client); - -#endif diff --git a/src/usbmuxd-proto.h b/src/usbmuxd-proto.h deleted file mode 100644 index 7f8c2d6..0000000 --- a/src/usbmuxd-proto.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Protocol defintion for usbmuxd proxy protocol */ - -#ifndef __USBMUXD_PROTO_H -#define __USBMUXD_PROTO_H - -#include <stdint.h> - -#define USBMUXD_SOCKET_FILE "/var/run/usbmuxd" - -struct usbmuxd_header { -	uint32_t length;    // length of message, including header -	uint32_t reserved;  // always zero -	uint32_t type;      // message type -	uint32_t tag;       // responses to this query will echo back this tag -} __attribute__((__packed__)); - -struct usbmuxd_result { -	struct usbmuxd_header header; -	uint32_t result; -} __attribute__((__packed__)); - -struct	usbmuxd_connect_request { -	struct usbmuxd_header header; -	uint32_t device_id; -	uint16_t tcp_dport;   // TCP port number -	uint16_t reserved;   // set to zero -} __attribute__((__packed__)); - -struct usbmuxd_device { -	uint32_t device_id; -	uint16_t product_id; -	char serial_number[40]; -} __attribute__((__packed__)); - -struct usbmuxd_device_info_record { -	struct usbmuxd_header header; -	struct usbmuxd_device device; -	char padding[222]; -} __attribute__((__packed__)); - -struct usbmuxd_scan_request { -	struct usbmuxd_header header; -} __attribute__((__packed__)); - -enum { -	USBMUXD_RESULT  = 1, -	USBMUXD_CONNECT = 2, -	USBMUXD_SCAN = 3, -	USBMUXD_DEVICE_INFO = 4, -}; - -#endif /* __USBMUXD_PROTO_H */ diff --git a/src/usbmuxd.h b/src/usbmuxd.h deleted file mode 100644 index ba45ec3..0000000 --- a/src/usbmuxd.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef __USBMUXD_H -#define __USBMUXD_H - -/** - * Array entry returned by 'usbmuxd_scan()' scanning. - * - * If more than one device is available, 'product_id' and - * 'serial_number' and be analysed to help make a selection. - * The relevant 'handle' should be passed to 'usbmuxd_connect()', to - * start a proxy connection.  The value 'handle' should be considered - * opaque and no presumption made about the meaning of its value. - */ -typedef struct { -	int handle; -	int product_id; -	char serial_number[41]; -} usbmuxd_scan_result; - -/** - * Contacts usbmuxd and performs a scan for connected devices. - * - * @param available_devices pointer to array of usbmuxd_scan_result. - * 	Array of available devices.  The required 'handle' - *	should be passed to 'usbmuxd_connect()'.  The returned array - *	is zero-terminated for convenience; the final (unused) - *	entry containing handle == 0.  The returned array pointer - *	should be freed by passing to 'free()' after use. - * - * @return number of available devices, zero on no devices, or negative on error - */ -int usbmuxd_scan(usbmuxd_scan_result **available_devices); - -/** - * Request proxy connect to  - * - * @param handle returned by 'usbmuxd_scan()' - * - * @param tcp_port TCP port number on device, in range 0-65535. - *	common values are 62078 for lockdown, and 22 for SSH. - * - * @return file descriptor socket of the connection, or -1 on error - */ -int usbmuxd_connect(const int handle, const unsigned short tcp_port); - -/** - * Disconnect. For now, this just closes the socket file descriptor. - * - * @param sfd socker file descriptor returned by usbmuxd_connect() - * - * @return 0 on success, -1 on error. - */ -int usbmuxd_disconnect(int sfd); - -/** - * Send data to the specified socket. - * - * @param sfd socket file descriptor returned by usbmuxd_connect() - * @param data buffer to send - * @param len size of buffer to send - * @param sent_bytes how many bytes sent - * - * @return 0 on success, a negative errno value otherwise. - */ -int usbmuxd_send(int sfd, const char *data, uint32_t len, uint32_t *sent_bytes); - -/** - * Receive data from the specified socket. - * - * @param sfd socket file descriptor returned by usbmuxd_connect() - * @param data buffer to put the data to - * @param len number of bytes to receive - * @param recv_bytes number of bytes received - * @param timeout how many milliseconds to wait for data - * - * @return 0 on success, a negative errno value otherwise. - */ -int usbmuxd_recv_timeout(int sfd, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout); - -/** - * Receive data from the specified socket with a default timeout. - * - * @param sfd socket file descriptor returned by usbmuxd_connect() - * @param data buffer to put the data to - * @param len number of bytes to receive - * @param recv_bytes number of bytes received - * - * @return 0 on success, a negative errno value otherwise. - */ -int usbmuxd_recv(int sfd, char *data, uint32_t len, uint32_t *recv_bytes); - -#endif /* __USBMUXD_H */ | 
