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 */ |