From 71d8775f865b431135cd3c178763d0a294b8ff9e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 20 Feb 2009 11:24:52 +0100 Subject: initial import --- Makefile | 26 ++ iphone.c | 1089 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ iphone.h | 79 +++++ iproxy.c | 329 ++++++++++++++++++ sock_stuff.c | 277 +++++++++++++++ sock_stuff.h | 27 ++ testclient.c | 148 ++++++++ usbmuxd.c | 795 ++++++++++++++++++++++++++++++++++++++++++ usbmuxd.h | 44 +++ 9 files changed, 2814 insertions(+) create mode 100644 Makefile create mode 100644 iphone.c create mode 100644 iphone.h create mode 100644 iproxy.c create mode 100644 sock_stuff.c create mode 100644 sock_stuff.h create mode 100644 testclient.c create mode 100644 usbmuxd.c create mode 100644 usbmuxd.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..04a36b3 --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +TARGET=usbmuxd +CFLAGS=-Wall +LDFLAGS=-lpthread -lusb -lrt + +objects = sock_stuff.o usbmuxd.o iphone.o + +all: $(TARGET) + +%.o: %.c %.h + $(CC) -o $@ $(CFLAGS) -c $< + +$(TARGET): $(objects) + $(CC) -o $@ $(LDFLAGS) $^ + +clean: + rm -f *.o $(TARGET) + +realclean: clean + rm -f *~ + +testclient: testclient.c sock_stuff.o + $(CC) $(LDFLAGS) -o testclient $(CFLAGS) $< sock_stuff.o + +iproxy: iproxy.c sock_stuff.o + $(CC) -lpthread -o iproxy $(CFLAGS) $< sock_stuff.o + diff --git a/iphone.c b/iphone.c new file mode 100644 index 0000000..9035be9 --- /dev/null +++ b/iphone.c @@ -0,0 +1,1089 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "iphone.h" + +#define BULKIN 0x85 +#define BULKOUT 0x04 +#define HEADERLEN 28 + +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint8_t uint8; + +static const uint8 TCP_FIN = 1; +static const uint8 TCP_SYN = 1 << 1; +static const uint8 TCP_RST = 1 << 2; +static const uint8 TCP_PSH = 1 << 3; +static const uint8 TCP_ACK = 1 << 4; +static const uint8 TCP_URG = 1 << 5; + +// I have trouble figuring out how to properly manage the windowing to +// the iPhone. It keeps sending back 512 and seems to drop off a cliff +// when the phone gets overwhelmed. In addition, the phone 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 phone is sending back to us, I've figured out some magic number +// constants which seem to work okay. +static const uint32 WINDOW_MAX = 5 * 1024; +static const uint32 WINDOW_INCREMENT = 512; + + +struct iphone_device_int { + char *buffer; + struct usb_dev_handle *device; + struct usb_device *__device; +}; + +typedef struct { + uint32 type, length, major, minor, allnull; +} usbmux_version_header; + +typedef struct { + uint32 type, length; + uint16 sport, dport; + uint32 scnt, ocnt; + uint8 offset, tcp_flags; + uint16 window, nullnull, length16; +} usbmux_tcp_header; + +struct iphone_umux_client_int { + usbmux_tcp_header *header; + iphone_device_t phone; + + 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 phone. + 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 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. + iphone_error_t error; +}; + + +typedef struct { + char* buffer; + int leftover; + int capacity; +} receivebuf_t; + + +static pthread_mutex_t iphonemutex = PTHREAD_MUTEX_INITIALIZER; +static iphone_umux_client_t *connlist = NULL; +static int clients = 0; +static receivebuf_t usbReceive = {NULL, 0, 0}; + + +/** + */ +int toto_debug = 0; +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) + fprintf(stderr, format, args); + + va_end(args); + +#endif +} + + +/** Creates a USBMux header containing version information + * + * @return A USBMux header + */ +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 phone which device to configure + */ +static iphone_error_t iphone_config_usb_device(iphone_device_t phone) +{ + int ret; + int bytes; + char buf[512]; + + log_debug_msg("setting configuration...\n"); + ret = usb_set_configuration(phone->device, 3); + if (ret != 0) { + log_debug_msg("Hm, usb_set_configuration returned %d: %s\n", ret, strerror(-ret)); +#if LIBUSB_HAS_GET_DRIVER_NP + log_debug_msg("trying to fix:\n"); + log_debug_msg("-> detaching kernel driver... "); + ret = usb_detach_kernel_driver_np(phone->device, phone->__device->config->interface->altsetting->bInterfaceNumber); + if (ret != 0) { + log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", ret, strerror(-ret)); + } else { + log_debug_msg("done.\n"); + log_debug_msg("setting configuration again... "); + ret = usb_set_configuration(phone->device, 3); + if (ret != 0) { + log_debug_msg("Error: usb_set_configuration returned %d: %s\n", ret, strerror(-ret)); + log_debug_msg("--> trying to continue anyway...\n"); + } else { + log_debug_msg("done.\n"); + } + } +#else + log_debug_msg("--> trying to continue anyway...\n"); +#endif + } else { + log_debug_msg("done.\n"); + } + + log_debug_msg("claiming interface... "); + ret = usb_claim_interface(phone->device, 1); + if (ret != 0) { + log_debug_msg("Error: usb_claim_interface returned %d: %s\n", ret, strerror(-ret)); + return IPHONE_E_NO_DEVICE; + } else { + log_debug_msg("done.\n"); + } + + do { + bytes = usb_bulk_read(phone->device, BULKIN, buf, 512, 800); + } while (bytes > 0); + + return IPHONE_E_SUCCESS; +} + +/** + * Given a USB bus and device number, returns a device handle to the iPhone 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 + * iphone_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 iphone_device_t, which must be set to NULL upon + * calling iphone_get_specific_device, which will be filled with a device + * descriptor on return. + * @return IPHONE_E_SUCCESS if ok, otherwise an error code. + */ +iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_device_t * device) +{ + struct usb_bus *bus, *busses; + struct usb_device *dev; + usbmux_version_header *version; + int bytes = 0; + + //check we can actually write in device + if (!device || (device && *device)) + return IPHONE_E_INVALID_ARG; + + iphone_device_t phone = (iphone_device_t) malloc(sizeof(struct iphone_device_int)); + + // Initialize the struct + phone->device = NULL; + phone->__device = NULL; + phone->buffer = NULL; + + // Initialize libusb + usb_init(); + usb_find_busses(); + usb_find_devices(); + busses = usb_get_busses(); + + // Set the device configuration + for (bus = busses; bus; bus = bus->next) + if (bus->location == bus_n) + for (dev = bus->devices; dev != NULL; dev = dev->next) + if (dev->devnum == dev_n) { + phone->__device = dev; + phone->device = usb_open(phone->__device); + iphone_config_usb_device(phone); + goto found; + } + + iphone_free_device(phone); + + log_debug_msg("iphone_get_specific_device: iPhone not found\n"); + return IPHONE_E_NO_DEVICE; + + found: + // Send the version command to the phone + version = version_header(); + bytes = usb_bulk_write(phone->device, BULKOUT, (char *) version, sizeof(*version), 800); + if (bytes < 20) { + log_debug_msg("get_iPhone(): libusb did NOT send enough!\n"); + if (bytes < 0) { + log_debug_msg("get_iPhone(): libusb gave me the error %d: %s (%s)\n", + bytes, usb_strerror(), strerror(-bytes)); + } + } + // Read the phone's response + bytes = usb_bulk_read(phone->device, BULKIN, (char *) version, sizeof(*version), 800); + + // Check for bad response + if (bytes < 20) { + free(version); + iphone_free_device(phone); + log_debug_msg("get_iPhone(): Invalid version message -- header too short.\n"); + if (bytes < 0) + log_debug_msg("get_iPhone(): libusb error message %d: %s (%s)\n", bytes, usb_strerror(), strerror(-bytes)); + return IPHONE_E_NOT_ENOUGH_DATA; + } + // Check for correct version + if (ntohl(version->major) == 1 && ntohl(version->minor) == 0) { + // We're all ready to roll. + fprintf(stderr, "get_iPhone() success\n"); + free(version); + *device = phone; + return IPHONE_E_SUCCESS; + } else { + // Bad header + iphone_free_device(phone); + free(version); + log_debug_msg("get_iPhone(): Received a bad header/invalid version number."); + return IPHONE_E_BAD_HEADER; + } + + // If it got to this point it's gotta be bad + log_debug_msg("get_iPhone(): Unknown error.\n"); + iphone_free_device(phone); + free(version); + return IPHONE_E_UNKNOWN_ERROR; // if it got to this point it's gotta be bad +} + + +/** + * Scans all USB busses and devices for a known AFC-compatible device and + * returns a handle to the first such device it finds. Known devices include + * those with vendor ID 0x05ac and product ID between 0x1290 and 0x1293 + * inclusive. + * + * This function is convenient, but on systems where higher-level abstractions + * (such as HAL) are available it may be preferable to use + * iphone_get_specific_device instead, because it can deal with multiple + * connected devices as well as devices not known to libiphone. + * + * @param device Upon calling this function, a pointer to a location of type + * iphone_device_t, which must have the value NULL. On return, this location + * will be filled with a handle to the device. + * @return IPHONE_E_SUCCESS if ok, otherwise an error code. + */ +iphone_error_t iphone_get_device(iphone_device_t * device) +{ + struct usb_bus *bus; + struct usb_device *dev; + + pthread_mutex_init(&iphonemutex, NULL); + + usb_init(); + usb_find_busses(); + usb_find_devices(); + + for (bus = usb_get_busses(); bus != NULL; bus = bus->next) + for (dev = bus->devices; dev != NULL; dev = dev->next) + if (dev->descriptor.idVendor == 0x05ac + && dev->descriptor.idProduct >= 0x1290 && dev->descriptor.idProduct <= 0x1293) + return iphone_get_specific_device(bus->location, dev->devnum, device); + + return IPHONE_E_NO_DEVICE; +} + +/** Cleans up an iPhone structure, then frees the structure itself. + * This is a library-level function; deals directly with the iPhone to tear + * down relations, but otherwise is mostly internal. + * + * @param phone A pointer to an iPhone structure. + */ +iphone_error_t iphone_free_device(iphone_device_t device) +{ + char buf[512]; + int bytes; + + if (!device) + return IPHONE_E_INVALID_ARG; + iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; + + do { + bytes = usb_bulk_read(device->device, BULKIN, buf, 512, 800); + } while (bytes > 0); + + if (device->buffer) { + free(device->buffer); + } + if (device->device) { + usb_release_interface(device->device, 1); + usb_close(device->device); + ret = IPHONE_E_SUCCESS; + } + free(device); + + pthread_mutex_destroy(&iphonemutex); + + return ret; +} + + + +/** Sends data to the phone + * This is a low-level (i.e. directly to phone) function. + * + * @param phone The iPhone to send data to + * @param data The data to send to the iPhone + * @param datalen The length of the data + * @return The number of bytes sent, or -ERRNO on error + */ +int send_to_phone(iphone_device_t phone, char *data, int datalen) +{ + if (!phone) + return -1; + + int timeout = 1000; + int retrycount = 0; + int bytes = 0; + do { + if (retrycount > 3) { + fprintf(stderr, "EPIC FAIL! aborting on retry count overload.\n"); + return -1; + } + + bytes = usb_bulk_write(phone->device, BULKOUT, data, datalen, timeout); + if (bytes == -ETIMEDOUT) { + // timed out waiting for write. + fprintf(stderr, "usb_bulk_write timeout error.\n"); + return bytes; + } + else if (bytes < 0) { + fprintf(stderr, "usb_bulk_write failed with error. err:%d (%s)(%s)\n", + bytes, usb_strerror(), strerror(-bytes)); + return -1; + } + else if (bytes == 0) { + fprintf(stderr, "usb_bulk_write sent nothing. retrying.\n"); + timeout = timeout * 4; + retrycount++; + continue; + } + else if (bytes < datalen) { + fprintf(stderr, "usb_bulk_write failed to send full dataload. %d of %d\n", bytes, datalen); + timeout = timeout * 4; + retrycount++; + data += bytes; + datalen -= bytes; + continue; + } + } + while(0); // fall out + + return bytes; +} + +/** + */ +int recv_from_phone_timeout(iphone_device_t phone, char *data, int datalen, int timeoutmillis) +{ + if (!phone) + return -1; + int bytes = 0; + + if (!phone) + return -1; + log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen); + + bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, timeoutmillis); + if (bytes < 0) { + // there are some things which are errors, others which are no problem. + // it's not documented in libUSB, but it seems that the error returns are + // just negated ERRNO values. + if (bytes == -ETIMEDOUT) { + // ignore this. it just means timeout reached before we + // picked up any data. no problem. + } + else { + fprintf(stderr, "recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), + strerror(-bytes)); + log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), + strerror(-bytes)); + } + return -1; + } + + return bytes; +} + +/** This function is a low-level (i.e. direct to iPhone) function. + * + * @param phone The iPhone to receive data from + * @param data Where to put data read + * @param datalen How much data to read in + * + * @return How many bytes were read in, or -1 on error. + */ +int recv_from_phone(iphone_device_t phone, char *data, int datalen) { + return recv_from_phone_timeout(phone, data, datalen, 100); +} + + +/** 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 + */ +usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port) +{ + usbmux_tcp_header *conn = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header)); + conn->type = htonl(6); + conn->length = HEADERLEN; + 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 = HEADERLEN; + 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(iphone_umux_client_t connection) +{ + pthread_mutex_lock(&iphonemutex); + + // update the global list of connections + iphone_umux_client_t *newlist = (iphone_umux_client_t *) malloc(sizeof(iphone_umux_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++; + } + } + free(connlist); + connlist = newlist; + clients--; + + // free up this connection + pthread_mutex_lock(&connection->mutex); + if (connection->recv_buffer) + free(connection->recv_buffer); + if (connection->header) + free(connection->header); + connection->r_len = 0; + pthread_mutex_unlock(&connection->mutex); + pthread_mutex_destroy(&connection->mutex); + free(connection); + + pthread_mutex_unlock(&iphonemutex); +} + +/** 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(iphone_umux_client_t connection) +{ + pthread_mutex_lock(&iphonemutex); + iphone_umux_client_t *newlist = + (iphone_umux_client_t *) realloc(connlist, sizeof(iphone_umux_client_t) * (clients + 1)); + newlist[clients] = connection; + connlist = newlist; + clients++; + pthread_mutex_unlock(&iphonemutex); +} + +/** + * 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(&iphonemutex); + 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(&iphonemutex); + + return newport; +} + +/** Initializes a connection on phone, with source port s_port and destination port d_port + * + * @param device The iPhone 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 IPHONE_E_SUCCESS on success, an error code otherwise. + */ +iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port, uint16_t dst_port, + iphone_umux_client_t * client) +{ + if (!device || !dst_port) + return IPHONE_E_INVALID_ARG; + + 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 + iphone_umux_client_t new_connection = (iphone_umux_client_t) malloc(sizeof(struct iphone_umux_client_int)); + new_connection->header = new_mux_packet(src_port, dst_port); + + // send TCP syn + if (new_connection && new_connection->header) { + new_connection->header->tcp_flags = TCP_SYN; + new_connection->header->length = htonl(new_connection->header->length); + new_connection->header->length16 = htons(new_connection->header->length16); + new_connection->header->scnt = 0; + new_connection->header->ocnt = 0; + new_connection->phone = 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 = IPHONE_E_SUCCESS; + if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) { + *client = new_connection; + return IPHONE_E_SUCCESS; + } else { + delete_connection(new_connection); + return IPHONE_E_NOT_ENOUGH_DATA; + } + } + // if we get to this point it's probably bad + return IPHONE_E_UNKNOWN_ERROR; +} + +/** 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 IPHONE_E_SUCCESS on success. + */ +iphone_error_t iphone_mux_free_client(iphone_umux_client_t client) +{ + if (!client || !client->phone) + return IPHONE_E_INVALID_ARG; + + pthread_mutex_lock(&client->mutex); + client->header->tcp_flags = TCP_FIN; + client->header->length = htonl(0x1C); + client->header->scnt = htonl(client->header->scnt); + client->header->ocnt = htonl(client->header->ocnt); + client->header->window = 0; + client->header->length16 = htons(0x1C); + int bytes = 0; + + bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800); + if (bytes < 0) + log_debug_msg("iphone_mux_free_client(): when writing, libusb gave me the error: %s\n", usb_strerror()); + + bytes = usb_bulk_read(client->phone->device, BULKIN, (char *) client->header, sizeof(usbmux_tcp_header), 800); + if (bytes < 0) + log_debug_msg("get_iPhone(): when reading, libusb gave me the error: %s\n", usb_strerror()); + + pthread_mutex_unlock(&client->mutex); + // 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); + + delete_connection(client); + + return IPHONE_E_SUCCESS; +} + + +/** Sends the given data over the selected connection. + * + * @param phone The iPhone to send to. + * @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 IPHONE_E_SUCCESS on success. + */ +iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, uint32_t datalen, uint32_t * sent_bytes) +{ + if (!client->phone || !client || !sent_bytes) + return IPHONE_E_INVALID_ARG; + + if (client->error != IPHONE_E_SUCCESS) { + return client->error; + } + + *sent_bytes = 0; + pthread_mutex_lock(&client->mutex); + + int sendresult = 0; + uint32 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) { + // timd 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 and pre-emptively htonl/htons it + client->header->length = htonl(blocksize); + client->header->length16 = htons(blocksize); + + // Put scnt and ocnt into big-endian notation + client->header->scnt = htonl(client->header->scnt); + client->header->ocnt = htonl(client->header->ocnt); + // Concatenation of stuff in the buffer. + memcpy(buffer, client->header, sizeof(usbmux_tcp_header)); + memcpy(buffer + sizeof(usbmux_tcp_header), data, datalen); + + sendresult = send_to_phone(client->phone, buffer, blocksize); + // Now that we've sent it off, we can clean up after our sloppy selves. + if (buffer) + free(buffer); + + // update counts ONLY if the send succeeded. + if (sendresult == blocksize) { + // Re-calculate scnt and ocnt + client->header->scnt = ntohl(client->header->scnt) + datalen; + client->header->ocnt = ntohl(client->header->ocnt); + // Revert lengths + client->header->length = ntohl(client->header->length); + client->header->length16 = ntohs(client->header->length16); + + client->wr_window -= blocksize; + } + + + pthread_mutex_unlock(&client->mutex); + + + if (sendresult == -ETIMEDOUT || sendresult == 0) { + // no problem for now... + *sent_bytes = 0; + return IPHONE_E_TIMEOUT; + } + else if (sendresult < 0) { + return IPHONE_E_UNKNOWN_ERROR; + } + else if (sendresult == blocksize) { + // actual number of data bytes sent. + *sent_bytes = sendresult - HEADERLEN; + return IPHONE_E_SUCCESS; + } + else { + fprintf(stderr, "usbsend managed to dump a packet that is not full size. %d of %d\n", + sendresult, blocksize); + return IPHONE_E_UNKNOWN_ERROR; + } +} + +/** 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) + */ +uint32 append_receive_buffer(iphone_umux_client_t client, char* packet) +{ + if (client == NULL || packet == NULL) return 0; + + usbmux_tcp_header *header = (usbmux_tcp_header *) packet; + char* data = &packet[HEADERLEN]; + uint32 packetlen = ntohl(header->length); + uint32 datalen = packetlen-HEADERLEN; + + 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 ) { + fprintf(stdout, "client is still waiting for handshake.\n"); + if (header->tcp_flags == (TCP_SYN | TCP_ACK)) { + fprintf(stdout, "yes, got syn+ack ; replying with ack.\n"); + client->header->tcp_flags = TCP_ACK; + client->header->length = htonl(sizeof(usbmux_tcp_header)); + client->header->length16 = htons(sizeof(usbmux_tcp_header)); + client->header->scnt = htonl(client->header->scnt + 1); + client->header->ocnt = header->ocnt; + // push it to USB + // TODO: need to check for error in the send here.... :( + if (send_to_phone(client->phone, (char *)client->header, sizeof(usbmux_tcp_header)) <= 0) { + fprintf(stdout, "%s: error when pushing to usb...\n", __func__); + } + // need to revert some of the fields back to host notation. + client->header->scnt = ntohl(client->header->scnt); + client->header->ocnt = ntohl(client->header->ocnt); + client->header->length = ntohl(client->header->length); + client->header->length16 = ntohs(client->header->length16); + } + else { + client->error = IPHONE_E_ECONNABORTED; + // woah... this connection failed us. + // TODO: somehow signal that this stream is a no-go. + fprintf(stderr, "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 = IPHONE_E_ECONNRESET; + fprintf(stderr, "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 phone starts to drop below this number, we quickly fall + // into connection reset problems. Once we see the reported window size + // start falling off, cut 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) { + 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. + */ +iphone_umux_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. + iphone_umux_client_t retval = NULL; + + // just for debugging check, I'm going to convert the numbers to host-endian. + uint16 hsport = ntohs(recv_header->sport); + uint16 hdport = ntohs(recv_header->dport); + + pthread_mutex_lock(&iphonemutex); + int i; + for (i = 0; i < clients; i++) { + uint16 csport = ntohs(connlist[i]->header->sport); + uint16 cdport = ntohs(connlist[i]->header->dport); + + if (hsport == cdport && hdport == csport) { + retval = connlist[i]; + break; + } + } + pthread_mutex_unlock(&iphonemutex); + + return retval; +} + +/** pull in a big USB bulk packet and distribute it to queues appropriately. + */ +void iphone_mux_pullbulk(iphone_device_t phone) +{ + static const int DEFAULT_CAPACITY = 128*1024; + if (usbReceive.buffer == NULL) { + usbReceive.capacity = DEFAULT_CAPACITY; + usbReceive.buffer = malloc(usbReceive.capacity); + usbReceive.leftover = 0; + } + + // start the cursor off just ahead of the leftover. + char* cursor = &usbReceive.buffer[usbReceive.leftover]; + // pull in content, note that the amount we can pull is capacity minus leftover + int readlen = recv_from_phone_timeout(phone, cursor, usbReceive.capacity - usbReceive.leftover, 5000); + if (readlen < 0) { + //fprintf(stderr, "recv_from_phone_timeout gave us an error.\n"); + readlen = 0; + } + if (readlen > 0) { + //fprintf(stdout, "recv_from_phone_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 + usbReceive.leftover += readlen; + + // reset the cursor to the front of that buffer and work through + // trying to decode packets out of them. + cursor = usbReceive.buffer; + while (1) { + // check if there's even sufficient data to decode a header + if (usbReceive.leftover < HEADERLEN) break; + usbmux_tcp_header *header = (usbmux_tcp_header *) cursor; + + // now that we have a header, check if there is sufficient data + // to construct a full packet, including its data + uint32 packetlen = ntohl(header->length); + if (usbReceive.leftover < packetlen) { + break; + } + + // ok... find the client this packet will get stuffed to. + iphone_umux_client_t client = find_client(header); + if (client == NULL) { + fprintf(stderr, "WARNING: client for packet cannot be found. dropping packet.\n"); + } + else { + // stuff the data + append_receive_buffer(client, cursor); + } + + // move the cursor and account for the consumption + cursor += packetlen; + usbReceive.leftover -= packetlen; + } + + // now, we need to manage any leftovers. + // I'm going to manage the leftovers by alloc'ing a new block and copying + // the 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 (usbReceive.leftover > 0 && cursor != usbReceive.buffer) { + char* newbuff = malloc(DEFAULT_CAPACITY); + memcpy(newbuff, cursor, usbReceive.leftover); + free(usbReceive.buffer); + usbReceive.buffer = newbuff; + usbReceive.capacity = DEFAULT_CAPACITY; + } +} + +/** + * return the error code stored in iphone_umux_client_t structure, + * e.g. non-zero when an usb read error occurs. + * + * @param client the umux client + * + * @return IPHONE_E_* error codes. + */ +iphone_error_t iphone_mux_get_error(iphone_umux_client_t client) +{ + if (!client) { + return 0; + } + + return client->error; +} + +/** This is a higher-level USBMuxTCP-like function + * + * @param connection The connection to receive data on. + * @param data Where to put the data we receive. + * @param datalen How much data to read. + * + * @return IPHONE_E_SUCCESS or error code if failure. + */ +iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes) +{ + return iphone_mux_recv_timeout(client, data, datalen, recv_bytes, 0); +} + +/** + @param timeout + */ +iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout) +{ + + if (!client || !data || datalen == 0 || !recv_bytes) + return IPHONE_E_INVALID_ARG; + + if (client->error != IPHONE_E_SUCCESS) 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; //millis * 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 (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 IPHONE_E_SUCCESS; +} diff --git a/iphone.h b/iphone.h new file mode 100644 index 0000000..e132cd5 --- /dev/null +++ b/iphone.h @@ -0,0 +1,79 @@ +/* + * 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 __IPHONE_H__ +#define __IPHONE_H__ + +#include +#include +#include + +//general errors +#define IPHONE_E_SUCCESS 0 +#define IPHONE_E_INVALID_ARG -1 +#define IPHONE_E_UNKNOWN_ERROR -2 +#define IPHONE_E_NO_DEVICE -3 +#define IPHONE_E_TIMEOUT -4 +#define IPHONE_E_NOT_ENOUGH_DATA -5 +#define IPHONE_E_BAD_HEADER -6 + +//lockdownd specific error +#define IPHONE_E_INVALID_CONF -7 +#define IPHONE_E_PAIRING_FAILED -8 +#define IPHONE_E_SSL_ERROR -9 +#define IPHONE_E_PLIST_ERROR -10 +#define IPHONE_E_DICT_ERROR -11 + +//afc specific error +#define IPHONE_E_NO_SUCH_FILE -12 + +//general TCP-style errors and conditions +#define IPHONE_E_ECONNABORTED -ECONNABORTED +#define IPHONE_E_ECONNRESET -ECONNRESET +#define IPHONE_E_ENOTCONN -ENOTCONN +#define IPHONE_E_ESHUTDOWN -ESHUTDOWN +#define IPHONE_E_ETIMEDOUT -ETIMEDOUT +#define IPHONE_E_ECONNREFUSED -ECONNREFUSED + + +typedef int16_t iphone_error_t; + +struct iphone_device_int; +typedef struct iphone_device_int *iphone_device_t; + +struct iphone_umux_client_int; +typedef struct iphone_umux_client_int *iphone_umux_client_t; + +iphone_error_t iphone_get_device ( iphone_device_t *device ); +iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_device_t * device); +iphone_error_t iphone_free_device ( iphone_device_t device ); + + +iphone_error_t iphone_mux_new_client ( iphone_device_t device, uint16_t src_port, uint16_t dst_port, iphone_umux_client_t *client ); +iphone_error_t iphone_mux_free_client ( iphone_umux_client_t client ); + +iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, uint32_t datalen, uint32_t * sent_bytes); + +iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes); +iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout); + +void iphone_mux_pullbulk(iphone_device_t phone); + +iphone_error_t iphone_mux_get_error(iphone_umux_client_t client); + +#endif diff --git a/iproxy.c b/iproxy.c new file mode 100644 index 0000000..df3d689 --- /dev/null +++ b/iproxy.c @@ -0,0 +1,329 @@ +/* + * iproxy -- proxy that enables tcp service access to iPhone/iPod + * via USB cable + * TODO: improve code... + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "usbmuxd.h" +#include "sock_stuff.h" + +#define SOCKET_FILE "/var/run/usbmuxd" + +volatile int stop_ctos = 0; +volatile int stop_stoc = 0; + +static uint16_t listen_port = 0; +static uint16_t device_port = 0; + +pthread_mutex_t smutex = PTHREAD_MUTEX_INITIALIZER; + +struct client_data { + int fd; + int sfd; +}; + +int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result) +{ + struct usbmux_result res; + int recv_len; + int i; + uint32_t rrr[5]; + + if (!result) { + return -EINVAL; + } + + if ((recv_len = recv_buf(sfd, &res, sizeof(res))) <= 0) { + perror("recv"); + return -errno; + } else { + memcpy(&rrr, &res, recv_len); + for (i = 0; i < recv_len/4; i++) { + fprintf(stderr, "%08x ", rrr[i]); + } + fprintf(stderr, "\n"); + if ((recv_len == sizeof(res)) + && (res.header.length == recv_len) + && (res.header.reserved == 0) + && (res.header.type == usbmux_result) + ) { + *result = res.result; + if (res.header.tag == tag) { + return 1; + } else { + return 0; + } + } + } + + return -1; +} + +void *run_stoc_loop(void *arg) +{ + struct client_data *cdata = (struct client_data*)arg; + int recv_len; + int sent; + char buffer[131072]; + + printf("%s: fd = %d\n", __func__, cdata->fd); + + while (!stop_stoc && cdata->fd>0 && cdata->sfd>0) { + recv_len = recv_buf_timeout(cdata->sfd, buffer, sizeof(buffer), 0, 5000); + if (recv_len <= 0) { + if (recv_len == 0) { + // try again + continue; + } else { + fprintf(stderr, "recv failed: %s\n", strerror(errno)); + break; + } + } else { + printf("received %d bytes from server\n", recv_len); + // send to socket + sent = send_buf(cdata->fd, buffer, recv_len); + if (sent < recv_len) { + if (sent <= 0) { + fprintf(stderr, "send failed: %s\n", strerror(errno)); + break; + } else { + fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len); + } + } else { + // sending succeeded, receive from device + printf("pushed %d bytes to client\n", sent); + } + } + } + close(cdata->fd); + cdata->fd = -1; + stop_ctos = 1; + + return NULL; +} + +void *run_ctos_loop(void *arg) +{ + struct client_data *cdata = (struct client_data*)arg; + int recv_len; + int sent; + char buffer[131072]; + pthread_t stoc = 0; + + printf("%s: fd = %d\n", __func__, cdata->fd); + + stop_stoc = 0; + pthread_create(&stoc, NULL, run_stoc_loop, cdata); + + while (!stop_ctos && cdata->fd>0 && cdata->sfd>0) { + recv_len = recv_buf_timeout(cdata->fd, buffer, sizeof(buffer), 0, 5000); + if (recv_len <= 0) { + if (recv_len == 0) { + // try again + continue; + } else { + fprintf(stderr, "recv failed: %s\n", strerror(errno)); + break; + } + } else { + printf("pulled %d bytes from client\n", recv_len); + // send to local socket + sent = send_buf(cdata->sfd, buffer, recv_len); + if (sent < recv_len) { + if (sent <= 0) { + fprintf(stderr, "send failed: %s\n", strerror(errno)); + break; + } else { + fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len); + } + } else { + // sending succeeded, receive from device + printf("sent %d bytes to server\n", sent); + } + } + } + close(cdata->fd); + cdata->fd = -1; + stop_stoc = 1; + + pthread_join(stoc, NULL); + + return NULL; +} + +int main(int argc, char **argv) +{ + int recv_len = 0; + int hello_done; + int connected; + uint32_t pktlen; + unsigned char *buf; + struct usbmux_header hello; + struct usbmux_dev_info device_info; + int sfd = -1; + + if (argc != 3) { + printf("usage: %s LOCAL_PORT DEVICE_PORT\n", argv[0]); + return 0; + } + + listen_port = atoi(argv[1]); + device_port = atoi(argv[2]); + + if (!listen_port) { + fprintf(stderr, "Invalid listen_port specified!\n"); + return -EINVAL; + } + + if (!device_port) { + fprintf(stderr, "Invalid device_port specified!\n"); + return -EINVAL; + } + + sfd = connect_unix_socket(SOCKET_FILE); + if (sfd < 0) { + printf("error opening socket, terminating.\n"); + return -1; + } + + // send hello + hello.length = sizeof(struct usbmux_header); + hello.reserved = 0; + hello.type = usbmux_hello; + hello.tag = 2; + + hello_done = 0; + connected = 0; + + fprintf(stdout, "sending Hello packet\n"); + if (send(sfd, &hello, hello.length, 0) == hello.length) { + uint32_t res = -1; + // get response + if (usbmuxd_get_result(sfd, hello.tag, &res) && (res==0)) { + fprintf(stdout, "Got Hello Response!\n"); + hello_done = 1; + } else { + fprintf(stderr, "Did not get Hello response (with result=0)...\n"); + close(sfd); + return -1; + } + + device_info.device_id = 0; + + if (hello_done) { + // get all devices + while (1) { + if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) { + buf = (unsigned char*)malloc(pktlen); + if (!buf) { + exit(-ENOMEM); + } + recv_len = recv_buf(sfd, buf, pktlen); + if (recv_len < pktlen) { + fprintf(stdout, "received less data than specified in header!\n"); + } + fprintf(stdout, "Received device data\n"); + //log_debug_buffer(stdout, (char*)buf, pktlen); + memcpy(&device_info, buf + sizeof(struct usbmux_header), sizeof(device_info)); + free(buf); + } else { + // we _should_ have all of them now. + // or perhaps an error occured. + break; + } + } + } + + if (device_info.device_id > 0) { + struct usbmux_connect_request c_req; + + fprintf(stdout, "Requesting connecion to device %d port %d\n", device_info.device_id, device_port); + + // try to connect to last device found + c_req.header.length = sizeof(c_req); + c_req.header.reserved = 0; + c_req.header.type = usbmux_connect; + c_req.header.tag = 3; + c_req.device_id = device_info.device_id; + c_req.port = htons(device_port); + c_req.reserved = 0; + + if (send_buf(sfd, &c_req, sizeof(c_req)) < 0) { + perror("send"); + } else { + // read ACK + res = -1; + fprintf(stdout, "Reading connect result...\n"); + if (usbmuxd_get_result(sfd, c_req.header.tag, &res)) { + if (res == 0) { + fprintf(stdout, "Connect success!\n"); + connected = 1; + } else { + fprintf(stderr, "Connect failed, Error code=%d\n", res); + } + } + } + } + + if (connected) { + int mysock = create_socket(listen_port); + if (mysock < 0) { + fprintf(stderr, "Error creating socket: %s\n", strerror(errno)); + } else { + pthread_t ctos; + struct sockaddr_in c_addr; + socklen_t len = sizeof(struct sockaddr_in); + struct client_data cdata; + int c_sock; + while (1) { + printf("waiting for connection\n"); + c_sock = accept(mysock, (struct sockaddr*)&c_addr, &len); + if (c_sock) { + printf("accepted connection, fd = %d\n", c_sock); + cdata.fd = c_sock; + cdata.sfd = sfd; + stop_ctos = 0; + pthread_create(&ctos, NULL, run_ctos_loop, &cdata); + pthread_join(ctos, NULL); + } else { + break; + } + } + close(c_sock); + close(mysock); + } + } else { + fprintf(stderr, "No attached device found?!\n"); + } + } + close(sfd); + + return 0; +} diff --git a/sock_stuff.c b/sock_stuff.c new file mode 100644 index 0000000..1a23bc1 --- /dev/null +++ b/sock_stuff.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sock_stuff.h" + +#define RECV_TIMEOUT 10000 + +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) { + 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)) { + 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) { + 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); + 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) { + fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr); + return -1; + } + + if (!hp->h_addr) { + 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) { + 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 fdread: + sret = select(fd+1,&fds,NULL,NULL,&to); + break; + case fdwrite: + sret = select(fd+1,NULL,&fds,NULL,&to); + break; + case fdexcept: + sret = select(fd+1,NULL,NULL,&fds,&to); + break; + } + + if (sret < 0) { + switch(errno) { + case EINTR: + // interrupt signal in select + fprintf(stderr, "%s: EINTR\n", __func__); + eagain = 1; + break; + case EAGAIN: + fprintf(stderr, "%s: EAGAIN\n", __func__); + break; + default: + 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, fdread, 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 + fprintf(stderr, "%s: fd=%d\n", __func__, fd); + return -1; + } + return result; +} + +int send_buf(int fd, void *data, size_t length) +{ + return send(fd, data, length, 0); +} + diff --git a/sock_stuff.h b/sock_stuff.h new file mode 100644 index 0000000..01082d1 --- /dev/null +++ b/sock_stuff.h @@ -0,0 +1,27 @@ +#ifndef __SOCK_STUFF_H +#define __SOCK_STUFF_H + +#include + +enum fd_mode +{ + fdread, + fdwrite, + fdexcept +}; +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); + +#endif /* __SOCK_STUFF_H */ + diff --git a/testclient.c b/testclient.c new file mode 100644 index 0000000..fafbf23 --- /dev/null +++ b/testclient.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "usbmuxd.h" +#include "sock_stuff.h" + +#define SOCKET_FILE "/var/run/usbmuxd" + +int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result) +{ + struct usbmux_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 == recv_len) + && (res.header.reserved == 0) + && (res.header.type == usbmux_result) + ) { + *result = res.result; + if (res.header.tag == tag) { + return 1; + } else { + return 0; + } + } + } + + return -1; +} + +int main(int argc, char **argv) +{ + int sfd; + int recv_len = 0; + int hello_done; + int connected; + uint32_t pktlen; + unsigned char *buf; + struct usbmux_header hello; + struct usbmux_dev_info device_info; + + sfd = connect_unix_socket(SOCKET_FILE); + if (sfd < 0) { + printf("error opening socket, terminating.\n"); + return -1; + } + + // send hello + hello.length = sizeof(struct usbmux_header); + hello.reserved = 0; + hello.type = usbmux_hello; + hello.tag = 2; + + hello_done = 0; + connected = 0; + + fprintf(stdout, "sending Hello packet\n"); + if (send(sfd, &hello, hello.length, 0) == hello.length) { + uint32_t res = -1; + // get response + if (usbmuxd_get_result(sfd, hello.tag, &res) && (res==0)) { + fprintf(stdout, "Got Hello Response!\n"); + hello_done = 1; + } else { + fprintf(stderr, "Did not get Hello response (with result=0)...\n"); + close(sfd); + return -1; + } + + device_info.device_id = 0; + + if (hello_done) { + // get all devices + while (1) { + if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) { + buf = (unsigned char*)malloc(pktlen); + if (!buf) { + exit(-ENOMEM); + } + recv_len = recv_buf(sfd, buf, pktlen); + if (recv_len < pktlen) { + fprintf(stdout, "received less data than specified in header!\n"); + } + fprintf(stdout, "got device data:\n"); + //log_debug_buffer(stdout, (char*)buf, pktlen); + memcpy(&device_info, buf + sizeof(struct usbmux_header), sizeof(device_info)); + free(buf); + } else { + // we _should_ have all of them now. + // or perhaps an error occured. + break; + } + } + } + + if (device_info.device_id > 0) { + struct usbmux_connect_request c_req; + + // try to connect to last device found + c_req.header.length = sizeof(c_req); + c_req.header.reserved = 0; + c_req.header.type = usbmux_connect; + c_req.header.tag = 3; + c_req.device_id = device_info.device_id; + c_req.port = htons(22); + c_req.reserved = 0; + + if (send_buf(sfd, &c_req, sizeof(c_req)) < 0) { + perror("send"); + } else { + // read ACK + res = -1; + if (usbmuxd_get_result(sfd, c_req.header.tag, &res)) { + if (res == 0) { + fprintf(stdout, "Connect success!\n"); + connected = 1; + } else { + fprintf(stderr, "Connect failed, Error code=%d\n", res); + } + } + } + } + + if (connected) { + + + // do communication now. + sleep(10); + } + } + close(sfd); + + return 0; +} diff --git a/usbmuxd.c b/usbmuxd.c new file mode 100644 index 0000000..37a7f9e --- /dev/null +++ b/usbmuxd.c @@ -0,0 +1,795 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usbmuxd.h" +#include "sock_stuff.h" + +#include "iphone.h" + +#define SOCKET_FILE "/var/run/usbmuxd" + +#define DEFAULT_TIMEOUT 4000 +#define DEFAULT_CHILDREN_CAPACITY 10 + +static int quit_flag = 0; +static int fsock = -1; + +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; + iphone_umux_client_t muxclient; +}; + +struct device_use_info { + uint32_t device_id; + iphone_device_t phone; + int use_count; +}; + +static struct device_use_info **device_use_list = NULL; +static int device_use_count = 0; +static pthread_mutex_t usbmux_mutex = PTHREAD_MUTEX_INITIALIZER; + +static void print_buffer(const char *data, const int length) +{ + int i; + int j; + unsigned char c; + + for(i=0; i= 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 int usbmuxd_get_request(int fd, void *data, size_t len) +{ + uint32_t pktlen; + int recv_len; + + if (peek_buf(fd, &pktlen, sizeof(pktlen)) < sizeof(pktlen)) { + return -errno; + } + + if (len < pktlen) { + // target buffer is to small to hold this packet! fix it! + fprintf(stderr, "%s: WARNING -- packet (%d) is larger than target buffer (%d)! Truncating.\n", __func__, pktlen, len); + pktlen = len; + } + + recv_len = recv_buf(fd, data, pktlen); + if (recv_len < pktlen) { + fprintf(stderr, "%s: Uh-oh, we got less than the packet's size, %d instead of %d...\n", __func__, recv_len, pktlen); + } + + return recv_len; +} + +static int usbmuxd_send_result(int fd, uint32_t tag, uint32_t result_code) +{ + struct usbmux_result res; + + res.header.length = sizeof(res); + res.header.reserved = 0; + res.header.type = usbmux_result; + res.header.tag = tag; + res.result = result_code; + + fprintf(stderr, "%s: tag=%d result=%d\n", __func__, res.header.tag, res.result); + + return send_buf(fd, &res, sizeof(res)); +} + +/** + * + */ +static void *usbmuxd_client_reader_thread(void *arg) +{ + struct client_data *cdata; + + char rbuffer[512]; + uint32_t rbuffersize = 512; + uint32_t rlen; + iphone_error_t err; + char *cursor; + ssize_t len; + int result; + + if (!arg) { + fprintf(stderr, "%s: invalid client_data supplied!\n", __func__); + cdata->reader_dead = 1; + return NULL; + } + + cdata = (struct client_data*)arg; + + cdata->reader_dead = 0; + + fprintf(stdout, "%s: started\n", __func__); + + while (!quit_flag && !cdata->reader_quit) { + result = check_fd(cdata->socket, fdwrite, DEFAULT_TIMEOUT); + if (result <= 0) { + if (result < 0) { + fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno)); + } + continue; + } + + rlen = 0; + err = iphone_mux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, &rlen, DEFAULT_TIMEOUT); + if (err != 0) { + fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err); + break; + } + + cursor = rbuffer; + while (rlen > 0) { + //printf("%s: \n", __func__); + //print_buffer(cursor, rlen); + //if ((rlen > 4) && !cursor[3]) { + len = send_buf(cdata->socket, cursor, rlen); + /*} else if (cursor[0] == 1) { + fprintf(stderr, "%s: Error message received: %s\n", __func__, cursor+1); + // we got an error message and no data. don't send it. + // TODO parse the error code and put it in the right place! + len = rlen; + }*/ + // calculate remainder + rlen -= len; + // advance cursor + cursor += len; + } + fsync(cdata->socket); + } + + fprintf(stdout, "%s: terminated\n", __func__); + + cdata->reader_dead = 1; + + return NULL; +} + +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; + iphone_error_t err; + + // trigger connection attempt if ready to write to client + result = check_fd(cdata->socket, fdwrite, DEFAULT_TIMEOUT); + if (result <= 0) { + if (result < 0) { + fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno)); + return result; + } + } else { + result = 0; + err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, DEFAULT_TIMEOUT); + if (err != 0) { + fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err); + usbmuxd_send_result(cdata->socket, cdata->tag, err); + } else { + if (rlen > 0) { + //print_buffer(buffer, rlen); + if ((buffer[0] == 1) && (rlen > 20) && !memcmp(buffer+1, "handleConnectResult:", 20)) { + // hm... we got an error message! + buffer[rlen] = 0; + fprintf(stderr, "%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); + } else { + usbmuxd_send_result(cdata->socket, cdata->tag, ENODATA); + } + return -2; + } 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); + return 0; + } + } + //fsync(cdata->socket); + } + return 0; +} + +/** + * 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[1024]; + ssize_t len; + ssize_t maxlen = sizeof(buffer); + uint32_t wlen; + iphone_error_t err; + + if (!arg) { + fprintf(stderr, "%s: invalid client_data provided!\n", __func__); + return NULL; + } + + cdata = (struct client_data*)arg; + + fprintf(stdout, "%s: started\n", __func__); + + if (usbmuxd_handleConnectResult(cdata)) { + goto leave; + } + + // starting mux reader thread + cdata->reader_quit = 0; + cdata->reader_dead = 0; + if (pthread_create(&cdata->reader, NULL, usbmuxd_client_reader_thread, cdata) != 0) { + fprintf(stderr, "%s: could not start client_reader thread\n", __func__); + cdata->reader = 0; + } + + while (!quit_flag && !cdata->reader_dead) { + result = check_fd(cdata->socket, fdread, DEFAULT_TIMEOUT); + if (result <= 0) { + if (result < 0) { + fprintf(stderr, "%s: Error: checkfd: %s\n", __func__, 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) { + fprintf(stderr, "%s: Error: recv: %s\n", __func__, strerror(errno)); + break; + } + + cursor = buffer; + do { + wlen = 0; + err = iphone_mux_send(cdata->muxclient, cursor, len, &wlen); + if (err == IPHONE_E_TIMEOUT) { + // some kind of timeout... just be patient and retry. + } else if (err != IPHONE_E_SUCCESS) { + fprintf(stderr, "%s: USB write error: %d\n", __func__, err); + len = -1; + break; + } + + // calculate remainder. + len -= wlen; + // advance cursor appropiately. + cursor += wlen; + } while ((len > 0) && !quit_flag); + if (len < 0) { + break; + } + } + +leave: + // cleanup + fprintf(stdout, "%s: terminating\n", __func__); + if (cdata->reader != 0) { + cdata->reader_quit = 1; + pthread_join(cdata->reader, NULL); + } + + cdata->handler_dead = 1; + + fprintf(stdout, "%s: terminated\n", __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 usbmux_header hello; + struct usbmux_dev_info_request dev_info_req; + struct usbmux_connect_request c_req; + + struct usb_bus *bus; + struct usb_device *dev; + + int recv_len; + int found = 0; + int res; + int i; + int sent_result; + iphone_error_t err; + + iphone_device_t phone; + struct device_use_info *cur_dev = NULL; + + if (!arg) { + fprintf(stderr, "%s: invalid client_data provided!\n", __func__); + return NULL; + } + + cdata = (struct client_data*)arg; + cdata->dead = 0; + + fprintf(stdout, "%s: started (fd=%d)\n", __func__, cdata->socket); + + if ((recv_len = usbmuxd_get_request(cdata->socket, &hello, sizeof(hello))) <= 0) { + fprintf(stderr, "%s: No Hello packet received, error %s\n", __func__, strerror(errno)); + goto leave; + } + + if ((recv_len == 16) && (hello.length == 16) + && (hello.reserved == 0) && (hello.type == usbmux_hello)) { + // send success response + usbmuxd_send_result(cdata->socket, hello.tag, 0); + } else { + // send error response and exit + fprintf(stderr, "%s: Invalid Hello packet received.\n", __func__); + // TODO is this required?! + usbmuxd_send_result(cdata->socket, hello.tag, EINVAL); + goto leave; + } + + // gather data about all iPhones/iPods attached + 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 <= 0x1293) + { + fprintf(stdout, "%s: Found device on bus %d, id %d\n", __func__, bus->location, dev->devnum); + found++; + + // construct packet + memset(&dev_info_req, 0, sizeof(dev_info_req)); + dev_info_req.header.length = sizeof(dev_info_req); + dev_info_req.header.type = usbmux_device_info; + dev_info_req.dev_info.device_id = dev->devnum; + dev_info_req.dev_info.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_req.dev_info.serial_number, sizeof(dev_info_req.dev_info.serial_number)+1); + usb_close(udev); + } + //pthread_mutex_unlock(&usbmux_mutex); + } + + print_buffer((char*)&dev_info_req, sizeof(dev_info_req)); + + // send it + if (send_buf(cdata->socket, &dev_info_req, sizeof(dev_info_req)) <= 0) { + fprintf(stderr, "%s: Error: Could not send device info: %s\n", __func__, strerror(errno)); + found--; + } + } + } + } + + // now wait for connect request + if (found <= 0) { + fprintf(stderr, "%s: No attached iPhone/iPod devices found.\n", __func__); + goto leave; + } + + memset(&c_req, 0, sizeof(c_req)); + if ((recv_len = usbmuxd_get_request(cdata->socket, &c_req, sizeof(c_req))) <= 0) { + fprintf(stderr, "%s: Did not receive any connect request.\n", __func__); + goto leave; + } + + if (c_req.header.type != usbmux_connect) { + fprintf(stderr, "%s: Unexpected packet of type %d received.\n", __func__, c_req.header.type); + goto leave; + } + + fprintf(stdout, "%s: Setting up connection to usb device #%d on port %d\n", __func__, c_req.device_id, ntohs(c_req.port)); + + // find the device, and open usb connection + phone = NULL; + cur_dev = NULL; + // first check if we already have an open connection + if (device_use_list) { + pthread_mutex_lock(&usbmux_mutex); + for (i = 0; i < device_use_count; i++) { + if (device_use_list[i]) { + if (device_use_list[i]->device_id == c_req.device_id) { + device_use_list[i]->use_count++; + cur_dev = device_use_list[i]; + phone = cur_dev->phone; + break; + } + } + } + pthread_mutex_unlock(&usbmux_mutex); + } + if (!phone) { + // if not found, make a new connection + if (iphone_get_specific_device(0, c_req.device_id, &phone) != IPHONE_E_SUCCESS) { + fprintf(stderr, "%s: device_id %d could not be opened\n", __func__, c_req.device_id); + usbmuxd_send_result(cdata->socket, c_req.header.tag, ENODEV); + goto leave; + } + // add to device list + cur_dev = (struct device_use_info*)malloc(sizeof(struct device_use_info)); + memset(cur_dev, 0, sizeof(struct device_use_info)); + cur_dev->use_count = 1; + cur_dev->device_id = c_req.device_id; + cur_dev->phone = phone; + + pthread_mutex_lock(&usbmux_mutex); + device_use_list = (struct device_use_info**)realloc(device_use_list, sizeof(struct device_use_info*) * (device_use_count+1)); + if (device_use_list) { + device_use_list[device_use_count] = cur_dev; + device_use_count++; + } + pthread_mutex_unlock(&usbmux_mutex); + } else { + fprintf(stdout, "%s: reusing usb connection device_id %d\n", __func__, c_req.device_id); + } + + // setup connection to iPhone/iPod +// pthread_mutex_lock(&usbmux_mutex); + res = iphone_mux_new_client(cur_dev->phone, 0, ntohs(c_req.port), &(cdata->muxclient)); +// pthread_mutex_unlock(&usbmux_mutex); + + if (res != 0) { + usbmuxd_send_result(cdata->socket, c_req.header.tag, res); + fprintf(stderr, "%s: mux_new_client returned %d, aborting.\n", __func__, res); + goto leave; + } + + // start connection handler thread + cdata->handler_dead = 0; + cdata->tag = c_req.header.tag; + if (pthread_create(&cdata->handler, NULL, usbmuxd_client_handler_thread, cdata) != 0) { + fprintf(stderr, "%s: could not create usbmuxd_client_handler_thread!\n", __func__); + cdata->handler = 0; + goto leave; + } + + sent_result = 0; + + // start reading data from the connected device + while (!quit_flag && !cdata->handler_dead) { + iphone_mux_pullbulk(cur_dev->phone); + err = iphone_mux_get_error(cdata->muxclient); + if (err != IPHONE_E_SUCCESS) { + break; + /*} else if (!sent_result) { + usbmuxd_send_result(cdata->socket, c_req.header.tag, 0); + sent_result = 1;*/ + } + } + + if (!sent_result) { + //fprintf(stderr, "Sending error message %d tag %d\n", err, c_req.header.tag); + err = iphone_mux_get_error(cdata->muxclient); + //usbmuxd_send_result(cdata->socket, c_req.header.tag, err); + } + + fprintf(stdout, "%s: terminating\n", __func__); + + // wait for handler thread to finish its work + if (cdata->handler != 0) { + pthread_join(cdata->handler, NULL); + } + + // time to clean up + if (cdata && cdata->muxclient) { // should be non-NULL + iphone_mux_free_client(cdata->muxclient); + } + +leave: + // this has to be freed only if it's not in use anymore as it closes + // the USB connection + if (cur_dev) { + if (cur_dev->use_count > 1) { + cur_dev->use_count--; + } else { + iphone_free_device(cur_dev->phone); + cur_dev->use_count = 0; + free(cur_dev); + cur_dev = NULL; + pthread_mutex_lock(&usbmux_mutex); + if (device_use_count > 1) { + struct device_use_info **newlist; + int j; + + newlist = (struct device_use_info**)malloc(sizeof(struct device_use_info*) * device_use_count-1); + for (i = 0; i < device_use_count; i++) { + if (device_use_list[i] != NULL) { + newlist[j++] = device_use_list[i]; + } + } + free(device_use_list); + device_use_list = newlist; + } else { + free(device_use_list); + device_use_list = NULL; + } + pthread_mutex_unlock(&usbmux_mutex); + } + } + + cdata->dead = 1; + + fprintf(stdout, "%s: terminated\n", __func__); + + return NULL; +} + +/** + * make this program run detached from the current console + */ +static int daemonize() +{ + // TODO still to be implemented, also logging is missing! + return 0; +} + +/** + * signal handler function for cleaning up stuff + */ +static void clean_exit(int sig) +{ + if (sig == SIGINT) { + fprintf(stdout, "CTRL+C pressed\n"); + } + quit_flag = 1; +} + +/** + * thread function that performs accept() and starts the required child + * threads to perform the rest of the communication stuff. + */ +static void *usbmuxd_accept_thread(void *arg) +{ + struct sockaddr_un c_addr; + socklen_t len = sizeof(struct sockaddr_un); + struct client_data *cdata; + struct client_data **children = NULL; + int children_capacity = DEFAULT_CHILDREN_CAPACITY; + int i = 0; + int result = 0; + int cnt; + + // 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) { + fprintf(stderr, "%s: Out of memory when allocating memory for child threads. Terminating.\n", __func__); + exit(EXIT_FAILURE); + } + memset(children, 0, sizeof(struct client_data*) * children_capacity); + + fprintf(stdout, "%s: waiting for connection\n", __func__); + while (!quit_flag) { + // Check the file descriptor before accepting a connection. + // If no connection attempt is made, just repeat... + result = check_fd(fsock, fdread, DEFAULT_TIMEOUT); + 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); + fprintf(stdout, "%s: reclaimed client thread (fd=%d)\n", __func__, 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 { + fprintf(stderr, "select error: %s\n", strerror(errno)); + continue; + } + } + + cdata = (struct client_data*)malloc(sizeof(struct client_data)); + memset(cdata, 0, sizeof(struct client_data)); + if (!cdata) { + quit_flag = 1; + fprintf(stderr, "%s: Error: Out of memory! Terminating.\n", __func__); + break; + } + + cdata->socket = accept(fsock, (struct sockaddr*)&c_addr, &len); + if (cdata->socket < 0) { + free(cdata); + if (errno == EINTR) { + continue; + } else { + fprintf(stderr, "%s: Error in accept: %s\n", __func__, strerror(errno)); + continue; + } + } + + fprintf(stdout, "%s: new client connected (fd=%d)\n", __func__, 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) { + fprintf(stderr, "%s: Out of memory when enlarging child thread buffer\n", __func__); + } + } + children[i] = cdata; + } else { + fprintf(stderr, "%s: Failed to create client_init_thread.\n", __func__); + close(cdata->socket); + free(cdata); + cdata = NULL; + } + } + + fprintf(stdout, "%s: terminating\n", __func__); + + // preparing for shutdown: wait for child threads to terminate (if any) + fprintf(stdout, "%s: waiting for child threads to terminate...\n", __func__); + for (i = 0; i < children_capacity; i++) { + if (children[i] != NULL) { + pthread_join(children[i]->thread, NULL); + free(children[i]); + } + } + + // delete the children set. + free(children); + children = NULL; + + fprintf(stdout, "%s: terminated.\n", __func__); + + return NULL; +} + +int main(int argc, char **argv) +{ + int foreground = 1; + pthread_t acceptor; + + fprintf(stdout, "usbmuxd: starting\n"); + + // TODO: Parameter checking. + + fsock = create_unix_socket(SOCKET_FILE); + if (fsock < 0) { + fprintf(stderr, "Could not create socket, exiting\n"); + return -1; + } + + chmod(SOCKET_FILE, 0666); + + if (!foreground) { + if (daemonize() < 0) { + exit(EXIT_FAILURE); + } + } + + // signal(SIGHUP, reload_conf); // none yet + signal(SIGINT, clean_exit); + signal(SIGQUIT, clean_exit); + signal(SIGTERM, clean_exit); + signal(SIGPIPE, SIG_IGN); + + if (pthread_create(&acceptor, NULL, usbmuxd_accept_thread, NULL) != 0) { + fprintf(stderr, "Failed to create server thread.\n"); + close(fsock); + return -1; + } + + // Relax here. Just wait for the accept thread to terminate. + pthread_join(acceptor, NULL); + + fprintf(stdout, "usbmuxd: terminating\n"); + if (fsock >= 0) { + close(fsock); + } + + unlink(SOCKET_FILE); + + return 0; +} + diff --git a/usbmuxd.h b/usbmuxd.h new file mode 100644 index 0000000..fcbee52 --- /dev/null +++ b/usbmuxd.h @@ -0,0 +1,44 @@ +#ifndef __USBMUXD_H +#define __USBMUXD_H + +#include + +struct usbmux_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 +}; + +struct usbmux_result { + struct usbmux_header header; + uint32_t result; +}; + +struct usbmux_connect_request { + struct usbmux_header header; + uint32_t device_id; + uint16_t port; // TCP port number + uint16_t reserved; // set to zero +}; + +struct usbmux_dev_info { + uint32_t device_id; + uint16_t product_id; + char serial_number[40]; +}; + +struct usbmux_dev_info_request { + struct usbmux_header header; + struct usbmux_dev_info dev_info; + unsigned char padding[222]; +}; + +enum { + usbmux_result = 1, + usbmux_connect = 2, + usbmux_hello = 3, + usbmux_device_info = 4, +}; + +#endif -- cgit v1.1-32-gdbae From 2ae80d9dd4855b0dd3e0c74e2f6d03b2b6ecd7c0 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 20 Feb 2009 14:31:45 +0100 Subject: Added comments and did some small code cleanup. --- usbmuxd.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/usbmuxd.c b/usbmuxd.c index 37a7f9e..8f2a6e9 100644 --- a/usbmuxd.c +++ b/usbmuxd.c @@ -70,6 +70,9 @@ static struct device_use_info **device_use_list = NULL; static int device_use_count = 0; static pthread_mutex_t usbmux_mutex = PTHREAD_MUTEX_INITIALIZER; +/** + * for debugging purposes. + */ static void print_buffer(const char *data, const int length) { int i; @@ -101,6 +104,17 @@ static void print_buffer(const char *data, const int length) printf("\n"); } +/** + * 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; @@ -117,13 +131,22 @@ static int usbmuxd_get_request(int fd, void *data, size_t len) } recv_len = recv_buf(fd, data, pktlen); - if (recv_len < pktlen) { + if ((recv_len > 0) && (recv_len < pktlen)) { fprintf(stderr, "%s: Uh-oh, we got less than the packet's size, %d instead of %d...\n", __func__, recv_len, pktlen); } 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 usbmux_result res; @@ -140,7 +163,12 @@ static int usbmuxd_send_result(int fd, uint32_t tag, uint32_t result_code) } /** + * 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) { @@ -184,16 +212,7 @@ static void *usbmuxd_client_reader_thread(void *arg) cursor = rbuffer; while (rlen > 0) { - //printf("%s: \n", __func__); - //print_buffer(cursor, rlen); - //if ((rlen > 4) && !cursor[3]) { - len = send_buf(cdata->socket, cursor, rlen); - /*} else if (cursor[0] == 1) { - fprintf(stderr, "%s: Error message received: %s\n", __func__, cursor+1); - // we got an error message and no data. don't send it. - // TODO parse the error code and put it in the right place! - len = rlen; - }*/ + len = send_buf(cdata->socket, cursor, rlen); // calculate remainder rlen -= len; // advance cursor @@ -209,6 +228,16 @@ static void *usbmuxd_client_reader_thread(void *arg) 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; @@ -219,7 +248,11 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) uint32_t rlen; iphone_error_t err; - // trigger connection attempt if ready to write to client + if (!cdata) { + fprintf(stderr, "%s: Invalid client_data provided!\n", __func__); + return -EINVAL; + } + result = check_fd(cdata->socket, fdwrite, DEFAULT_TIMEOUT); if (result <= 0) { if (result < 0) { @@ -231,7 +264,8 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, DEFAULT_TIMEOUT); if (err != 0) { fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err); - usbmuxd_send_result(cdata->socket, cdata->tag, err); + usbmuxd_send_result(cdata->socket, cdata->tag, -err); + return err; } else { if (rlen > 0) { //print_buffer(buffer, rlen); @@ -242,10 +276,11 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) 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; } - return -2; } else { // send success result usbmuxd_send_result(cdata->socket, cdata->tag, 0); @@ -255,12 +290,11 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) } else { // no server greeting? this seems to be ok. send success. usbmuxd_send_result(cdata->socket, cdata->tag, 0); - return 0; } } //fsync(cdata->socket); } - return 0; + return result; } /** @@ -612,7 +646,7 @@ static int daemonize() } /** - * signal handler function for cleaning up stuff + * signal handler function for cleaning up properly */ static void clean_exit(int sig) { @@ -745,6 +779,9 @@ static void *usbmuxd_accept_thread(void *arg) return NULL; } +/** + * main function. + */ int main(int argc, char **argv) { int foreground = 1; -- cgit v1.1-32-gdbae From 471b064f182bf0770729546607b0aa920c46419b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 23 Feb 2009 21:36:08 +0100 Subject: Small update. Now usbmuxd is only contacted when a client connects to the local listen port. This allows re-connects afterwards. --- iproxy.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 150 insertions(+), 36 deletions(-) diff --git a/iproxy.c b/iproxy.c index df3d689..d88b7ff 100644 --- a/iproxy.c +++ b/iproxy.c @@ -36,9 +36,6 @@ #define SOCKET_FILE "/var/run/usbmuxd" -volatile int stop_ctos = 0; -volatile int stop_stoc = 0; - static uint16_t listen_port = 0; static uint16_t device_port = 0; @@ -47,6 +44,8 @@ pthread_mutex_t smutex = PTHREAD_MUTEX_INITIALIZER; struct client_data { int fd; int sfd; + volatile int stop_ctos; + volatile int stop_stoc; }; int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result) @@ -95,7 +94,7 @@ void *run_stoc_loop(void *arg) printf("%s: fd = %d\n", __func__, cdata->fd); - while (!stop_stoc && cdata->fd>0 && cdata->sfd>0) { + while (!cdata->stop_stoc && cdata->fd>0 && cdata->sfd>0) { recv_len = recv_buf_timeout(cdata->sfd, buffer, sizeof(buffer), 0, 5000); if (recv_len <= 0) { if (recv_len == 0) { @@ -124,7 +123,7 @@ void *run_stoc_loop(void *arg) } close(cdata->fd); cdata->fd = -1; - stop_ctos = 1; + cdata->stop_ctos = 1; return NULL; } @@ -139,10 +138,10 @@ void *run_ctos_loop(void *arg) printf("%s: fd = %d\n", __func__, cdata->fd); - stop_stoc = 0; + cdata->stop_stoc = 0; pthread_create(&stoc, NULL, run_stoc_loop, cdata); - while (!stop_ctos && cdata->fd>0 && cdata->sfd>0) { + while (!cdata->stop_ctos && cdata->fd>0 && cdata->sfd>0) { recv_len = recv_buf_timeout(cdata->fd, buffer, sizeof(buffer), 0, 5000); if (recv_len <= 0) { if (recv_len == 0) { @@ -171,15 +170,16 @@ void *run_ctos_loop(void *arg) } close(cdata->fd); cdata->fd = -1; - stop_stoc = 1; + cdata->stop_stoc = 1; pthread_join(stoc, NULL); return NULL; } -int main(int argc, char **argv) +void *acceptor_thread(void *arg) { + struct client_data *cdata; int recv_len = 0; int hello_done; int connected; @@ -187,7 +187,117 @@ int main(int argc, char **argv) unsigned char *buf; struct usbmux_header hello; struct usbmux_dev_info device_info; - int sfd = -1; + pthread_t ctos; + + if (!arg) { + fprintf(stderr, "invalid client_data provided!\n"); + return NULL; + } + + cdata = (struct client_data*)arg; + + cdata->sfd = connect_unix_socket(SOCKET_FILE); + if (cdata->sfd < 0) { + printf("error opening socket, terminating.\n"); + return NULL; + } + + // send hello + hello.length = sizeof(struct usbmux_header); + hello.reserved = 0; + hello.type = usbmux_hello; + hello.tag = 2; + + hello_done = 0; + connected = 0; + + fprintf(stdout, "sending Hello packet\n"); + if (send(cdata->sfd, &hello, hello.length, 0) == hello.length) { + uint32_t res = -1; + // get response + if (usbmuxd_get_result(cdata->sfd, hello.tag, &res) && (res==0)) { + fprintf(stdout, "Got Hello Response!\n"); + hello_done = 1; + } else { + fprintf(stderr, "Did not get Hello response (with result=0)...\n"); + close(cdata->sfd); + cdata->sfd = -1; + return NULL; + } + + device_info.device_id = 0; + + if (hello_done) { + // get all devices + while (1) { + if (recv_buf_timeout(cdata->sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) { + buf = (unsigned char*)malloc(pktlen); + if (!buf) { + exit(-ENOMEM); + } + recv_len = recv_buf(cdata->sfd, buf, pktlen); + if (recv_len < pktlen) { + fprintf(stdout, "received less data than specified in header!\n"); + } + fprintf(stdout, "Received device data\n"); + //log_debug_buffer(stdout, (char*)buf, pktlen); + memcpy(&device_info, buf + sizeof(struct usbmux_header), sizeof(device_info)); + free(buf); + } else { + // we _should_ have all of them now. + // or perhaps an error occured. + break; + } + } + } + + if (device_info.device_id > 0) { + struct usbmux_connect_request c_req; + + fprintf(stdout, "Requesting connecion to device %d port %d\n", device_info.device_id, device_port); + + // try to connect to last device found + c_req.header.length = sizeof(c_req); + c_req.header.reserved = 0; + c_req.header.type = usbmux_connect; + c_req.header.tag = 3; + c_req.device_id = device_info.device_id; + c_req.port = htons(device_port); + c_req.reserved = 0; + + if (send_buf(cdata->sfd, &c_req, sizeof(c_req)) < 0) { + perror("send"); + } else { + // read ACK + res = -1; + fprintf(stdout, "Reading connect result...\n"); + if (usbmuxd_get_result(cdata->sfd, c_req.header.tag, &res)) { + if (res == 0) { + fprintf(stdout, "Connect success!\n"); + connected = 1; + } else { + fprintf(stderr, "Connect failed, Error code=%d\n", res); + } + } + } + } + + if (connected) { + cdata->stop_ctos = 0; + pthread_create(&ctos, NULL, run_ctos_loop, cdata); + pthread_join(ctos, NULL); + } else { + fprintf(stderr, "Error connecting to device!\n"); + } + } + close(cdata->sfd); + + return NULL; +} + +int main(int argc, char **argv) +{ + int mysock = -1; if (argc != 3) { printf("usage: %s LOCAL_PORT DEVICE_PORT\n", argv[0]); @@ -207,6 +317,34 @@ int main(int argc, char **argv) return -EINVAL; } + // first create the listening socket endpoint waiting for connections. + mysock = create_socket(listen_port); + if (mysock < 0) { + fprintf(stderr, "Error creating socket: %s\n", strerror(errno)); + return -errno; + } else { + pthread_t acceptor; + struct sockaddr_in c_addr; + socklen_t len = sizeof(struct sockaddr_in); + struct client_data cdata; + int c_sock; + while (1) { + printf("waiting for connection\n"); + c_sock = accept(mysock, (struct sockaddr*)&c_addr, &len); + if (c_sock) { + printf("accepted connection, fd = %d\n", c_sock); + cdata.fd = c_sock; + pthread_create(&acceptor, NULL, acceptor_thread, &cdata); + pthread_join(acceptor, NULL); + } else { + break; + } + } + close(c_sock); + close(mysock); + } + +/* sfd = connect_unix_socket(SOCKET_FILE); if (sfd < 0) { printf("error opening socket, terminating.\n"); @@ -293,37 +431,13 @@ int main(int argc, char **argv) } if (connected) { - int mysock = create_socket(listen_port); - if (mysock < 0) { - fprintf(stderr, "Error creating socket: %s\n", strerror(errno)); - } else { - pthread_t ctos; - struct sockaddr_in c_addr; - socklen_t len = sizeof(struct sockaddr_in); - struct client_data cdata; - int c_sock; - while (1) { - printf("waiting for connection\n"); - c_sock = accept(mysock, (struct sockaddr*)&c_addr, &len); - if (c_sock) { - printf("accepted connection, fd = %d\n", c_sock); - cdata.fd = c_sock; - cdata.sfd = sfd; - stop_ctos = 0; - pthread_create(&ctos, NULL, run_ctos_loop, &cdata); - pthread_join(ctos, NULL); - } else { - break; - } - } - close(c_sock); - close(mysock); - } + // } else { fprintf(stderr, "No attached device found?!\n"); } } close(sfd); +*/ return 0; } -- cgit v1.1-32-gdbae From 97e6c8b7bb89c7f08ad46050598c15a55ea3f436 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 25 Feb 2009 18:08:46 +0100 Subject: fix: close socket properly --- iproxy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iproxy.c b/iproxy.c index d88b7ff..a58365a 100644 --- a/iproxy.c +++ b/iproxy.c @@ -290,6 +290,7 @@ void *acceptor_thread(void *arg) fprintf(stderr, "Error connecting to device!\n"); } } + close(cdata->fd); close(cdata->sfd); return NULL; -- cgit v1.1-32-gdbae From 6e2946da89ce8c44ac2b78e49c8fc934974d021d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 25 Feb 2009 18:09:19 +0100 Subject: big endian fix and some improvements, now multi-client capable --- iphone.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++----------- usbmuxd.c | 61 +++++++++++++++-------- 2 files changed, 175 insertions(+), 48 deletions(-) diff --git a/iphone.c b/iphone.c index 9035be9..bf0d5de 100644 --- a/iphone.c +++ b/iphone.c @@ -132,6 +132,61 @@ void log_debug_msg(const char *format, ...) #endif } +#ifdef DEBUG +/** + * for debugging purposes. + */ +static void print_buffer(const char *data, const int length) +{ + int i; + int j; + unsigned char c; + + for(i=0; i= 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"); +} +#endif + +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); + } +} + +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 * @@ -392,6 +447,12 @@ int send_to_phone(iphone_device_t phone, char *data, int datalen) int timeout = 1000; int retrycount = 0; int bytes = 0; + +#ifdef DEBUG + printf("===============================\n%s: trying to send\n", __func__); + print_buffer(data, datalen); + printf("===============================\n"); +#endif do { if (retrycount > 3) { fprintf(stderr, "EPIC FAIL! aborting on retry count overload.\n"); @@ -426,6 +487,14 @@ int send_to_phone(iphone_device_t phone, char *data, int datalen) } while(0); // fall out +#ifdef DEBUG + if (bytes > 0) { + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + printf("%s: sent to phone\n", __func__); + print_buffer(data, bytes); + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + } +#endif return bytes; } @@ -459,6 +528,15 @@ int recv_from_phone_timeout(iphone_device_t phone, char *data, int datalen, int return -1; } +#ifdef DEBUG + if (bytes > 0) { + printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + printf("%s: received from phone:\n", __func__); + print_buffer(data, bytes); + printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + } +#endif + return bytes; } @@ -621,8 +699,8 @@ iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port, // send TCP syn if (new_connection && new_connection->header) { new_connection->header->tcp_flags = TCP_SYN; - new_connection->header->length = htonl(new_connection->header->length); - new_connection->header->length16 = htons(new_connection->header->length16); + 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->phone = device; @@ -635,6 +713,8 @@ iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port, new_connection->wr_window = 0; add_connection(new_connection); new_connection->error = IPHONE_E_SUCCESS; + hton_header(new_connection->header); + printf("%s: send_to_phone (%d --> %d)\n", __func__, ntohs(new_connection->header->sport), ntohs(new_connection->header->dport)); if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) { *client = new_connection; return IPHONE_E_SUCCESS; @@ -661,11 +741,10 @@ iphone_error_t iphone_mux_free_client(iphone_umux_client_t client) pthread_mutex_lock(&client->mutex); client->header->tcp_flags = TCP_FIN; - client->header->length = htonl(0x1C); - client->header->scnt = htonl(client->header->scnt); - client->header->ocnt = htonl(client->header->ocnt); + client->header->length = 0x1C; client->header->window = 0; - client->header->length16 = htons(0x1C); + client->header->length16 = 0x1C; + hton_header(client->header); int bytes = 0; bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800); @@ -731,31 +810,29 @@ iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, ui // 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 and pre-emptively htonl/htons it - client->header->length = htonl(blocksize); - client->header->length16 = htons(blocksize); + // Set the length + client->header->length = blocksize; + client->header->length16 = blocksize; - // Put scnt and ocnt into big-endian notation - client->header->scnt = htonl(client->header->scnt); - client->header->ocnt = htonl(client->header->ocnt); + // 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); + printf("%s: send_to_phone(%d --> %d)\n", __func__, ntohs(client->header->sport), ntohs(client->header->dport)); sendresult = send_to_phone(client->phone, 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 (sendresult == blocksize) { - // Re-calculate scnt and ocnt - client->header->scnt = ntohl(client->header->scnt) + datalen; - client->header->ocnt = ntohl(client->header->ocnt); - // Revert lengths - client->header->length = ntohl(client->header->length); - client->header->length16 = ntohs(client->header->length16); - + // Re-calculate scnt + client->header->scnt += datalen; client->wr_window -= blocksize; } @@ -812,20 +889,19 @@ uint32 append_receive_buffer(iphone_umux_client_t client, char* packet) if (header->tcp_flags == (TCP_SYN | TCP_ACK)) { fprintf(stdout, "yes, got syn+ack ; replying with ack.\n"); client->header->tcp_flags = TCP_ACK; - client->header->length = htonl(sizeof(usbmux_tcp_header)); - client->header->length16 = htons(sizeof(usbmux_tcp_header)); - client->header->scnt = htonl(client->header->scnt + 1); + 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.... :( + printf("%s: send_to_phone (%d --> %d)\n", __func__, ntohs(client->header->sport), ntohs(client->header->dport)); if (send_to_phone(client->phone, (char *)client->header, sizeof(usbmux_tcp_header)) <= 0) { fprintf(stdout, "%s: error when pushing to usb...\n", __func__); } // need to revert some of the fields back to host notation. - client->header->scnt = ntohl(client->header->scnt); - client->header->ocnt = ntohl(client->header->ocnt); - client->header->length = ntohl(client->header->length); - client->header->length16 = ntohs(client->header->length16); + ntoh_header(client->header); } else { client->error = IPHONE_E_ECONNABORTED; @@ -843,7 +919,33 @@ uint32 append_receive_buffer(iphone_umux_client_t client, char* packet) // larger number. if (header->tcp_flags & TCP_RST) { client->error = IPHONE_E_ECONNRESET; - fprintf(stderr, "peer sent connection reset. setting error: %d\n", client->error); + + 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. + fprintf(stdout, "received status message: %s\n", e_msg); + datalen = 0; + break; + case 1: + fprintf(stderr, "received error message: %s\n", e_msg); + datalen = 0; + break; + default: + fprintf(stderr, "received unknown message (type 0x%02x): %s\n", data[0], e_msg); + //datalen = 0; // <-- we let this commented out for testing + break; + } + } else { + fprintf(stderr, "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. @@ -954,7 +1056,7 @@ void iphone_mux_pullbulk(iphone_device_t phone) readlen = 0; } if (readlen > 0) { - //fprintf(stdout, "recv_from_phone_timeout pulled an extra %d bytes\n", readlen); + //fprintf(stdout, "recv_from_phone_timeout pulled an extra %d bytes\n", readlen); } // the amount of content we have to work with is the remainder plus @@ -968,7 +1070,9 @@ void iphone_mux_pullbulk(iphone_device_t phone) // check if there's even sufficient data to decode a header if (usbReceive.leftover < HEADERLEN) break; usbmux_tcp_header *header = (usbmux_tcp_header *) cursor; - + + printf("%s: recv_from_phone_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 packetlen = ntohl(header->length); diff --git a/usbmuxd.c b/usbmuxd.c index 8f2a6e9..0f4339c 100644 --- a/usbmuxd.c +++ b/usbmuxd.c @@ -47,6 +47,12 @@ static int quit_flag = 0; static int fsock = -1; +struct device_use_info { + uint32_t device_id; + iphone_device_t phone; + int use_count; +}; + struct client_data { volatile int dead; int socket; @@ -58,18 +64,25 @@ struct client_data { int reader_dead; int handler_dead; iphone_umux_client_t muxclient; -}; - -struct device_use_info { - uint32_t device_id; - iphone_device_t phone; - int use_count; + struct device_use_info *duinfo; }; static struct device_use_info **device_use_list = NULL; static int device_use_count = 0; static pthread_mutex_t usbmux_mutex = PTHREAD_MUTEX_INITIALIZER; +/** + * mutex for mutual exclusion of calling the iphone_mux_send function + * TODO: I don't know if we really need this? + */ +static pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** + * mutex to keep the reader threads from reading partial packages + */ +static pthread_mutex_t reader_mutex = PTHREAD_MUTEX_INITIALIZER; + +#ifdef DEBUG /** * for debugging purposes. */ @@ -103,6 +116,7 @@ static void print_buffer(const char *data, const int length) } printf("\n"); } +#endif /** * Read incoming usbmuxd packet. If the packet is larger than @@ -192,7 +206,7 @@ static void *usbmuxd_client_reader_thread(void *arg) cdata->reader_dead = 0; - fprintf(stdout, "%s: started\n", __func__); + fprintf(stdout, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); while (!quit_flag && !cdata->reader_quit) { result = check_fd(cdata->socket, fdwrite, DEFAULT_TIMEOUT); @@ -204,9 +218,11 @@ static void *usbmuxd_client_reader_thread(void *arg) } rlen = 0; + //pthread_mutex_lock(&usbmux_mutex); err = iphone_mux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, &rlen, DEFAULT_TIMEOUT); + //pthread_mutex_unlock(&usbmux_mutex); if (err != 0) { - fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err); + fprintf(stderr, "%s[%d:%d]: encountered USB read error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); break; } @@ -221,7 +237,7 @@ static void *usbmuxd_client_reader_thread(void *arg) fsync(cdata->socket); } - fprintf(stdout, "%s: terminated\n", __func__); + fprintf(stdout, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); cdata->reader_dead = 1; @@ -268,7 +284,6 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) return err; } else { if (rlen > 0) { - //print_buffer(buffer, rlen); if ((buffer[0] == 1) && (rlen > 20) && !memcmp(buffer+1, "handleConnectResult:", 20)) { // hm... we got an error message! buffer[rlen] = 0; @@ -319,7 +334,7 @@ static void *usbmuxd_client_handler_thread(void *arg) cdata = (struct client_data*)arg; - fprintf(stdout, "%s: started\n", __func__); + fprintf(stdout, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id,cdata->duinfo->use_count); if (usbmuxd_handleConnectResult(cdata)) { goto leave; @@ -349,18 +364,20 @@ static void *usbmuxd_client_handler_thread(void *arg) break; } if (len < 0) { - fprintf(stderr, "%s: Error: recv: %s\n", __func__, strerror(errno)); + fprintf(stderr, "%s[%d:%d]: Error: recv: %s\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, strerror(errno)); break; } cursor = buffer; + + pthread_mutex_lock(&writer_mutex); do { wlen = 0; err = iphone_mux_send(cdata->muxclient, cursor, len, &wlen); if (err == IPHONE_E_TIMEOUT) { // some kind of timeout... just be patient and retry. } else if (err != IPHONE_E_SUCCESS) { - fprintf(stderr, "%s: USB write error: %d\n", __func__, err); + fprintf(stderr, "%s[%d:%d]: USB write error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); len = -1; break; } @@ -370,6 +387,7 @@ static void *usbmuxd_client_handler_thread(void *arg) // advance cursor appropiately. cursor += wlen; } while ((len > 0) && !quit_flag); + pthread_mutex_unlock(&writer_mutex); if (len < 0) { break; } @@ -377,7 +395,7 @@ static void *usbmuxd_client_handler_thread(void *arg) leave: // cleanup - fprintf(stdout, "%s: terminating\n", __func__); + fprintf(stdout, "%s[%d:%d]: terminating\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); if (cdata->reader != 0) { cdata->reader_quit = 1; pthread_join(cdata->reader, NULL); @@ -385,7 +403,7 @@ leave: cdata->handler_dead = 1; - fprintf(stdout, "%s: terminated\n", __func__); + fprintf(stdout, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); return NULL; } @@ -472,7 +490,9 @@ static void *usbmuxd_client_init_thread(void *arg) //pthread_mutex_unlock(&usbmux_mutex); } +#ifdef DEBUG print_buffer((char*)&dev_info_req, sizeof(dev_info_req)); +#endif // send it if (send_buf(cdata->socket, &dev_info_req, sizeof(dev_info_req)) <= 0) { @@ -534,6 +554,8 @@ static void *usbmuxd_client_init_thread(void *arg) cur_dev->device_id = c_req.device_id; cur_dev->phone = phone; + fprintf(stdout, "%s: device_use_count = %d\n", __func__, device_use_count); + pthread_mutex_lock(&usbmux_mutex); device_use_list = (struct device_use_info**)realloc(device_use_list, sizeof(struct device_use_info*) * (device_use_count+1)); if (device_use_list) { @@ -559,6 +581,7 @@ static void *usbmuxd_client_init_thread(void *arg) // start connection handler thread cdata->handler_dead = 0; cdata->tag = c_req.header.tag; + cdata->duinfo = cur_dev; if (pthread_create(&cdata->handler, NULL, usbmuxd_client_handler_thread, cdata) != 0) { fprintf(stderr, "%s: could not create usbmuxd_client_handler_thread!\n", __func__); cdata->handler = 0; @@ -569,13 +592,12 @@ static void *usbmuxd_client_init_thread(void *arg) // start reading data from the connected device while (!quit_flag && !cdata->handler_dead) { + pthread_mutex_lock(&reader_mutex); iphone_mux_pullbulk(cur_dev->phone); err = iphone_mux_get_error(cdata->muxclient); + pthread_mutex_unlock(&reader_mutex); if (err != IPHONE_E_SUCCESS) { break; - /*} else if (!sent_result) { - usbmuxd_send_result(cdata->socket, c_req.header.tag, 0); - sent_result = 1;*/ } } @@ -630,6 +652,7 @@ leave: } cdata->dead = 1; + close(cdata->socket); fprintf(stdout, "%s: terminated\n", __func__); @@ -684,7 +707,7 @@ static void *usbmuxd_accept_thread(void *arg) while (!quit_flag) { // Check the file descriptor before accepting a connection. // If no connection attempt is made, just repeat... - result = check_fd(fsock, fdread, DEFAULT_TIMEOUT); + result = check_fd(fsock, fdread, 1000); if (result <= 0) { if (result == 0) { // cleanup -- cgit v1.1-32-gdbae From 523c44d0018c2e8480b37ac917aef7469b4b3a65 Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Wed, 25 Feb 2009 20:01:34 +0100 Subject: A Readme, Makefile updates and cosmetic changes. --- .gitignore | 6 + Makefile | 35 +-- Readme.txt | 34 +++ iproxy.c | 54 ++-- main.c | 853 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sock_stuff.c | 8 +- sock_stuff.h | 6 +- testclient.c | 32 ++- usbmuxd.c | 855 ----------------------------------------------------------- usbmuxd.h | 46 ++-- 10 files changed, 987 insertions(+), 942 deletions(-) create mode 100644 .gitignore create mode 100644 Readme.txt create mode 100644 main.c delete mode 100644 usbmuxd.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..26cda67 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*~ +*.o +.*.swp +iproxy +testclient +usbmuxd diff --git a/Makefile b/Makefile index 04a36b3..2036ddc 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,31 @@ -TARGET=usbmuxd -CFLAGS=-Wall -LDFLAGS=-lpthread -lusb -lrt +TARGETS=usbmuxd iproxy testclient +CFLAGS=-Wall -g +LIBS=-lpthread -lusb -lrt +LDFLAGS= -objects = sock_stuff.o usbmuxd.o iphone.o +all: $(TARGETS) -all: $(TARGET) +main.o: main.c usbmuxd.h sock_stuff.h iphone.h +iphone.o: iproxy.c iphone.h usbmuxd.h sock_stuff.h +sock_stuff.o: sock_stuff.c sock_stuff.h +testclient.o: testclient.c sock_stuff.h -%.o: %.c %.h +%.o: %.c $(CC) -o $@ $(CFLAGS) -c $< -$(TARGET): $(objects) - $(CC) -o $@ $(LDFLAGS) $^ +usbmuxd: main.o sock_stuff.o iphone.o + $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) + +testclient: testclient.o sock_stuff.o + $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) + +iproxy: iproxy.o sock_stuff.o + $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) clean: - rm -f *.o $(TARGET) + rm -f *.o $(TARGETS) realclean: clean rm -f *~ -testclient: testclient.c sock_stuff.o - $(CC) $(LDFLAGS) -o testclient $(CFLAGS) $< sock_stuff.o - -iproxy: iproxy.c sock_stuff.o - $(CC) -lpthread -o iproxy $(CFLAGS) $< sock_stuff.o - +.PHONY: all clean realclean diff --git a/Readme.txt b/Readme.txt new file mode 100644 index 0000000..deece52 --- /dev/null +++ b/Readme.txt @@ -0,0 +1,34 @@ +Build +===== + + make + +Use +=== + + sudo ./usbmuxd & + ./iproxy 2222 22 & + ssh -p 2222 root@localhost + +Muwahahaha. Hopefully you get the normal SSH login prompt. + + Unfortunately, as of 2009-02-24 this only survives for a single + connection. You will have to restart the 'iproxy' part. + +SSH +=== + +If your iphone is rooted, but isn't running SSH, you will need to +mount it with 'ifuse --afc2' (to access the root directory of the +device). + +And then edit: + + /Library/LaunchDaemons/com.openssh.sshd.plist + +to _remove_ the lines: + + Diabled + + +Reboot the device and then sshd should be running. diff --git a/iproxy.c b/iproxy.c index a58365a..775b819 100644 --- a/iproxy.c +++ b/iproxy.c @@ -34,8 +34,6 @@ #include "usbmuxd.h" #include "sock_stuff.h" -#define SOCKET_FILE "/var/run/usbmuxd" - static uint16_t listen_port = 0; static uint16_t device_port = 0; @@ -50,7 +48,7 @@ struct client_data { int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result) { - struct usbmux_result res; + struct usbmuxd_result res; int recv_len; int i; uint32_t rrr[5]; @@ -71,7 +69,7 @@ int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result) if ((recv_len == sizeof(res)) && (res.header.length == recv_len) && (res.header.reserved == 0) - && (res.header.type == usbmux_result) + && (res.header.type == USBMUXD_RESULT) ) { *result = res.result; if (res.header.tag == tag) { @@ -185,8 +183,8 @@ void *acceptor_thread(void *arg) int connected; uint32_t pktlen; unsigned char *buf; - struct usbmux_header hello; - struct usbmux_dev_info device_info; + struct usbmuxd_hello hello; + struct usbmuxd_device_info device_info; pthread_t ctos; if (!arg) { @@ -196,26 +194,26 @@ void *acceptor_thread(void *arg) cdata = (struct client_data*)arg; - cdata->sfd = connect_unix_socket(SOCKET_FILE); + cdata->sfd = connect_unix_socket(USBMUXD_SOCKET_FILE); if (cdata->sfd < 0) { printf("error opening socket, terminating.\n"); return NULL; } // send hello - hello.length = sizeof(struct usbmux_header); - hello.reserved = 0; - hello.type = usbmux_hello; - hello.tag = 2; + hello.header.length = sizeof(struct usbmuxd_hello); + hello.header.reserved = 0; + hello.header.type = USBMUXD_HELLO; + hello.header.tag = 2; hello_done = 0; connected = 0; fprintf(stdout, "sending Hello packet\n"); - if (send(cdata->sfd, &hello, hello.length, 0) == hello.length) { + if (send(cdata->sfd, &hello, hello.header.length, 0) == hello.header.length) { uint32_t res = -1; // get response - if (usbmuxd_get_result(cdata->sfd, hello.tag, &res) && (res==0)) { + if (usbmuxd_get_result(cdata->sfd, hello.header.tag, &res) && (res==0)) { fprintf(stdout, "Got Hello Response!\n"); hello_done = 1; } else { @@ -241,7 +239,7 @@ void *acceptor_thread(void *arg) } fprintf(stdout, "Received device data\n"); //log_debug_buffer(stdout, (char*)buf, pktlen); - memcpy(&device_info, buf + sizeof(struct usbmux_header), sizeof(device_info)); + memcpy(&device_info, buf + sizeof(struct usbmuxd_header), sizeof(device_info)); free(buf); } else { // we _should_ have all of them now. @@ -252,17 +250,17 @@ void *acceptor_thread(void *arg) } if (device_info.device_id > 0) { - struct usbmux_connect_request c_req; + struct usbmuxd_connect_request c_req; fprintf(stdout, "Requesting connecion to device %d port %d\n", device_info.device_id, device_port); // try to connect to last device found c_req.header.length = sizeof(c_req); c_req.header.reserved = 0; - c_req.header.type = usbmux_connect; + c_req.header.type = USBMUXD_CONNECT; c_req.header.tag = 3; c_req.device_id = device_info.device_id; - c_req.port = htons(device_port); + c_req.tcp_dport = htons(device_port); c_req.reserved = 0; if (send_buf(cdata->sfd, &c_req, sizeof(c_req)) < 0) { @@ -346,26 +344,26 @@ int main(int argc, char **argv) } /* - sfd = connect_unix_socket(SOCKET_FILE); + sfd = connect_unix_socket(USBMUXD_SOCKET_FILE); if (sfd < 0) { printf("error opening socket, terminating.\n"); return -1; } // send hello - hello.length = sizeof(struct usbmux_header); - hello.reserved = 0; - hello.type = usbmux_hello; - hello.tag = 2; + hello.header.length = sizeof(hello); + hello.header.reserved = 0; + hello.header.type = USBMUXD_HELLO; + hello.header.tag = 2; hello_done = 0; connected = 0; fprintf(stdout, "sending Hello packet\n"); - if (send(sfd, &hello, hello.length, 0) == hello.length) { + if (send(sfd, &hello, hello.header.length, 0) == hello.header.length) { uint32_t res = -1; // get response - if (usbmuxd_get_result(sfd, hello.tag, &res) && (res==0)) { + if (usbmuxd_get_result(sfd, hello.header.tag, &res) && (res==0)) { fprintf(stdout, "Got Hello Response!\n"); hello_done = 1; } else { @@ -390,7 +388,7 @@ int main(int argc, char **argv) } fprintf(stdout, "Received device data\n"); //log_debug_buffer(stdout, (char*)buf, pktlen); - memcpy(&device_info, buf + sizeof(struct usbmux_header), sizeof(device_info)); + memcpy(&device_info, buf + sizeof(struct usbmuxd_header), sizeof(device_info)); free(buf); } else { // we _should_ have all of them now. @@ -401,17 +399,17 @@ int main(int argc, char **argv) } if (device_info.device_id > 0) { - struct usbmux_connect_request c_req; + struct usbmuxd_connect_request c_req; fprintf(stdout, "Requesting connecion to device %d port %d\n", device_info.device_id, device_port); // try to connect to last device found c_req.header.length = sizeof(c_req); c_req.header.reserved = 0; - c_req.header.type = usbmux_connect; + c_req.header.type = USBMUXD_CONNECT; c_req.header.tag = 3; c_req.device_id = device_info.device_id; - c_req.port = htons(device_port); + c_req.tcp_dport = htons(device_port); c_req.reserved = 0; if (send_buf(sfd, &c_req, sizeof(c_req)) < 0) { diff --git a/main.c b/main.c new file mode 100644 index 0000000..bf062b7 --- /dev/null +++ b/main.c @@ -0,0 +1,853 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usbmuxd.h" +#include "sock_stuff.h" + +#include "iphone.h" + +#define DEFAULT_TIMEOUT 4000 +#define DEFAULT_CHILDREN_CAPACITY 10 + +static int quit_flag = 0; +static int fsock = -1; + +struct device_use_info { + uint32_t device_id; + iphone_device_t phone; + int use_count; +}; + +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; + iphone_umux_client_t muxclient; + struct device_use_info *duinfo; +}; + +static struct device_use_info **device_use_list = NULL; +static int device_use_count = 0; +static pthread_mutex_t usbmux_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** + * mutex for mutual exclusion of calling the iphone_mux_send function + * TODO: I don't know if we really need this? + */ +static pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** + * mutex to keep the reader threads from reading partial packages + */ +static pthread_mutex_t reader_mutex = PTHREAD_MUTEX_INITIALIZER; + +#ifdef DEBUG +/** + * for debugging purposes. + */ +static void print_buffer(const char *data, const int length) +{ + int i; + int j; + unsigned char c; + + for(i=0; i= 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"); +} +#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)) < sizeof(pktlen)) { + return -errno; + } + + if (len < pktlen) { + // target buffer is to small to hold this packet! fix it! + fprintf(stderr, "%s: WARNING -- packet (%d) is larger than target buffer (%d)! Truncating.\n", __func__, pktlen, len); + pktlen = len; + } + + recv_len = recv_buf(fd, data, pktlen); + if ((recv_len > 0) && (recv_len < pktlen)) { + fprintf(stderr, "%s: Uh-oh, we got less than the packet's size, %d instead of %d...\n", __func__, recv_len, pktlen); + } + + 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; + + res.header.length = sizeof(res); + res.header.reserved = 0; + res.header.type = USBMUXD_RESULT; + res.header.tag = tag; + res.result = result_code; + + fprintf(stderr, "%s: tag=%d result=%d\n", __func__, res.header.tag, res.result); + + return send_buf(fd, &res, sizeof(res)); +} + +/** + * 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; + iphone_error_t err; + char *cursor; + ssize_t len; + int result; + + if (!arg) { + fprintf(stderr, "%s: invalid client_data supplied!\n", __func__); + cdata->reader_dead = 1; + return NULL; + } + + cdata = (struct client_data*)arg; + + cdata->reader_dead = 0; + + fprintf(stdout, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + + while (!quit_flag && !cdata->reader_quit) { + result = check_fd(cdata->socket, FD_WRITE, DEFAULT_TIMEOUT); + if (result <= 0) { + if (result < 0) { + fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno)); + } + continue; + } + + rlen = 0; + //pthread_mutex_lock(&usbmux_mutex); + err = iphone_mux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, &rlen, DEFAULT_TIMEOUT); + //pthread_mutex_unlock(&usbmux_mutex); + if (err != 0) { + fprintf(stderr, "%s[%d:%d]: encountered USB read error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); + break; + } + + cursor = rbuffer; + while (rlen > 0) { + len = send_buf(cdata->socket, cursor, rlen); + // calculate remainder + rlen -= len; + // advance cursor + cursor += len; + } + fsync(cdata->socket); + } + + fprintf(stdout, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + + 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; + iphone_error_t err; + + if (!cdata) { + fprintf(stderr, "%s: Invalid client_data provided!\n", __func__); + return -EINVAL; + } + + result = check_fd(cdata->socket, FD_WRITE, DEFAULT_TIMEOUT); + if (result <= 0) { + if (result < 0) { + fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno)); + return result; + } + } else { + result = 0; + err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, DEFAULT_TIMEOUT); + if (err != 0) { + fprintf(stderr, "%s: encountered USB read error: %d\n", __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; + fprintf(stderr, "%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[1024]; + ssize_t len; + ssize_t maxlen = sizeof(buffer); + uint32_t wlen; + iphone_error_t err; + + if (!arg) { + fprintf(stderr, "%s: invalid client_data provided!\n", __func__); + return NULL; + } + + cdata = (struct client_data*)arg; + + fprintf(stdout, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id,cdata->duinfo->use_count); + + if (usbmuxd_handleConnectResult(cdata)) { + goto leave; + } + + // starting mux reader thread + cdata->reader_quit = 0; + cdata->reader_dead = 0; + if (pthread_create(&cdata->reader, NULL, usbmuxd_client_reader_thread, cdata) != 0) { + fprintf(stderr, "%s: could not start client_reader thread\n", __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) { + fprintf(stderr, "%s: Error: checkfd: %s\n", __func__, 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) { + fprintf(stderr, "%s[%d:%d]: Error: recv: %s\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, strerror(errno)); + break; + } + + cursor = buffer; + + pthread_mutex_lock(&writer_mutex); + do { + wlen = 0; + err = iphone_mux_send(cdata->muxclient, cursor, len, &wlen); + if (err == IPHONE_E_TIMEOUT) { + // some kind of timeout... just be patient and retry. + } else if (err != IPHONE_E_SUCCESS) { + fprintf(stderr, "%s[%d:%d]: USB write error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); + len = -1; + break; + } + + // calculate remainder. + len -= wlen; + // advance cursor appropiately. + cursor += wlen; + } while ((len > 0) && !quit_flag); + pthread_mutex_unlock(&writer_mutex); + if (len < 0) { + break; + } + } + +leave: + // cleanup + fprintf(stdout, "%s[%d:%d]: terminating\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + if (cdata->reader != 0) { + cdata->reader_quit = 1; + pthread_join(cdata->reader, NULL); + } + + cdata->handler_dead = 1; + + fprintf(stdout, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + 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_hello hello; + struct usbmuxd_device_info_request dev_info_req; + struct usbmuxd_connect_request c_req; + + struct usb_bus *bus; + struct usb_device *dev; + + int recv_len; + int found = 0; + int res; + int i; + int sent_result; + iphone_error_t err; + + iphone_device_t phone; + struct device_use_info *cur_dev = NULL; + + if (!arg) { + fprintf(stderr, "%s: invalid client_data provided!\n", __func__); + return NULL; + } + + cdata = (struct client_data*)arg; + cdata->dead = 0; + + fprintf(stdout, "%s: started (fd=%d)\n", __func__, cdata->socket); + + if ((recv_len = usbmuxd_get_request(cdata->socket, &hello, sizeof(hello))) <= 0) { + fprintf(stderr, "%s: No Hello packet received, error %s\n", __func__, strerror(errno)); + goto leave; + } + + if ((recv_len == sizeof(hello)) && (hello.header.length == sizeof(hello)) + && (hello.header.reserved == 0) && (hello.header.type == USBMUXD_HELLO)) { + // send success response + usbmuxd_send_result(cdata->socket, hello.header.tag, 0); + } else { + // send error response and exit + fprintf(stderr, "%s: Invalid Hello packet received.\n", __func__); + // TODO is this required?! + usbmuxd_send_result(cdata->socket, hello.header.tag, EINVAL); + goto leave; + } + + // gather data about all iPhones/iPods attached + 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 <= 0x1293) + { + fprintf(stdout, "%s: Found device on bus %d, id %d\n", __func__, bus->location, dev->devnum); + found++; + + // construct packet + memset(&dev_info_req, 0, sizeof(dev_info_req)); + dev_info_req.header.length = sizeof(dev_info_req); + dev_info_req.header.type = USBMUXD_DEVICE_INFO; + dev_info_req.device_info.device_id = dev->devnum; + dev_info_req.device_info.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_req.device_info.serial_number, sizeof(dev_info_req.device_info.serial_number)+1); + usb_close(udev); + } + //pthread_mutex_unlock(&usbmux_mutex); + } + +#ifdef DEBUG + print_buffer((char*)&dev_info_req, sizeof(dev_info_req)); +#endif + + // send it + if (send_buf(cdata->socket, &dev_info_req, sizeof(dev_info_req)) <= 0) { + fprintf(stderr, "%s: Error: Could not send device info: %s\n", __func__, strerror(errno)); + found--; + } + } + } + } + + // now wait for connect request + if (found <= 0) { + fprintf(stderr, "%s: No attached iPhone/iPod devices found.\n", __func__); + goto leave; + } + + memset(&c_req, 0, sizeof(c_req)); + if ((recv_len = usbmuxd_get_request(cdata->socket, &c_req, sizeof(c_req))) <= 0) { + fprintf(stderr, "%s: Did not receive any connect request.\n", __func__); + goto leave; + } + + if (c_req.header.type != USBMUXD_CONNECT) { + fprintf(stderr, "%s: Unexpected packet of type %d received.\n", __func__, c_req.header.type); + goto leave; + } + + fprintf(stdout, "%s: Setting up connection to usb device #%d on port %d\n", __func__, c_req.device_id, ntohs(c_req.tcp_dport)); + + // find the device, and open usb connection + phone = NULL; + cur_dev = NULL; + // first check if we already have an open connection + if (device_use_list) { + pthread_mutex_lock(&usbmux_mutex); + for (i = 0; i < device_use_count; i++) { + if (device_use_list[i]) { + if (device_use_list[i]->device_id == c_req.device_id) { + device_use_list[i]->use_count++; + cur_dev = device_use_list[i]; + phone = cur_dev->phone; + break; + } + } + } + pthread_mutex_unlock(&usbmux_mutex); + } + if (!phone) { + // if not found, make a new connection + if (iphone_get_specific_device(0, c_req.device_id, &phone) != IPHONE_E_SUCCESS) { + fprintf(stderr, "%s: device_id %d could not be opened\n", __func__, c_req.device_id); + usbmuxd_send_result(cdata->socket, c_req.header.tag, ENODEV); + goto leave; + } + // add to device list + cur_dev = (struct device_use_info*)malloc(sizeof(struct device_use_info)); + memset(cur_dev, 0, sizeof(struct device_use_info)); + cur_dev->use_count = 1; + cur_dev->device_id = c_req.device_id; + cur_dev->phone = phone; + + fprintf(stdout, "%s: device_use_count = %d\n", __func__, device_use_count); + + pthread_mutex_lock(&usbmux_mutex); + device_use_list = (struct device_use_info**)realloc(device_use_list, sizeof(struct device_use_info*) * (device_use_count+1)); + if (device_use_list) { + device_use_list[device_use_count] = cur_dev; + device_use_count++; + } + pthread_mutex_unlock(&usbmux_mutex); + } else { + fprintf(stdout, "%s: reusing usb connection device_id %d\n", __func__, c_req.device_id); + } + + // setup connection to iPhone/iPod +// pthread_mutex_lock(&usbmux_mutex); + res = iphone_mux_new_client(cur_dev->phone, 0, ntohs(c_req.tcp_dport), &(cdata->muxclient)); +// pthread_mutex_unlock(&usbmux_mutex); + + if (res != 0) { + usbmuxd_send_result(cdata->socket, c_req.header.tag, res); + fprintf(stderr, "%s: mux_new_client returned %d, aborting.\n", __func__, res); + goto leave; + } + + // start connection handler thread + cdata->handler_dead = 0; + cdata->tag = c_req.header.tag; + cdata->duinfo = cur_dev; + if (pthread_create(&cdata->handler, NULL, usbmuxd_client_handler_thread, cdata) != 0) { + fprintf(stderr, "%s: could not create usbmuxd_client_handler_thread!\n", __func__); + cdata->handler = 0; + goto leave; + } + + sent_result = 0; + + // start reading data from the connected device + while (!quit_flag && !cdata->handler_dead) { + pthread_mutex_lock(&reader_mutex); + iphone_mux_pullbulk(cur_dev->phone); + err = iphone_mux_get_error(cdata->muxclient); + pthread_mutex_unlock(&reader_mutex); + if (err != IPHONE_E_SUCCESS) { + break; + } + } + + if (!sent_result) { + //fprintf(stderr, "Sending error message %d tag %d\n", err, c_req.header.tag); + err = iphone_mux_get_error(cdata->muxclient); + //usbmuxd_send_result(cdata->socket, c_req.header.tag, err); + } + + fprintf(stdout, "%s: terminating\n", __func__); + + // wait for handler thread to finish its work + if (cdata->handler != 0) { + pthread_join(cdata->handler, NULL); + } + + // time to clean up + if (cdata && cdata->muxclient) { // should be non-NULL + iphone_mux_free_client(cdata->muxclient); + } + +leave: + // this has to be freed only if it's not in use anymore as it closes + // the USB connection + if (cur_dev) { + if (cur_dev->use_count > 1) { + cur_dev->use_count--; + } else { + iphone_free_device(cur_dev->phone); + cur_dev->use_count = 0; + free(cur_dev); + cur_dev = NULL; + pthread_mutex_lock(&usbmux_mutex); + if (device_use_count > 1) { + struct device_use_info **newlist; + int j; + + newlist = (struct device_use_info**)malloc(sizeof(struct device_use_info*) * device_use_count-1); + for (i = 0; i < device_use_count; i++) { + if (device_use_list[i] != NULL) { + newlist[j++] = device_use_list[i]; + } + } + free(device_use_list); + device_use_list = newlist; + } else { + free(device_use_list); + device_use_list = NULL; + } + pthread_mutex_unlock(&usbmux_mutex); + } + } + + cdata->dead = 1; + close(cdata->socket); + + fprintf(stdout, "%s: terminated\n", __func__); + + return NULL; +} + +/** + * make this program run detached from the current console + */ +static int daemonize() +{ + // TODO still to be implemented, also logging is missing! + return 0; +} + +/** + * signal handler function for cleaning up properly + */ +static void clean_exit(int sig) +{ + if (sig == SIGINT) { + fprintf(stdout, "CTRL+C pressed\n"); + } + quit_flag = 1; +} + +/** + * thread function that performs accept() and starts the required child + * threads to perform the rest of the communication stuff. + */ +static void *usbmuxd_accept_thread(void *arg) +{ + struct sockaddr_un c_addr; + socklen_t len = sizeof(struct sockaddr_un); + struct client_data *cdata; + struct client_data **children = NULL; + int children_capacity = DEFAULT_CHILDREN_CAPACITY; + int i = 0; + int result = 0; + int cnt; + + // 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) { + fprintf(stderr, "%s: Out of memory when allocating memory for child threads. Terminating.\n", __func__); + exit(EXIT_FAILURE); + } + memset(children, 0, sizeof(struct client_data*) * children_capacity); + + fprintf(stdout, "%s: waiting for connection\n", __func__); + 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); + fprintf(stdout, "%s: reclaimed client thread (fd=%d)\n", __func__, 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 { + fprintf(stderr, "select error: %s\n", strerror(errno)); + continue; + } + } + + cdata = (struct client_data*)malloc(sizeof(struct client_data)); + memset(cdata, 0, sizeof(struct client_data)); + if (!cdata) { + quit_flag = 1; + fprintf(stderr, "%s: Error: Out of memory! Terminating.\n", __func__); + break; + } + + cdata->socket = accept(fsock, (struct sockaddr*)&c_addr, &len); + if (cdata->socket < 0) { + free(cdata); + if (errno == EINTR) { + continue; + } else { + fprintf(stderr, "%s: Error in accept: %s\n", __func__, strerror(errno)); + continue; + } + } + + fprintf(stdout, "%s: new client connected (fd=%d)\n", __func__, 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) { + fprintf(stderr, "%s: Out of memory when enlarging child thread buffer\n", __func__); + } + } + children[i] = cdata; + } else { + fprintf(stderr, "%s: Failed to create client_init_thread.\n", __func__); + close(cdata->socket); + free(cdata); + cdata = NULL; + } + } + + fprintf(stdout, "%s: terminating\n", __func__); + + // preparing for shutdown: wait for child threads to terminate (if any) + fprintf(stdout, "%s: waiting for child threads to terminate...\n", __func__); + for (i = 0; i < children_capacity; i++) { + if (children[i] != NULL) { + pthread_join(children[i]->thread, NULL); + free(children[i]); + } + } + + // delete the children set. + free(children); + children = NULL; + + fprintf(stdout, "%s: terminated.\n", __func__); + + return NULL; +} + +/** + * main function. + */ +int main(int argc, char **argv) +{ + int foreground = 1; + pthread_t acceptor; + + fprintf(stdout, "usbmuxd: starting\n"); + + // TODO: Parameter checking. + + fsock = create_unix_socket(USBMUXD_SOCKET_FILE); + if (fsock < 0) { + fprintf(stderr, "Could not create socket, exiting\n"); + return -1; + } + + chmod(USBMUXD_SOCKET_FILE, 0666); + + if (!foreground) { + if (daemonize() < 0) { + exit(EXIT_FAILURE); + } + } + + // signal(SIGHUP, reload_conf); // none yet + signal(SIGINT, clean_exit); + signal(SIGQUIT, clean_exit); + signal(SIGTERM, clean_exit); + signal(SIGPIPE, SIG_IGN); + + if (pthread_create(&acceptor, NULL, usbmuxd_accept_thread, NULL) != 0) { + fprintf(stderr, "Failed to create server thread.\n"); + close(fsock); + return -1; + } + + // Relax here. Just wait for the accept thread to terminate. + pthread_join(acceptor, NULL); + + fprintf(stdout, "usbmuxd: terminating\n"); + if (fsock >= 0) { + close(fsock); + } + + unlink(USBMUXD_SOCKET_FILE); + + return 0; +} + diff --git a/sock_stuff.c b/sock_stuff.c index 1a23bc1..3d11a27 100644 --- a/sock_stuff.c +++ b/sock_stuff.c @@ -208,13 +208,13 @@ int check_fd(int fd, fd_mode fdm, unsigned int timeout) do { eagain = 0; switch(fdm) { - case fdread: + case FD_READ: sret = select(fd+1,&fds,NULL,NULL,&to); break; - case fdwrite: + case FD_WRITE: sret = select(fd+1,NULL,&fds,NULL,&to); break; - case fdexcept: + case FD_EXCEPT: sret = select(fd+1,NULL,NULL,&fds,&to); break; } @@ -255,7 +255,7 @@ int recv_buf_timeout(int fd, void *data, size_t length, int flags, unsigned int int result; // check if data is available - res = check_fd(fd, fdread, timeout); + res = check_fd(fd, FD_READ, timeout); if (res <= 0) { return res; } diff --git a/sock_stuff.h b/sock_stuff.h index 01082d1..9965f4e 100644 --- a/sock_stuff.h +++ b/sock_stuff.h @@ -5,9 +5,9 @@ enum fd_mode { - fdread, - fdwrite, - fdexcept + FD_READ, + FD_WRITE, + FD_EXCEPT }; typedef enum fd_mode fd_mode; diff --git a/testclient.c b/testclient.c index fafbf23..679b6d0 100644 --- a/testclient.c +++ b/testclient.c @@ -10,11 +10,9 @@ #include "usbmuxd.h" #include "sock_stuff.h" -#define SOCKET_FILE "/var/run/usbmuxd" - int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result) { - struct usbmux_result res; + struct usbmuxd_result res; int recv_len; if (!result) { @@ -28,7 +26,7 @@ int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result) if ((recv_len == sizeof(res)) && (res.header.length == recv_len) && (res.header.reserved == 0) - && (res.header.type == usbmux_result) + && (res.header.type == USBMUXD_RESULT) ) { *result = res.result; if (res.header.tag == tag) { @@ -50,29 +48,29 @@ int main(int argc, char **argv) int connected; uint32_t pktlen; unsigned char *buf; - struct usbmux_header hello; - struct usbmux_dev_info device_info; + struct usbmuxd_hello hello; + struct usbmuxd_device_info device_info; - sfd = connect_unix_socket(SOCKET_FILE); + sfd = connect_unix_socket(USBMUXD_SOCKET_FILE); if (sfd < 0) { printf("error opening socket, terminating.\n"); return -1; } // send hello - hello.length = sizeof(struct usbmux_header); - hello.reserved = 0; - hello.type = usbmux_hello; - hello.tag = 2; + hello.header.length = sizeof(struct usbmuxd_hello); + hello.header.reserved = 0; + hello.header.type = USBMUXD_HELLO; + hello.header.tag = 2; hello_done = 0; connected = 0; fprintf(stdout, "sending Hello packet\n"); - if (send(sfd, &hello, hello.length, 0) == hello.length) { + if (send(sfd, &hello, hello.header.length, 0) == hello.header.length) { uint32_t res = -1; // get response - if (usbmuxd_get_result(sfd, hello.tag, &res) && (res==0)) { + if (usbmuxd_get_result(sfd, hello.header.tag, &res) && (res==0)) { fprintf(stdout, "Got Hello Response!\n"); hello_done = 1; } else { @@ -97,7 +95,7 @@ int main(int argc, char **argv) } fprintf(stdout, "got device data:\n"); //log_debug_buffer(stdout, (char*)buf, pktlen); - memcpy(&device_info, buf + sizeof(struct usbmux_header), sizeof(device_info)); + memcpy(&device_info, buf + sizeof(struct usbmuxd_header), sizeof(device_info)); free(buf); } else { // we _should_ have all of them now. @@ -108,15 +106,15 @@ int main(int argc, char **argv) } if (device_info.device_id > 0) { - struct usbmux_connect_request c_req; + struct usbmuxd_connect_request c_req; // try to connect to last device found c_req.header.length = sizeof(c_req); c_req.header.reserved = 0; - c_req.header.type = usbmux_connect; + c_req.header.type = USBMUXD_CONNECT; c_req.header.tag = 3; c_req.device_id = device_info.device_id; - c_req.port = htons(22); + c_req.tcp_dport = htons(22); c_req.reserved = 0; if (send_buf(sfd, &c_req, sizeof(c_req)) < 0) { diff --git a/usbmuxd.c b/usbmuxd.c deleted file mode 100644 index 0f4339c..0000000 --- a/usbmuxd.c +++ /dev/null @@ -1,855 +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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "usbmuxd.h" -#include "sock_stuff.h" - -#include "iphone.h" - -#define SOCKET_FILE "/var/run/usbmuxd" - -#define DEFAULT_TIMEOUT 4000 -#define DEFAULT_CHILDREN_CAPACITY 10 - -static int quit_flag = 0; -static int fsock = -1; - -struct device_use_info { - uint32_t device_id; - iphone_device_t phone; - int use_count; -}; - -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; - iphone_umux_client_t muxclient; - struct device_use_info *duinfo; -}; - -static struct device_use_info **device_use_list = NULL; -static int device_use_count = 0; -static pthread_mutex_t usbmux_mutex = PTHREAD_MUTEX_INITIALIZER; - -/** - * mutex for mutual exclusion of calling the iphone_mux_send function - * TODO: I don't know if we really need this? - */ -static pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER; - -/** - * mutex to keep the reader threads from reading partial packages - */ -static pthread_mutex_t reader_mutex = PTHREAD_MUTEX_INITIALIZER; - -#ifdef DEBUG -/** - * for debugging purposes. - */ -static void print_buffer(const char *data, const int length) -{ - int i; - int j; - unsigned char c; - - for(i=0; i= 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"); -} -#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)) < sizeof(pktlen)) { - return -errno; - } - - if (len < pktlen) { - // target buffer is to small to hold this packet! fix it! - fprintf(stderr, "%s: WARNING -- packet (%d) is larger than target buffer (%d)! Truncating.\n", __func__, pktlen, len); - pktlen = len; - } - - recv_len = recv_buf(fd, data, pktlen); - if ((recv_len > 0) && (recv_len < pktlen)) { - fprintf(stderr, "%s: Uh-oh, we got less than the packet's size, %d instead of %d...\n", __func__, recv_len, pktlen); - } - - 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 usbmux_result res; - - res.header.length = sizeof(res); - res.header.reserved = 0; - res.header.type = usbmux_result; - res.header.tag = tag; - res.result = result_code; - - fprintf(stderr, "%s: tag=%d result=%d\n", __func__, res.header.tag, res.result); - - return send_buf(fd, &res, sizeof(res)); -} - -/** - * 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; - iphone_error_t err; - char *cursor; - ssize_t len; - int result; - - if (!arg) { - fprintf(stderr, "%s: invalid client_data supplied!\n", __func__); - cdata->reader_dead = 1; - return NULL; - } - - cdata = (struct client_data*)arg; - - cdata->reader_dead = 0; - - fprintf(stdout, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); - - while (!quit_flag && !cdata->reader_quit) { - result = check_fd(cdata->socket, fdwrite, DEFAULT_TIMEOUT); - if (result <= 0) { - if (result < 0) { - fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno)); - } - continue; - } - - rlen = 0; - //pthread_mutex_lock(&usbmux_mutex); - err = iphone_mux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, &rlen, DEFAULT_TIMEOUT); - //pthread_mutex_unlock(&usbmux_mutex); - if (err != 0) { - fprintf(stderr, "%s[%d:%d]: encountered USB read error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); - break; - } - - cursor = rbuffer; - while (rlen > 0) { - len = send_buf(cdata->socket, cursor, rlen); - // calculate remainder - rlen -= len; - // advance cursor - cursor += len; - } - fsync(cdata->socket); - } - - fprintf(stdout, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); - - 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; - iphone_error_t err; - - if (!cdata) { - fprintf(stderr, "%s: Invalid client_data provided!\n", __func__); - return -EINVAL; - } - - result = check_fd(cdata->socket, fdwrite, DEFAULT_TIMEOUT); - if (result <= 0) { - if (result < 0) { - fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno)); - return result; - } - } else { - result = 0; - err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, DEFAULT_TIMEOUT); - if (err != 0) { - fprintf(stderr, "%s: encountered USB read error: %d\n", __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; - fprintf(stderr, "%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[1024]; - ssize_t len; - ssize_t maxlen = sizeof(buffer); - uint32_t wlen; - iphone_error_t err; - - if (!arg) { - fprintf(stderr, "%s: invalid client_data provided!\n", __func__); - return NULL; - } - - cdata = (struct client_data*)arg; - - fprintf(stdout, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id,cdata->duinfo->use_count); - - if (usbmuxd_handleConnectResult(cdata)) { - goto leave; - } - - // starting mux reader thread - cdata->reader_quit = 0; - cdata->reader_dead = 0; - if (pthread_create(&cdata->reader, NULL, usbmuxd_client_reader_thread, cdata) != 0) { - fprintf(stderr, "%s: could not start client_reader thread\n", __func__); - cdata->reader = 0; - } - - while (!quit_flag && !cdata->reader_dead) { - result = check_fd(cdata->socket, fdread, DEFAULT_TIMEOUT); - if (result <= 0) { - if (result < 0) { - fprintf(stderr, "%s: Error: checkfd: %s\n", __func__, 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) { - fprintf(stderr, "%s[%d:%d]: Error: recv: %s\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, strerror(errno)); - break; - } - - cursor = buffer; - - pthread_mutex_lock(&writer_mutex); - do { - wlen = 0; - err = iphone_mux_send(cdata->muxclient, cursor, len, &wlen); - if (err == IPHONE_E_TIMEOUT) { - // some kind of timeout... just be patient and retry. - } else if (err != IPHONE_E_SUCCESS) { - fprintf(stderr, "%s[%d:%d]: USB write error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); - len = -1; - break; - } - - // calculate remainder. - len -= wlen; - // advance cursor appropiately. - cursor += wlen; - } while ((len > 0) && !quit_flag); - pthread_mutex_unlock(&writer_mutex); - if (len < 0) { - break; - } - } - -leave: - // cleanup - fprintf(stdout, "%s[%d:%d]: terminating\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); - if (cdata->reader != 0) { - cdata->reader_quit = 1; - pthread_join(cdata->reader, NULL); - } - - cdata->handler_dead = 1; - - fprintf(stdout, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); - 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 usbmux_header hello; - struct usbmux_dev_info_request dev_info_req; - struct usbmux_connect_request c_req; - - struct usb_bus *bus; - struct usb_device *dev; - - int recv_len; - int found = 0; - int res; - int i; - int sent_result; - iphone_error_t err; - - iphone_device_t phone; - struct device_use_info *cur_dev = NULL; - - if (!arg) { - fprintf(stderr, "%s: invalid client_data provided!\n", __func__); - return NULL; - } - - cdata = (struct client_data*)arg; - cdata->dead = 0; - - fprintf(stdout, "%s: started (fd=%d)\n", __func__, cdata->socket); - - if ((recv_len = usbmuxd_get_request(cdata->socket, &hello, sizeof(hello))) <= 0) { - fprintf(stderr, "%s: No Hello packet received, error %s\n", __func__, strerror(errno)); - goto leave; - } - - if ((recv_len == 16) && (hello.length == 16) - && (hello.reserved == 0) && (hello.type == usbmux_hello)) { - // send success response - usbmuxd_send_result(cdata->socket, hello.tag, 0); - } else { - // send error response and exit - fprintf(stderr, "%s: Invalid Hello packet received.\n", __func__); - // TODO is this required?! - usbmuxd_send_result(cdata->socket, hello.tag, EINVAL); - goto leave; - } - - // gather data about all iPhones/iPods attached - 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 <= 0x1293) - { - fprintf(stdout, "%s: Found device on bus %d, id %d\n", __func__, bus->location, dev->devnum); - found++; - - // construct packet - memset(&dev_info_req, 0, sizeof(dev_info_req)); - dev_info_req.header.length = sizeof(dev_info_req); - dev_info_req.header.type = usbmux_device_info; - dev_info_req.dev_info.device_id = dev->devnum; - dev_info_req.dev_info.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_req.dev_info.serial_number, sizeof(dev_info_req.dev_info.serial_number)+1); - usb_close(udev); - } - //pthread_mutex_unlock(&usbmux_mutex); - } - -#ifdef DEBUG - print_buffer((char*)&dev_info_req, sizeof(dev_info_req)); -#endif - - // send it - if (send_buf(cdata->socket, &dev_info_req, sizeof(dev_info_req)) <= 0) { - fprintf(stderr, "%s: Error: Could not send device info: %s\n", __func__, strerror(errno)); - found--; - } - } - } - } - - // now wait for connect request - if (found <= 0) { - fprintf(stderr, "%s: No attached iPhone/iPod devices found.\n", __func__); - goto leave; - } - - memset(&c_req, 0, sizeof(c_req)); - if ((recv_len = usbmuxd_get_request(cdata->socket, &c_req, sizeof(c_req))) <= 0) { - fprintf(stderr, "%s: Did not receive any connect request.\n", __func__); - goto leave; - } - - if (c_req.header.type != usbmux_connect) { - fprintf(stderr, "%s: Unexpected packet of type %d received.\n", __func__, c_req.header.type); - goto leave; - } - - fprintf(stdout, "%s: Setting up connection to usb device #%d on port %d\n", __func__, c_req.device_id, ntohs(c_req.port)); - - // find the device, and open usb connection - phone = NULL; - cur_dev = NULL; - // first check if we already have an open connection - if (device_use_list) { - pthread_mutex_lock(&usbmux_mutex); - for (i = 0; i < device_use_count; i++) { - if (device_use_list[i]) { - if (device_use_list[i]->device_id == c_req.device_id) { - device_use_list[i]->use_count++; - cur_dev = device_use_list[i]; - phone = cur_dev->phone; - break; - } - } - } - pthread_mutex_unlock(&usbmux_mutex); - } - if (!phone) { - // if not found, make a new connection - if (iphone_get_specific_device(0, c_req.device_id, &phone) != IPHONE_E_SUCCESS) { - fprintf(stderr, "%s: device_id %d could not be opened\n", __func__, c_req.device_id); - usbmuxd_send_result(cdata->socket, c_req.header.tag, ENODEV); - goto leave; - } - // add to device list - cur_dev = (struct device_use_info*)malloc(sizeof(struct device_use_info)); - memset(cur_dev, 0, sizeof(struct device_use_info)); - cur_dev->use_count = 1; - cur_dev->device_id = c_req.device_id; - cur_dev->phone = phone; - - fprintf(stdout, "%s: device_use_count = %d\n", __func__, device_use_count); - - pthread_mutex_lock(&usbmux_mutex); - device_use_list = (struct device_use_info**)realloc(device_use_list, sizeof(struct device_use_info*) * (device_use_count+1)); - if (device_use_list) { - device_use_list[device_use_count] = cur_dev; - device_use_count++; - } - pthread_mutex_unlock(&usbmux_mutex); - } else { - fprintf(stdout, "%s: reusing usb connection device_id %d\n", __func__, c_req.device_id); - } - - // setup connection to iPhone/iPod -// pthread_mutex_lock(&usbmux_mutex); - res = iphone_mux_new_client(cur_dev->phone, 0, ntohs(c_req.port), &(cdata->muxclient)); -// pthread_mutex_unlock(&usbmux_mutex); - - if (res != 0) { - usbmuxd_send_result(cdata->socket, c_req.header.tag, res); - fprintf(stderr, "%s: mux_new_client returned %d, aborting.\n", __func__, res); - goto leave; - } - - // start connection handler thread - cdata->handler_dead = 0; - cdata->tag = c_req.header.tag; - cdata->duinfo = cur_dev; - if (pthread_create(&cdata->handler, NULL, usbmuxd_client_handler_thread, cdata) != 0) { - fprintf(stderr, "%s: could not create usbmuxd_client_handler_thread!\n", __func__); - cdata->handler = 0; - goto leave; - } - - sent_result = 0; - - // start reading data from the connected device - while (!quit_flag && !cdata->handler_dead) { - pthread_mutex_lock(&reader_mutex); - iphone_mux_pullbulk(cur_dev->phone); - err = iphone_mux_get_error(cdata->muxclient); - pthread_mutex_unlock(&reader_mutex); - if (err != IPHONE_E_SUCCESS) { - break; - } - } - - if (!sent_result) { - //fprintf(stderr, "Sending error message %d tag %d\n", err, c_req.header.tag); - err = iphone_mux_get_error(cdata->muxclient); - //usbmuxd_send_result(cdata->socket, c_req.header.tag, err); - } - - fprintf(stdout, "%s: terminating\n", __func__); - - // wait for handler thread to finish its work - if (cdata->handler != 0) { - pthread_join(cdata->handler, NULL); - } - - // time to clean up - if (cdata && cdata->muxclient) { // should be non-NULL - iphone_mux_free_client(cdata->muxclient); - } - -leave: - // this has to be freed only if it's not in use anymore as it closes - // the USB connection - if (cur_dev) { - if (cur_dev->use_count > 1) { - cur_dev->use_count--; - } else { - iphone_free_device(cur_dev->phone); - cur_dev->use_count = 0; - free(cur_dev); - cur_dev = NULL; - pthread_mutex_lock(&usbmux_mutex); - if (device_use_count > 1) { - struct device_use_info **newlist; - int j; - - newlist = (struct device_use_info**)malloc(sizeof(struct device_use_info*) * device_use_count-1); - for (i = 0; i < device_use_count; i++) { - if (device_use_list[i] != NULL) { - newlist[j++] = device_use_list[i]; - } - } - free(device_use_list); - device_use_list = newlist; - } else { - free(device_use_list); - device_use_list = NULL; - } - pthread_mutex_unlock(&usbmux_mutex); - } - } - - cdata->dead = 1; - close(cdata->socket); - - fprintf(stdout, "%s: terminated\n", __func__); - - return NULL; -} - -/** - * make this program run detached from the current console - */ -static int daemonize() -{ - // TODO still to be implemented, also logging is missing! - return 0; -} - -/** - * signal handler function for cleaning up properly - */ -static void clean_exit(int sig) -{ - if (sig == SIGINT) { - fprintf(stdout, "CTRL+C pressed\n"); - } - quit_flag = 1; -} - -/** - * thread function that performs accept() and starts the required child - * threads to perform the rest of the communication stuff. - */ -static void *usbmuxd_accept_thread(void *arg) -{ - struct sockaddr_un c_addr; - socklen_t len = sizeof(struct sockaddr_un); - struct client_data *cdata; - struct client_data **children = NULL; - int children_capacity = DEFAULT_CHILDREN_CAPACITY; - int i = 0; - int result = 0; - int cnt; - - // 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) { - fprintf(stderr, "%s: Out of memory when allocating memory for child threads. Terminating.\n", __func__); - exit(EXIT_FAILURE); - } - memset(children, 0, sizeof(struct client_data*) * children_capacity); - - fprintf(stdout, "%s: waiting for connection\n", __func__); - while (!quit_flag) { - // Check the file descriptor before accepting a connection. - // If no connection attempt is made, just repeat... - result = check_fd(fsock, fdread, 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); - fprintf(stdout, "%s: reclaimed client thread (fd=%d)\n", __func__, 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 { - fprintf(stderr, "select error: %s\n", strerror(errno)); - continue; - } - } - - cdata = (struct client_data*)malloc(sizeof(struct client_data)); - memset(cdata, 0, sizeof(struct client_data)); - if (!cdata) { - quit_flag = 1; - fprintf(stderr, "%s: Error: Out of memory! Terminating.\n", __func__); - break; - } - - cdata->socket = accept(fsock, (struct sockaddr*)&c_addr, &len); - if (cdata->socket < 0) { - free(cdata); - if (errno == EINTR) { - continue; - } else { - fprintf(stderr, "%s: Error in accept: %s\n", __func__, strerror(errno)); - continue; - } - } - - fprintf(stdout, "%s: new client connected (fd=%d)\n", __func__, 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) { - fprintf(stderr, "%s: Out of memory when enlarging child thread buffer\n", __func__); - } - } - children[i] = cdata; - } else { - fprintf(stderr, "%s: Failed to create client_init_thread.\n", __func__); - close(cdata->socket); - free(cdata); - cdata = NULL; - } - } - - fprintf(stdout, "%s: terminating\n", __func__); - - // preparing for shutdown: wait for child threads to terminate (if any) - fprintf(stdout, "%s: waiting for child threads to terminate...\n", __func__); - for (i = 0; i < children_capacity; i++) { - if (children[i] != NULL) { - pthread_join(children[i]->thread, NULL); - free(children[i]); - } - } - - // delete the children set. - free(children); - children = NULL; - - fprintf(stdout, "%s: terminated.\n", __func__); - - return NULL; -} - -/** - * main function. - */ -int main(int argc, char **argv) -{ - int foreground = 1; - pthread_t acceptor; - - fprintf(stdout, "usbmuxd: starting\n"); - - // TODO: Parameter checking. - - fsock = create_unix_socket(SOCKET_FILE); - if (fsock < 0) { - fprintf(stderr, "Could not create socket, exiting\n"); - return -1; - } - - chmod(SOCKET_FILE, 0666); - - if (!foreground) { - if (daemonize() < 0) { - exit(EXIT_FAILURE); - } - } - - // signal(SIGHUP, reload_conf); // none yet - signal(SIGINT, clean_exit); - signal(SIGQUIT, clean_exit); - signal(SIGTERM, clean_exit); - signal(SIGPIPE, SIG_IGN); - - if (pthread_create(&acceptor, NULL, usbmuxd_accept_thread, NULL) != 0) { - fprintf(stderr, "Failed to create server thread.\n"); - close(fsock); - return -1; - } - - // Relax here. Just wait for the accept thread to terminate. - pthread_join(acceptor, NULL); - - fprintf(stdout, "usbmuxd: terminating\n"); - if (fsock >= 0) { - close(fsock); - } - - unlink(SOCKET_FILE); - - return 0; -} - diff --git a/usbmuxd.h b/usbmuxd.h index fcbee52..d749baf 100644 --- a/usbmuxd.h +++ b/usbmuxd.h @@ -3,42 +3,48 @@ #include -struct usbmux_header { +#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 usbmux_result { - struct usbmux_header header; +struct usbmuxd_result { + struct usbmuxd_header header; uint32_t result; -}; +} __attribute__((__packed__)); -struct usbmux_connect_request { - struct usbmux_header header; +struct usbmuxd_connect_request { + struct usbmuxd_header header; uint32_t device_id; - uint16_t port; // TCP port number + uint16_t tcp_dport; // TCP port number uint16_t reserved; // set to zero -}; +} __attribute__((__packed__)); -struct usbmux_dev_info { +struct usbmuxd_device_info { uint32_t device_id; uint16_t product_id; char serial_number[40]; -}; +} __attribute__((__packed__)); -struct usbmux_dev_info_request { - struct usbmux_header header; - struct usbmux_dev_info dev_info; - unsigned char padding[222]; -}; +struct usbmuxd_device_info_request { + struct usbmuxd_header header; + struct usbmuxd_device_info device_info; + char padding[222]; +} __attribute__((__packed__)); + +struct usbmuxd_hello { + struct usbmuxd_header header; +} __attribute__((__packed__)); enum { - usbmux_result = 1, - usbmux_connect = 2, - usbmux_hello = 3, - usbmux_device_info = 4, + USBMUXD_RESULT = 1, + USBMUXD_CONNECT = 2, + USBMUXD_HELLO = 3, + USBMUXD_DEVICE_INFO = 4, }; #endif -- cgit v1.1-32-gdbae From 3c10f1396431e5512cea36cb9d848dad984f862d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 25 Feb 2009 20:40:49 +0100 Subject: Removed the restart iproxy part, as it is history now. --- Readme.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Readme.txt b/Readme.txt index deece52..5cb74f9 100644 --- a/Readme.txt +++ b/Readme.txt @@ -3,6 +3,7 @@ Build make + Use === @@ -12,8 +13,6 @@ Use Muwahahaha. Hopefully you get the normal SSH login prompt. - Unfortunately, as of 2009-02-24 this only survives for a single - connection. You will have to restart the 'iproxy' part. SSH === -- cgit v1.1-32-gdbae From eb92d308e2dfba6656b5279e138feee75f2fddb2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 25 Feb 2009 22:13:49 +0100 Subject: Authors file added. --- AUTHORS | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 AUTHORS diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..5b8075b --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Nikias Bassen +Paul Sladen -- cgit v1.1-32-gdbae From f909955d615df615d5c48c2e5829d5e861bcfb2d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 26 Feb 2009 22:25:28 +0100 Subject: proper multi-device support (untested) --- main.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/main.c b/main.c index bf062b7..9bcdece 100644 --- a/main.c +++ b/main.c @@ -49,6 +49,11 @@ struct device_use_info { uint32_t device_id; iphone_device_t phone; int use_count; + /* mutex for mutual exclusion of calling the iphone_mux_send function + * TODO: I don't know if we need really need this? */ + pthread_mutex_t writer_mutex; + /* mutex to keep the reader threads from reading partial packages */ + pthread_mutex_t reader_mutex; }; struct client_data { @@ -69,17 +74,6 @@ static struct device_use_info **device_use_list = NULL; static int device_use_count = 0; static pthread_mutex_t usbmux_mutex = PTHREAD_MUTEX_INITIALIZER; -/** - * mutex for mutual exclusion of calling the iphone_mux_send function - * TODO: I don't know if we really need this? - */ -static pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER; - -/** - * mutex to keep the reader threads from reading partial packages - */ -static pthread_mutex_t reader_mutex = PTHREAD_MUTEX_INITIALIZER; - #ifdef DEBUG /** * for debugging purposes. @@ -216,9 +210,9 @@ static void *usbmuxd_client_reader_thread(void *arg) } rlen = 0; - //pthread_mutex_lock(&usbmux_mutex); + //pthread_mutex_lock(&cdata->duinfo->reader_mutex); err = iphone_mux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, &rlen, DEFAULT_TIMEOUT); - //pthread_mutex_unlock(&usbmux_mutex); + //pthread_mutex_unlock(&cdata->duinfo->reader_mutex); if (err != 0) { fprintf(stderr, "%s[%d:%d]: encountered USB read error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); break; @@ -275,7 +269,9 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) } } else { result = 0; + pthread_mutex_lock(&cdata->duinfo->reader_mutex); err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, DEFAULT_TIMEOUT); + pthread_mutex_unlock(&cdata->duinfo->reader_mutex); if (err != 0) { fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err); usbmuxd_send_result(cdata->socket, cdata->tag, -err); @@ -335,8 +331,10 @@ static void *usbmuxd_client_handler_thread(void *arg) fprintf(stdout, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id,cdata->duinfo->use_count); if (usbmuxd_handleConnectResult(cdata)) { + fprintf(stderr, "handleConnectResult: Error\n"); goto leave; } + fprintf(stdout, "handleConnectResult: Success\n"); // starting mux reader thread cdata->reader_quit = 0; @@ -368,7 +366,7 @@ static void *usbmuxd_client_handler_thread(void *arg) cursor = buffer; - pthread_mutex_lock(&writer_mutex); + pthread_mutex_lock(&cdata->duinfo->writer_mutex); do { wlen = 0; err = iphone_mux_send(cdata->muxclient, cursor, len, &wlen); @@ -385,7 +383,7 @@ static void *usbmuxd_client_handler_thread(void *arg) // advance cursor appropiately. cursor += wlen; } while ((len > 0) && !quit_flag); - pthread_mutex_unlock(&writer_mutex); + pthread_mutex_unlock(&cdata->duinfo->writer_mutex); if (len < 0) { break; } @@ -551,6 +549,8 @@ static void *usbmuxd_client_init_thread(void *arg) cur_dev->use_count = 1; cur_dev->device_id = c_req.device_id; cur_dev->phone = phone; + pthread_mutex_init(&cur_dev->reader_mutex, NULL); + pthread_mutex_init(&cur_dev->writer_mutex, NULL); fprintf(stdout, "%s: device_use_count = %d\n", __func__, device_use_count); @@ -588,12 +588,15 @@ static void *usbmuxd_client_init_thread(void *arg) sent_result = 0; + // TODO: wait for connect result? + // if connect failed, don't run this loop: + // start reading data from the connected device while (!quit_flag && !cdata->handler_dead) { - pthread_mutex_lock(&reader_mutex); + pthread_mutex_lock(&cur_dev->reader_mutex); iphone_mux_pullbulk(cur_dev->phone); err = iphone_mux_get_error(cdata->muxclient); - pthread_mutex_unlock(&reader_mutex); + pthread_mutex_unlock(&cur_dev->reader_mutex); if (err != IPHONE_E_SUCCESS) { break; } @@ -626,6 +629,8 @@ leave: } else { iphone_free_device(cur_dev->phone); cur_dev->use_count = 0; + pthread_mutex_destroy(&cur_dev->reader_mutex); + pthread_mutex_destroy(&cur_dev->writer_mutex); free(cur_dev); cur_dev = NULL; pthread_mutex_lock(&usbmux_mutex); @@ -787,7 +792,7 @@ static void *usbmuxd_accept_thread(void *arg) for (i = 0; i < children_capacity; i++) { if (children[i] != NULL) { pthread_join(children[i]->thread, NULL); - free(children[i]); + free(children[i]); } } -- cgit v1.1-32-gdbae From 365b6c9b208e483af751a43a9ccc8885553859ee Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 27 Feb 2009 03:00:27 +0100 Subject: 1) Now, every device is only handled by one thread for bulk usb reading instead of one thread for each connection to the same device. 2) Removed usbmuxd_accept_thread and moved code into main() directly. --- main.c | 183 +++++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 110 insertions(+), 73 deletions(-) diff --git a/main.c b/main.c index 9bcdece..5c67055 100644 --- a/main.c +++ b/main.c @@ -49,11 +49,13 @@ struct device_use_info { uint32_t device_id; iphone_device_t phone; int use_count; + pthread_t bulk_reader; + pthread_mutex_t mutex; /* mutex for mutual exclusion of calling the iphone_mux_send function * TODO: I don't know if we need really need this? */ pthread_mutex_t writer_mutex; /* mutex to keep the reader threads from reading partial packages */ - pthread_mutex_t reader_mutex; + //pthread_mutex_t reader_mutex; }; struct client_data { @@ -66,6 +68,7 @@ struct client_data { int reader_quit; int reader_dead; int handler_dead; + int connected; iphone_umux_client_t muxclient; struct device_use_info *duinfo; }; @@ -269,9 +272,9 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) } } else { result = 0; - pthread_mutex_lock(&cdata->duinfo->reader_mutex); + //pthread_mutex_lock(&cdata->duinfo->reader_mutex); err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, DEFAULT_TIMEOUT); - pthread_mutex_unlock(&cdata->duinfo->reader_mutex); + //pthread_mutex_unlock(&cdata->duinfo->reader_mutex); if (err != 0) { fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err); usbmuxd_send_result(cdata->socket, cdata->tag, -err); @@ -403,6 +406,46 @@ leave: 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_use_info *cur_dev; + + if (!arg) { + fprintf(stderr, "%s: Invalid client_data provided\n", __func__); + return NULL; + } + + cur_dev = (struct device_use_info*)arg; + + printf("%s: started\n", __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); + + //pthread_mutex_lock(&cur_dev->reader_mutex); + iphone_mux_pullbulk(cur_dev->phone); + //err = iphone_mux_get_error(cdata->muxclient); + //pthread_mutex_unlock(&cur_dev->reader_mutex); + //if (err != IPHONE_E_SUCCESS) { + // break; + //} + } + + printf("%s: terminated\n", __func__); + + return NULL; +} + /** * This thread is started when a new connection is accepted. * It performs the handshake, then waits for the connect packet and @@ -422,8 +465,8 @@ static void *usbmuxd_client_init_thread(void *arg) int found = 0; int res; int i; - int sent_result; - iphone_error_t err; +// int sent_result; +// iphone_error_t err; iphone_device_t phone; struct device_use_info *cur_dev = NULL; @@ -549,10 +592,12 @@ static void *usbmuxd_client_init_thread(void *arg) cur_dev->use_count = 1; cur_dev->device_id = c_req.device_id; cur_dev->phone = phone; - pthread_mutex_init(&cur_dev->reader_mutex, NULL); + pthread_mutex_init(&cur_dev->mutex, NULL); + //pthread_mutex_init(&cur_dev->reader_mutex, NULL); pthread_mutex_init(&cur_dev->writer_mutex, NULL); fprintf(stdout, "%s: device_use_count = %d\n", __func__, device_use_count); + pthread_create(&cur_dev->bulk_reader, NULL, usbmuxd_bulk_reader_thread, cur_dev); pthread_mutex_lock(&usbmux_mutex); device_use_list = (struct device_use_info**)realloc(device_use_list, sizeof(struct device_use_info*) * (device_use_count+1)); @@ -586,11 +631,12 @@ static void *usbmuxd_client_init_thread(void *arg) goto leave; } - sent_result = 0; + //sent_result = 0; // TODO: wait for connect result? // if connect failed, don't run this loop: + /* // start reading data from the connected device while (!quit_flag && !cdata->handler_dead) { pthread_mutex_lock(&cur_dev->reader_mutex); @@ -606,14 +652,16 @@ static void *usbmuxd_client_init_thread(void *arg) //fprintf(stderr, "Sending error message %d tag %d\n", err, c_req.header.tag); err = iphone_mux_get_error(cdata->muxclient); //usbmuxd_send_result(cdata->socket, c_req.header.tag, err); - } + }*/ - fprintf(stdout, "%s: terminating\n", __func__); + //fprintf(stdout, "%s: terminating\n", __func__); // wait for handler thread to finish its work if (cdata->handler != 0) { pthread_join(cdata->handler, NULL); } + + fprintf(stdout, "%s: closing connection\n", __func__); // time to clean up if (cdata && cdata->muxclient) { // should be non-NULL @@ -621,16 +669,25 @@ static void *usbmuxd_client_init_thread(void *arg) } leave: + fprintf(stdout, "%s: terminating\n", __func__); + // this has to be freed only if it's not in use anymore as it closes // the USB connection if (cur_dev) { + pthread_mutex_lock(&cur_dev->mutex); if (cur_dev->use_count > 1) { + printf("%s: decreasing device use count\n", __func__); cur_dev->use_count--; + pthread_mutex_unlock(&cur_dev->mutex); } else { - iphone_free_device(cur_dev->phone); + printf("%s: last client disconnected, cleaning up\n", __func__); cur_dev->use_count = 0; - pthread_mutex_destroy(&cur_dev->reader_mutex); + pthread_mutex_unlock(&cur_dev->mutex); + pthread_join(cur_dev->bulk_reader, NULL); + iphone_free_device(cur_dev->phone); + //pthread_mutex_destroy(&cur_dev->reader_mutex); pthread_mutex_destroy(&cur_dev->writer_mutex); + pthread_mutex_destroy(&cur_dev->mutex); free(cur_dev); cur_dev = NULL; pthread_mutex_lock(&usbmux_mutex); @@ -683,30 +740,54 @@ static void clean_exit(int sig) } /** - * thread function that performs accept() and starts the required child - * threads to perform the rest of the communication stuff. + * main function. Initializes all stuff and then loops waiting in accept. */ -static void *usbmuxd_accept_thread(void *arg) +int main(int argc, char **argv) { + int foreground = 1; struct sockaddr_un c_addr; socklen_t len = sizeof(struct sockaddr_un); - struct client_data *cdata; + struct client_data *cdata = NULL; struct client_data **children = NULL; int children_capacity = DEFAULT_CHILDREN_CAPACITY; int i = 0; int result = 0; - int cnt; + int cnt = 0; + + fprintf(stdout, "usbmuxd: starting\n"); + + // TODO: Parameter checking. + + fsock = create_unix_socket(USBMUXD_SOCKET_FILE); + if (fsock < 0) { + fprintf(stderr, "Could not create socket, exiting\n"); + return -1; + } + + chmod(USBMUXD_SOCKET_FILE, 0666); + + if (!foreground) { + if (daemonize() < 0) { + exit(EXIT_FAILURE); + } + } + + // signal(SIGHUP, reload_conf); // none yet + signal(SIGINT, clean_exit); + signal(SIGQUIT, clean_exit); + signal(SIGTERM, clean_exit); + signal(SIGPIPE, SIG_IGN); // 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) { - fprintf(stderr, "%s: Out of memory when allocating memory for child threads. Terminating.\n", __func__); + fprintf(stderr, "usbmuxd: Out of memory when allocating memory for child threads. Terminating.\n"); exit(EXIT_FAILURE); } memset(children, 0, sizeof(struct client_data*) * children_capacity); - fprintf(stdout, "%s: waiting for connection\n", __func__); + fprintf(stdout, "usbmuxd: waiting for connection\n"); while (!quit_flag) { // Check the file descriptor before accepting a connection. // If no connection attempt is made, just repeat... @@ -718,7 +799,7 @@ static void *usbmuxd_accept_thread(void *arg) if (children[i]) { if (children[i]->dead != 0) { pthread_join(children[i]->thread, NULL); - fprintf(stdout, "%s: reclaimed client thread (fd=%d)\n", __func__, children[i]->socket); + fprintf(stdout, "usbmuxd: reclaimed client thread (fd=%d)\n", children[i]->socket); free(children[i]); children[i] = NULL; cnt++; @@ -737,7 +818,7 @@ static void *usbmuxd_accept_thread(void *arg) } continue; } else { - fprintf(stderr, "select error: %s\n", strerror(errno)); + fprintf(stderr, "usbmuxd: select error: %s\n", strerror(errno)); continue; } } @@ -746,7 +827,7 @@ static void *usbmuxd_accept_thread(void *arg) memset(cdata, 0, sizeof(struct client_data)); if (!cdata) { quit_flag = 1; - fprintf(stderr, "%s: Error: Out of memory! Terminating.\n", __func__); + fprintf(stderr, "usbmuxd: Error: Out of memory! Terminating.\n"); break; } @@ -756,12 +837,12 @@ static void *usbmuxd_accept_thread(void *arg) if (errno == EINTR) { continue; } else { - fprintf(stderr, "%s: Error in accept: %s\n", __func__, strerror(errno)); + fprintf(stderr, "usbmuxd: Error in accept: %s\n", strerror(errno)); continue; } } - fprintf(stdout, "%s: new client connected (fd=%d)\n", __func__, cdata->socket); + fprintf(stdout, "usbmuxd: new client connected (fd=%d)\n", cdata->socket); // create client thread: if (pthread_create(&cdata->thread, NULL, usbmuxd_client_init_thread, cdata) == 0) { @@ -773,22 +854,22 @@ static void *usbmuxd_accept_thread(void *arg) children_capacity++; children = realloc(children, sizeof(struct client_data*) * children_capacity); if (!children) { - fprintf(stderr, "%s: Out of memory when enlarging child thread buffer\n", __func__); + fprintf(stderr, "usbmuxd: Out of memory when enlarging child thread buffer\n"); } } children[i] = cdata; } else { - fprintf(stderr, "%s: Failed to create client_init_thread.\n", __func__); + fprintf(stderr, "usbmuxd: Failed to create client_init_thread.\n"); close(cdata->socket); free(cdata); cdata = NULL; } } - fprintf(stdout, "%s: terminating\n", __func__); + fprintf(stdout, "usbmuxd: terminating\n"); // preparing for shutdown: wait for child threads to terminate (if any) - fprintf(stdout, "%s: waiting for child threads to terminate...\n", __func__); + fprintf(stdout, "usbmuxd: waiting for child threads to terminate...\n"); for (i = 0; i < children_capacity; i++) { if (children[i] != NULL) { pthread_join(children[i]->thread, NULL); @@ -800,59 +881,15 @@ static void *usbmuxd_accept_thread(void *arg) free(children); children = NULL; - fprintf(stdout, "%s: terminated.\n", __func__); - - return NULL; -} -/** - * main function. - */ -int main(int argc, char **argv) -{ - int foreground = 1; - pthread_t acceptor; - - fprintf(stdout, "usbmuxd: starting\n"); - - // TODO: Parameter checking. - - fsock = create_unix_socket(USBMUXD_SOCKET_FILE); - if (fsock < 0) { - fprintf(stderr, "Could not create socket, exiting\n"); - return -1; - } - - chmod(USBMUXD_SOCKET_FILE, 0666); - - if (!foreground) { - if (daemonize() < 0) { - exit(EXIT_FAILURE); - } - } - - // signal(SIGHUP, reload_conf); // none yet - signal(SIGINT, clean_exit); - signal(SIGQUIT, clean_exit); - signal(SIGTERM, clean_exit); - signal(SIGPIPE, SIG_IGN); - - if (pthread_create(&acceptor, NULL, usbmuxd_accept_thread, NULL) != 0) { - fprintf(stderr, "Failed to create server thread.\n"); - close(fsock); - return -1; - } - - // Relax here. Just wait for the accept thread to terminate. - pthread_join(acceptor, NULL); - - fprintf(stdout, "usbmuxd: terminating\n"); if (fsock >= 0) { close(fsock); } unlink(USBMUXD_SOCKET_FILE); + fprintf(stdout, "usbmuxd: terminated\n"); + return 0; } -- cgit v1.1-32-gdbae From 2a5d90a74586d16a072f941f5e5748dc2af89daa Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 27 Feb 2009 12:50:02 +0100 Subject: Removed the (already commented out) reader_mutex, as it is not needed, and iphone_mux_pullbulk is only running once per device and the iphone_mux_recv_timeout function does it's own locking. --- main.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/main.c b/main.c index 5c67055..2f08fec 100644 --- a/main.c +++ b/main.c @@ -54,8 +54,6 @@ struct device_use_info { /* mutex for mutual exclusion of calling the iphone_mux_send function * TODO: I don't know if we need really need this? */ pthread_mutex_t writer_mutex; - /* mutex to keep the reader threads from reading partial packages */ - //pthread_mutex_t reader_mutex; }; struct client_data { @@ -213,9 +211,7 @@ static void *usbmuxd_client_reader_thread(void *arg) } rlen = 0; - //pthread_mutex_lock(&cdata->duinfo->reader_mutex); err = iphone_mux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, &rlen, DEFAULT_TIMEOUT); - //pthread_mutex_unlock(&cdata->duinfo->reader_mutex); if (err != 0) { fprintf(stderr, "%s[%d:%d]: encountered USB read error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); break; @@ -272,9 +268,7 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) } } else { result = 0; - //pthread_mutex_lock(&cdata->duinfo->reader_mutex); err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, DEFAULT_TIMEOUT); - //pthread_mutex_unlock(&cdata->duinfo->reader_mutex); if (err != 0) { fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err); usbmuxd_send_result(cdata->socket, cdata->tag, -err); @@ -432,10 +426,8 @@ static void *usbmuxd_bulk_reader_thread(void *arg) } pthread_mutex_unlock(&cur_dev->mutex); - //pthread_mutex_lock(&cur_dev->reader_mutex); iphone_mux_pullbulk(cur_dev->phone); //err = iphone_mux_get_error(cdata->muxclient); - //pthread_mutex_unlock(&cur_dev->reader_mutex); //if (err != IPHONE_E_SUCCESS) { // break; //} @@ -593,7 +585,6 @@ static void *usbmuxd_client_init_thread(void *arg) cur_dev->device_id = c_req.device_id; cur_dev->phone = phone; pthread_mutex_init(&cur_dev->mutex, NULL); - //pthread_mutex_init(&cur_dev->reader_mutex, NULL); pthread_mutex_init(&cur_dev->writer_mutex, NULL); fprintf(stdout, "%s: device_use_count = %d\n", __func__, device_use_count); @@ -639,10 +630,8 @@ static void *usbmuxd_client_init_thread(void *arg) /* // start reading data from the connected device while (!quit_flag && !cdata->handler_dead) { - pthread_mutex_lock(&cur_dev->reader_mutex); iphone_mux_pullbulk(cur_dev->phone); err = iphone_mux_get_error(cdata->muxclient); - pthread_mutex_unlock(&cur_dev->reader_mutex); if (err != IPHONE_E_SUCCESS) { break; } @@ -685,7 +674,6 @@ leave: pthread_mutex_unlock(&cur_dev->mutex); pthread_join(cur_dev->bulk_reader, NULL); iphone_free_device(cur_dev->phone); - //pthread_mutex_destroy(&cur_dev->reader_mutex); pthread_mutex_destroy(&cur_dev->writer_mutex); pthread_mutex_destroy(&cur_dev->mutex); free(cur_dev); -- cgit v1.1-32-gdbae From b4f59ac150e3b1df1683b7dc58e009b3e90bcdee Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 4 Mar 2009 02:45:36 +0100 Subject: Modified handshake sequence so that connect request can be made without prior hello, just as the usbmux-proxy utitliy does and most likely the original usbmuxd works too: - client opens a first connection to usbmuxd, sends hello, and receives the device list in return - client opens a second connection, sends a connect request and after successful connect the data packets are transferred via this connection. So the second connection does not begin with a hello but with a connection request directly -- currently the first connection still waits for a connect request but closes down if nothing is received. Changed all stdout to stderr in main.c --- main.c | 114 +++++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 69 insertions(+), 45 deletions(-) diff --git a/main.c b/main.c index 2f08fec..ec9b007 100644 --- a/main.c +++ b/main.c @@ -122,7 +122,7 @@ static void print_buffer(const char *data, const int length) * * @return */ -static int usbmuxd_get_request(int fd, void *data, size_t len) +static int usbmuxd_get_request(int fd, void **data, size_t len) { uint32_t pktlen; int recv_len; @@ -131,17 +131,27 @@ static int usbmuxd_get_request(int fd, void *data, size_t len) return -errno; } - if (len < pktlen) { + if (len == 0) { + // allocate buffer space + *data = malloc(pktlen); + } else if (len < pktlen) { // target buffer is to small to hold this packet! fix it! fprintf(stderr, "%s: WARNING -- packet (%d) is larger than target buffer (%d)! Truncating.\n", __func__, pktlen, len); pktlen = len; } - recv_len = recv_buf(fd, data, pktlen); + recv_len = recv_buf(fd, *data, pktlen); if ((recv_len > 0) && (recv_len < pktlen)) { fprintf(stderr, "%s: Uh-oh, we got less than the packet's size, %d instead of %d...\n", __func__, recv_len, pktlen); } +#ifdef DEBUG + if (*data && (recv_len > 0)) { + fprintf(stderr, "%s: received:\n", __func__); + print_buffer(*data,recv_len); + } +#endif + return recv_len; } @@ -199,7 +209,7 @@ static void *usbmuxd_client_reader_thread(void *arg) cdata->reader_dead = 0; - fprintf(stdout, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + fprintf(stderr, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); while (!quit_flag && !cdata->reader_quit) { result = check_fd(cdata->socket, FD_WRITE, DEFAULT_TIMEOUT); @@ -228,7 +238,7 @@ static void *usbmuxd_client_reader_thread(void *arg) fsync(cdata->socket); } - fprintf(stdout, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + fprintf(stderr, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); cdata->reader_dead = 1; @@ -325,13 +335,13 @@ static void *usbmuxd_client_handler_thread(void *arg) cdata = (struct client_data*)arg; - fprintf(stdout, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id,cdata->duinfo->use_count); + fprintf(stderr, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id,cdata->duinfo->use_count); if (usbmuxd_handleConnectResult(cdata)) { fprintf(stderr, "handleConnectResult: Error\n"); goto leave; } - fprintf(stdout, "handleConnectResult: Success\n"); + fprintf(stderr, "handleConnectResult: Success\n"); // starting mux reader thread cdata->reader_quit = 0; @@ -388,7 +398,7 @@ static void *usbmuxd_client_handler_thread(void *arg) leave: // cleanup - fprintf(stdout, "%s[%d:%d]: terminating\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + fprintf(stderr, "%s[%d:%d]: terminating\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); if (cdata->reader != 0) { cdata->reader_quit = 1; pthread_join(cdata->reader, NULL); @@ -396,7 +406,7 @@ leave: cdata->handler_dead = 1; - fprintf(stdout, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + fprintf(stderr, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); return NULL; } @@ -446,9 +456,9 @@ static void *usbmuxd_bulk_reader_thread(void *arg) static void *usbmuxd_client_init_thread(void *arg) { struct client_data *cdata; - struct usbmuxd_hello hello; + struct usbmuxd_hello *hello = NULL; struct usbmuxd_device_info_request dev_info_req; - struct usbmuxd_connect_request c_req; + struct usbmuxd_connect_request *c_req = NULL; struct usb_bus *bus; struct usb_device *dev; @@ -471,22 +481,27 @@ static void *usbmuxd_client_init_thread(void *arg) cdata = (struct client_data*)arg; cdata->dead = 0; - fprintf(stdout, "%s: started (fd=%d)\n", __func__, cdata->socket); + fprintf(stderr, "%s: started (fd=%d)\n", __func__, cdata->socket); - if ((recv_len = usbmuxd_get_request(cdata->socket, &hello, sizeof(hello))) <= 0) { + if ((recv_len = usbmuxd_get_request(cdata->socket, (void**)&hello, 0)) <= 0) { fprintf(stderr, "%s: No Hello packet received, error %s\n", __func__, strerror(errno)); goto leave; } - if ((recv_len == sizeof(hello)) && (hello.header.length == sizeof(hello)) - && (hello.header.reserved == 0) && (hello.header.type == USBMUXD_HELLO)) { + if ((recv_len == sizeof(struct usbmuxd_hello)) && (hello->header.length == sizeof(struct usbmuxd_hello)) + && (hello->header.reserved == 0) && (hello->header.type == USBMUXD_HELLO)) { // send success response - usbmuxd_send_result(cdata->socket, hello.header.tag, 0); + fprintf(stderr, "%s: Got Hello packet!\n", __func__); + usbmuxd_send_result(cdata->socket, hello->header.tag, 0); + } else if ((recv_len == sizeof(struct usbmuxd_connect_request)) && (hello->header.type == USBMUXD_CONNECT)) { + c_req = (struct usbmuxd_connect_request*)hello; + hello = NULL; + goto connect; } else { // send error response and exit fprintf(stderr, "%s: Invalid Hello packet received.\n", __func__); // TODO is this required?! - usbmuxd_send_result(cdata->socket, hello.header.tag, EINVAL); + usbmuxd_send_result(cdata->socket, hello->header.tag, EINVAL); goto leave; } @@ -501,7 +516,7 @@ static void *usbmuxd_client_init_thread(void *arg) && dev->descriptor.idProduct >= 0x1290 && dev->descriptor.idProduct <= 0x1293) { - fprintf(stdout, "%s: Found device on bus %d, id %d\n", __func__, bus->location, dev->devnum); + fprintf(stderr, "%s: Found device on bus %d, id %d\n", __func__, bus->location, dev->devnum); found++; // construct packet @@ -540,18 +555,20 @@ static void *usbmuxd_client_init_thread(void *arg) goto leave; } - memset(&c_req, 0, sizeof(c_req)); - if ((recv_len = usbmuxd_get_request(cdata->socket, &c_req, sizeof(c_req))) <= 0) { + //memset(&c_req, 0, sizeof(c_req)); + if ((recv_len = usbmuxd_get_request(cdata->socket, (void**)&c_req, 0)) <= 0) { fprintf(stderr, "%s: Did not receive any connect request.\n", __func__); goto leave; } - if (c_req.header.type != USBMUXD_CONNECT) { - fprintf(stderr, "%s: Unexpected packet of type %d received.\n", __func__, c_req.header.type); +connect: + + if (c_req->header.type != USBMUXD_CONNECT) { + fprintf(stderr, "%s: Unexpected packet of type %d received.\n", __func__, c_req->header.type); goto leave; } - fprintf(stdout, "%s: Setting up connection to usb device #%d on port %d\n", __func__, c_req.device_id, ntohs(c_req.tcp_dport)); + fprintf(stderr, "%s: Setting up connection to usb device #%d on port %d\n", __func__, c_req->device_id, ntohs(c_req->tcp_dport)); // find the device, and open usb connection phone = NULL; @@ -561,7 +578,7 @@ static void *usbmuxd_client_init_thread(void *arg) pthread_mutex_lock(&usbmux_mutex); for (i = 0; i < device_use_count; i++) { if (device_use_list[i]) { - if (device_use_list[i]->device_id == c_req.device_id) { + if (device_use_list[i]->device_id == c_req->device_id) { device_use_list[i]->use_count++; cur_dev = device_use_list[i]; phone = cur_dev->phone; @@ -573,21 +590,21 @@ static void *usbmuxd_client_init_thread(void *arg) } if (!phone) { // if not found, make a new connection - if (iphone_get_specific_device(0, c_req.device_id, &phone) != IPHONE_E_SUCCESS) { - fprintf(stderr, "%s: device_id %d could not be opened\n", __func__, c_req.device_id); - usbmuxd_send_result(cdata->socket, c_req.header.tag, ENODEV); + if (iphone_get_specific_device(0, c_req->device_id, &phone) != IPHONE_E_SUCCESS) { + fprintf(stderr, "%s: device_id %d could not be opened\n", __func__, c_req->device_id); + usbmuxd_send_result(cdata->socket, c_req->header.tag, ENODEV); goto leave; } // add to device list cur_dev = (struct device_use_info*)malloc(sizeof(struct device_use_info)); memset(cur_dev, 0, sizeof(struct device_use_info)); cur_dev->use_count = 1; - cur_dev->device_id = c_req.device_id; + cur_dev->device_id = c_req->device_id; cur_dev->phone = phone; pthread_mutex_init(&cur_dev->mutex, NULL); pthread_mutex_init(&cur_dev->writer_mutex, NULL); - fprintf(stdout, "%s: device_use_count = %d\n", __func__, device_use_count); + fprintf(stderr, "%s: device_use_count = %d\n", __func__, device_use_count); pthread_create(&cur_dev->bulk_reader, NULL, usbmuxd_bulk_reader_thread, cur_dev); pthread_mutex_lock(&usbmux_mutex); @@ -598,23 +615,23 @@ static void *usbmuxd_client_init_thread(void *arg) } pthread_mutex_unlock(&usbmux_mutex); } else { - fprintf(stdout, "%s: reusing usb connection device_id %d\n", __func__, c_req.device_id); + fprintf(stderr, "%s: reusing usb connection device_id %d\n", __func__, c_req->device_id); } // setup connection to iPhone/iPod // pthread_mutex_lock(&usbmux_mutex); - res = iphone_mux_new_client(cur_dev->phone, 0, ntohs(c_req.tcp_dport), &(cdata->muxclient)); + res = iphone_mux_new_client(cur_dev->phone, 0, ntohs(c_req->tcp_dport), &(cdata->muxclient)); // pthread_mutex_unlock(&usbmux_mutex); if (res != 0) { - usbmuxd_send_result(cdata->socket, c_req.header.tag, res); + usbmuxd_send_result(cdata->socket, c_req->header.tag, res); fprintf(stderr, "%s: mux_new_client returned %d, aborting.\n", __func__, res); goto leave; } // start connection handler thread cdata->handler_dead = 0; - cdata->tag = c_req.header.tag; + cdata->tag = c_req->header.tag; cdata->duinfo = cur_dev; if (pthread_create(&cdata->handler, NULL, usbmuxd_client_handler_thread, cdata) != 0) { fprintf(stderr, "%s: could not create usbmuxd_client_handler_thread!\n", __func__); @@ -643,14 +660,14 @@ static void *usbmuxd_client_init_thread(void *arg) //usbmuxd_send_result(cdata->socket, c_req.header.tag, err); }*/ - //fprintf(stdout, "%s: terminating\n", __func__); + //fprintf(stderr, "%s: terminating\n", __func__); // wait for handler thread to finish its work if (cdata->handler != 0) { pthread_join(cdata->handler, NULL); } - fprintf(stdout, "%s: closing connection\n", __func__); + fprintf(stderr, "%s: closing connection\n", __func__); // time to clean up if (cdata && cdata->muxclient) { // should be non-NULL @@ -658,7 +675,14 @@ static void *usbmuxd_client_init_thread(void *arg) } leave: - fprintf(stdout, "%s: terminating\n", __func__); + fprintf(stderr, "%s: terminating\n", __func__); + + if (hello) { + free(hello); + } + 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 @@ -702,7 +726,7 @@ leave: cdata->dead = 1; close(cdata->socket); - fprintf(stdout, "%s: terminated\n", __func__); + fprintf(stderr, "%s: terminated\n", __func__); return NULL; } @@ -722,7 +746,7 @@ static int daemonize() static void clean_exit(int sig) { if (sig == SIGINT) { - fprintf(stdout, "CTRL+C pressed\n"); + fprintf(stderr, "CTRL+C pressed\n"); } quit_flag = 1; } @@ -742,7 +766,7 @@ int main(int argc, char **argv) int result = 0; int cnt = 0; - fprintf(stdout, "usbmuxd: starting\n"); + fprintf(stderr, "usbmuxd: starting\n"); // TODO: Parameter checking. @@ -775,7 +799,7 @@ int main(int argc, char **argv) } memset(children, 0, sizeof(struct client_data*) * children_capacity); - fprintf(stdout, "usbmuxd: waiting for connection\n"); + fprintf(stderr, "usbmuxd: waiting for connection\n"); while (!quit_flag) { // Check the file descriptor before accepting a connection. // If no connection attempt is made, just repeat... @@ -787,7 +811,7 @@ int main(int argc, char **argv) if (children[i]) { if (children[i]->dead != 0) { pthread_join(children[i]->thread, NULL); - fprintf(stdout, "usbmuxd: reclaimed client thread (fd=%d)\n", children[i]->socket); + fprintf(stderr, "usbmuxd: reclaimed client thread (fd=%d)\n", children[i]->socket); free(children[i]); children[i] = NULL; cnt++; @@ -830,7 +854,7 @@ int main(int argc, char **argv) } } - fprintf(stdout, "usbmuxd: new client connected (fd=%d)\n", cdata->socket); + fprintf(stderr, "usbmuxd: new client connected (fd=%d)\n", cdata->socket); // create client thread: if (pthread_create(&cdata->thread, NULL, usbmuxd_client_init_thread, cdata) == 0) { @@ -854,10 +878,10 @@ int main(int argc, char **argv) } } - fprintf(stdout, "usbmuxd: terminating\n"); + fprintf(stderr, "usbmuxd: terminating\n"); // preparing for shutdown: wait for child threads to terminate (if any) - fprintf(stdout, "usbmuxd: waiting for child threads to terminate...\n"); + fprintf(stderr, "usbmuxd: waiting for child threads to terminate...\n"); for (i = 0; i < children_capacity; i++) { if (children[i] != NULL) { pthread_join(children[i]->thread, NULL); @@ -876,7 +900,7 @@ int main(int argc, char **argv) unlink(USBMUXD_SOCKET_FILE); - fprintf(stdout, "usbmuxd: terminated\n"); + fprintf(stderr, "usbmuxd: terminated\n"); return 0; } -- cgit v1.1-32-gdbae From ae400d0e6b5061802ace123fc26a56c2fb669bb4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 8 Mar 2009 21:31:36 +0100 Subject: Some more debugging output and more mutexes to help resolve the f***ing SIGSEVs. --- Makefile | 2 +- iphone.c | 6 ++++++ main.c | 30 ++++++++++++++++++++++++++---- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 2036ddc..3971798 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ TARGETS=usbmuxd iproxy testclient -CFLAGS=-Wall -g +CFLAGS=-Wall -g -DDEBUG LIBS=-lpthread -lusb -lrt LDFLAGS= diff --git a/iphone.c b/iphone.c index bf0d5de..0a2b6cc 100644 --- a/iphone.c +++ b/iphone.c @@ -449,9 +449,11 @@ int send_to_phone(iphone_device_t phone, char *data, int datalen) int bytes = 0; #ifdef DEBUG + #ifdef DEBUG_MORE printf("===============================\n%s: trying to send\n", __func__); print_buffer(data, datalen); printf("===============================\n"); + #endif #endif do { if (retrycount > 3) { @@ -980,6 +982,7 @@ uint32 append_receive_buffer(iphone_umux_client_t client, char* packet) // ensure there is enough space, either by first malloc or realloc if (datalen > 0) { + fprintf(stderr, "%s: putting %d bytes into client's recv_buffer\n", __func__, datalen); if (client->r_len == 0) dobroadcast = 1; if (client->recv_buffer == NULL) { @@ -1077,6 +1080,7 @@ void iphone_mux_pullbulk(iphone_device_t phone) // to construct a full packet, including its data uint32 packetlen = ntohl(header->length); if (usbReceive.leftover < packetlen) { + printf("%s: not enough data to construct a full packet\n", __func__); break; } @@ -1087,6 +1091,7 @@ void iphone_mux_pullbulk(iphone_device_t phone) } else { // stuff the data + fprintf(stderr, "%s: found client, calling append_receive_buffer\n", __func__); append_receive_buffer(client, cursor); } @@ -1104,6 +1109,7 @@ void iphone_mux_pullbulk(iphone_device_t phone) // if there are no leftovers, we just leave the datastructure as is, // and re-use the block next time. if (usbReceive.leftover > 0 && cursor != usbReceive.buffer) { + fprintf(stderr, "%s: we got a leftover, so handle it\n", __func__); char* newbuff = malloc(DEFAULT_CAPACITY); memcpy(newbuff, cursor, usbReceive.leftover); free(usbReceive.buffer); diff --git a/main.c b/main.c index ec9b007..8fa2b81 100644 --- a/main.c +++ b/main.c @@ -74,6 +74,7 @@ struct client_data { static struct device_use_info **device_use_list = NULL; static int device_use_count = 0; static pthread_mutex_t usbmux_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t usb_mutex = PTHREAD_MUTEX_INITIALIZER; #ifdef DEBUG /** @@ -167,6 +168,7 @@ static int usbmuxd_get_request(int fd, void **data, size_t len) 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; @@ -176,7 +178,9 @@ static int usbmuxd_send_result(int fd, uint32_t tag, uint32_t result_code) fprintf(stderr, "%s: tag=%d result=%d\n", __func__, res.header.tag, res.result); - return send_buf(fd, &res, sizeof(res)); + ret = send_buf(fd, &res, sizeof(res)); + fsync(fd); // let's get it sent + return ret; } /** @@ -278,7 +282,7 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) } } else { result = 0; - err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, DEFAULT_TIMEOUT); + err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, 1000); if (err != 0) { fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err); usbmuxd_send_result(cdata->socket, cdata->tag, -err); @@ -505,11 +509,17 @@ static void *usbmuxd_client_init_thread(void *arg) goto leave; } + pthread_mutex_lock(&usb_mutex); + fprintf(stderr, "%s: usb init\n", __func__); // gather data about all iPhones/iPods attached usb_init(); + fprintf(stderr, "%s: usb find busses\n", __func__); usb_find_busses(); + fprintf(stderr, "%s: usb find devices\n", __func__); usb_find_devices(); + fprintf(stderr, "%s: Looking for attached devices...\n", __func__); + for (bus = usb_get_busses(); bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { if (dev->descriptor.idVendor == 0x05ac @@ -548,13 +558,16 @@ static void *usbmuxd_client_init_thread(void *arg) } } } + pthread_mutex_unlock(&usb_mutex); - // now wait for connect request if (found <= 0) { fprintf(stderr, "%s: No attached iPhone/iPod devices found.\n", __func__); goto leave; } + fprintf(stderr, "%s: Waiting for connect request\n", __func__); + + // 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) { fprintf(stderr, "%s: Did not receive any connect request.\n", __func__); @@ -590,12 +603,19 @@ connect: } if (!phone) { // if not found, make a new connection + fprintf(stderr, "%s: creating new usb connection, device_id=%d\n", __func__, c_req->device_id); + + pthread_mutex_lock(&usb_mutex); if (iphone_get_specific_device(0, c_req->device_id, &phone) != IPHONE_E_SUCCESS) { + pthread_mutex_unlock(&usb_mutex); fprintf(stderr, "%s: device_id %d could not be opened\n", __func__, c_req->device_id); usbmuxd_send_result(cdata->socket, c_req->header.tag, ENODEV); goto leave; } + pthread_mutex_unlock(&usb_mutex); + // add to device list + fprintf(stderr, "%s: add to device list\n", __func__); cur_dev = (struct device_use_info*)malloc(sizeof(struct device_use_info)); memset(cur_dev, 0, sizeof(struct device_use_info)); cur_dev->use_count = 1; @@ -615,7 +635,7 @@ connect: } pthread_mutex_unlock(&usbmux_mutex); } else { - fprintf(stderr, "%s: reusing usb connection device_id %d\n", __func__, c_req->device_id); + fprintf(stderr, "%s: reusing usb connection, device_id=%d\n", __func__, c_req->device_id); } // setup connection to iPhone/iPod @@ -697,7 +717,9 @@ leave: cur_dev->use_count = 0; pthread_mutex_unlock(&cur_dev->mutex); pthread_join(cur_dev->bulk_reader, NULL); + pthread_mutex_lock(&usb_mutex); iphone_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); -- cgit v1.1-32-gdbae From d7122e75ef6f28764630714d4720f98b9050d5ef Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 11 Mar 2009 03:03:25 +0100 Subject: bug fix for connect_socket function --- sock_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sock_stuff.c b/sock_stuff.c index 3d11a27..cdc39d1 100644 --- a/sock_stuff.c +++ b/sock_stuff.c @@ -173,7 +173,7 @@ int connect_socket(const char *addr, uint16_t port) memset((void *)&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr = (uint32_t)hp->h_addr; + saddr.sin_addr.s_addr = *(uint32_t*)hp->h_addr; saddr.sin_port = htons(port); if (connect(sfd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) { -- cgit v1.1-32-gdbae From 53efe85b04af43a08acda8ce58b39800d027a597 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 11 Mar 2009 15:42:26 +0100 Subject: debug message refined --- sock_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sock_stuff.c b/sock_stuff.c index cdc39d1..796a0f9 100644 --- a/sock_stuff.c +++ b/sock_stuff.c @@ -264,7 +264,7 @@ int recv_buf_timeout(int fd, void *data, size_t length, int flags, unsigned int result = recv(fd, data, length, flags); if (res > 0 && result == 0) { // but this is an error condition - fprintf(stderr, "%s: fd=%d\n", __func__, fd); + fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd); return -1; } return result; -- cgit v1.1-32-gdbae From 5868567ca219c6dedd48462c44b21be78c3587e3 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 12 Mar 2009 03:25:18 +0100 Subject: changed the usbReceive buffer to a per-device buffer instead of one global buffer for all devices (untested but should work). --- iphone.c | 72 +++++++++++++++++++++++++++++++++++++--------------------------- main.c | 3 ++- 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/iphone.c b/iphone.c index 0a2b6cc..f4c747e 100644 --- a/iphone.c +++ b/iphone.c @@ -53,11 +53,17 @@ static const uint8 TCP_URG = 1 << 5; static const uint32 WINDOW_MAX = 5 * 1024; static const uint32 WINDOW_INCREMENT = 512; +typedef struct { + char* buffer; + int leftover; + int capacity; +} receivebuf_t; struct iphone_device_int { char *buffer; struct usb_dev_handle *device; struct usb_device *__device; + receivebuf_t usbReceive; }; typedef struct { @@ -100,17 +106,10 @@ struct iphone_umux_client_int { }; -typedef struct { - char* buffer; - int leftover; - int capacity; -} receivebuf_t; - - static pthread_mutex_t iphonemutex = PTHREAD_MUTEX_INITIALIZER; static iphone_umux_client_t *connlist = NULL; static int clients = 0; -static receivebuf_t usbReceive = {NULL, 0, 0}; +//static receivebuf_t usbReceive = {NULL, 0, 0}; /** @@ -275,7 +274,7 @@ static iphone_error_t iphone_config_usb_device(iphone_device_t phone) */ iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_device_t * device) { - struct usb_bus *bus, *busses; + struct usb_bus *bus; struct usb_device *dev; usbmux_version_header *version; int bytes = 0; @@ -295,10 +294,9 @@ iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_device_t usb_init(); usb_find_busses(); usb_find_devices(); - busses = usb_get_busses(); // Set the device configuration - for (bus = busses; bus; bus = bus->next) + for (bus = usb_get_busses(); bus; bus = bus->next) if (bus->location == bus_n) for (dev = bus->devices; dev != NULL; dev = dev->next) if (dev->devnum == dev_n) { @@ -417,6 +415,9 @@ iphone_error_t iphone_free_device(iphone_device_t device) if (device->buffer) { free(device->buffer); } + if (device->usbReceive.buffer) { + free(device->usbReceive.buffer); + } if (device->device) { usb_release_interface(device->device, 1); usb_close(device->device); @@ -586,10 +587,13 @@ usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port) */ static void delete_connection(iphone_umux_client_t connection) { + iphone_umux_client_t *newlist = NULL; + pthread_mutex_lock(&iphonemutex); // update the global list of connections - iphone_umux_client_t *newlist = (iphone_umux_client_t *) malloc(sizeof(iphone_umux_client_t) * (clients - 1)); + if (clients > 1) { + newlist = (iphone_umux_client_t *) malloc(sizeof(iphone_umux_client_t) * (clients - 1)); int i = 0, j = 0; for (i = 0; i < clients; i++) { if (connlist[i] == connection) @@ -599,9 +603,12 @@ static void delete_connection(iphone_umux_client_t connection) j++; } } + } + if (connlist) { free(connlist); - connlist = newlist; - clients--; + } + connlist = newlist; + clients--; // free up this connection pthread_mutex_lock(&connection->mutex); @@ -1043,17 +1050,22 @@ iphone_umux_client_t find_client(usbmux_tcp_header* recv_header) */ void iphone_mux_pullbulk(iphone_device_t phone) { + if (!phone) { + fprintf(stderr, "iphone_mux_pullbulk: invalid argument\n"); + return; + } + static const int DEFAULT_CAPACITY = 128*1024; - if (usbReceive.buffer == NULL) { - usbReceive.capacity = DEFAULT_CAPACITY; - usbReceive.buffer = malloc(usbReceive.capacity); - usbReceive.leftover = 0; + if (phone->usbReceive.buffer == NULL) { + phone->usbReceive.capacity = DEFAULT_CAPACITY; + phone->usbReceive.buffer = malloc(phone->usbReceive.capacity); + phone->usbReceive.leftover = 0; } // start the cursor off just ahead of the leftover. - char* cursor = &usbReceive.buffer[usbReceive.leftover]; + char* cursor = &phone->usbReceive.buffer[phone->usbReceive.leftover]; // pull in content, note that the amount we can pull is capacity minus leftover - int readlen = recv_from_phone_timeout(phone, cursor, usbReceive.capacity - usbReceive.leftover, 5000); + int readlen = recv_from_phone_timeout(phone, cursor, phone->usbReceive.capacity - phone->usbReceive.leftover, 5000); if (readlen < 0) { //fprintf(stderr, "recv_from_phone_timeout gave us an error.\n"); readlen = 0; @@ -1064,14 +1076,14 @@ void iphone_mux_pullbulk(iphone_device_t phone) // the amount of content we have to work with is the remainder plus // what we managed to read - usbReceive.leftover += readlen; + phone->usbReceive.leftover += readlen; // reset the cursor to the front of that buffer and work through // trying to decode packets out of them. - cursor = usbReceive.buffer; + cursor = phone->usbReceive.buffer; while (1) { // check if there's even sufficient data to decode a header - if (usbReceive.leftover < HEADERLEN) break; + if (phone->usbReceive.leftover < HEADERLEN) break; usbmux_tcp_header *header = (usbmux_tcp_header *) cursor; printf("%s: recv_from_phone_timeout (%d --> %d)\n", __func__, ntohs(header->sport), ntohs(header->dport)); @@ -1079,7 +1091,7 @@ void iphone_mux_pullbulk(iphone_device_t phone) // now that we have a header, check if there is sufficient data // to construct a full packet, including its data uint32 packetlen = ntohl(header->length); - if (usbReceive.leftover < packetlen) { + if (phone->usbReceive.leftover < packetlen) { printf("%s: not enough data to construct a full packet\n", __func__); break; } @@ -1097,7 +1109,7 @@ void iphone_mux_pullbulk(iphone_device_t phone) // move the cursor and account for the consumption cursor += packetlen; - usbReceive.leftover -= packetlen; + phone->usbReceive.leftover -= packetlen; } // now, we need to manage any leftovers. @@ -1108,13 +1120,13 @@ void iphone_mux_pullbulk(iphone_device_t phone) // // if there are no leftovers, we just leave the datastructure as is, // and re-use the block next time. - if (usbReceive.leftover > 0 && cursor != usbReceive.buffer) { + if (phone->usbReceive.leftover > 0 && cursor != phone->usbReceive.buffer) { fprintf(stderr, "%s: we got a leftover, so handle it\n", __func__); char* newbuff = malloc(DEFAULT_CAPACITY); - memcpy(newbuff, cursor, usbReceive.leftover); - free(usbReceive.buffer); - usbReceive.buffer = newbuff; - usbReceive.capacity = DEFAULT_CAPACITY; + memcpy(newbuff, cursor, phone->usbReceive.leftover); + free(phone->usbReceive.buffer); + phone->usbReceive.buffer = newbuff; + phone->usbReceive.capacity = DEFAULT_CAPACITY; } } diff --git a/main.c b/main.c index 8fa2b81..8009ae2 100644 --- a/main.c +++ b/main.c @@ -510,8 +510,9 @@ static void *usbmuxd_client_init_thread(void *arg) } pthread_mutex_lock(&usb_mutex); - fprintf(stderr, "%s: usb init\n", __func__); // gather data about all iPhones/iPods attached + + fprintf(stderr, "%s: usb init\n", __func__); usb_init(); fprintf(stderr, "%s: usb find busses\n", __func__); usb_find_busses(); -- cgit v1.1-32-gdbae From e619bed09a001f074858fe084dc93d60924beca0 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 12 Mar 2009 12:26:57 +0100 Subject: initialization was missing and causing strange segmentation faults. --- iphone.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iphone.c b/iphone.c index f4c747e..3dccf71 100644 --- a/iphone.c +++ b/iphone.c @@ -290,6 +290,11 @@ iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_device_t phone->__device = NULL; phone->buffer = NULL; + // don't forget these: + phone->usbReceive.buffer = NULL; + phone->usbReceive.leftover = 0; + phone->usbReceive.capacity = 0; + // Initialize libusb usb_init(); usb_find_busses(); -- cgit v1.1-32-gdbae From 2c3c90055ba597ee9df271403de0dcdd620244f7 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 15 Mar 2009 03:09:34 +0100 Subject: increased buffer size in client handler and added missing variable initialization. --- main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index 8009ae2..9e487fe 100644 --- a/main.c +++ b/main.c @@ -326,7 +326,7 @@ static void *usbmuxd_client_handler_thread(void *arg) struct client_data *cdata; int result; char *cursor; - char buffer[1024]; + char buffer[65536]; ssize_t len; ssize_t maxlen = sizeof(buffer); uint32_t wlen; @@ -474,7 +474,7 @@ static void *usbmuxd_client_init_thread(void *arg) // int sent_result; // iphone_error_t err; - iphone_device_t phone; + iphone_device_t phone = NULL; struct device_use_info *cur_dev = NULL; if (!arg) { -- cgit v1.1-32-gdbae From 87957c6f9476655fee8512e46021b21db45c4018 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 19 Mar 2009 03:15:31 +0100 Subject: forgot setting device_use_count variable in cleanup code --- main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.c b/main.c index 9e487fe..f08a196 100644 --- a/main.c +++ b/main.c @@ -738,9 +738,11 @@ leave: } free(device_use_list); device_use_list = newlist; + device_use_count--; } else { free(device_use_list); device_use_list = NULL; + device_use_count = 0; } pthread_mutex_unlock(&usbmux_mutex); } -- cgit v1.1-32-gdbae From 659110808d9ceef21593baca51b2b11ae92b43a3 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 23 Mar 2009 19:00:52 +0100 Subject: changed timeout in handleConnectRequest renamed hello request to scan request --- main.c | 24 ++++++++++++------------ usbmuxd.h | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/main.c b/main.c index f08a196..76f5c20 100644 --- a/main.c +++ b/main.c @@ -282,7 +282,7 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) } } else { result = 0; - err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, 1000); + err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, 100); if (err != 0) { fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err); usbmuxd_send_result(cdata->socket, cdata->tag, -err); @@ -460,7 +460,7 @@ static void *usbmuxd_bulk_reader_thread(void *arg) static void *usbmuxd_client_init_thread(void *arg) { struct client_data *cdata; - struct usbmuxd_hello *hello = NULL; + struct usbmuxd_scan_request *s_req = NULL; struct usbmuxd_device_info_request dev_info_req; struct usbmuxd_connect_request *c_req = NULL; @@ -487,25 +487,25 @@ static void *usbmuxd_client_init_thread(void *arg) fprintf(stderr, "%s: started (fd=%d)\n", __func__, cdata->socket); - if ((recv_len = usbmuxd_get_request(cdata->socket, (void**)&hello, 0)) <= 0) { + if ((recv_len = usbmuxd_get_request(cdata->socket, (void**)&s_req, 0)) <= 0) { fprintf(stderr, "%s: No Hello packet received, error %s\n", __func__, strerror(errno)); goto leave; } - if ((recv_len == sizeof(struct usbmuxd_hello)) && (hello->header.length == sizeof(struct usbmuxd_hello)) - && (hello->header.reserved == 0) && (hello->header.type == USBMUXD_HELLO)) { + 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 fprintf(stderr, "%s: Got Hello packet!\n", __func__); - usbmuxd_send_result(cdata->socket, hello->header.tag, 0); - } else if ((recv_len == sizeof(struct usbmuxd_connect_request)) && (hello->header.type == USBMUXD_CONNECT)) { - c_req = (struct usbmuxd_connect_request*)hello; - hello = NULL; + 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 fprintf(stderr, "%s: Invalid Hello packet received.\n", __func__); // TODO is this required?! - usbmuxd_send_result(cdata->socket, hello->header.tag, EINVAL); + usbmuxd_send_result(cdata->socket, s_req->header.tag, EINVAL); goto leave; } @@ -698,8 +698,8 @@ connect: leave: fprintf(stderr, "%s: terminating\n", __func__); - if (hello) { - free(hello); + if (s_req) { + free(s_req); } if (c_req) { free(c_req); diff --git a/usbmuxd.h b/usbmuxd.h index d749baf..a79df37 100644 --- a/usbmuxd.h +++ b/usbmuxd.h @@ -36,14 +36,14 @@ struct usbmuxd_device_info_request { char padding[222]; } __attribute__((__packed__)); -struct usbmuxd_hello { +struct usbmuxd_scan_request { struct usbmuxd_header header; } __attribute__((__packed__)); enum { USBMUXD_RESULT = 1, USBMUXD_CONNECT = 2, - USBMUXD_HELLO = 3, + USBMUXD_SCAN = 3, USBMUXD_DEVICE_INFO = 4, }; -- cgit v1.1-32-gdbae From a9d3cca2b5a5f3f4ff66ffa08795d102a3e72183 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 26 Mar 2009 12:28:05 +0100 Subject: adopted for "hello" -> "scan" rename --- iproxy.c | 127 ++++++++--------------------------------------------------- testclient.c | 32 +++++++-------- 2 files changed, 32 insertions(+), 127 deletions(-) diff --git a/iproxy.c b/iproxy.c index 775b819..93bbf89 100644 --- a/iproxy.c +++ b/iproxy.c @@ -179,12 +179,12 @@ void *acceptor_thread(void *arg) { struct client_data *cdata; int recv_len = 0; - int hello_done; + int scan_done; int connected; uint32_t pktlen; unsigned char *buf; - struct usbmuxd_hello hello; - struct usbmuxd_device_info device_info; + struct usbmuxd_scan_request scan; + struct am_device_info device_info; pthread_t ctos; if (!arg) { @@ -200,24 +200,24 @@ void *acceptor_thread(void *arg) return NULL; } - // send hello - hello.header.length = sizeof(struct usbmuxd_hello); - hello.header.reserved = 0; - hello.header.type = USBMUXD_HELLO; - hello.header.tag = 2; + // send scan + scan.header.length = sizeof(struct usbmuxd_scan_request); + scan.header.reserved = 0; + scan.header.type = USBMUXD_SCAN; + scan.header.tag = 2; - hello_done = 0; + scan_done = 0; connected = 0; - fprintf(stdout, "sending Hello packet\n"); - if (send(cdata->sfd, &hello, hello.header.length, 0) == hello.header.length) { + fprintf(stdout, "sending scan packet\n"); + if (send(cdata->sfd, &scan, scan.header.length, 0) == scan.header.length) { uint32_t res = -1; // get response - if (usbmuxd_get_result(cdata->sfd, hello.header.tag, &res) && (res==0)) { - fprintf(stdout, "Got Hello Response!\n"); - hello_done = 1; + if (usbmuxd_get_result(cdata->sfd, scan.header.tag, &res) && (res==0)) { + fprintf(stdout, "Got response to scan request!\n"); + scan_done = 1; } else { - fprintf(stderr, "Did not get Hello response (with result=0)...\n"); + fprintf(stderr, "Did not get response to scan request (with result=0)...\n"); close(cdata->sfd); cdata->sfd = -1; return NULL; @@ -225,7 +225,7 @@ void *acceptor_thread(void *arg) device_info.device_id = 0; - if (hello_done) { + if (scan_done) { // get all devices while (1) { if (recv_buf_timeout(cdata->sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) { @@ -343,100 +343,5 @@ int main(int argc, char **argv) close(mysock); } -/* - sfd = connect_unix_socket(USBMUXD_SOCKET_FILE); - if (sfd < 0) { - printf("error opening socket, terminating.\n"); - return -1; - } - - // send hello - hello.header.length = sizeof(hello); - hello.header.reserved = 0; - hello.header.type = USBMUXD_HELLO; - hello.header.tag = 2; - - hello_done = 0; - connected = 0; - - fprintf(stdout, "sending Hello packet\n"); - if (send(sfd, &hello, hello.header.length, 0) == hello.header.length) { - uint32_t res = -1; - // get response - if (usbmuxd_get_result(sfd, hello.header.tag, &res) && (res==0)) { - fprintf(stdout, "Got Hello Response!\n"); - hello_done = 1; - } else { - fprintf(stderr, "Did not get Hello response (with result=0)...\n"); - close(sfd); - return -1; - } - - device_info.device_id = 0; - - if (hello_done) { - // get all devices - while (1) { - if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) { - buf = (unsigned char*)malloc(pktlen); - if (!buf) { - exit(-ENOMEM); - } - recv_len = recv_buf(sfd, buf, pktlen); - if (recv_len < pktlen) { - fprintf(stdout, "received less data than specified in header!\n"); - } - fprintf(stdout, "Received device data\n"); - //log_debug_buffer(stdout, (char*)buf, pktlen); - memcpy(&device_info, buf + sizeof(struct usbmuxd_header), sizeof(device_info)); - free(buf); - } else { - // we _should_ have all of them now. - // or perhaps an error occured. - break; - } - } - } - - if (device_info.device_id > 0) { - struct usbmuxd_connect_request c_req; - - fprintf(stdout, "Requesting connecion to device %d port %d\n", device_info.device_id, device_port); - - // try to connect to last device found - 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 = device_info.device_id; - c_req.tcp_dport = htons(device_port); - c_req.reserved = 0; - - if (send_buf(sfd, &c_req, sizeof(c_req)) < 0) { - perror("send"); - } else { - // read ACK - res = -1; - fprintf(stdout, "Reading connect result...\n"); - if (usbmuxd_get_result(sfd, c_req.header.tag, &res)) { - if (res == 0) { - fprintf(stdout, "Connect success!\n"); - connected = 1; - } else { - fprintf(stderr, "Connect failed, Error code=%d\n", res); - } - } - } - } - - if (connected) { - // - } else { - fprintf(stderr, "No attached device found?!\n"); - } - } - close(sfd); -*/ - return 0; } diff --git a/testclient.c b/testclient.c index 679b6d0..dc2dd28 100644 --- a/testclient.c +++ b/testclient.c @@ -44,12 +44,12 @@ int main(int argc, char **argv) { int sfd; int recv_len = 0; - int hello_done; + int scan_done; int connected; uint32_t pktlen; unsigned char *buf; - struct usbmuxd_hello hello; - struct usbmuxd_device_info device_info; + struct usbmuxd_scan_request scan; + struct am_device_info device_info; sfd = connect_unix_socket(USBMUXD_SOCKET_FILE); if (sfd < 0) { @@ -57,31 +57,31 @@ int main(int argc, char **argv) return -1; } - // send hello - hello.header.length = sizeof(struct usbmuxd_hello); - hello.header.reserved = 0; - hello.header.type = USBMUXD_HELLO; - hello.header.tag = 2; + // send scan + scan.header.length = sizeof(struct usbmuxd_scan_request); + scan.header.reserved = 0; + scan.header.type = USBMUXD_SCAN; + scan.header.tag = 2; - hello_done = 0; + scan_done = 0; connected = 0; - fprintf(stdout, "sending Hello packet\n"); - if (send(sfd, &hello, hello.header.length, 0) == hello.header.length) { + fprintf(stdout, "sending scan packet\n"); + if (send(sfd, &scan, scan.header.length, 0) == scan.header.length) { uint32_t res = -1; // get response - if (usbmuxd_get_result(sfd, hello.header.tag, &res) && (res==0)) { - fprintf(stdout, "Got Hello Response!\n"); - hello_done = 1; + if (usbmuxd_get_result(sfd, scan.header.tag, &res) && (res==0)) { + fprintf(stdout, "Got response to scan request!\n"); + scan_done = 1; } else { - fprintf(stderr, "Did not get Hello response (with result=0)...\n"); + fprintf(stderr, "Did not get response to scan request (with result=0)...\n"); close(sfd); return -1; } device_info.device_id = 0; - if (hello_done) { + if (scan_done) { // get all devices while (1) { if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) { -- cgit v1.1-32-gdbae From 0491d931b5a0a35bf7a9af0a84dcfe06611bedf9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 26 Mar 2009 12:29:07 +0100 Subject: adopted for "hello" -> "scan" rename --- usbmuxd.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usbmuxd.h b/usbmuxd.h index a79df37..c768ee9 100644 --- a/usbmuxd.h +++ b/usbmuxd.h @@ -24,7 +24,7 @@ struct usbmuxd_connect_request { uint16_t reserved; // set to zero } __attribute__((__packed__)); -struct usbmuxd_device_info { +struct am_device_info { uint32_t device_id; uint16_t product_id; char serial_number[40]; @@ -32,7 +32,7 @@ struct usbmuxd_device_info { struct usbmuxd_device_info_request { struct usbmuxd_header header; - struct usbmuxd_device_info device_info; + struct am_device_info device_info; char padding[222]; } __attribute__((__packed__)); -- cgit v1.1-32-gdbae From a8d088cf480f306fc5724a7590a59d61d62af382 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 27 Mar 2009 01:31:41 +0100 Subject: Makefile: install target added --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index 3971798..ece8ebb 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ TARGETS=usbmuxd iproxy testclient CFLAGS=-Wall -g -DDEBUG LIBS=-lpthread -lusb -lrt LDFLAGS= +INSTALL_PREFIX=/usr all: $(TARGETS) @@ -28,4 +29,8 @@ clean: realclean: clean rm -f *~ +install: all + cp usbmuxd $(INSTALL_PREFIX)/sbin/ + cp usbmuxd.h $(INSTALL_PREFIX)/include/ + .PHONY: all clean realclean -- cgit v1.1-32-gdbae From 9aec772bf67aa4817f0f5f6f9a262ec1eff4d986 Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Fri, 27 Mar 2009 01:35:26 +0100 Subject: Make all fprintf(stderr) be >= verbose level Signed-off-by: Nikias Bassen --- main.c | 169 +++++++++++++++++++++++++++++++---------------------------- sock_stuff.c | 29 ++++++---- sock_stuff.h | 2 + 3 files changed, 109 insertions(+), 91 deletions(-) diff --git a/main.c b/main.c index 76f5c20..e196b8c 100644 --- a/main.c +++ b/main.c @@ -41,9 +41,11 @@ #define DEFAULT_TIMEOUT 4000 #define DEFAULT_CHILDREN_CAPACITY 10 +#define DEBUG_LEVEL 0 static int quit_flag = 0; static int fsock = -1; +static int verbose = DEBUG_LEVEL; struct device_use_info { uint32_t device_id; @@ -80,22 +82,22 @@ static pthread_mutex_t usb_mutex = PTHREAD_MUTEX_INITIALIZER; /** * for debugging purposes. */ -static void print_buffer(const char *data, const int length) +static void print_buffer(FILE *fp, const char *data, const int length) { int i; int j; unsigned char c; for(i=0; i= 4) fprintf(fp, "%04x: ", i); for (j=0;j<16;j++) { if (i+j >= length) { printf(" "); continue; } - printf("%02hhx ", *(data+i+j)); + if (verbose >= 4) printf("%02hhx ", *(data+i+j)); } - printf(" | "); + if (verbose >= 4) fprintf(fp, " | "); for(j=0;j<16;j++) { if (i+j >= length) break; @@ -104,11 +106,11 @@ static void print_buffer(const char *data, const int length) printf("."); continue; } - printf("%c", c); + if (verbose >= 4) fprintf(fp, "%c", c); } - printf("\n"); + if (verbose >= 4) fprintf(fp, "\n"); } - printf("\n"); + if (verbose >= 4) fprintf(fp, "\n"); } #endif @@ -137,19 +139,19 @@ static int usbmuxd_get_request(int fd, void **data, size_t len) *data = malloc(pktlen); } else if (len < pktlen) { // target buffer is to small to hold this packet! fix it! - fprintf(stderr, "%s: WARNING -- packet (%d) is larger than target buffer (%d)! Truncating.\n", __func__, pktlen, len); + if (verbose >= 2) fprintf(stderr, "%s: WARNING -- packet (%d) is larger than target buffer (%d)! Truncating.\n", __func__, pktlen, len); pktlen = len; } recv_len = recv_buf(fd, *data, pktlen); if ((recv_len > 0) && (recv_len < pktlen)) { - fprintf(stderr, "%s: Uh-oh, we got less than the packet's size, %d instead of %d...\n", __func__, recv_len, pktlen); + if (verbose >= 2) fprintf(stderr, "%s: Uh-oh, we got less than the packet's size, %d instead of %d...\n", __func__, recv_len, pktlen); } #ifdef DEBUG - if (*data && (recv_len > 0)) { - fprintf(stderr, "%s: received:\n", __func__); - print_buffer(*data,recv_len); + if (*data && (recv_len > 0) && verbose >= 4) { + if (verbose >= 3) fprintf(stderr, "%s: received:\n", __func__); + print_buffer(stderr, *data, recv_len); } #endif @@ -176,7 +178,7 @@ static int usbmuxd_send_result(int fd, uint32_t tag, uint32_t result_code) res.header.tag = tag; res.result = result_code; - fprintf(stderr, "%s: tag=%d result=%d\n", __func__, res.header.tag, res.result); + if (verbose >= 4) fprintf(stderr, "%s: tag=%d result=%d\n", __func__, res.header.tag, res.result); ret = send_buf(fd, &res, sizeof(res)); fsync(fd); // let's get it sent @@ -204,7 +206,7 @@ static void *usbmuxd_client_reader_thread(void *arg) int result; if (!arg) { - fprintf(stderr, "%s: invalid client_data supplied!\n", __func__); + if (verbose >= 2) fprintf(stderr, "%s: invalid client_data supplied!\n", __func__); cdata->reader_dead = 1; return NULL; } @@ -213,13 +215,13 @@ static void *usbmuxd_client_reader_thread(void *arg) cdata->reader_dead = 0; - fprintf(stderr, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); while (!quit_flag && !cdata->reader_quit) { result = check_fd(cdata->socket, FD_WRITE, DEFAULT_TIMEOUT); if (result <= 0) { if (result < 0) { - fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno)); + if (verbose >= 2) fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno)); } continue; } @@ -227,7 +229,7 @@ static void *usbmuxd_client_reader_thread(void *arg) rlen = 0; err = iphone_mux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, &rlen, DEFAULT_TIMEOUT); if (err != 0) { - fprintf(stderr, "%s[%d:%d]: encountered USB read error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); + if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: encountered USB read error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); break; } @@ -242,7 +244,7 @@ static void *usbmuxd_client_reader_thread(void *arg) fsync(cdata->socket); } - fprintf(stderr, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); cdata->reader_dead = 1; @@ -270,21 +272,21 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) iphone_error_t err; if (!cdata) { - fprintf(stderr, "%s: Invalid client_data provided!\n", __func__); + if (verbose >= 2) fprintf(stderr, "%s: Invalid client_data provided!\n", __func__); return -EINVAL; } result = check_fd(cdata->socket, FD_WRITE, DEFAULT_TIMEOUT); if (result <= 0) { if (result < 0) { - fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno)); + if (verbose >= 2) fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno)); return result; } } else { result = 0; err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, 100); if (err != 0) { - fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err); + if (verbose >= 2) fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err); usbmuxd_send_result(cdata->socket, cdata->tag, -err); return err; } else { @@ -292,7 +294,7 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) if ((buffer[0] == 1) && (rlen > 20) && !memcmp(buffer+1, "handleConnectResult:", 20)) { // hm... we got an error message! buffer[rlen] = 0; - fprintf(stderr, "%s: %s\n", __func__, buffer+22); + if (verbose >= 1) fprintf(stderr, "%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); @@ -333,25 +335,26 @@ static void *usbmuxd_client_handler_thread(void *arg) iphone_error_t err; if (!arg) { - fprintf(stderr, "%s: invalid client_data provided!\n", __func__); + if (verbose >= 3) fprintf(stderr, "%s: invalid client_data provided!\n", __func__); return NULL; } cdata = (struct client_data*)arg; - fprintf(stderr, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id,cdata->duinfo->use_count); + if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id,cdata->duinfo->use_count); if (usbmuxd_handleConnectResult(cdata)) { - fprintf(stderr, "handleConnectResult: Error\n"); + if (verbose >= 3) fprintf(stderr, "handleConnectResult: Error\n"); goto leave; + } else { + if (verbose >= 3) fprintf(stderr, "handleConnectResult: Success\n"); } - fprintf(stderr, "handleConnectResult: Success\n"); // starting mux reader thread cdata->reader_quit = 0; cdata->reader_dead = 0; if (pthread_create(&cdata->reader, NULL, usbmuxd_client_reader_thread, cdata) != 0) { - fprintf(stderr, "%s: could not start client_reader thread\n", __func__); + if (verbose >= 2) fprintf(stderr, "%s: could not start client_reader thread\n", __func__); cdata->reader = 0; } @@ -359,7 +362,7 @@ static void *usbmuxd_client_handler_thread(void *arg) result = check_fd(cdata->socket, FD_READ, DEFAULT_TIMEOUT); if (result <= 0) { if (result < 0) { - fprintf(stderr, "%s: Error: checkfd: %s\n", __func__, strerror(errno)); + if (verbose >= 3) fprintf(stderr, "%s: Error: checkfd: %s\n", __func__, strerror(errno)); } continue; } @@ -371,7 +374,7 @@ static void *usbmuxd_client_handler_thread(void *arg) break; } if (len < 0) { - fprintf(stderr, "%s[%d:%d]: Error: recv: %s\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, strerror(errno)); + if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: Error: recv: %s\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, strerror(errno)); break; } @@ -384,7 +387,7 @@ static void *usbmuxd_client_handler_thread(void *arg) if (err == IPHONE_E_TIMEOUT) { // some kind of timeout... just be patient and retry. } else if (err != IPHONE_E_SUCCESS) { - fprintf(stderr, "%s[%d:%d]: USB write error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); + if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: USB write error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); len = -1; break; } @@ -402,7 +405,7 @@ static void *usbmuxd_client_handler_thread(void *arg) leave: // cleanup - fprintf(stderr, "%s[%d:%d]: terminating\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + if (verbose >= 3) fprintf(stderr, "%s[%d:%d]: terminating\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); if (cdata->reader != 0) { cdata->reader_quit = 1; pthread_join(cdata->reader, NULL); @@ -410,7 +413,7 @@ leave: cdata->handler_dead = 1; - fprintf(stderr, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + if (verbose >= 3) fprintf(stderr, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); return NULL; } @@ -423,13 +426,13 @@ static void *usbmuxd_bulk_reader_thread(void *arg) struct device_use_info *cur_dev; if (!arg) { - fprintf(stderr, "%s: Invalid client_data provided\n", __func__); + if (verbose >= 3) fprintf(stderr, "%s: Invalid client_data provided\n", __func__); return NULL; } cur_dev = (struct device_use_info*)arg; - printf("%s: started\n", __func__); + if (verbose >= 5) fprintf(stderr, "%s: started\n", __func__); while (!quit_flag && cur_dev) { @@ -447,7 +450,7 @@ static void *usbmuxd_bulk_reader_thread(void *arg) //} } - printf("%s: terminated\n", __func__); + if (verbose >= 5) fprintf(stderr, "%s: terminated\n", __func__); return NULL; } @@ -478,24 +481,24 @@ static void *usbmuxd_client_init_thread(void *arg) struct device_use_info *cur_dev = NULL; if (!arg) { - fprintf(stderr, "%s: invalid client_data provided!\n", __func__); + if (verbose >= 1) fprintf(stderr, "%s: invalid client_data provided!\n", __func__); return NULL; } cdata = (struct client_data*)arg; cdata->dead = 0; - fprintf(stderr, "%s: started (fd=%d)\n", __func__, cdata->socket); + if (verbose >= 2) fprintf(stderr, "%s: started (fd=%d)\n", __func__, cdata->socket); if ((recv_len = usbmuxd_get_request(cdata->socket, (void**)&s_req, 0)) <= 0) { - fprintf(stderr, "%s: No Hello packet received, error %s\n", __func__, strerror(errno)); + if (verbose >= 2) fprintf(stderr, "%s: No Hello packet received, error %s\n", __func__, 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 - fprintf(stderr, "%s: Got Hello packet!\n", __func__); + if (verbose >= 3) fprintf(stderr, "%s: Got Hello packet!\n", __func__); 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; @@ -503,7 +506,7 @@ static void *usbmuxd_client_init_thread(void *arg) goto connect; } else { // send error response and exit - fprintf(stderr, "%s: Invalid Hello packet received.\n", __func__); + if (verbose >= 2) fprintf(stderr, "%s: Invalid Hello packet received.\n", __func__); // TODO is this required?! usbmuxd_send_result(cdata->socket, s_req->header.tag, EINVAL); goto leave; @@ -512,14 +515,14 @@ static void *usbmuxd_client_init_thread(void *arg) pthread_mutex_lock(&usb_mutex); // gather data about all iPhones/iPods attached - fprintf(stderr, "%s: usb init\n", __func__); + if (verbose >= 5) fprintf(stderr, "%s: usb init\n", __func__); usb_init(); - fprintf(stderr, "%s: usb find busses\n", __func__); + if (verbose >= 5) fprintf(stderr, "%s: usb find busses\n", __func__); usb_find_busses(); - fprintf(stderr, "%s: usb find devices\n", __func__); + if (verbose >= 5) fprintf(stderr, "%s: usb find devices\n", __func__); usb_find_devices(); - fprintf(stderr, "%s: Looking for attached devices...\n", __func__); + if (verbose >= 2) fprintf(stderr, "%s: Looking for attached devices...\n", __func__); for (bus = usb_get_busses(); bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { @@ -527,7 +530,7 @@ static void *usbmuxd_client_init_thread(void *arg) && dev->descriptor.idProduct >= 0x1290 && dev->descriptor.idProduct <= 0x1293) { - fprintf(stderr, "%s: Found device on bus %d, id %d\n", __func__, bus->location, dev->devnum); + if (verbose >= 1) fprintf(stderr, "%s: Found device on bus %d, id %d\n", __func__, bus->location, dev->devnum); found++; // construct packet @@ -548,12 +551,12 @@ static void *usbmuxd_client_init_thread(void *arg) } #ifdef DEBUG - print_buffer((char*)&dev_info_req, sizeof(dev_info_req)); + if (verbose >= 4) print_buffer(stderr, (char*)&dev_info_req, sizeof(dev_info_req)); #endif // send it if (send_buf(cdata->socket, &dev_info_req, sizeof(dev_info_req)) <= 0) { - fprintf(stderr, "%s: Error: Could not send device info: %s\n", __func__, strerror(errno)); + if (verbose >= 3) fprintf(stderr, "%s: Error: Could not send device info: %s\n", __func__, strerror(errno)); found--; } } @@ -562,27 +565,27 @@ static void *usbmuxd_client_init_thread(void *arg) pthread_mutex_unlock(&usb_mutex); if (found <= 0) { - fprintf(stderr, "%s: No attached iPhone/iPod devices found.\n", __func__); + if (verbose >= 1) fprintf(stderr, "%s: No attached iPhone/iPod devices found.\n", __func__); goto leave; } - fprintf(stderr, "%s: Waiting for connect request\n", __func__); + if (verbose >= 2) fprintf(stderr, "%s: Waiting for connect request\n", __func__); // 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) { - fprintf(stderr, "%s: Did not receive any connect request.\n", __func__); + if (verbose >= 3) fprintf(stderr, "%s: Did not receive any connect request.\n", __func__); goto leave; } connect: if (c_req->header.type != USBMUXD_CONNECT) { - fprintf(stderr, "%s: Unexpected packet of type %d received.\n", __func__, c_req->header.type); + if (verbose >= 2) fprintf(stderr, "%s: Unexpected packet of type %d received.\n", __func__, c_req->header.type); goto leave; } - fprintf(stderr, "%s: Setting up connection to usb device #%d on port %d\n", __func__, c_req->device_id, ntohs(c_req->tcp_dport)); + if (verbose >= 3) fprintf(stderr, "%s: Setting up connection to usb device #%d on port %d\n", __func__, c_req->device_id, ntohs(c_req->tcp_dport)); // find the device, and open usb connection phone = NULL; @@ -604,19 +607,19 @@ connect: } if (!phone) { // if not found, make a new connection - fprintf(stderr, "%s: creating new usb connection, device_id=%d\n", __func__, c_req->device_id); + if (verbose >= 2) fprintf(stderr, "%s: creating new usb connection, device_id=%d\n", __func__, c_req->device_id); pthread_mutex_lock(&usb_mutex); if (iphone_get_specific_device(0, c_req->device_id, &phone) != IPHONE_E_SUCCESS) { pthread_mutex_unlock(&usb_mutex); - fprintf(stderr, "%s: device_id %d could not be opened\n", __func__, c_req->device_id); + if (verbose >= 1) fprintf(stderr, "%s: device_id %d could not be opened\n", __func__, c_req->device_id); usbmuxd_send_result(cdata->socket, c_req->header.tag, ENODEV); goto leave; } pthread_mutex_unlock(&usb_mutex); // add to device list - fprintf(stderr, "%s: add to device list\n", __func__); + if (verbose >= 3) fprintf(stderr, "%s: add to device list\n", __func__); cur_dev = (struct device_use_info*)malloc(sizeof(struct device_use_info)); memset(cur_dev, 0, sizeof(struct device_use_info)); cur_dev->use_count = 1; @@ -625,7 +628,7 @@ connect: pthread_mutex_init(&cur_dev->mutex, NULL); pthread_mutex_init(&cur_dev->writer_mutex, NULL); - fprintf(stderr, "%s: device_use_count = %d\n", __func__, device_use_count); + if (verbose >= 3) fprintf(stderr, "%s: device_use_count = %d\n", __func__, device_use_count); pthread_create(&cur_dev->bulk_reader, NULL, usbmuxd_bulk_reader_thread, cur_dev); pthread_mutex_lock(&usbmux_mutex); @@ -636,7 +639,7 @@ connect: } pthread_mutex_unlock(&usbmux_mutex); } else { - fprintf(stderr, "%s: reusing usb connection, device_id=%d\n", __func__, c_req->device_id); + if (verbose >= 3) fprintf(stderr, "%s: reusing usb connection, device_id=%d\n", __func__, c_req->device_id); } // setup connection to iPhone/iPod @@ -646,7 +649,7 @@ connect: if (res != 0) { usbmuxd_send_result(cdata->socket, c_req->header.tag, res); - fprintf(stderr, "%s: mux_new_client returned %d, aborting.\n", __func__, res); + if (verbose >= 1) fprintf(stderr, "%s: mux_new_client returned %d, aborting.\n", __func__, res); goto leave; } @@ -655,7 +658,7 @@ connect: cdata->tag = c_req->header.tag; cdata->duinfo = cur_dev; if (pthread_create(&cdata->handler, NULL, usbmuxd_client_handler_thread, cdata) != 0) { - fprintf(stderr, "%s: could not create usbmuxd_client_handler_thread!\n", __func__); + if (verbose >= 3) fprintf(stderr, "%s: could not create usbmuxd_client_handler_thread!\n", __func__); cdata->handler = 0; goto leave; } @@ -688,7 +691,7 @@ connect: pthread_join(cdata->handler, NULL); } - fprintf(stderr, "%s: closing connection\n", __func__); + if (verbose >= 2) fprintf(stderr, "%s: closing connection\n", __func__); // time to clean up if (cdata && cdata->muxclient) { // should be non-NULL @@ -696,7 +699,7 @@ connect: } leave: - fprintf(stderr, "%s: terminating\n", __func__); + if (verbose >= 2) fprintf(stderr, "%s: terminating\n", __func__); if (s_req) { free(s_req); @@ -710,11 +713,11 @@ leave: if (cur_dev) { pthread_mutex_lock(&cur_dev->mutex); if (cur_dev->use_count > 1) { - printf("%s: decreasing device use count\n", __func__); + if (verbose >= 5) fprintf(stderr, "%s: decreasing device use count\n", __func__); cur_dev->use_count--; pthread_mutex_unlock(&cur_dev->mutex); } else { - printf("%s: last client disconnected, cleaning up\n", __func__); + if (verbose >= 3) fprintf(stderr, "%s: last client disconnected, cleaning up\n", __func__); cur_dev->use_count = 0; pthread_mutex_unlock(&cur_dev->mutex); pthread_join(cur_dev->bulk_reader, NULL); @@ -751,7 +754,7 @@ leave: cdata->dead = 1; close(cdata->socket); - fprintf(stderr, "%s: terminated\n", __func__); + if (verbose >= 5) fprintf(stderr, "%s: terminated\n", __func__); return NULL; } @@ -771,7 +774,7 @@ static int daemonize() static void clean_exit(int sig) { if (sig == SIGINT) { - fprintf(stderr, "CTRL+C pressed\n"); + if (verbose >= 1) fprintf(stderr, "CTRL+C pressed\n"); } quit_flag = 1; } @@ -787,17 +790,23 @@ int main(int argc, char **argv) struct client_data *cdata = NULL; struct client_data **children = NULL; int children_capacity = DEFAULT_CHILDREN_CAPACITY; - int i = 0; + int i; int result = 0; int cnt = 0; - fprintf(stderr, "usbmuxd: starting\n"); + for (i = 1; i < argc; i++) { + if (argv[i] != NULL && (!strncmp("-v", argv[i], 2) || !strncmp("--verbose", argv[i], 10))) { + sock_stuff_set_verbose(++verbose); + } + } + + if (verbose >= 2) fprintf(stderr, "usbmuxd: starting\n"); // TODO: Parameter checking. fsock = create_unix_socket(USBMUXD_SOCKET_FILE); if (fsock < 0) { - fprintf(stderr, "Could not create socket, exiting\n"); + if (verbose >= 1) fprintf(stderr, "Could not create socket, exiting\n"); return -1; } @@ -819,12 +828,12 @@ int main(int argc, char **argv) // buffer gets enlarged later. children = (struct client_data**)malloc(sizeof(struct client_data*) * children_capacity); if (!children) { - fprintf(stderr, "usbmuxd: Out of memory when allocating memory for child threads. Terminating.\n"); + if (verbose >= 2) fprintf(stderr, "usbmuxd: Out of memory when allocating memory for child threads. Terminating.\n"); exit(EXIT_FAILURE); } memset(children, 0, sizeof(struct client_data*) * children_capacity); - fprintf(stderr, "usbmuxd: waiting for connection\n"); + if (verbose >= 2) fprintf(stderr, "usbmuxd: waiting for connection\n"); while (!quit_flag) { // Check the file descriptor before accepting a connection. // If no connection attempt is made, just repeat... @@ -836,7 +845,7 @@ int main(int argc, char **argv) if (children[i]) { if (children[i]->dead != 0) { pthread_join(children[i]->thread, NULL); - fprintf(stderr, "usbmuxd: reclaimed client thread (fd=%d)\n", children[i]->socket); + if (verbose >= 3) fprintf(stderr, "usbmuxd: reclaimed client thread (fd=%d)\n", children[i]->socket); free(children[i]); children[i] = NULL; cnt++; @@ -855,7 +864,7 @@ int main(int argc, char **argv) } continue; } else { - fprintf(stderr, "usbmuxd: select error: %s\n", strerror(errno)); + if (verbose >= 3) fprintf(stderr, "usbmuxd: select error: %s\n", strerror(errno)); continue; } } @@ -864,7 +873,7 @@ int main(int argc, char **argv) memset(cdata, 0, sizeof(struct client_data)); if (!cdata) { quit_flag = 1; - fprintf(stderr, "usbmuxd: Error: Out of memory! Terminating.\n"); + if (verbose >= 1) fprintf(stderr, "usbmuxd: Error: Out of memory! Terminating.\n"); break; } @@ -874,12 +883,12 @@ int main(int argc, char **argv) if (errno == EINTR) { continue; } else { - fprintf(stderr, "usbmuxd: Error in accept: %s\n", strerror(errno)); + if (verbose >= 3) fprintf(stderr, "usbmuxd: Error in accept: %s\n", strerror(errno)); continue; } } - fprintf(stderr, "usbmuxd: new client connected (fd=%d)\n", cdata->socket); + if (verbose >= 1) fprintf(stderr, "usbmuxd: new client connected (fd=%d)\n", cdata->socket); // create client thread: if (pthread_create(&cdata->thread, NULL, usbmuxd_client_init_thread, cdata) == 0) { @@ -891,22 +900,22 @@ int main(int argc, char **argv) children_capacity++; children = realloc(children, sizeof(struct client_data*) * children_capacity); if (!children) { - fprintf(stderr, "usbmuxd: Out of memory when enlarging child thread buffer\n"); + if (verbose >= 1) fprintf(stderr, "usbmuxd: Out of memory when enlarging child thread buffer\n"); } } children[i] = cdata; } else { - fprintf(stderr, "usbmuxd: Failed to create client_init_thread.\n"); + if (verbose >= 3) fprintf(stderr, "usbmuxd: Failed to create client_init_thread.\n"); close(cdata->socket); free(cdata); cdata = NULL; } } - fprintf(stderr, "usbmuxd: terminating\n"); + if (verbose >= 3) fprintf(stderr, "usbmuxd: terminating\n"); // preparing for shutdown: wait for child threads to terminate (if any) - fprintf(stderr, "usbmuxd: waiting for child threads to terminate...\n"); + if (verbose >= 2) fprintf(stderr, "usbmuxd: waiting for child threads to terminate...\n"); for (i = 0; i < children_capacity; i++) { if (children[i] != NULL) { pthread_join(children[i]->thread, NULL); @@ -925,7 +934,7 @@ int main(int argc, char **argv) unlink(USBMUXD_SOCKET_FILE); - fprintf(stderr, "usbmuxd: terminated\n"); + if (verbose >= 1) fprintf(stderr, "usbmuxd: terminated\n"); return 0; } diff --git a/sock_stuff.c b/sock_stuff.c index 796a0f9..78249e6 100644 --- a/sock_stuff.c +++ b/sock_stuff.c @@ -13,6 +13,13 @@ #define RECV_TIMEOUT 10000 +static int verbose = 0; + +void sock_stuff_set_verbose(int level) +{ + verbose = level; +} + int create_unix_socket (const char *filename) { struct sockaddr_un name; @@ -68,19 +75,19 @@ int connect_unix_socket(const char *filename) // check if socket file exists... if (stat(filename, &fst) != 0) { - fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename, strerror(errno)); + 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)) { - fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__, filename); + 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) { - fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno)); + if (verbose >= 2) fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno)); return -1; } @@ -94,7 +101,7 @@ int connect_unix_socket(const char *filename) if (connect(sfd, (struct sockaddr*)&name, size) < 0) { close(sfd); - fprintf(stderr, "%s: connect: %s\n", __func__, strerror(errno)); + if (verbose >= 2) fprintf(stderr, "%s: connect: %s\n", __func__, strerror(errno)); return -1; } @@ -151,12 +158,12 @@ int connect_socket(const char *addr, uint16_t port) } if ((hp = gethostbyname(addr)) == NULL) { - fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr); + if (verbose >= 2) fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr); return -1; } if (!hp->h_addr) { - fprintf(stderr, "%s: gethostbyname returned NULL address!\n", __func__); + if (verbose >= 2) fprintf(stderr, "%s: gethostbyname returned NULL address!\n", __func__); return -1; } @@ -193,7 +200,7 @@ int check_fd(int fd, fd_mode fdm, unsigned int timeout) struct timeval to; if (fd <= 0) { - fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd); + if (verbose >= 2) fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd); return -1; } @@ -223,14 +230,14 @@ int check_fd(int fd, fd_mode fdm, unsigned int timeout) switch(errno) { case EINTR: // interrupt signal in select - fprintf(stderr, "%s: EINTR\n", __func__); + if (verbose >= 2) fprintf(stderr, "%s: EINTR\n", __func__); eagain = 1; break; case EAGAIN: - fprintf(stderr, "%s: EAGAIN\n", __func__); + if (verbose >= 2) fprintf(stderr, "%s: EAGAIN\n", __func__); break; default: - fprintf(stderr, "%s: select failed: %s\n", __func__, strerror(errno)); + if (verbose >= 2) fprintf(stderr, "%s: select failed: %s\n", __func__, strerror(errno)); return -1; } } @@ -264,7 +271,7 @@ int recv_buf_timeout(int fd, void *data, size_t length, int flags, unsigned int result = recv(fd, data, length, flags); if (res > 0 && result == 0) { // but this is an error condition - fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd); + if (verbose >= 3) fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd); return -1; } return result; diff --git a/sock_stuff.h b/sock_stuff.h index 9965f4e..b9766ba 100644 --- a/sock_stuff.h +++ b/sock_stuff.h @@ -23,5 +23,7 @@ int recv_buf_timeout(int fd, void *data, size_t size, int flags, unsigned int ti int send_buf(int fd, void *data, size_t size); +void sock_stuff_set_verbose(int level); + #endif /* __SOCK_STUFF_H */ -- cgit v1.1-32-gdbae From 6c427211553ee9f5433fb4314d66b68ffb45bae6 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 27 Mar 2009 01:38:34 +0100 Subject: renamed struct usbmuxd_device_info_request to usbmuxd_device_info_record as it is infact an informational record for the client program and not a request. --- main.c | 18 +++++++++--------- usbmuxd.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/main.c b/main.c index e196b8c..a0b6b74 100644 --- a/main.c +++ b/main.c @@ -464,7 +464,7 @@ static void *usbmuxd_client_init_thread(void *arg) { struct client_data *cdata; struct usbmuxd_scan_request *s_req = NULL; - struct usbmuxd_device_info_request dev_info_req; + struct usbmuxd_device_info_record dev_info_rec; struct usbmuxd_connect_request *c_req = NULL; struct usb_bus *bus; @@ -534,28 +534,28 @@ static void *usbmuxd_client_init_thread(void *arg) found++; // construct packet - memset(&dev_info_req, 0, sizeof(dev_info_req)); - dev_info_req.header.length = sizeof(dev_info_req); - dev_info_req.header.type = USBMUXD_DEVICE_INFO; - dev_info_req.device_info.device_id = dev->devnum; - dev_info_req.device_info.product_id = dev->descriptor.idProduct; + 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; + dev_info_rec.device_info.device_id = dev->devnum; + dev_info_rec.device_info.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_req.device_info.serial_number, sizeof(dev_info_req.device_info.serial_number)+1); + usb_get_string_simple(udev, dev->descriptor.iSerialNumber, dev_info_rec.device_info.serial_number, sizeof(dev_info_rec.device_info.serial_number)+1); usb_close(udev); } //pthread_mutex_unlock(&usbmux_mutex); } #ifdef DEBUG - if (verbose >= 4) print_buffer(stderr, (char*)&dev_info_req, sizeof(dev_info_req)); + if (verbose >= 4) print_buffer(stderr, (char*)&dev_info_rec, sizeof(dev_info_rec)); #endif // send it - if (send_buf(cdata->socket, &dev_info_req, sizeof(dev_info_req)) <= 0) { + if (send_buf(cdata->socket, &dev_info_rec, sizeof(dev_info_rec)) <= 0) { if (verbose >= 3) fprintf(stderr, "%s: Error: Could not send device info: %s\n", __func__, strerror(errno)); found--; } diff --git a/usbmuxd.h b/usbmuxd.h index c768ee9..896bb39 100644 --- a/usbmuxd.h +++ b/usbmuxd.h @@ -30,7 +30,7 @@ struct am_device_info { char serial_number[40]; } __attribute__((__packed__)); -struct usbmuxd_device_info_request { +struct usbmuxd_device_info_record { struct usbmuxd_header header; struct am_device_info device_info; char padding[222]; -- cgit v1.1-32-gdbae From 91d76eb4e449dec0cb23d56886817d9910963559 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 28 Mar 2009 01:28:01 +0100 Subject: Readme.txt renamed to README --- README | 33 +++++++++++++++++++++++++++++++++ Readme.txt | 33 --------------------------------- 2 files changed, 33 insertions(+), 33 deletions(-) create mode 100644 README delete mode 100644 Readme.txt diff --git a/README b/README new file mode 100644 index 0000000..5cb74f9 --- /dev/null +++ b/README @@ -0,0 +1,33 @@ +Build +===== + + make + + +Use +=== + + sudo ./usbmuxd & + ./iproxy 2222 22 & + ssh -p 2222 root@localhost + +Muwahahaha. Hopefully you get the normal SSH login prompt. + + +SSH +=== + +If your iphone is rooted, but isn't running SSH, you will need to +mount it with 'ifuse --afc2' (to access the root directory of the +device). + +And then edit: + + /Library/LaunchDaemons/com.openssh.sshd.plist + +to _remove_ the lines: + + Diabled + + +Reboot the device and then sshd should be running. diff --git a/Readme.txt b/Readme.txt deleted file mode 100644 index 5cb74f9..0000000 --- a/Readme.txt +++ /dev/null @@ -1,33 +0,0 @@ -Build -===== - - make - - -Use -=== - - sudo ./usbmuxd & - ./iproxy 2222 22 & - ssh -p 2222 root@localhost - -Muwahahaha. Hopefully you get the normal SSH login prompt. - - -SSH -=== - -If your iphone is rooted, but isn't running SSH, you will need to -mount it with 'ifuse --afc2' (to access the root directory of the -device). - -And then edit: - - /Library/LaunchDaemons/com.openssh.sshd.plist - -to _remove_ the lines: - - Diabled - - -Reboot the device and then sshd should be running. -- cgit v1.1-32-gdbae From 50fc7586b2abf8a5ce999235c82d9de1bab98bfd Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 28 Mar 2009 01:29:57 +0100 Subject: debugging output fixed 'libusbmuxd' added to simplify use of usbmuxd in external tools testclient removed setting of configuration 3 disabled (to be handled by udev) --- Makefile | 14 +++-- iphone.c | 16 ++++-- iproxy.c | 160 +++++++++---------------------------------------------- libusbmuxd.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ libusbmuxd.h | 27 ++++++++++ main.c | 18 +++---- testclient.c | 146 -------------------------------------------------- usbmuxd.h | 5 +- 8 files changed, 253 insertions(+), 303 deletions(-) create mode 100644 libusbmuxd.c create mode 100644 libusbmuxd.h delete mode 100644 testclient.c diff --git a/Makefile b/Makefile index ece8ebb..55d396d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -TARGETS=usbmuxd iproxy testclient -CFLAGS=-Wall -g -DDEBUG +TARGETS=usbmuxd iproxy +CFLAGS=-I. -Wall -g -DDEBUG LIBS=-lpthread -lusb -lrt LDFLAGS= INSTALL_PREFIX=/usr @@ -7,9 +7,10 @@ INSTALL_PREFIX=/usr all: $(TARGETS) main.o: main.c usbmuxd.h sock_stuff.h iphone.h -iphone.o: iproxy.c iphone.h usbmuxd.h sock_stuff.h +iphone.o: iphone.c iphone.h usbmuxd.h sock_stuff.h sock_stuff.o: sock_stuff.c sock_stuff.h -testclient.o: testclient.c sock_stuff.h +libusbmuxd.o: libusbmuxd.c libusbmuxd.h usbmuxd.h +iproxy.o: iproxy.c sock_stuff.h %.o: %.c $(CC) -o $@ $(CFLAGS) -c $< @@ -17,10 +18,7 @@ testclient.o: testclient.c sock_stuff.h usbmuxd: main.o sock_stuff.o iphone.o $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) -testclient: testclient.o sock_stuff.o - $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) - -iproxy: iproxy.o sock_stuff.o +iproxy: iproxy.o libusbmuxd.o sock_stuff.o $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) clean: diff --git a/iphone.c b/iphone.c index 3dccf71..060bba2 100644 --- a/iphone.c +++ b/iphone.c @@ -114,7 +114,7 @@ static int clients = 0; /** */ -int toto_debug = 0; +int toto_debug = 1; void log_debug_msg(const char *format, ...) { #ifndef STRIP_DEBUG_CODE @@ -124,7 +124,7 @@ void log_debug_msg(const char *format, ...) va_start(args, format); if (toto_debug) - fprintf(stderr, format, args); + vfprintf(stderr, format, args); va_end(args); @@ -215,6 +215,12 @@ static iphone_error_t iphone_config_usb_device(iphone_device_t phone) int bytes; char buf[512]; + log_debug_msg("checking configuration...\n"); + if (phone->__device->config->bConfigurationValue != 3) { + log_debug_msg("WARNING: usb device configuration is not 3 as expected!\n"); + } + +#if 0 log_debug_msg("setting configuration...\n"); ret = usb_set_configuration(phone->device, 3); if (ret != 0) { @@ -242,6 +248,7 @@ static iphone_error_t iphone_config_usb_device(iphone_device_t phone) } else { log_debug_msg("done.\n"); } +#endif log_debug_msg("claiming interface... "); ret = usb_claim_interface(phone->device, 1); @@ -307,8 +314,9 @@ iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_device_t if (dev->devnum == dev_n) { phone->__device = dev; phone->device = usb_open(phone->__device); - iphone_config_usb_device(phone); - goto found; + if (iphone_config_usb_device(phone) == IPHONE_E_SUCCESS) { + goto found; + } } iphone_free_device(phone); diff --git a/iproxy.c b/iproxy.c index 93bbf89..896dbff 100644 --- a/iproxy.c +++ b/iproxy.c @@ -31,8 +31,9 @@ #include #include #include -#include "usbmuxd.h" +#include #include "sock_stuff.h" +#include "libusbmuxd.h" static uint16_t listen_port = 0; static uint16_t device_port = 0; @@ -46,43 +47,6 @@ struct client_data { volatile int stop_stoc; }; -int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result) -{ - struct usbmuxd_result res; - int recv_len; - int i; - uint32_t rrr[5]; - - if (!result) { - return -EINVAL; - } - - if ((recv_len = recv_buf(sfd, &res, sizeof(res))) <= 0) { - perror("recv"); - return -errno; - } else { - memcpy(&rrr, &res, recv_len); - for (i = 0; i < recv_len/4; i++) { - fprintf(stderr, "%08x ", rrr[i]); - } - fprintf(stderr, "\n"); - if ((recv_len == sizeof(res)) - && (res.header.length == 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; -} - void *run_stoc_loop(void *arg) { struct client_data *cdata = (struct client_data*)arg; @@ -178,13 +142,7 @@ void *run_ctos_loop(void *arg) void *acceptor_thread(void *arg) { struct client_data *cdata; - int recv_len = 0; - int scan_done; - int connected; - uint32_t pktlen; - unsigned char *buf; - struct usbmuxd_scan_request scan; - struct am_device_info device_info; + usbmuxd_device_t *dev_list = NULL; pthread_t ctos; if (!arg) { @@ -194,102 +152,36 @@ void *acceptor_thread(void *arg) cdata = (struct client_data*)arg; - cdata->sfd = connect_unix_socket(USBMUXD_SOCKET_FILE); - if (cdata->sfd < 0) { - printf("error opening socket, terminating.\n"); + if (usbmuxd_scan(&dev_list) != 0) { + printf("Connecting to usbmuxd failed, terminating.\n"); + free(dev_list); return NULL; } - // send scan - scan.header.length = sizeof(struct usbmuxd_scan_request); - scan.header.reserved = 0; - scan.header.type = USBMUXD_SCAN; - scan.header.tag = 2; - - scan_done = 0; - connected = 0; - - fprintf(stdout, "sending scan packet\n"); - if (send(cdata->sfd, &scan, scan.header.length, 0) == scan.header.length) { - uint32_t res = -1; - // get response - if (usbmuxd_get_result(cdata->sfd, scan.header.tag, &res) && (res==0)) { - fprintf(stdout, "Got response to scan request!\n"); - scan_done = 1; - } else { - fprintf(stderr, "Did not get response to scan request (with result=0)...\n"); - close(cdata->sfd); - cdata->sfd = -1; - return NULL; - } - - device_info.device_id = 0; - - if (scan_done) { - // get all devices - while (1) { - if (recv_buf_timeout(cdata->sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) { - buf = (unsigned char*)malloc(pktlen); - if (!buf) { - exit(-ENOMEM); - } - recv_len = recv_buf(cdata->sfd, buf, pktlen); - if (recv_len < pktlen) { - fprintf(stdout, "received less data than specified in header!\n"); - } - fprintf(stdout, "Received device data\n"); - //log_debug_buffer(stdout, (char*)buf, pktlen); - memcpy(&device_info, buf + sizeof(struct usbmuxd_header), sizeof(device_info)); - free(buf); - } else { - // we _should_ have all of them now. - // or perhaps an error occured. - break; - } - } - } - - if (device_info.device_id > 0) { - struct usbmuxd_connect_request c_req; - - fprintf(stdout, "Requesting connecion to device %d port %d\n", device_info.device_id, device_port); + if (!dev_list || dev_list[0].device_id == 0) { + printf("No connected device found, terminating.\n"); + free(dev_list); + return NULL; + } - // try to connect to last device found - 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 = device_info.device_id; - c_req.tcp_dport = htons(device_port); - c_req.reserved = 0; + fprintf(stdout, "Requesting connecion to device %d port %d\n", dev_list[0].device_id, device_port); - if (send_buf(cdata->sfd, &c_req, sizeof(c_req)) < 0) { - perror("send"); - } else { - // read ACK - res = -1; - fprintf(stdout, "Reading connect result...\n"); - if (usbmuxd_get_result(cdata->sfd, c_req.header.tag, &res)) { - if (res == 0) { - fprintf(stdout, "Connect success!\n"); - connected = 1; - } else { - fprintf(stderr, "Connect failed, Error code=%d\n", res); - } - } - } - } + cdata->sfd = usbmuxd_connect(dev_list[0].device_id, device_port); + free(dev_list); + if (cdata->sfd < 0) { + fprintf(stderr, "Error connecting to device!\n"); + } else { + cdata->stop_ctos = 0; + pthread_create(&ctos, NULL, run_ctos_loop, cdata); + pthread_join(ctos, NULL); + } - if (connected) { - cdata->stop_ctos = 0; - pthread_create(&ctos, NULL, run_ctos_loop, cdata); - pthread_join(ctos, NULL); - } else { - fprintf(stderr, "Error connecting to device!\n"); - } + if (cdata->fd > 0) { + close(cdata->fd); + } + if (cdata->sfd > 0) { + close(cdata->sfd); } - close(cdata->fd); - close(cdata->sfd); return NULL; } diff --git a/libusbmuxd.c b/libusbmuxd.c new file mode 100644 index 0000000..4e4ec10 --- /dev/null +++ b/libusbmuxd.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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 == 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_device_t **devices) +{ + struct usbmuxd_scan_request s_req; + int sfd; + int scan_success = 0; + uint32_t res; + uint32_t pktlen; + int recv_len; + usbmuxd_device_t *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) == 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; + } + + *devices = NULL; + // receive device list + while (1) { + if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 500) == 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 (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_device_t*)realloc(*devices, sizeof(usbmuxd_device_t) * (dev_cnt+1)); + if (newlist) { + memcpy(newlist+dev_cnt, &dev_info_pkt.device, sizeof(usbmuxd_device_t)); + *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_device_t*)realloc(*devices, sizeof(usbmuxd_device_t) * (dev_cnt+1)); + memset(newlist+dev_cnt, 0, sizeof(usbmuxd_device_t)); + *devices = newlist; + + return 0; +} + +int usbmuxd_connect(uint32_t device_id, uint16_t 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 = device_id; + c_req.tcp_dport = htons(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; +} diff --git a/libusbmuxd.h b/libusbmuxd.h new file mode 100644 index 0000000..82f9a47 --- /dev/null +++ b/libusbmuxd.h @@ -0,0 +1,27 @@ +#ifndef __LIBUSBMUXD_H +#define __LIBUSBMUXD_H + +#include + +/** + * Contacts usbmuxd via it's unix domain socket and performs a scan for + * connected devices. + * + * @param devices Pointer to an array of usbmuxd_device_t. + * Assumed initially NULL, will be allocated by this function. + * + * @return number of devices found, negative on error + */ +int usbmuxd_scan(usbmuxd_device_t **devices); + +/** + * Performs the connect procedure via usbmuxd. + * + * @param device_id USB device number of the device to connect to + * @param port Port number to connect to + * + * @return socket of the connection, negative on error + */ +int usbmuxd_connect(uint32_t device_id, uint16_t port); + +#endif /* __LIBUSBMUXD_H */ diff --git a/main.c b/main.c index a0b6b74..fc8eef2 100644 --- a/main.c +++ b/main.c @@ -92,10 +92,10 @@ static void print_buffer(FILE *fp, const char *data, const int length) if (verbose >= 4) fprintf(fp, "%04x: ", i); for (j=0;j<16;j++) { if (i+j >= length) { - printf(" "); + if (verbose >= 4) fprintf(fp, " "); continue; } - if (verbose >= 4) printf("%02hhx ", *(data+i+j)); + if (verbose >= 4) fprintf(fp, "%02hhx ", *(data+i+j)); } if (verbose >= 4) fprintf(fp, " | "); for(j=0;j<16;j++) { @@ -103,7 +103,7 @@ static void print_buffer(FILE *fp, const char *data, const int length) break; c = *(data+i+j); if ((c < 32) || (c > 127)) { - printf("."); + if (verbose >= 4) fprintf(fp, "."); continue; } if (verbose >= 4) fprintf(fp, "%c", c); @@ -491,14 +491,14 @@ static void *usbmuxd_client_init_thread(void *arg) if (verbose >= 2) fprintf(stderr, "%s: started (fd=%d)\n", __func__, cdata->socket); if ((recv_len = usbmuxd_get_request(cdata->socket, (void**)&s_req, 0)) <= 0) { - if (verbose >= 2) fprintf(stderr, "%s: No Hello packet received, error %s\n", __func__, strerror(errno)); + if (verbose >= 2) fprintf(stderr, "%s: No scan packet received, error %s\n", __func__, 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) fprintf(stderr, "%s: Got Hello packet!\n", __func__); + if (verbose >= 3) fprintf(stderr, "%s: Got scan packet!\n", __func__); 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; @@ -506,7 +506,7 @@ static void *usbmuxd_client_init_thread(void *arg) goto connect; } else { // send error response and exit - if (verbose >= 2) fprintf(stderr, "%s: Invalid Hello packet received.\n", __func__); + if (verbose >= 2) fprintf(stderr, "%s: Invalid scan packet received.\n", __func__); // TODO is this required?! usbmuxd_send_result(cdata->socket, s_req->header.tag, EINVAL); goto leave; @@ -537,14 +537,14 @@ static void *usbmuxd_client_init_thread(void *arg) 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; - dev_info_rec.device_info.device_id = dev->devnum; - dev_info_rec.device_info.product_id = dev->descriptor.idProduct; + dev_info_rec.device.device_id = dev->devnum; + 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_info.serial_number, sizeof(dev_info_rec.device_info.serial_number)+1); + 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); } //pthread_mutex_unlock(&usbmux_mutex); diff --git a/testclient.c b/testclient.c deleted file mode 100644 index dc2dd28..0000000 --- a/testclient.c +++ /dev/null @@ -1,146 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "usbmuxd.h" -#include "sock_stuff.h" - -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 == 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 main(int argc, char **argv) -{ - int sfd; - int recv_len = 0; - int scan_done; - int connected; - uint32_t pktlen; - unsigned char *buf; - struct usbmuxd_scan_request scan; - struct am_device_info device_info; - - sfd = connect_unix_socket(USBMUXD_SOCKET_FILE); - if (sfd < 0) { - printf("error opening socket, terminating.\n"); - return -1; - } - - // send scan - scan.header.length = sizeof(struct usbmuxd_scan_request); - scan.header.reserved = 0; - scan.header.type = USBMUXD_SCAN; - scan.header.tag = 2; - - scan_done = 0; - connected = 0; - - fprintf(stdout, "sending scan packet\n"); - if (send(sfd, &scan, scan.header.length, 0) == scan.header.length) { - uint32_t res = -1; - // get response - if (usbmuxd_get_result(sfd, scan.header.tag, &res) && (res==0)) { - fprintf(stdout, "Got response to scan request!\n"); - scan_done = 1; - } else { - fprintf(stderr, "Did not get response to scan request (with result=0)...\n"); - close(sfd); - return -1; - } - - device_info.device_id = 0; - - if (scan_done) { - // get all devices - while (1) { - if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) { - buf = (unsigned char*)malloc(pktlen); - if (!buf) { - exit(-ENOMEM); - } - recv_len = recv_buf(sfd, buf, pktlen); - if (recv_len < pktlen) { - fprintf(stdout, "received less data than specified in header!\n"); - } - fprintf(stdout, "got device data:\n"); - //log_debug_buffer(stdout, (char*)buf, pktlen); - memcpy(&device_info, buf + sizeof(struct usbmuxd_header), sizeof(device_info)); - free(buf); - } else { - // we _should_ have all of them now. - // or perhaps an error occured. - break; - } - } - } - - if (device_info.device_id > 0) { - struct usbmuxd_connect_request c_req; - - // try to connect to last device found - 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 = device_info.device_id; - c_req.tcp_dport = htons(22); - c_req.reserved = 0; - - if (send_buf(sfd, &c_req, sizeof(c_req)) < 0) { - perror("send"); - } else { - // read ACK - res = -1; - if (usbmuxd_get_result(sfd, c_req.header.tag, &res)) { - if (res == 0) { - fprintf(stdout, "Connect success!\n"); - connected = 1; - } else { - fprintf(stderr, "Connect failed, Error code=%d\n", res); - } - } - } - } - - if (connected) { - - - // do communication now. - sleep(10); - } - } - close(sfd); - - return 0; -} diff --git a/usbmuxd.h b/usbmuxd.h index 896bb39..0749c87 100644 --- a/usbmuxd.h +++ b/usbmuxd.h @@ -24,15 +24,16 @@ struct usbmuxd_connect_request { uint16_t reserved; // set to zero } __attribute__((__packed__)); -struct am_device_info { +struct usbmuxd_device { uint32_t device_id; uint16_t product_id; char serial_number[40]; } __attribute__((__packed__)); +typedef struct usbmuxd_device usbmuxd_device_t; struct usbmuxd_device_info_record { struct usbmuxd_header header; - struct am_device_info device_info; + struct usbmuxd_device device; char padding[222]; } __attribute__((__packed__)); -- cgit v1.1-32-gdbae From 15ea7e8a03ab519115b19b4b84c2ead96bf6c88c Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 19:04:38 +0200 Subject: [PATCH] usbmuxd/libusbmuxd.h: separate logic from implementation tweak public parameter and struct names for clarity fix usbmuxd_scan() to return number of devices per documentation expand public documentation in libusbmux.h Signed-off-by: Nikias Bassen --- iproxy.c | 13 ++++++------- libusbmuxd.c | 34 +++++++++++++++++++++------------- libusbmuxd.h | 42 ++++++++++++++++++++++++++++++------------ usbmuxd.h | 3 ++- 4 files changed, 59 insertions(+), 33 deletions(-) diff --git a/iproxy.c b/iproxy.c index 896dbff..199c51e 100644 --- a/iproxy.c +++ b/iproxy.c @@ -31,7 +31,6 @@ #include #include #include -#include #include "sock_stuff.h" #include "libusbmuxd.h" @@ -142,7 +141,7 @@ void *run_ctos_loop(void *arg) void *acceptor_thread(void *arg) { struct client_data *cdata; - usbmuxd_device_t *dev_list = NULL; + usbmuxd_scan_result *dev_list = NULL; pthread_t ctos; if (!arg) { @@ -152,21 +151,21 @@ void *acceptor_thread(void *arg) cdata = (struct client_data*)arg; - if (usbmuxd_scan(&dev_list) != 0) { + if (usbmuxd_scan(&dev_list) < 0) { printf("Connecting to usbmuxd failed, terminating.\n"); free(dev_list); return NULL; } - if (!dev_list || dev_list[0].device_id == 0) { + if (dev_list == NULL || dev_list[0].handle == 0) { printf("No connected device found, terminating.\n"); free(dev_list); return NULL; } - fprintf(stdout, "Requesting connecion to device %d port %d\n", dev_list[0].device_id, device_port); + fprintf(stdout, "Requesting connecion to device handle == %d, port %d\n", dev_list[0].handle, device_port); - cdata->sfd = usbmuxd_connect(dev_list[0].device_id, device_port); + cdata->sfd = usbmuxd_connect(dev_list[0].handle, device_port); free(dev_list); if (cdata->sfd < 0) { fprintf(stderr, "Error connecting to device!\n"); @@ -191,7 +190,7 @@ int main(int argc, char **argv) int mysock = -1; if (argc != 3) { - printf("usage: %s LOCAL_PORT DEVICE_PORT\n", argv[0]); + printf("usage: %s LOCAL_TCP_PORT DEVICE_TCP_PORT\n", argv[0]); return 0; } diff --git a/libusbmuxd.c b/libusbmuxd.c index 4e4ec10..ed331aa 100644 --- a/libusbmuxd.c +++ b/libusbmuxd.c @@ -7,7 +7,11 @@ #include #include +// usbmuxd public interface +#include +// usbmuxd protocol #include +// socket utility functions #include "sock_stuff.h" static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result) @@ -40,7 +44,7 @@ static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result) return -1; } -int usbmuxd_scan(usbmuxd_device_t **devices) +int usbmuxd_scan(usbmuxd_scan_result **available_devices) { struct usbmuxd_scan_request s_req; int sfd; @@ -48,7 +52,7 @@ int usbmuxd_scan(usbmuxd_device_t **devices) uint32_t res; uint32_t pktlen; int recv_len; - usbmuxd_device_t *newlist = NULL; + usbmuxd_scan_result *newlist = NULL; struct usbmuxd_device_info_record dev_info_pkt; int dev_cnt = 0; @@ -81,7 +85,7 @@ int usbmuxd_scan(usbmuxd_device_t **devices) return -1; } - *devices = NULL; + *available_devices = NULL; // receive device list while (1) { if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 500) == 4) { @@ -99,10 +103,14 @@ int usbmuxd_scan(usbmuxd_device_t **devices) 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_device_t*)realloc(*devices, sizeof(usbmuxd_device_t) * (dev_cnt+1)); + newlist = (usbmuxd_scan_result *)realloc(*available_devices, sizeof(usbmuxd_scan_result) * (dev_cnt+1)); if (newlist) { - memcpy(newlist+dev_cnt, &dev_info_pkt.device, sizeof(usbmuxd_device_t)); - *devices = 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__); @@ -117,14 +125,14 @@ int usbmuxd_scan(usbmuxd_device_t **devices) } // terminating zero record - newlist = (usbmuxd_device_t*)realloc(*devices, sizeof(usbmuxd_device_t) * (dev_cnt+1)); - memset(newlist+dev_cnt, 0, sizeof(usbmuxd_device_t)); - *devices = newlist; + 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 0; + return dev_cnt; } -int usbmuxd_connect(uint32_t device_id, uint16_t port) +int usbmuxd_connect(const int handle, const unsigned short tcp_port) { int sfd; struct usbmuxd_connect_request c_req; @@ -141,8 +149,8 @@ int usbmuxd_connect(uint32_t device_id, uint16_t port) c_req.header.reserved = 0; c_req.header.type = USBMUXD_CONNECT; c_req.header.tag = 3; - c_req.device_id = device_id; - c_req.tcp_dport = htons(port); + 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) { diff --git a/libusbmuxd.h b/libusbmuxd.h index 82f9a47..da99f1f 100644 --- a/libusbmuxd.h +++ b/libusbmuxd.h @@ -1,27 +1,45 @@ #ifndef __LIBUSBMUXD_H #define __LIBUSBMUXD_H -#include +/** + * 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 via it's unix domain socket and performs a scan for - * connected devices. + * Contacts usbmuxd and performs a scan for connected devices. * - * @param devices Pointer to an array of usbmuxd_device_t. - * Assumed initially NULL, will be allocated by this function. + * @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 devices found, negative on error + * @return number of available devices, zero on no devices, or negative on error */ -int usbmuxd_scan(usbmuxd_device_t **devices); +int usbmuxd_scan(usbmuxd_scan_result **available_devices); /** - * Performs the connect procedure via usbmuxd. + * Request proxy connect to + * + * @param handle returned by 'usbmuxd_scan()' * - * @param device_id USB device number of the device to connect to - * @param port Port number to connect to + * @param tcp_port TCP port number on device, in range 0-65535. + * common values are 62078 for lockdown, and 22 for SSH. * - * @return socket of the connection, negative on error + * @return file descriptor socket of the connection, or -1 on error */ -int usbmuxd_connect(uint32_t device_id, uint16_t port); +int usbmuxd_connect(const int handle, const unsigned short tcp_port); #endif /* __LIBUSBMUXD_H */ diff --git a/usbmuxd.h b/usbmuxd.h index 0749c87..cc9b9d7 100644 --- a/usbmuxd.h +++ b/usbmuxd.h @@ -1,3 +1,5 @@ +/* Protocol defintion for usbmuxd proxy protocol */ + #ifndef __USBMUXD_H #define __USBMUXD_H @@ -29,7 +31,6 @@ struct usbmuxd_device { uint16_t product_id; char serial_number[40]; } __attribute__((__packed__)); -typedef struct usbmuxd_device usbmuxd_device_t; struct usbmuxd_device_info_record { struct usbmuxd_header header; -- cgit v1.1-32-gdbae From da537aae30386c8b3bdc5075b96971b5776a7176 Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 19:07:39 +0200 Subject: [PATCH] iproxy: print count and serial_number of device(s) Signed-off-by: Nikias Bassen --- iproxy.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iproxy.c b/iproxy.c index 199c51e..56e30ed 100644 --- a/iproxy.c +++ b/iproxy.c @@ -143,6 +143,7 @@ void *acceptor_thread(void *arg) struct client_data *cdata; usbmuxd_scan_result *dev_list = NULL; pthread_t ctos; + int count; if (!arg) { fprintf(stderr, "invalid client_data provided!\n"); @@ -151,19 +152,21 @@ void *acceptor_thread(void *arg) cdata = (struct client_data*)arg; - if (usbmuxd_scan(&dev_list) < 0) { + if ((count = usbmuxd_scan(&dev_list)) < 0) { printf("Connecting to usbmuxd failed, terminating.\n"); free(dev_list); return NULL; } + fprintf(stdout, "Number of available devices == %d\n", count); + if (dev_list == NULL || dev_list[0].handle == 0) { printf("No connected device found, terminating.\n"); free(dev_list); return NULL; } - fprintf(stdout, "Requesting connecion to device handle == %d, port %d\n", dev_list[0].handle, device_port); + fprintf(stdout, "Requesting connecion to device handle == %d (serial: %s), port %d\n", dev_list[0].handle, dev_list[0].serial_number, device_port); cdata->sfd = usbmuxd_connect(dev_list[0].handle, device_port); free(dev_list); -- cgit v1.1-32-gdbae From 16a161e315c12a6837fcdb15c270ac42feef8e9b Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 19:10:56 +0200 Subject: [PATCH] renamed: usbmuxd.h -> usbmuxd-proto.h renamed: libusbmuxd.h -> usbmuxd.h Use 'install' in Makefile build libusbmuxd.so (use with '#include ' and -lusbmuxd Signed-off-by: Nikias Bassen --- libusbmuxd.h | 45 ---------------------------- usbmuxd.h | 97 ++++++++++++++++++++++++++++-------------------------------- 2 files changed, 45 insertions(+), 97 deletions(-) delete mode 100644 libusbmuxd.h diff --git a/libusbmuxd.h b/libusbmuxd.h deleted file mode 100644 index da99f1f..0000000 --- a/libusbmuxd.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __LIBUSBMUXD_H -#define __LIBUSBMUXD_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); - -#endif /* __LIBUSBMUXD_H */ diff --git a/usbmuxd.h b/usbmuxd.h index cc9b9d7..da99f1f 100644 --- a/usbmuxd.h +++ b/usbmuxd.h @@ -1,52 +1,45 @@ -/* Protocol defintion for usbmuxd proxy protocol */ - -#ifndef __USBMUXD_H -#define __USBMUXD_H - -#include - -#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 +#ifndef __LIBUSBMUXD_H +#define __LIBUSBMUXD_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); + +#endif /* __LIBUSBMUXD_H */ -- cgit v1.1-32-gdbae From 968dc229afd75e670a92b24eb48222aa347d756b Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 19:13:36 +0200 Subject: [PATCH] renamed: usbmuxd.h -> usbmuxd-proto.h renamed: libusbmuxd.h -> usbmuxd.h Use 'install' in Makefile build libusbmuxd.so (use with '#include ' and -lusbmuxd add *.so to .gitignore Really this time. Signed-off-by: Nikias Bassen --- Makefile | 29 +++++++++++++++++++---------- README | 1 - iproxy.c | 2 +- libusbmuxd.c | 4 ++-- main.c | 2 +- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 55d396d..e0c8971 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,20 @@ -TARGETS=usbmuxd iproxy -CFLAGS=-I. -Wall -g -DDEBUG +TARGETS=usbmuxd iproxy libusbmuxd.so +CFLAGS=-I. -Wall -g -DDEBUG -fPIC LIBS=-lpthread -lusb -lrt -LDFLAGS= +LDFLAGS=-L. INSTALL_PREFIX=/usr all: $(TARGETS) -main.o: main.c usbmuxd.h sock_stuff.h iphone.h +main.o: main.c usbmuxd-proto.h sock_stuff.h iphone.h iphone.o: iphone.c iphone.h usbmuxd.h sock_stuff.h sock_stuff.o: sock_stuff.c sock_stuff.h -libusbmuxd.o: libusbmuxd.c libusbmuxd.h usbmuxd.h +libusbmuxd.o: libusbmuxd.c usbmuxd.h usbmuxd-proto.h iproxy.o: iproxy.c sock_stuff.h +libusbmuxd.so: libusbmuxd.o sock_stuff.o + +%.so: %.o + $(CC) -o $@ -shared -Wl,-soname,$@.1 $^ %.o: %.c $(CC) -o $@ $(CFLAGS) -c $< @@ -18,17 +22,22 @@ iproxy.o: iproxy.c sock_stuff.h usbmuxd: main.o sock_stuff.o iphone.o $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) -iproxy: iproxy.o libusbmuxd.o sock_stuff.o - $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) +iproxy: iproxy.o + $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) -lusbmuxd clean: - rm -f *.o $(TARGETS) + rm -f *.o *.so $(TARGETS) realclean: clean rm -f *~ install: all - cp usbmuxd $(INSTALL_PREFIX)/sbin/ - cp usbmuxd.h $(INSTALL_PREFIX)/include/ + install -m 755 usbmuxd $(INSTALL_PREFIX)/sbin/ + # protocol + install -m 644 usbmuxd-proto.h $(INSTALL_PREFIX)/include/ + # iproxy + install -m 644 libusbmux.so $(INSTALL_PREFIX)/lib/ + install -m 644 usbmuxd.h $(INSTALL_PREFIX)/include/ + install -m 755 iproxy $(INSTALL_PREFIX)/bin/ .PHONY: all clean realclean diff --git a/README b/README index 5cb74f9..b36c0c0 100644 --- a/README +++ b/README @@ -3,7 +3,6 @@ Build make - Use === diff --git a/iproxy.c b/iproxy.c index 56e30ed..527ebf6 100644 --- a/iproxy.c +++ b/iproxy.c @@ -32,7 +32,7 @@ #include #include #include "sock_stuff.h" -#include "libusbmuxd.h" +#include "usbmuxd.h" static uint16_t listen_port = 0; static uint16_t device_port = 0; diff --git a/libusbmuxd.c b/libusbmuxd.c index ed331aa..1a9b4b8 100644 --- a/libusbmuxd.c +++ b/libusbmuxd.c @@ -8,9 +8,9 @@ #include // usbmuxd public interface -#include -// usbmuxd protocol #include +// usbmuxd protocol +#include // socket utility functions #include "sock_stuff.h" diff --git a/main.c b/main.c index fc8eef2..832ff7f 100644 --- a/main.c +++ b/main.c @@ -34,7 +34,7 @@ #include #include -#include "usbmuxd.h" +#include "usbmuxd-proto.h" #include "sock_stuff.h" #include "iphone.h" -- cgit v1.1-32-gdbae From 8f9c1679334cb1b019c3db1d5663e0b5102f5eca Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 19:16:06 +0200 Subject: [PATCH] update .gitignore (really) Signed-off-by: Nikias Bassen --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 26cda67..e6a7834 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ *~ *.o +*.so .*.swp iproxy -testclient usbmuxd -- cgit v1.1-32-gdbae From a1ba5d23745404e237a1441948176a923cd63345 Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 19:18:40 +0200 Subject: [PATCH] install in /usr/local add uninstall target add 85-usbmuxd.rules + install in /usr/local/lib/udev/rules.d (if that directory even gets scanned) Signed-off-by: Nikias Bassen --- Makefile | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e0c8971..40c1e0a 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ TARGETS=usbmuxd iproxy libusbmuxd.so CFLAGS=-I. -Wall -g -DDEBUG -fPIC LIBS=-lpthread -lusb -lrt LDFLAGS=-L. -INSTALL_PREFIX=/usr +INSTALL_PREFIX=/usr/local all: $(TARGETS) @@ -33,6 +33,8 @@ realclean: clean install: all install -m 755 usbmuxd $(INSTALL_PREFIX)/sbin/ + # udev crack + install -m 644 85-usbmuxd.rules $(INSTALL_PREFIX)/lib/udev/rules.d/ # protocol install -m 644 usbmuxd-proto.h $(INSTALL_PREFIX)/include/ # iproxy @@ -40,4 +42,12 @@ install: all install -m 644 usbmuxd.h $(INSTALL_PREFIX)/include/ install -m 755 iproxy $(INSTALL_PREFIX)/bin/ +uninstall: + -rm $(INSTALL_PREFIX)/sbin/usbmuxd + -rm $(INSTALL_PREFIX)/lib/udev/rules.d/85-usbmuxd.rules + -rm $(INSTALL_PREFIX)/include/usbmuxd-proto.h + -rm $(INSTALL_PREFIX)/lib/libusbmux.so + -rm $(INSTALL_PREFIX)/include/usbmuxd.h + -rm $(INSTALL_PREFIX)/bin/iproxy + .PHONY: all clean realclean -- cgit v1.1-32-gdbae From 1e3a46b7558f0b598b3080110b269055514bde05 Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 19:27:02 +0200 Subject: [PATCH] use install -D for unusual udev/rules.d fix Makefile to be libusbmux_d_.so in one place Signed-off-by: Nikias Bassen --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 40c1e0a..083b5c6 100644 --- a/Makefile +++ b/Makefile @@ -34,11 +34,11 @@ realclean: clean install: all install -m 755 usbmuxd $(INSTALL_PREFIX)/sbin/ # udev crack - install -m 644 85-usbmuxd.rules $(INSTALL_PREFIX)/lib/udev/rules.d/ + install -D -m 644 85-usbmuxd.rules $(INSTALL_PREFIX)/lib/udev/rules.d/85-usbmuxd.rules # protocol install -m 644 usbmuxd-proto.h $(INSTALL_PREFIX)/include/ # iproxy - install -m 644 libusbmux.so $(INSTALL_PREFIX)/lib/ + install -m 644 libusbmuxd.so $(INSTALL_PREFIX)/lib/ install -m 644 usbmuxd.h $(INSTALL_PREFIX)/include/ install -m 755 iproxy $(INSTALL_PREFIX)/bin/ -- cgit v1.1-32-gdbae From 19f83d2e9dbbd03d9cb8a09b915fd1e74c551bda Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 19:27:49 +0200 Subject: [PATCH] Makefile: fix libusbmux_d_.so for uninstall too Signed-off-by: Nikias Bassen --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 083b5c6..f395de6 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ uninstall: -rm $(INSTALL_PREFIX)/sbin/usbmuxd -rm $(INSTALL_PREFIX)/lib/udev/rules.d/85-usbmuxd.rules -rm $(INSTALL_PREFIX)/include/usbmuxd-proto.h - -rm $(INSTALL_PREFIX)/lib/libusbmux.so + -rm $(INSTALL_PREFIX)/lib/libusbmuxd.so -rm $(INSTALL_PREFIX)/include/usbmuxd.h -rm $(INSTALL_PREFIX)/bin/iproxy -- cgit v1.1-32-gdbae From c9d137f59bdf3b8d2376ff20685870c5d3e92b5e Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 19:37:18 +0200 Subject: [PATCH] install udev rules into /etc/udev/rules.d/ install to make them work Signed-off-by: Nikias Bassen --- Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f395de6..fa5576b 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,8 @@ realclean: clean install: all install -m 755 usbmuxd $(INSTALL_PREFIX)/sbin/ # udev crack - install -D -m 644 85-usbmuxd.rules $(INSTALL_PREFIX)/lib/udev/rules.d/85-usbmuxd.rules + #install -D -m 644 85-usbmuxd.rules $(INSTALL_PREFIX)/lib/udev/rules.d/85-usbmuxd.rules + install -m 644 85-usbmuxd.rules /etc/udev/rules.d/85-usbmuxd.rules # protocol install -m 644 usbmuxd-proto.h $(INSTALL_PREFIX)/include/ # iproxy @@ -44,7 +45,8 @@ install: all uninstall: -rm $(INSTALL_PREFIX)/sbin/usbmuxd - -rm $(INSTALL_PREFIX)/lib/udev/rules.d/85-usbmuxd.rules + #-rm $(INSTALL_PREFIX)/lib/udev/rules.d/85-usbmuxd.rules + -rm /etc/udev/rules.d/85-usbmuxd.rules -rm $(INSTALL_PREFIX)/include/usbmuxd-proto.h -rm $(INSTALL_PREFIX)/lib/libusbmuxd.so -rm $(INSTALL_PREFIX)/include/usbmuxd.h -- cgit v1.1-32-gdbae From 096bb6ed89596b10efbdf6f732106ff5295449fd Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 19:46:08 +0200 Subject: [PATCH] Expand README Signed-off-by: Nikias Bassen --- README | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/README b/README index b36c0c0..42ca40a 100644 --- a/README +++ b/README @@ -1,26 +1,65 @@ -Build -===== +Background +========== + +'usbmuxd' stands for "USB multiplexing daemon". To the user/developer +what it actually does is to proxy requests over a USB cable on directly +to a listening TCP port on the iPhone. + +Multiple connections to different TCP ports can happen in parallel. +An example (and useful) tool called 'iproxy' is included that allows +you to forward localhost ports to the device---allows SSH over USB on +jailbroken devices, or allowing access the lockdown daemon (and then +to all of the file access, sync, notification and backup services +running on the device). + +This higher-level layers are handled by libiphone. The version of +libiphone compatible with the 'usbmuxd' infrastructure is called +'libiphone-usbmuxd'. 'ifuse' is then able to sit on top of this. + + +Building +======== make + sudo make install + -Use -=== +Running (with magic) +==================== - sudo ./usbmuxd & + (Unplug + replug your iPhone) ./iproxy 2222 22 & ssh -p 2222 root@localhost -Muwahahaha. Hopefully you get the normal SSH login prompt. +Hopefully you get the normal SSH login prompt. You may still lots of +debugging output for the moment. If this is getting in the way of +your ssh login, then run the 'ssh' command from a different xterminal +or virtual console. + + +Running (without magic) +======================= + +If 'udev' is _not_ automatically running on your machine and picking +up the new .rules file, you will need to start usbmuxd by hand first. +Check it's running and that there is only one copy with 'ps aux | grep +usbmuxd'. + + sudo usbmuxd & + ./iproxy 2222 22 & + ssh -p 2222 root@localhost -SSH -=== +Tip: Starting SSH if disabled +============================= -If your iphone is rooted, but isn't running SSH, you will need to -mount it with 'ifuse --afc2' (to access the root directory of the -device). +If your iphone is rooted, but SSH isn't started and you _cannot_ (for +instance, cracked/broken screen) get to the Services control panel on +the device, then you can start the SSH service over the USB by +mounting the (jailbroken) filesystem. -And then edit: +You will need to mount it usbing 'ifuse --afc2' (to access the root +directory of the device), and then edit: /Library/LaunchDaemons/com.openssh.sshd.plist -- cgit v1.1-32-gdbae From c6b43ebca43b2a44bccd15bf950e1cad921071b1 Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 19:47:54 +0200 Subject: [PATCH] Add a "README.devel" Signed-off-by: Nikias Bassen --- README.devel | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 README.devel diff --git a/README.devel b/README.devel new file mode 100644 index 0000000..727e095 --- /dev/null +++ b/README.devel @@ -0,0 +1,50 @@ +Background +========== + +'libusbmuxd' makes it really simple to talk to a running 'usbmuxd' and +hides all the details for you. There are two function calls: + +usbmuxd_scan() +-------------- + +This returns a list of all available iPhone-like devices that are +available for talking to. The returned array contains the USB +product_id, hex formatted serial_number of any iPhones/iTouches and a +non-descript 'handle' for all those devices that are within range (as +of March 2009, that means a device directly plugged into the +computer's USB port). + +Once you have found the device you want to communicate with, take its +'handle' and pass this to usbmuxd_connect(). + +usbmuxd_connect() +----------------- + +This takes a handle, a destination port number and tries to setup +a proxy a connection. It returns a file-descriptor which you should +be able to read(), write() and select() on like any other active network +socket connection. + + +Technical details +================= + +When usbmuxd is running (normally started, or stopped as a result of +'udev' auto-insertion messages), it provides a socket interface in +'/var/run/usbmuxd' that is designed to be compatible with the socket +interface that is provided on MacOSX. + +The structures for communicating over this device are documented +in the 'usbmuxd-proto.h', but you shouldn't need to view them +directly if you are using the libusbmuxd.so library for easy access. + + +Example +======= + +#include + +... + +gcc -o leetphone leetphone.c -lusbmuxd + -- cgit v1.1-32-gdbae From 1a8b5bb89af79bb08ccede29a36aecb3c2ca839d Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 19:49:46 +0200 Subject: Added missing usbmuxd-proto.h file Signed-off-by: Nikias Bassen --- usbmuxd-proto.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 usbmuxd-proto.h diff --git a/usbmuxd-proto.h b/usbmuxd-proto.h new file mode 100644 index 0000000..868ee06 --- /dev/null +++ b/usbmuxd-proto.h @@ -0,0 +1,52 @@ +/* Protocol defintion for usbmuxd proxy protocol */ + +#ifndef __USBMUXD_H +#define __USBMUXD_H + +#include + +#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 */ -- cgit v1.1-32-gdbae From e652af13edb7e47e1a0770c40448b93e93d0daa5 Mon Sep 17 00:00:00 2001 From: Paul Sladen Date: Sun, 29 Mar 2009 20:14:20 +0200 Subject: Added file 85-usbmuxd.rules Signed-off-by: Nikias Bassen --- 85-usbmuxd.rules | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 85-usbmuxd.rules diff --git a/85-usbmuxd.rules b/85-usbmuxd.rules new file mode 100644 index 0000000..90d49ea --- /dev/null +++ b/85-usbmuxd.rules @@ -0,0 +1,37 @@ +# usbmuxd (iPhone "Apple Mobile Device" MUXer listening on /var/run/usbmuxd) +#if +#SUBSYSTEMS=="usb_interface", SYMLINK+="usbmux/interface" + +#SUBSYSTEMS!="usb", GOTO="usbmuxd_rules_end" # stops the whole script working +ATTR{idVendor}!="05ac", GOTO="usbmuxd_rules_end" + +# If it's plug insertion, flip it into dual "PTP + Apple Mobile Device" configuration +# This allows another application to switch it later without it getting switched back (hopefully) +# TODO: check iPod Touch/3G +SUBSYSTEM=="usb", ACTION=="add", ATTR{product}=="iPhone", ATTR{bConfigurationValue}!="3", ATTR{bConfigurationValue}="3", GOTO="usbmuxd_rules_end" + +# SYMLINK the usbmux endpoints, if we get them +# TODO: Multiple devices +# TODO: work out how to make nice, incrementing usbmux/{0,1,2,3}-in for +LABEL="usbmuxd_rules_usbmux" + +# ff/fe/02 == usbmux +# +#ACTION=="add", + +# Try to symlink the interface, containing the endpoints. +# ...But it doesn't work +#KERNELS=="7-3:3.1", SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="01", ATTRS{bAlternateSetting}==" 0", ATTRS{bNumEndpoints}=="02", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="fe", ATTRS{bInterfaceProtocol}=="02", SYMLINK+="usbmux/prettyplease", RUN+="/bin/ls -l /dev/usbmux/prettyplease" + +#ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="fe", ATTRS{bInterfaceProtocol}=="02", SYMLINK+="usbmux/interface" + +# Cute names, really they should have nice numerically increasing names. +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", SYMLINK+="usbmux/in" +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbmux/out" + +# Start and stop 'usbmuxd' as required. +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --background --make-pidfile --pidfile /var/run/usbmuxd.pid --exec /usr/local/sbin/usbmuxd" +ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 2 --pidfile /var/run/usbmuxd.pid --exec /usr/local/sbin/usbmuxd" + +# skip +LABEL="usbmuxd_rules_end" -- cgit v1.1-32-gdbae From 22073a7c051fb263f3d9481dfef844ccfc2a18d0 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 29 Mar 2009 20:15:07 +0200 Subject: [PATCH] build libusbmuxd.so before iproxy --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fa5576b..13a9914 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -TARGETS=usbmuxd iproxy libusbmuxd.so +TARGETS=usbmuxd libusbmuxd.so iproxy CFLAGS=-I. -Wall -g -DDEBUG -fPIC LIBS=-lpthread -lusb -lrt LDFLAGS=-L. -- cgit v1.1-32-gdbae From f0e505a4042d656a62b3ded832d2d9ea2defcf69 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 29 Mar 2009 20:19:33 +0200 Subject: ifdefs updated --- usbmuxd-proto.h | 4 ++-- usbmuxd.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/usbmuxd-proto.h b/usbmuxd-proto.h index 868ee06..7f8c2d6 100644 --- a/usbmuxd-proto.h +++ b/usbmuxd-proto.h @@ -1,7 +1,7 @@ /* Protocol defintion for usbmuxd proxy protocol */ -#ifndef __USBMUXD_H -#define __USBMUXD_H +#ifndef __USBMUXD_PROTO_H +#define __USBMUXD_PROTO_H #include diff --git a/usbmuxd.h b/usbmuxd.h index da99f1f..15e97ee 100644 --- a/usbmuxd.h +++ b/usbmuxd.h @@ -1,5 +1,5 @@ -#ifndef __LIBUSBMUXD_H -#define __LIBUSBMUXD_H +#ifndef __USBMUXD_H +#define __USBMUXD_H /** * Array entry returned by 'usbmuxd_scan()' scanning. @@ -42,4 +42,4 @@ int usbmuxd_scan(usbmuxd_scan_result **available_devices); */ int usbmuxd_connect(const int handle, const unsigned short tcp_port); -#endif /* __LIBUSBMUXD_H */ +#endif /* __USBMUXD_H */ -- cgit v1.1-32-gdbae From 0080c074ba46c0a4eae6561f40c6b4c749ac0ab1 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 6 Apr 2009 14:47:05 +0200 Subject: silence some debugging output --- libusbmuxd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libusbmuxd.c b/libusbmuxd.c index 1a9b4b8..9cccb40 100644 --- a/libusbmuxd.c +++ b/libusbmuxd.c @@ -157,10 +157,10 @@ int usbmuxd_connect(const int handle, const unsigned short tcp_port) perror("send"); } else { // read ACK - fprintf(stderr, "%s: Reading connect result...\n", __func__); + //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__); + //fprintf(stderr, "%s: Connect success!\n", __func__); connected = 1; } else { fprintf(stderr, "%s: Connect failed, Error code=%d\n", __func__, res); -- cgit v1.1-32-gdbae From 466ff3c456383456630ce9d67abae991566c158e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 8 Apr 2009 01:08:37 +0200 Subject: Implemented lockfile stuff to prevent multiple running instances. Implemented daemonizing, use -f to run in foreground. Implemented logging to syslog (or to std{out,err} when running in foreground). Modified the udev rules file (removed --pidfile etc.). --- 85-usbmuxd.rules | 4 +- main.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 190 insertions(+), 27 deletions(-) diff --git a/85-usbmuxd.rules b/85-usbmuxd.rules index 90d49ea..69ddef8 100644 --- a/85-usbmuxd.rules +++ b/85-usbmuxd.rules @@ -30,8 +30,8 @@ ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", SYMLINK+="usbm ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbmux/out" # Start and stop 'usbmuxd' as required. -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --background --make-pidfile --pidfile /var/run/usbmuxd.pid --exec /usr/local/sbin/usbmuxd" -ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 2 --pidfile /var/run/usbmuxd.pid --exec /usr/local/sbin/usbmuxd" +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec /usr/local/sbin/usbmuxd" +ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 2 --exec /usr/local/sbin/usbmuxd" # skip LABEL="usbmuxd_rules_end" diff --git a/main.c b/main.c index 832ff7f..0af0735 100644 --- a/main.c +++ b/main.c @@ -24,6 +24,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -43,9 +47,12 @@ #define DEFAULT_CHILDREN_CAPACITY 10 #define DEBUG_LEVEL 0 +#define LOCKFILE "/var/run/usbmuxd.lock" + static int quit_flag = 0; static int fsock = -1; static int verbose = DEBUG_LEVEL; +static int foreground = 0; struct device_use_info { uint32_t device_id; @@ -764,7 +771,43 @@ leave: */ static int daemonize() { - // TODO still to be implemented, also logging is missing! + 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 + freopen("/dev/null", "r", stdin); + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); + return 0; } @@ -779,12 +822,85 @@ static void clean_exit(int sig) quit_flag = 1; } +static void logmsg(int prio, 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); +} + +static void usage() +{ + printf("usage: usbmuxd [options]\n"); + printf("\t-h|--help print this message.\n"); + printf("\t-v|--verbose be verbose\n"); + printf("\t-f|--foreground do not daemonize\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' }, + { NULL, 0, NULL, 0} + }; + int c; + + while (1) { + c = getopt_long(argc, argv, "hfv", 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; + default: + usage(); + exit(2); + } + } +} + /** * main function. Initializes all stuff and then loops waiting in accept. */ int main(int argc, char **argv) { - int foreground = 1; struct sockaddr_un c_addr; socklen_t len = sizeof(struct sockaddr_un); struct client_data *cdata = NULL; @@ -793,20 +909,47 @@ int main(int argc, char **argv) int i; int result = 0; int cnt = 0; + FILE *lfd = NULL; + struct flock lock; - for (i = 1; i < argc; i++) { - if (argv[i] != NULL && (!strncmp("-v", argv[i], 2) || !strncmp("--verbose", argv[i], 10))) { - sock_stuff_set_verbose(++verbose); - } + parse_opts(argc, argv); + + argc -= optind; + argv += optind; + + if (!foreground) { + openlog("usbmuxd", LOG_PID, 0); } - if (verbose >= 2) fprintf(stderr, "usbmuxd: starting\n"); + if (verbose >= 2) logmsg(LOG_NOTICE, "starting"); - // TODO: Parameter checking. + // signal(SIGHUP, reload_conf); // none yet + signal(SIGINT, clean_exit); + signal(SIGQUIT, clean_exit); + signal(SIGTERM, clean_exit); + 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) { + logmsg(LOG_NOTICE, "another instance is already running. exiting."); + return -1; + } + } fsock = create_unix_socket(USBMUXD_SOCKET_FILE); if (fsock < 0) { - if (verbose >= 1) fprintf(stderr, "Could not create socket, exiting\n"); + logmsg(LOG_ERR, "Could not create socket, exiting"); + if (!foreground) { + closelog(); + } return -1; } @@ -814,26 +957,36 @@ int main(int argc, char **argv) if (!foreground) { if (daemonize() < 0) { + fprintf(stderr, "usbmuxd: FATAL: Could not daemonize!\n"); + syslog(LOG_ERR, "FATAL: Could not daemonize!"); + closelog(); exit(EXIT_FAILURE); } } - // signal(SIGHUP, reload_conf); // none yet - signal(SIGINT, clean_exit); - signal(SIGQUIT, clean_exit); - signal(SIGTERM, clean_exit); - signal(SIGPIPE, SIG_IGN); + // 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; + fcntl(fileno(lfd), F_SETLK, &lock); + } // 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) { - if (verbose >= 2) fprintf(stderr, "usbmuxd: Out of memory when allocating memory for child threads. Terminating.\n"); + 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) fprintf(stderr, "usbmuxd: waiting for connection\n"); + 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... @@ -845,7 +998,7 @@ int main(int argc, char **argv) if (children[i]) { if (children[i]->dead != 0) { pthread_join(children[i]->thread, NULL); - if (verbose >= 3) fprintf(stderr, "usbmuxd: reclaimed client thread (fd=%d)\n", children[i]->socket); + if (verbose >= 3) logmsg(LOG_NOTICE, "reclaimed client thread (fd=%d)", children[i]->socket); free(children[i]); children[i] = NULL; cnt++; @@ -864,7 +1017,7 @@ int main(int argc, char **argv) } continue; } else { - if (verbose >= 3) fprintf(stderr, "usbmuxd: select error: %s\n", strerror(errno)); + if (verbose >= 3) logmsg(LOG_ERR, "usbmuxd: select error: %s", strerror(errno)); continue; } } @@ -873,7 +1026,7 @@ int main(int argc, char **argv) memset(cdata, 0, sizeof(struct client_data)); if (!cdata) { quit_flag = 1; - if (verbose >= 1) fprintf(stderr, "usbmuxd: Error: Out of memory! Terminating.\n"); + logmsg(LOG_ERR, "Error: Out of memory! Terminating."); break; } @@ -883,12 +1036,12 @@ int main(int argc, char **argv) if (errno == EINTR) { continue; } else { - if (verbose >= 3) fprintf(stderr, "usbmuxd: Error in accept: %s\n", strerror(errno)); + if (verbose >= 3) logmsg(LOG_ERR, "Error in accept: %s", strerror(errno)); continue; } } - if (verbose >= 1) fprintf(stderr, "usbmuxd: new client connected (fd=%d)\n", cdata->socket); + 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) { @@ -900,19 +1053,19 @@ int main(int argc, char **argv) children_capacity++; children = realloc(children, sizeof(struct client_data*) * children_capacity); if (!children) { - if (verbose >= 1) fprintf(stderr, "usbmuxd: Out of memory when enlarging child thread buffer\n"); + logmsg(LOG_ERR, "Out of memory when enlarging child thread buffer"); } } children[i] = cdata; } else { - if (verbose >= 3) fprintf(stderr, "usbmuxd: Failed to create client_init_thread.\n"); + logmsg(LOG_ERR, "Failed to create client_init_thread."); close(cdata->socket); free(cdata); cdata = NULL; } } - if (verbose >= 3) fprintf(stderr, "usbmuxd: terminating\n"); + if (verbose >= 3) logmsg(LOG_NOTICE, "terminating"); // preparing for shutdown: wait for child threads to terminate (if any) if (verbose >= 2) fprintf(stderr, "usbmuxd: waiting for child threads to terminate...\n"); @@ -934,7 +1087,17 @@ int main(int argc, char **argv) unlink(USBMUXD_SOCKET_FILE); - if (verbose >= 1) fprintf(stderr, "usbmuxd: terminated\n"); + // unlock lock file and close it. + if (lfd) { + lock.l_type = F_UNLCK; + fcntl(fileno(lfd), F_SETLK, lock); + fclose(lfd); + } + + if (verbose >= 1) logmsg(LOG_NOTICE, "usbmuxd: terminated"); + if (!foreground) { + closelog(); + } return 0; } -- cgit v1.1-32-gdbae From 05e6e479a0ba45a5b164e4e18fbbbb1c600554b0 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 8 Apr 2009 01:50:34 +0200 Subject: added --exit-on-no-devices option. --- main.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index 0af0735..8560aac 100644 --- a/main.c +++ b/main.c @@ -53,6 +53,7 @@ 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; struct device_use_info { uint32_t device_id; @@ -869,12 +870,13 @@ static void parse_opts(int argc, char **argv) { "help", 0, NULL, 'h' }, { "foreground", 0, NULL, 'f' }, { "verbose", 0, NULL, 'v' }, + { "exit-on-no-devices", 0, NULL, 'e' }, { NULL, 0, NULL, 0} }; int c; while (1) { - c = getopt_long(argc, argv, "hfv", longopts, (int *) 0); + c = getopt_long(argc, argv, "hfve", longopts, (int *) 0); if (c == -1) { break; } @@ -889,6 +891,9 @@ static void parse_opts(int argc, char **argv) case 'v': sock_stuff_set_verbose(++verbose); break; + case 'e': + exit_on_no_devices = 1; + break; default: usage(); exit(2); @@ -896,6 +901,35 @@ static void parse_opts(int argc, char **argv) } } +/** + * 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 <= 0x1293) + { + res++; + } + } + } + + return res; +} + /** * main function. Initializes all stuff and then loops waiting in accept. */ @@ -944,6 +978,13 @@ int main(int argc, char **argv) } } + 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"); -- cgit v1.1-32-gdbae From 3aa04f1fc526d7f8d33ebafb7ab7c130350b81ed Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 8 Apr 2009 13:05:33 +0200 Subject: increased read timeout for the device record reading procedure, as the short wait sometimes results in "no devices found" --- libusbmuxd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libusbmuxd.c b/libusbmuxd.c index 9cccb40..c12a7c0 100644 --- a/libusbmuxd.c +++ b/libusbmuxd.c @@ -88,7 +88,7 @@ int usbmuxd_scan(usbmuxd_scan_result **available_devices) *available_devices = NULL; // receive device list while (1) { - if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 500) == 4) { + 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); -- cgit v1.1-32-gdbae From 4402ead1fcc01a75e1632be04e910359f23e9881 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 8 Apr 2009 13:15:06 +0200 Subject: Start bulk reader thread _after_ successfully creating a connection to to prevent pthread locking with uninitialized locking variable. Still only started once per device. --- main.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index 8560aac..a75a440 100644 --- a/main.c +++ b/main.c @@ -633,11 +633,11 @@ connect: 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) fprintf(stderr, "%s: device_use_count = %d\n", __func__, device_use_count); - pthread_create(&cur_dev->bulk_reader, NULL, usbmuxd_bulk_reader_thread, cur_dev); pthread_mutex_lock(&usbmux_mutex); device_use_list = (struct device_use_info**)realloc(device_use_list, sizeof(struct device_use_info*) * (device_use_count+1)); @@ -661,6 +661,11 @@ connect: goto leave; } + // start bulk reader thread (once per device) + if (cur_dev->bulk_reader == 0) { + pthread_create(&cur_dev->bulk_reader, NULL, usbmuxd_bulk_reader_thread, cur_dev); + } + // start connection handler thread cdata->handler_dead = 0; cdata->tag = c_req->header.tag; @@ -728,7 +733,9 @@ leave: if (verbose >= 3) fprintf(stderr, "%s: last client disconnected, cleaning up\n", __func__); cur_dev->use_count = 0; pthread_mutex_unlock(&cur_dev->mutex); - pthread_join(cur_dev->bulk_reader, NULL); + if (cur_dev->bulk_reader != 0) { + pthread_join(cur_dev->bulk_reader, NULL); + } pthread_mutex_lock(&usb_mutex); iphone_free_device(cur_dev->phone); pthread_mutex_unlock(&usb_mutex); -- cgit v1.1-32-gdbae From 77c3fb13d54e892b63b7f037a19262ef18ca7f64 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Apr 2009 05:12:32 +0200 Subject: better(?) error handling --- main.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/main.c b/main.c index a75a440..c0bb340 100644 --- a/main.c +++ b/main.c @@ -244,11 +244,20 @@ static void *usbmuxd_client_reader_thread(void *arg) cursor = rbuffer; while (rlen > 0) { len = send_buf(cdata->socket, cursor, rlen); + if (len <= 0) { + fprintf(stderr, "Error: send returned %d\n", len); + err = 1; + break; + } // calculate remainder rlen -= len; // advance cursor cursor += len; } + if (err != 0) { + fprintf(stderr, "Error when writing to client...\n"); + break; + } fsync(cdata->socket); } @@ -432,7 +441,7 @@ leave: static void *usbmuxd_bulk_reader_thread(void *arg) { struct device_use_info *cur_dev; - + if (!arg) { if (verbose >= 3) fprintf(stderr, "%s: Invalid client_data provided\n", __func__); return NULL; @@ -443,7 +452,7 @@ static void *usbmuxd_bulk_reader_thread(void *arg) if (verbose >= 5) fprintf(stderr, "%s: started\n", __func__); while (!quit_flag && cur_dev) { - + pthread_mutex_lock(&cur_dev->mutex); if (cur_dev->use_count <= 0) { pthread_mutex_unlock(&cur_dev->mutex); @@ -458,7 +467,7 @@ static void *usbmuxd_bulk_reader_thread(void *arg) //} } - if (verbose >= 5) fprintf(stderr, "%s: terminated\n", __func__); + if (verbose >= 0) fprintf(stderr, "%s: terminated\n", __func__); return NULL; } @@ -726,7 +735,7 @@ leave: if (cur_dev) { pthread_mutex_lock(&cur_dev->mutex); if (cur_dev->use_count > 1) { - if (verbose >= 5) fprintf(stderr, "%s: decreasing device use count\n", __func__); + if (verbose >= 0) fprintf(stderr, "%s: decreasing device use count (from %d to %d)\n", __func__, cur_dev->use_count, cur_dev->use_count-1); cur_dev->use_count--; pthread_mutex_unlock(&cur_dev->mutex); } else { @@ -734,6 +743,7 @@ leave: cur_dev->use_count = 0; pthread_mutex_unlock(&cur_dev->mutex); if (cur_dev->bulk_reader != 0) { + fprintf(stderr, "%s: joining bulk_reader...\n", __func__); pthread_join(cur_dev->bulk_reader, NULL); } pthread_mutex_lock(&usb_mutex); @@ -1035,7 +1045,7 @@ int main(int argc, char **argv) memset(children, 0, sizeof(struct client_data*) * children_capacity); if (verbose >= 2) logmsg(LOG_NOTICE, "waiting for connection"); - while (!quit_flag) { + 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); @@ -1119,7 +1129,7 @@ int main(int argc, char **argv) if (verbose >= 2) fprintf(stderr, "usbmuxd: waiting for child threads to terminate...\n"); for (i = 0; i < children_capacity; i++) { if (children[i] != NULL) { - pthread_join(children[i]->thread, NULL); + pthread_join(children[i]->thread, NULL); free(children[i]); } } -- cgit v1.1-32-gdbae From 780cc38dde3dda7aeccc1d9043669f3493d79ccf Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 10 Apr 2009 14:07:09 +0200 Subject: suppressed warning about wrong configuration value. libusb does not seem to know about the change that was made via the udev rule/sysfs change --- iphone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iphone.c b/iphone.c index 060bba2..ad9dafd 100644 --- a/iphone.c +++ b/iphone.c @@ -215,12 +215,12 @@ static iphone_error_t iphone_config_usb_device(iphone_device_t phone) int bytes; char buf[512]; +#if 0 log_debug_msg("checking configuration...\n"); if (phone->__device->config->bConfigurationValue != 3) { log_debug_msg("WARNING: usb device configuration is not 3 as expected!\n"); } -#if 0 log_debug_msg("setting configuration...\n"); ret = usb_set_configuration(phone->device, 3); if (ret != 0) { -- cgit v1.1-32-gdbae From 0915fa88ac895e2ccbe6e34669c8b1bd73a5034e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 12 Apr 2009 13:05:28 +0200 Subject: silence debugging output (error messages remain) --- iproxy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iproxy.c b/iproxy.c index 527ebf6..3cb2894 100644 --- a/iproxy.c +++ b/iproxy.c @@ -66,7 +66,7 @@ void *run_stoc_loop(void *arg) break; } } else { - printf("received %d bytes from server\n", recv_len); +// printf("received %d bytes from server\n", recv_len); // send to socket sent = send_buf(cdata->fd, buffer, recv_len); if (sent < recv_len) { @@ -78,7 +78,7 @@ void *run_stoc_loop(void *arg) } } else { // sending succeeded, receive from device - printf("pushed %d bytes to client\n", sent); +// printf("pushed %d bytes to client\n", sent); } } } @@ -113,7 +113,7 @@ void *run_ctos_loop(void *arg) break; } } else { - printf("pulled %d bytes from client\n", recv_len); +// printf("pulled %d bytes from client\n", recv_len); // send to local socket sent = send_buf(cdata->sfd, buffer, recv_len); if (sent < recv_len) { @@ -125,7 +125,7 @@ void *run_ctos_loop(void *arg) } } else { // sending succeeded, receive from device - printf("sent %d bytes to server\n", sent); +// printf("sent %d bytes to server\n", sent); } } } -- cgit v1.1-32-gdbae From e1751b8c02822da3881b41a8e07a36665a163130 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 12 Apr 2009 13:09:25 +0200 Subject: better error handling, some cleanup, and changed confusing struct/variable naming. --- iphone.c | 49 ++++++++++++++---------- iphone.h | 3 +- main.c | 128 +++++++++++++++++++++++++++------------------------------------ 3 files changed, 86 insertions(+), 94 deletions(-) diff --git a/iphone.c b/iphone.c index ad9dafd..5cceb95 100644 --- a/iphone.c +++ b/iphone.c @@ -114,7 +114,13 @@ static int clients = 0; /** */ -int toto_debug = 1; +int toto_debug = 0; + +void iphone_set_debug(int e) +{ + toto_debug = e; +} + void log_debug_msg(const char *format, ...) { #ifndef STRIP_DEBUG_CODE @@ -518,13 +524,11 @@ int send_to_phone(iphone_device_t phone, char *data, int datalen) */ int recv_from_phone_timeout(iphone_device_t phone, char *data, int datalen, int timeoutmillis) { - if (!phone) - return -1; int bytes = 0; if (!phone) - return -1; - log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen); + return -EINVAL; + //log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen); bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, timeoutmillis); if (bytes < 0) { @@ -534,6 +538,7 @@ int recv_from_phone_timeout(iphone_device_t phone, char *data, int datalen, int if (bytes == -ETIMEDOUT) { // ignore this. it just means timeout reached before we // picked up any data. no problem. + return 0; } else { fprintf(stderr, "recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), @@ -541,7 +546,7 @@ int recv_from_phone_timeout(iphone_device_t phone, char *data, int datalen, int log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), strerror(-bytes)); } - return -1; + return bytes; } #ifdef DEBUG @@ -736,7 +741,7 @@ iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port, add_connection(new_connection); new_connection->error = IPHONE_E_SUCCESS; hton_header(new_connection->header); - printf("%s: send_to_phone (%d --> %d)\n", __func__, ntohs(new_connection->header->sport), ntohs(new_connection->header->dport)); + log_debug_msg("%s: send_to_phone (%d --> %d)\n", __func__, ntohs(new_connection->header->sport), ntohs(new_connection->header->dport)); if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) { *client = new_connection; return IPHONE_E_SUCCESS; @@ -842,7 +847,7 @@ iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, ui memcpy(buffer, client->header, sizeof(usbmux_tcp_header)); memcpy(buffer + sizeof(usbmux_tcp_header), data, datalen); - printf("%s: send_to_phone(%d --> %d)\n", __func__, ntohs(client->header->sport), ntohs(client->header->dport)); + log_debug_msg("%s: send_to_phone(%d --> %d)\n", __func__, ntohs(client->header->sport), ntohs(client->header->dport)); sendresult = send_to_phone(client->phone, buffer, blocksize); // Now that we've sent it off, we can clean up after our sloppy selves. if (buffer) @@ -907,9 +912,9 @@ uint32 append_receive_buffer(iphone_umux_client_t client, char* packet) // falls on our responsibility because we are the ones reading in // feedback. if (client->header->scnt == 0 && client->header->ocnt == 0 ) { - fprintf(stdout, "client is still waiting for handshake.\n"); + log_debug_msg("client is still waiting for handshake.\n"); if (header->tcp_flags == (TCP_SYN | TCP_ACK)) { - fprintf(stdout, "yes, got syn+ack ; replying with ack.\n"); + 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); @@ -918,9 +923,9 @@ uint32 append_receive_buffer(iphone_umux_client_t client, char* packet) hton_header(client->header); // push it to USB // TODO: need to check for error in the send here.... :( - printf("%s: send_to_phone (%d --> %d)\n", __func__, ntohs(client->header->sport), ntohs(client->header->dport)); + log_debug_msg("%s: send_to_phone (%d --> %d)\n", __func__, ntohs(client->header->sport), ntohs(client->header->dport)); if (send_to_phone(client->phone, (char *)client->header, sizeof(usbmux_tcp_header)) <= 0) { - fprintf(stdout, "%s: error when pushing to usb...\n", __func__); + log_debug_msg("%s: error when pushing to usb...\n", __func__); } // need to revert some of the fields back to host notation. ntoh_header(client->header); @@ -929,7 +934,7 @@ uint32 append_receive_buffer(iphone_umux_client_t client, char* packet) client->error = IPHONE_E_ECONNABORTED; // woah... this connection failed us. // TODO: somehow signal that this stream is a no-go. - fprintf(stderr, "WOAH! client failed to get proper syn+ack.\n"); + log_debug_msg("WOAH! client failed to get proper syn+ack.\n"); } } @@ -1002,7 +1007,7 @@ uint32 append_receive_buffer(iphone_umux_client_t client, char* packet) // ensure there is enough space, either by first malloc or realloc if (datalen > 0) { - fprintf(stderr, "%s: putting %d bytes into client's recv_buffer\n", __func__, datalen); + 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) { @@ -1061,13 +1066,14 @@ iphone_umux_client_t find_client(usbmux_tcp_header* recv_header) /** pull in a big USB bulk packet and distribute it to queues appropriately. */ -void iphone_mux_pullbulk(iphone_device_t phone) +int iphone_mux_pullbulk(iphone_device_t phone) { if (!phone) { fprintf(stderr, "iphone_mux_pullbulk: invalid argument\n"); - return; + return -EINVAL; } + int res = 0; static const int DEFAULT_CAPACITY = 128*1024; if (phone->usbReceive.buffer == NULL) { phone->usbReceive.capacity = DEFAULT_CAPACITY; @@ -1080,6 +1086,7 @@ void iphone_mux_pullbulk(iphone_device_t phone) // pull in content, note that the amount we can pull is capacity minus leftover int readlen = recv_from_phone_timeout(phone, cursor, phone->usbReceive.capacity - phone->usbReceive.leftover, 5000); if (readlen < 0) { + res = readlen; //fprintf(stderr, "recv_from_phone_timeout gave us an error.\n"); readlen = 0; } @@ -1099,24 +1106,24 @@ void iphone_mux_pullbulk(iphone_device_t phone) if (phone->usbReceive.leftover < HEADERLEN) break; usbmux_tcp_header *header = (usbmux_tcp_header *) cursor; - printf("%s: recv_from_phone_timeout (%d --> %d)\n", __func__, ntohs(header->sport), ntohs(header->dport)); + log_debug_msg("%s: recv_from_phone_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 packetlen = ntohl(header->length); if (phone->usbReceive.leftover < packetlen) { - printf("%s: not enough data to construct a full packet\n", __func__); + fprintf(stderr, "%s: not enough data to construct a full packet\n", __func__); break; } // ok... find the client this packet will get stuffed to. iphone_umux_client_t client = find_client(header); if (client == NULL) { - fprintf(stderr, "WARNING: client for packet cannot be found. dropping packet.\n"); + log_debug_msg("WARNING: client for packet cannot be found. dropping packet.\n"); } else { // stuff the data - fprintf(stderr, "%s: found client, calling append_receive_buffer\n", __func__); + log_debug_msg("%s: found client, calling append_receive_buffer\n", __func__); append_receive_buffer(client, cursor); } @@ -1141,6 +1148,8 @@ void iphone_mux_pullbulk(iphone_device_t phone) phone->usbReceive.buffer = newbuff; phone->usbReceive.capacity = DEFAULT_CAPACITY; } + + return res; } /** diff --git a/iphone.h b/iphone.h index e132cd5..fcef32a 100644 --- a/iphone.h +++ b/iphone.h @@ -50,6 +50,7 @@ #define IPHONE_E_ETIMEDOUT -ETIMEDOUT #define IPHONE_E_ECONNREFUSED -ECONNREFUSED +void iphone_set_debug(int e); typedef int16_t iphone_error_t; @@ -72,7 +73,7 @@ iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, ui iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes); iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout); -void iphone_mux_pullbulk(iphone_device_t phone); +int iphone_mux_pullbulk(iphone_device_t phone); iphone_error_t iphone_mux_get_error(iphone_umux_client_t client); diff --git a/main.c b/main.c index c0bb340..6b1b6ce 100644 --- a/main.c +++ b/main.c @@ -55,7 +55,7 @@ static int verbose = DEBUG_LEVEL; static int foreground = 0; static int exit_on_no_devices = 0; -struct device_use_info { +struct device_info { uint32_t device_id; iphone_device_t phone; int use_count; @@ -78,11 +78,11 @@ struct client_data { int handler_dead; int connected; iphone_umux_client_t muxclient; - struct device_use_info *duinfo; + struct device_info *dev; }; -static struct device_use_info **device_use_list = NULL; -static int device_use_count = 0; +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; @@ -223,7 +223,7 @@ static void *usbmuxd_client_reader_thread(void *arg) cdata->reader_dead = 0; - if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: started\n", __func__, cdata->dev->device_id, cdata->dev->use_count); while (!quit_flag && !cdata->reader_quit) { result = check_fd(cdata->socket, FD_WRITE, DEFAULT_TIMEOUT); @@ -237,7 +237,7 @@ static void *usbmuxd_client_reader_thread(void *arg) rlen = 0; err = iphone_mux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, &rlen, DEFAULT_TIMEOUT); if (err != 0) { - if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: encountered USB read error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); + if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: encountered USB read error: %d\n", __func__, cdata->dev->device_id, cdata->dev->use_count, err); break; } @@ -261,7 +261,7 @@ static void *usbmuxd_client_reader_thread(void *arg) fsync(cdata->socket); } - if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: terminated\n", __func__, cdata->dev->device_id, cdata->dev->use_count); cdata->reader_dead = 1; @@ -358,7 +358,7 @@ static void *usbmuxd_client_handler_thread(void *arg) cdata = (struct client_data*)arg; - if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: started\n", __func__, cdata->duinfo->device_id,cdata->duinfo->use_count); + if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: started\n", __func__, cdata->dev->device_id,cdata->dev->use_count); if (usbmuxd_handleConnectResult(cdata)) { if (verbose >= 3) fprintf(stderr, "handleConnectResult: Error\n"); @@ -391,20 +391,20 @@ static void *usbmuxd_client_handler_thread(void *arg) break; } if (len < 0) { - if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: Error: recv: %s\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, strerror(errno)); + if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: Error: recv: %s\n", __func__, cdata->dev->device_id, cdata->dev->use_count, strerror(errno)); break; } cursor = buffer; - pthread_mutex_lock(&cdata->duinfo->writer_mutex); + pthread_mutex_lock(&cdata->dev->writer_mutex); do { wlen = 0; err = iphone_mux_send(cdata->muxclient, cursor, len, &wlen); if (err == IPHONE_E_TIMEOUT) { // some kind of timeout... just be patient and retry. } else if (err != IPHONE_E_SUCCESS) { - if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: USB write error: %d\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count, err); + if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: USB write error: %d\n", __func__, cdata->dev->device_id, cdata->dev->use_count, err); len = -1; break; } @@ -414,7 +414,7 @@ static void *usbmuxd_client_handler_thread(void *arg) // advance cursor appropiately. cursor += wlen; } while ((len > 0) && !quit_flag); - pthread_mutex_unlock(&cdata->duinfo->writer_mutex); + pthread_mutex_unlock(&cdata->dev->writer_mutex); if (len < 0) { break; } @@ -422,7 +422,7 @@ static void *usbmuxd_client_handler_thread(void *arg) leave: // cleanup - if (verbose >= 3) fprintf(stderr, "%s[%d:%d]: terminating\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + if (verbose >= 3) fprintf(stderr, "%s[%d:%d]: terminating\n", __func__, cdata->dev->device_id, cdata->dev->use_count); if (cdata->reader != 0) { cdata->reader_quit = 1; pthread_join(cdata->reader, NULL); @@ -430,7 +430,7 @@ leave: cdata->handler_dead = 1; - if (verbose >= 3) fprintf(stderr, "%s[%d:%d]: terminated\n", __func__, cdata->duinfo->device_id, cdata->duinfo->use_count); + if (verbose >= 3) fprintf(stderr, "%s[%d:%d]: terminated\n", __func__, cdata->dev->device_id, cdata->dev->use_count); return NULL; } @@ -440,14 +440,15 @@ leave: */ static void *usbmuxd_bulk_reader_thread(void *arg) { - struct device_use_info *cur_dev; + struct device_info *cur_dev; + int err; if (!arg) { if (verbose >= 3) fprintf(stderr, "%s: Invalid client_data provided\n", __func__); return NULL; } - cur_dev = (struct device_use_info*)arg; + cur_dev = (struct device_info*)arg; if (verbose >= 5) fprintf(stderr, "%s: started\n", __func__); @@ -460,11 +461,10 @@ static void *usbmuxd_bulk_reader_thread(void *arg) } pthread_mutex_unlock(&cur_dev->mutex); - iphone_mux_pullbulk(cur_dev->phone); - //err = iphone_mux_get_error(cdata->muxclient); - //if (err != IPHONE_E_SUCCESS) { - // break; - //} + if ((err = iphone_mux_pullbulk(cur_dev->phone)) < 0) { + if (verbose >= 1) fprintf(stderr, "%s: error %d when reading from device\n", __func__, err); + break; + } } if (verbose >= 0) fprintf(stderr, "%s: terminated\n", __func__); @@ -495,7 +495,7 @@ static void *usbmuxd_client_init_thread(void *arg) // iphone_error_t err; iphone_device_t phone = NULL; - struct device_use_info *cur_dev = NULL; + struct device_info *cur_dev = NULL; if (!arg) { if (verbose >= 1) fprintf(stderr, "%s: invalid client_data provided!\n", __func__); @@ -608,13 +608,13 @@ connect: phone = NULL; cur_dev = NULL; // first check if we already have an open connection - if (device_use_list) { + if (devices) { pthread_mutex_lock(&usbmux_mutex); - for (i = 0; i < device_use_count; i++) { - if (device_use_list[i]) { - if (device_use_list[i]->device_id == c_req->device_id) { - device_use_list[i]->use_count++; - cur_dev = device_use_list[i]; + 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; } @@ -635,10 +635,11 @@ connect: } pthread_mutex_unlock(&usb_mutex); - // add to device list + // create device object + pthread_mutex_lock(&usbmux_mutex); if (verbose >= 3) fprintf(stderr, "%s: add to device list\n", __func__); - cur_dev = (struct device_use_info*)malloc(sizeof(struct device_use_info)); - memset(cur_dev, 0, sizeof(struct device_use_info)); + 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; @@ -646,13 +647,13 @@ connect: pthread_mutex_init(&cur_dev->mutex, NULL); pthread_mutex_init(&cur_dev->writer_mutex, NULL); - if (verbose >= 3) fprintf(stderr, "%s: device_use_count = %d\n", __func__, device_use_count); + if (verbose >= 3) fprintf(stderr, "%s: device_count = %d\n", __func__, device_count); - pthread_mutex_lock(&usbmux_mutex); - device_use_list = (struct device_use_info**)realloc(device_use_list, sizeof(struct device_use_info*) * (device_use_count+1)); - if (device_use_list) { - device_use_list[device_use_count] = cur_dev; - device_use_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; + devices++; } pthread_mutex_unlock(&usbmux_mutex); } else { @@ -671,43 +672,22 @@ connect: } // 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); // start connection handler thread cdata->handler_dead = 0; cdata->tag = c_req->header.tag; - cdata->duinfo = cur_dev; + cdata->dev = cur_dev; if (pthread_create(&cdata->handler, NULL, usbmuxd_client_handler_thread, cdata) != 0) { if (verbose >= 3) fprintf(stderr, "%s: could not create usbmuxd_client_handler_thread!\n", __func__); cdata->handler = 0; goto leave; } - //sent_result = 0; - - // TODO: wait for connect result? - // if connect failed, don't run this loop: - - /* - // start reading data from the connected device - while (!quit_flag && !cdata->handler_dead) { - iphone_mux_pullbulk(cur_dev->phone); - err = iphone_mux_get_error(cdata->muxclient); - if (err != IPHONE_E_SUCCESS) { - break; - } - } - - if (!sent_result) { - //fprintf(stderr, "Sending error message %d tag %d\n", err, c_req.header.tag); - err = iphone_mux_get_error(cdata->muxclient); - //usbmuxd_send_result(cdata->socket, c_req.header.tag, err); - }*/ - - //fprintf(stderr, "%s: terminating\n", __func__); - // wait for handler thread to finish its work if (cdata->handler != 0) { pthread_join(cdata->handler, NULL); @@ -754,23 +734,23 @@ leave: free(cur_dev); cur_dev = NULL; pthread_mutex_lock(&usbmux_mutex); - if (device_use_count > 1) { - struct device_use_info **newlist; + if (device_count > 1) { + struct device_info **newlist; int j; - newlist = (struct device_use_info**)malloc(sizeof(struct device_use_info*) * device_use_count-1); - for (i = 0; i < device_use_count; i++) { - if (device_use_list[i] != NULL) { - newlist[j++] = device_use_list[i]; + 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(device_use_list); - device_use_list = newlist; - device_use_count--; + free(devices); + devices = newlist; + device_count--; } else { - free(device_use_list); - device_use_list = NULL; - device_use_count = 0; + free(devices); + devices = NULL; + device_count = 0; } pthread_mutex_unlock(&usbmux_mutex); } @@ -1013,6 +993,8 @@ int main(int argc, char **argv) chmod(USBMUXD_SOCKET_FILE, 0666); + if (verbose >= 3) iphone_set_debug(1); + if (!foreground) { if (daemonize() < 0) { fprintf(stderr, "usbmuxd: FATAL: Could not daemonize!\n"); -- cgit v1.1-32-gdbae From 322a3e80835aacc2abaa802545143ebde69d21da Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Mon, 13 Apr 2009 05:37:35 +0200 Subject: Check for set usb_device in iphone_free_device to avoid libusb segfault Signed-off-by: Nikias Bassen --- iphone.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/iphone.c b/iphone.c index 5cceb95..6be85e6 100644 --- a/iphone.c +++ b/iphone.c @@ -427,9 +427,11 @@ iphone_error_t iphone_free_device(iphone_device_t device) return IPHONE_E_INVALID_ARG; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - do { - bytes = usb_bulk_read(device->device, BULKIN, buf, 512, 800); - } while (bytes > 0); + if (device->device) { + do { + bytes = usb_bulk_read(device->device, BULKIN, buf, 512, 800); + } while (bytes > 0); + } if (device->buffer) { free(device->buffer); -- cgit v1.1-32-gdbae From d6e0cb81973e99aa61c4b36e3e4a4dcd475c1e59 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 13 Apr 2009 13:54:57 +0200 Subject: [URGENT][BUGFIX] use device_count++ instead of device++. No further comment. --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index 6b1b6ce..87104d3 100644 --- a/main.c +++ b/main.c @@ -653,7 +653,7 @@ connect: devices = (struct device_info**)realloc(devices, sizeof(struct device_info*) * (device_count+1)); if (devices) { devices[device_count] = cur_dev; - devices++; + device_count++; } pthread_mutex_unlock(&usbmux_mutex); } else { -- cgit v1.1-32-gdbae From 9932dadfc7ddc65ccb3d2988df1a6dcc9cf536c5 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 13 Apr 2009 14:22:24 +0200 Subject: This _should_ fix a race condition that happens when a client is about to cleanup the stuff that is used by another client that is about to set up a new connection. Increased timeout in sock_stuff from 10 to 20 seconds and decreased the pullbulk recv timeout from 5 to 3 seconds. --- iphone.c | 2 +- main.c | 11 +++++------ sock_stuff.c | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/iphone.c b/iphone.c index 6be85e6..662432b 100644 --- a/iphone.c +++ b/iphone.c @@ -1086,7 +1086,7 @@ int iphone_mux_pullbulk(iphone_device_t phone) // start the cursor off just ahead of the leftover. char* cursor = &phone->usbReceive.buffer[phone->usbReceive.leftover]; // pull in content, note that the amount we can pull is capacity minus leftover - int readlen = recv_from_phone_timeout(phone, cursor, phone->usbReceive.capacity - phone->usbReceive.leftover, 5000); + int readlen = recv_from_phone_timeout(phone, cursor, phone->usbReceive.capacity - phone->usbReceive.leftover, 3000); if (readlen < 0) { res = readlen; //fprintf(stderr, "recv_from_phone_timeout gave us an error.\n"); diff --git a/main.c b/main.c index 87104d3..eba154e 100644 --- a/main.c +++ b/main.c @@ -605,11 +605,11 @@ connect: if (verbose >= 3) fprintf(stderr, "%s: Setting up connection to usb device #%d on port %d\n", __func__, c_req->device_id, 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) { - pthread_mutex_lock(&usbmux_mutex); for (i = 0; i < device_count; i++) { if (devices[i]) { if (devices[i]->device_id == c_req->device_id) { @@ -620,7 +620,6 @@ connect: } } } - pthread_mutex_unlock(&usbmux_mutex); } if (!phone) { // if not found, make a new connection @@ -629,6 +628,7 @@ connect: pthread_mutex_lock(&usb_mutex); if (iphone_get_specific_device(0, c_req->device_id, &phone) != IPHONE_E_SUCCESS) { pthread_mutex_unlock(&usb_mutex); + pthread_mutex_unlock(&usbmux_mutex); if (verbose >= 1) fprintf(stderr, "%s: device_id %d could not be opened\n", __func__, c_req->device_id); usbmuxd_send_result(cdata->socket, c_req->header.tag, ENODEV); goto leave; @@ -636,7 +636,6 @@ connect: pthread_mutex_unlock(&usb_mutex); // create device object - pthread_mutex_lock(&usbmux_mutex); if (verbose >= 3) fprintf(stderr, "%s: add to device list\n", __func__); cur_dev = (struct device_info*)malloc(sizeof(struct device_info)); memset(cur_dev, 0, sizeof(struct device_info)); @@ -655,10 +654,10 @@ connect: devices[device_count] = cur_dev; device_count++; } - pthread_mutex_unlock(&usbmux_mutex); } else { if (verbose >= 3) fprintf(stderr, "%s: reusing usb connection, device_id=%d\n", __func__, c_req->device_id); } + pthread_mutex_unlock(&usbmux_mutex); // setup connection to iPhone/iPod // pthread_mutex_lock(&usbmux_mutex); @@ -712,6 +711,7 @@ leave: // 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) { @@ -733,7 +733,6 @@ leave: pthread_mutex_destroy(&cur_dev->mutex); free(cur_dev); cur_dev = NULL; - pthread_mutex_lock(&usbmux_mutex); if (device_count > 1) { struct device_info **newlist; int j; @@ -752,9 +751,9 @@ leave: devices = NULL; device_count = 0; } - pthread_mutex_unlock(&usbmux_mutex); } } + pthread_mutex_unlock(&usbmux_mutex); cdata->dead = 1; close(cdata->socket); diff --git a/sock_stuff.c b/sock_stuff.c index 78249e6..8a06135 100644 --- a/sock_stuff.c +++ b/sock_stuff.c @@ -11,7 +11,7 @@ #include #include "sock_stuff.h" -#define RECV_TIMEOUT 10000 +#define RECV_TIMEOUT 20000 static int verbose = 0; @@ -75,7 +75,7 @@ int connect_unix_socket(const char *filename) // check if socket file exists... if (stat(filename, &fst) != 0) { - if (verbose >= 2) fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename, strerror(errno)); + if (verbose >= 2) fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename, strerror(errno)); return -1; } -- cgit v1.1-32-gdbae From a5245005b41cbae1ccee805fbef8d3e343c9b312 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 14 Apr 2009 13:15:10 +0200 Subject: Logging and debugging refined. --- iphone.c | 10 +++- main.c | 190 +++++++++++++++++++++++++++++++++------------------------------ 2 files changed, 107 insertions(+), 93 deletions(-) diff --git a/iphone.c b/iphone.c index 662432b..db68349 100644 --- a/iphone.c +++ b/iphone.c @@ -143,7 +143,8 @@ void log_debug_msg(const char *format, ...) */ static void print_buffer(const char *data, const int length) { - int i; + if (toto_debug > 0) { + int i; int j; unsigned char c; @@ -170,6 +171,7 @@ static void print_buffer(const char *data, const int length) printf("\n"); } printf("\n"); + } } #endif @@ -356,7 +358,7 @@ iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_device_t // Check for correct version if (ntohl(version->major) == 1 && ntohl(version->minor) == 0) { // We're all ready to roll. - fprintf(stderr, "get_iPhone() success\n"); + log_debug_msg("get_iPhone() success\n"); free(version); *device = phone; return IPHONE_E_SUCCESS; @@ -513,10 +515,12 @@ int send_to_phone(iphone_device_t phone, char *data, int datalen) #ifdef DEBUG if (bytes > 0) { + if (toto_debug > 0) { printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); printf("%s: sent to phone\n", __func__); print_buffer(data, bytes); printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + } } #endif return bytes; @@ -553,10 +557,12 @@ int recv_from_phone_timeout(iphone_device_t phone, char *data, int datalen, int #ifdef DEBUG if (bytes > 0) { + if (toto_debug > 0) { printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); printf("%s: received from phone:\n", __func__); print_buffer(data, bytes); printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + } } #endif diff --git a/main.c b/main.c index eba154e..157ecbb 100644 --- a/main.c +++ b/main.c @@ -49,6 +49,8 @@ #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; @@ -86,6 +88,44 @@ 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, 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. @@ -147,18 +187,18 @@ static int usbmuxd_get_request(int fd, void **data, size_t len) *data = malloc(pktlen); } else if (len < pktlen) { // target buffer is to small to hold this packet! fix it! - if (verbose >= 2) fprintf(stderr, "%s: WARNING -- packet (%d) is larger than target buffer (%d)! Truncating.\n", __func__, pktlen, len); + 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) && (recv_len < pktlen)) { - if (verbose >= 2) fprintf(stderr, "%s: Uh-oh, we got less than the packet's size, %d instead of %d...\n", __func__, 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) { - if (verbose >= 3) fprintf(stderr, "%s: received:\n", __func__); + fprintf(stderr, "%s: received:\n", __func__); print_buffer(stderr, *data, recv_len); } #endif @@ -186,7 +226,7 @@ static int usbmuxd_send_result(int fd, uint32_t tag, uint32_t result_code) res.header.tag = tag; res.result = result_code; - if (verbose >= 4) fprintf(stderr, "%s: tag=%d result=%d\n", __func__, res.header.tag, res.result); + 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 @@ -214,7 +254,7 @@ static void *usbmuxd_client_reader_thread(void *arg) int result; if (!arg) { - if (verbose >= 2) fprintf(stderr, "%s: invalid client_data supplied!\n", __func__); + if (verbose >= 2) logmsg(LOG_ERR, "%s: invalid client_data supplied!", __func__); cdata->reader_dead = 1; return NULL; } @@ -223,13 +263,13 @@ static void *usbmuxd_client_reader_thread(void *arg) cdata->reader_dead = 0; - if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: started\n", __func__, cdata->dev->device_id, cdata->dev->use_count); + if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%d:%d]: started", __func__, cdata->dev->device_id, 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) fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno)); + if (verbose >= 2) logmsg(LOG_ERR, "%s: select error: %s", __func__, strerror(errno)); } continue; } @@ -237,7 +277,7 @@ static void *usbmuxd_client_reader_thread(void *arg) rlen = 0; err = iphone_mux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, &rlen, DEFAULT_TIMEOUT); if (err != 0) { - if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: encountered USB read error: %d\n", __func__, cdata->dev->device_id, cdata->dev->use_count, err); + if (verbose >= 2) logmsg(LOG_ERR, "%s[%d:%d]: encountered USB read error: %d", __func__, cdata->dev->device_id, cdata->dev->use_count, err); break; } @@ -245,7 +285,7 @@ static void *usbmuxd_client_reader_thread(void *arg) while (rlen > 0) { len = send_buf(cdata->socket, cursor, rlen); if (len <= 0) { - fprintf(stderr, "Error: send returned %d\n", len); + logmsg(LOG_ERR, "%s: Error: send returned %d", __func__, len); err = 1; break; } @@ -255,13 +295,13 @@ static void *usbmuxd_client_reader_thread(void *arg) cursor += len; } if (err != 0) { - fprintf(stderr, "Error when writing to client...\n"); + logmsg(LOG_ERR, "%s: Error when writing to client...", __func__); break; } fsync(cdata->socket); } - if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: terminated\n", __func__, cdata->dev->device_id, cdata->dev->use_count); + if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%d:%d]: terminated", __func__, cdata->dev->device_id, cdata->dev->use_count); cdata->reader_dead = 1; @@ -289,21 +329,21 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) iphone_error_t err; if (!cdata) { - if (verbose >= 2) fprintf(stderr, "%s: Invalid client_data provided!\n", __func__); + 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) fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno)); + if (verbose >= 2) logmsg(LOG_ERR, "%s: select error: %s", __func__, strerror(errno)); return result; } } else { result = 0; err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, 100); if (err != 0) { - if (verbose >= 2) fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err); + 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 { @@ -311,7 +351,7 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) if ((buffer[0] == 1) && (rlen > 20) && !memcmp(buffer+1, "handleConnectResult:", 20)) { // hm... we got an error message! buffer[rlen] = 0; - if (verbose >= 1) fprintf(stderr, "%s: %s\n", __func__, buffer+22); + 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); @@ -352,26 +392,26 @@ static void *usbmuxd_client_handler_thread(void *arg) iphone_error_t err; if (!arg) { - if (verbose >= 3) fprintf(stderr, "%s: invalid client_data provided!\n", __func__); + if (verbose >= 2) logmsg(LOG_ERR, "%s: invalid client_data provided!", __func__); return NULL; } cdata = (struct client_data*)arg; - if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: started\n", __func__, cdata->dev->device_id,cdata->dev->use_count); + if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%d:%d]: started", __func__, cdata->dev->device_id,cdata->dev->use_count); if (usbmuxd_handleConnectResult(cdata)) { - if (verbose >= 3) fprintf(stderr, "handleConnectResult: Error\n"); + if (verbose >= 3) logmsg(LOG_ERR, "handleConnectResult: Error"); goto leave; } else { - if (verbose >= 3) fprintf(stderr, "handleConnectResult: Success\n"); + 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) fprintf(stderr, "%s: could not start client_reader thread\n", __func__); + if (verbose >= 2) logmsg(LOG_ERR, "%s: could not start client_reader thread", __func__); cdata->reader = 0; } @@ -379,7 +419,7 @@ static void *usbmuxd_client_handler_thread(void *arg) result = check_fd(cdata->socket, FD_READ, DEFAULT_TIMEOUT); if (result <= 0) { if (result < 0) { - if (verbose >= 3) fprintf(stderr, "%s: Error: checkfd: %s\n", __func__, strerror(errno)); + if (verbose >= 3) logmsg(LOG_ERR, "%s: Error: checkfd: %s", __func__, strerror(errno)); } continue; } @@ -391,7 +431,7 @@ static void *usbmuxd_client_handler_thread(void *arg) break; } if (len < 0) { - if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: Error: recv: %s\n", __func__, cdata->dev->device_id, cdata->dev->use_count, strerror(errno)); + if (verbose >= 2) logmsg(LOG_ERR, "%s[%d:%d]: Error: recv: %s", __func__, cdata->dev->device_id, cdata->dev->use_count, strerror(errno)); break; } @@ -404,7 +444,7 @@ static void *usbmuxd_client_handler_thread(void *arg) if (err == IPHONE_E_TIMEOUT) { // some kind of timeout... just be patient and retry. } else if (err != IPHONE_E_SUCCESS) { - if (verbose >= 2) fprintf(stderr, "%s[%d:%d]: USB write error: %d\n", __func__, cdata->dev->device_id, cdata->dev->use_count, err); + if (verbose >= 2) logmsg(LOG_ERR, "%s[%d:%d]: USB write error: %d", __func__, cdata->dev->device_id, cdata->dev->use_count, err); len = -1; break; } @@ -422,7 +462,7 @@ static void *usbmuxd_client_handler_thread(void *arg) leave: // cleanup - if (verbose >= 3) fprintf(stderr, "%s[%d:%d]: terminating\n", __func__, cdata->dev->device_id, cdata->dev->use_count); + if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%d:%d]: terminating", __func__, cdata->dev->device_id, cdata->dev->use_count); if (cdata->reader != 0) { cdata->reader_quit = 1; pthread_join(cdata->reader, NULL); @@ -430,7 +470,7 @@ leave: cdata->handler_dead = 1; - if (verbose >= 3) fprintf(stderr, "%s[%d:%d]: terminated\n", __func__, cdata->dev->device_id, cdata->dev->use_count); + if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%d:%d]: terminated", __func__, cdata->dev->device_id, cdata->dev->use_count); return NULL; } @@ -444,13 +484,13 @@ static void *usbmuxd_bulk_reader_thread(void *arg) int err; if (!arg) { - if (verbose >= 3) fprintf(stderr, "%s: Invalid client_data provided\n", __func__); + if (verbose >= 2) logmsg(LOG_ERR, "%s: Invalid client_data provided", __func__); return NULL; } cur_dev = (struct device_info*)arg; - if (verbose >= 5) fprintf(stderr, "%s: started\n", __func__); + if (verbose >= 3) logmsg(LOG_NOTICE, "%s: started", __func__); while (!quit_flag && cur_dev) { @@ -462,12 +502,12 @@ static void *usbmuxd_bulk_reader_thread(void *arg) pthread_mutex_unlock(&cur_dev->mutex); if ((err = iphone_mux_pullbulk(cur_dev->phone)) < 0) { - if (verbose >= 1) fprintf(stderr, "%s: error %d when reading from device\n", __func__, err); + if (verbose >= 1) logmsg(LOG_ERR, "%s: error %d when reading from device", __func__, err); break; } } - if (verbose >= 0) fprintf(stderr, "%s: terminated\n", __func__); + if (verbose >= 3) logmsg(LOG_NOTICE, "%s: terminated", __func__); return NULL; } @@ -498,24 +538,24 @@ static void *usbmuxd_client_init_thread(void *arg) struct device_info *cur_dev = NULL; if (!arg) { - if (verbose >= 1) fprintf(stderr, "%s: invalid client_data provided!\n", __func__); + 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 >= 2) fprintf(stderr, "%s: started (fd=%d)\n", __func__, cdata->socket); + 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) fprintf(stderr, "%s: No scan packet received, error %s\n", __func__, strerror(errno)); + 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) fprintf(stderr, "%s: Got scan packet!\n", __func__); + 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; @@ -523,7 +563,7 @@ static void *usbmuxd_client_init_thread(void *arg) goto connect; } else { // send error response and exit - if (verbose >= 2) fprintf(stderr, "%s: Invalid scan packet received.\n", __func__); + 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; @@ -532,14 +572,14 @@ static void *usbmuxd_client_init_thread(void *arg) pthread_mutex_lock(&usb_mutex); // gather data about all iPhones/iPods attached - if (verbose >= 5) fprintf(stderr, "%s: usb init\n", __func__); + if (verbose >= 5) logmsg(LOG_DEBUG, "%s[%x]: usb init", __func__, THREAD); usb_init(); - if (verbose >= 5) fprintf(stderr, "%s: usb find busses\n", __func__); + if (verbose >= 5) logmsg(LOG_DEBUG, "%s[%x]: usb find busses", __func__, THREAD); usb_find_busses(); - if (verbose >= 5) fprintf(stderr, "%s: usb find devices\n", __func__); + if (verbose >= 5) logmsg(LOG_DEBUG, "%s[%x]: usb find devices", __func__, THREAD); usb_find_devices(); - if (verbose >= 2) fprintf(stderr, "%s: Looking for attached devices...\n", __func__); + 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) { @@ -547,7 +587,7 @@ static void *usbmuxd_client_init_thread(void *arg) && dev->descriptor.idProduct >= 0x1290 && dev->descriptor.idProduct <= 0x1293) { - if (verbose >= 1) fprintf(stderr, "%s: Found device on bus %d, id %d\n", __func__, bus->location, dev->devnum); + if (verbose >= 1) logmsg(LOG_NOTICE, "%s[%x]: Found device on bus %d, id %d", __func__, THREAD, bus->location, dev->devnum); found++; // construct packet @@ -573,7 +613,7 @@ static void *usbmuxd_client_init_thread(void *arg) // send it if (send_buf(cdata->socket, &dev_info_rec, sizeof(dev_info_rec)) <= 0) { - if (verbose >= 3) fprintf(stderr, "%s: Error: Could not send device info: %s\n", __func__, strerror(errno)); + if (verbose >= 3) logmsg(LOG_ERR, "%s[%x]: Error: Could not send device info: %s", __func__, THREAD, strerror(errno)); found--; } } @@ -582,27 +622,27 @@ static void *usbmuxd_client_init_thread(void *arg) pthread_mutex_unlock(&usb_mutex); if (found <= 0) { - if (verbose >= 1) fprintf(stderr, "%s: No attached iPhone/iPod devices found.\n", __func__); + if (verbose >= 1) logmsg(LOG_NOTICE, "%s[%x]: No attached iPhone/iPod devices found.", __func__, THREAD); goto leave; } - if (verbose >= 2) fprintf(stderr, "%s: Waiting for connect request\n", __func__); + 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) fprintf(stderr, "%s: Did not receive any connect request.\n", __func__); + 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) fprintf(stderr, "%s: Unexpected packet of type %d received.\n", __func__, c_req->header.type); + 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) fprintf(stderr, "%s: Setting up connection to usb device #%d on port %d\n", __func__, c_req->device_id, ntohs(c_req->tcp_dport)); + if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%x]: Setting up connection to usb device #%d on port %d", __func__, THREAD, c_req->device_id, ntohs(c_req->tcp_dport)); // find the device, and open usb connection pthread_mutex_lock(&usbmux_mutex); @@ -623,20 +663,20 @@ connect: } if (!phone) { // if not found, make a new connection - if (verbose >= 2) fprintf(stderr, "%s: creating new usb connection, device_id=%d\n", __func__, c_req->device_id); + if (verbose >= 2) logmsg(LOG_NOTICE, "%s[%x]: creating new usb connection, device_id=%d", __func__, THREAD, c_req->device_id); pthread_mutex_lock(&usb_mutex); if (iphone_get_specific_device(0, c_req->device_id, &phone) != IPHONE_E_SUCCESS) { pthread_mutex_unlock(&usb_mutex); pthread_mutex_unlock(&usbmux_mutex); - if (verbose >= 1) fprintf(stderr, "%s: device_id %d could not be opened\n", __func__, c_req->device_id); + if (verbose >= 1) logmsg(LOG_ERR, "%s[%x]: device_id %d could not be opened", __func__, THREAD, c_req->device_id); usbmuxd_send_result(cdata->socket, c_req->header.tag, ENODEV); goto leave; } pthread_mutex_unlock(&usb_mutex); // create device object - if (verbose >= 3) fprintf(stderr, "%s: add to device list\n", __func__); + 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; @@ -646,7 +686,7 @@ connect: pthread_mutex_init(&cur_dev->mutex, NULL); pthread_mutex_init(&cur_dev->writer_mutex, NULL); - if (verbose >= 3) fprintf(stderr, "%s: device_count = %d\n", __func__, device_count); + 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)); @@ -655,7 +695,7 @@ connect: device_count++; } } else { - if (verbose >= 3) fprintf(stderr, "%s: reusing usb connection, device_id=%d\n", __func__, c_req->device_id); + if (verbose >= 2) logmsg(LOG_NOTICE, "%s[%x]: reusing usb connection, device_id=%d", __func__, THREAD, c_req->device_id); } pthread_mutex_unlock(&usbmux_mutex); @@ -666,7 +706,7 @@ connect: if (res != 0) { usbmuxd_send_result(cdata->socket, c_req->header.tag, res); - if (verbose >= 1) fprintf(stderr, "%s: mux_new_client returned %d, aborting.\n", __func__, res); + if (verbose >= 1) logmsg(LOG_ERR, "%s[%x]: mux_new_client returned %d, aborting.", __func__, THREAD, res); goto leave; } @@ -682,7 +722,7 @@ connect: cdata->tag = c_req->header.tag; cdata->dev = cur_dev; if (pthread_create(&cdata->handler, NULL, usbmuxd_client_handler_thread, cdata) != 0) { - if (verbose >= 3) fprintf(stderr, "%s: could not create usbmuxd_client_handler_thread!\n", __func__); + if (verbose >= 1) logmsg(LOG_ERR, "%s[%x]: could not create usbmuxd_client_handler_thread!", __func__, THREAD); cdata->handler = 0; goto leave; } @@ -692,7 +732,7 @@ connect: pthread_join(cdata->handler, NULL); } - if (verbose >= 2) fprintf(stderr, "%s: closing connection\n", __func__); + if (verbose >= 2) logmsg(LOG_NOTICE, "%s[%x]: closing connection", __func__, THREAD); // time to clean up if (cdata && cdata->muxclient) { // should be non-NULL @@ -700,7 +740,7 @@ connect: } leave: - if (verbose >= 2) fprintf(stderr, "%s: terminating\n", __func__); + if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%x]: terminating", __func__, THREAD); if (s_req) { free(s_req); @@ -715,15 +755,15 @@ leave: if (cur_dev) { pthread_mutex_lock(&cur_dev->mutex); if (cur_dev->use_count > 1) { - if (verbose >= 0) fprintf(stderr, "%s: decreasing device use count (from %d to %d)\n", __func__, cur_dev->use_count, 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 >= 3) fprintf(stderr, "%s: last client disconnected, cleaning up\n", __func__); + 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) { - fprintf(stderr, "%s: joining bulk_reader...\n", __func__); + 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); @@ -758,7 +798,7 @@ leave: cdata->dead = 1; close(cdata->socket); - if (verbose >= 5) fprintf(stderr, "%s: terminated\n", __func__); + if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%x]: terminated", __func__, THREAD); return NULL; } @@ -819,38 +859,6 @@ static void clean_exit(int sig) quit_flag = 1; } -static void logmsg(int prio, 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); -} - static void usage() { printf("usage: usbmuxd [options]\n"); @@ -1107,7 +1115,7 @@ int main(int argc, char **argv) if (verbose >= 3) logmsg(LOG_NOTICE, "terminating"); // preparing for shutdown: wait for child threads to terminate (if any) - if (verbose >= 2) fprintf(stderr, "usbmuxd: waiting for child threads to terminate...\n"); + 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); -- cgit v1.1-32-gdbae From 8cc8ac0157aaa901a43b70c1dfb3d1f4c7b443fe Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 17 Apr 2009 13:48:39 +0200 Subject: Fixed datatypes and added a comment for 'recv_from_phone_timeout' --- iphone.c | 64 ++++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/iphone.c b/iphone.c index db68349..8d1f96e 100644 --- a/iphone.c +++ b/iphone.c @@ -30,16 +30,12 @@ #define BULKOUT 0x04 #define HEADERLEN 28 -typedef uint16_t uint16; -typedef uint32_t uint32; -typedef uint8_t uint8; - -static const uint8 TCP_FIN = 1; -static const uint8 TCP_SYN = 1 << 1; -static const uint8 TCP_RST = 1 << 2; -static const uint8 TCP_PSH = 1 << 3; -static const uint8 TCP_ACK = 1 << 4; -static const uint8 TCP_URG = 1 << 5; +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 iPhone. It keeps sending back 512 and seems to drop off a cliff @@ -50,8 +46,8 @@ static const uint8 TCP_URG = 1 << 5; // Since I'm not sure how in the hell to interpret the window sizes that // the phone is sending back to us, I've figured out some magic number // constants which seem to work okay. -static const uint32 WINDOW_MAX = 5 * 1024; -static const uint32 WINDOW_INCREMENT = 512; +static const uint32_t WINDOW_MAX = 5 * 1024; +static const uint32_t WINDOW_INCREMENT = 512; typedef struct { char* buffer; @@ -67,15 +63,15 @@ struct iphone_device_int { }; typedef struct { - uint32 type, length, major, minor, allnull; + uint32_t type, length, major, minor, allnull; } usbmux_version_header; typedef struct { - uint32 type, length; - uint16 sport, dport; - uint32 scnt, ocnt; - uint8 offset, tcp_flags; - uint16 window, nullnull, length16; + 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 iphone_umux_client_int { @@ -93,7 +89,7 @@ struct iphone_umux_client_int { // 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 wr_pending_scnt; + uint32_t wr_pending_scnt; long wr_window; pthread_mutex_t mutex; @@ -526,7 +522,15 @@ int send_to_phone(iphone_device_t phone, char *data, int datalen) return bytes; } -/** +/** Receives data from the phone + * This function is a low-level (i.e. direct from iPhone) function. + * + * @param phone The iPhone 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. */ int recv_from_phone_timeout(iphone_device_t phone, char *data, int datalen, int timeoutmillis) { @@ -589,7 +593,7 @@ int recv_from_phone(iphone_device_t phone, char *data, int datalen) { * * @return A USBMux packet */ -usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port) +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); @@ -828,7 +832,7 @@ iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, ui pthread_mutex_lock(&client->mutex); int sendresult = 0; - uint32 blocksize = 0; + uint32_t blocksize = 0; if (client->wr_window <= 0) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); @@ -903,14 +907,14 @@ iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, ui * * @return number of bytes consumed (header + data) */ -uint32 append_receive_buffer(iphone_umux_client_t client, char* packet) +uint32_t append_receive_buffer(iphone_umux_client_t client, char* packet) { if (client == NULL || packet == NULL) return 0; usbmux_tcp_header *header = (usbmux_tcp_header *) packet; char* data = &packet[HEADERLEN]; - uint32 packetlen = ntohl(header->length); - uint32 datalen = packetlen-HEADERLEN; + uint32_t packetlen = ntohl(header->length); + uint32_t datalen = packetlen-HEADERLEN; int dobroadcast = 0; @@ -1053,14 +1057,14 @@ iphone_umux_client_t find_client(usbmux_tcp_header* recv_header) iphone_umux_client_t retval = NULL; // just for debugging check, I'm going to convert the numbers to host-endian. - uint16 hsport = ntohs(recv_header->sport); - uint16 hdport = ntohs(recv_header->dport); + uint16_t hsport = ntohs(recv_header->sport); + uint16_t hdport = ntohs(recv_header->dport); pthread_mutex_lock(&iphonemutex); int i; for (i = 0; i < clients; i++) { - uint16 csport = ntohs(connlist[i]->header->sport); - uint16 cdport = ntohs(connlist[i]->header->dport); + uint16_t csport = ntohs(connlist[i]->header->sport); + uint16_t cdport = ntohs(connlist[i]->header->dport); if (hsport == cdport && hdport == csport) { retval = connlist[i]; @@ -1118,7 +1122,7 @@ int iphone_mux_pullbulk(iphone_device_t phone) // now that we have a header, check if there is sufficient data // to construct a full packet, including its data - uint32 packetlen = ntohl(header->length); + uint32_t packetlen = ntohl(header->length); if (phone->usbReceive.leftover < packetlen) { fprintf(stderr, "%s: not enough data to construct a full packet\n", __func__); break; -- cgit v1.1-32-gdbae From 0c6f89a76daae408688c88f03982e93da9a367c1 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 17 Apr 2009 14:28:03 +0200 Subject: fix: don't init or destroy static mutex plus: some indentation, error message, and used code cleanup --- iphone.c | 52 ++++++++++++++-------------------------------------- 1 file changed, 14 insertions(+), 38 deletions(-) diff --git a/iphone.c b/iphone.c index 8d1f96e..3c9a55e 100644 --- a/iphone.c +++ b/iphone.c @@ -105,7 +105,6 @@ struct iphone_umux_client_int { static pthread_mutex_t iphonemutex = PTHREAD_MUTEX_INITIALIZER; static iphone_umux_client_t *connlist = NULL; static int clients = 0; -//static receivebuf_t usbReceive = {NULL, 0, 0}; /** @@ -395,8 +394,6 @@ iphone_error_t iphone_get_device(iphone_device_t * device) struct usb_bus *bus; struct usb_device *dev; - pthread_mutex_init(&iphonemutex, NULL); - usb_init(); usb_find_busses(); usb_find_devices(); @@ -443,8 +440,6 @@ iphone_error_t iphone_free_device(iphone_device_t device) ret = IPHONE_E_SUCCESS; } free(device); - - pthread_mutex_destroy(&iphonemutex); return ret; } @@ -488,8 +483,7 @@ int send_to_phone(iphone_device_t phone, char *data, int datalen) return bytes; } else if (bytes < 0) { - fprintf(stderr, "usb_bulk_write failed with error. err:%d (%s)(%s)\n", - bytes, usb_strerror(), strerror(-bytes)); + fprintf(stderr, "usb_bulk_write failed with error. err:%d (%s)(%s)\n", bytes, usb_strerror(), strerror(-bytes)); return -1; } else if (bytes == 0) { @@ -534,28 +528,23 @@ int send_to_phone(iphone_device_t phone, char *data, int datalen) */ int recv_from_phone_timeout(iphone_device_t phone, char *data, int datalen, int timeoutmillis) { - int bytes = 0; - if (!phone) return -EINVAL; //log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen); - bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, timeoutmillis); + int bytes = usb_bulk_read(phone->device, 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) { - // there are some things which are errors, others which are no problem. - // it's not documented in libUSB, but it seems that the error returns are - // just negated ERRNO values. - if (bytes == -ETIMEDOUT) { - // ignore this. it just means timeout reached before we - // picked up any data. no problem. - return 0; - } - else { - fprintf(stderr, "recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), - strerror(-bytes)); - log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), - strerror(-bytes)); - } + if (bytes == -ETIMEDOUT) { + // ignore this. it just means timeout reached before we + // picked up any data. no problem. + return 0; + } else { + fprintf(stderr, "recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), strerror(-bytes)); + log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), strerror(-bytes)); + } return bytes; } @@ -573,19 +562,6 @@ int recv_from_phone_timeout(iphone_device_t phone, char *data, int datalen, int return bytes; } -/** This function is a low-level (i.e. direct to iPhone) function. - * - * @param phone The iPhone to receive data from - * @param data Where to put data read - * @param datalen How much data to read in - * - * @return How many bytes were read in, or -1 on error. - */ -int recv_from_phone(iphone_device_t phone, char *data, int datalen) { - return recv_from_phone_timeout(phone, data, datalen, 100); -} - - /** Creates a USBMux packet for the given set of ports. * * @param s_port The source port for the connection. @@ -1239,7 +1215,7 @@ iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, } pthread_mutex_unlock(&client->mutex); - + return IPHONE_E_SUCCESS; } -- cgit v1.1-32-gdbae From 16c87ebc50974aac4f91b8e3649eec0d03300d6f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 17 Apr 2009 15:24:44 +0200 Subject: fix: don't free the connection in iphone_mux_free_client let it happen inside iphone_mux_pullbulk after append_receive_buffer --- iphone.c | 53 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/iphone.c b/iphone.c index 3c9a55e..c57df61 100644 --- a/iphone.c +++ b/iphone.c @@ -99,6 +99,8 @@ struct iphone_umux_client_int { // this will then be set to the error that caused the broken stream. // no further operations other than free_client will be allowed. iphone_error_t error; + + int cleanup; }; @@ -728,6 +730,7 @@ iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port, new_connection->wr_window = 0; add_connection(new_connection); new_connection->error = IPHONE_E_SUCCESS; + new_connection->cleanup = 0; hton_header(new_connection->header); log_debug_msg("%s: send_to_phone (%d --> %d)\n", __func__, ntohs(new_connection->header->sport), ntohs(new_connection->header->dport)); if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) { @@ -754,36 +757,33 @@ iphone_error_t iphone_mux_free_client(iphone_umux_client_t client) if (!client || !client->phone) return IPHONE_E_INVALID_ARG; - pthread_mutex_lock(&client->mutex); + iphone_error_t result = IPHONE_E_SUCCESS; + pthread_mutex_lock(&client->mutex); client->header->tcp_flags = TCP_FIN; client->header->length = 0x1C; client->header->window = 0; client->header->length16 = 0x1C; hton_header(client->header); - int bytes = 0; - bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800); - if (bytes < 0) - log_debug_msg("iphone_mux_free_client(): when writing, libusb gave me the error: %s\n", usb_strerror()); + if (send_to_phone(client->phone, (char*)client->header, sizeof(usbmux_tcp_header)) < 0) { + log_debug_msg("%s: error sending TCP_FIN\n", __func__); + result = IPHONE_E_UNKNOWN_ERROR; + } - bytes = usb_bulk_read(client->phone->device, BULKIN, (char *) client->header, sizeof(usbmux_tcp_header), 800); - if (bytes < 0) - log_debug_msg("get_iPhone(): when reading, libusb gave me the error: %s\n", usb_strerror()); - - pthread_mutex_unlock(&client->mutex); - // 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); + client->cleanup = 1; - delete_connection(client); + // 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); - return IPHONE_E_SUCCESS; -} + pthread_mutex_unlock(&client->mutex); + return result; +} /** Sends the given data over the selected connection. * @@ -1113,6 +1113,19 @@ int iphone_mux_pullbulk(iphone_device_t phone) // 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, == IPHONE_E_ECONNRESET + // might be a better check here + if (client->error != IPHONE_E SUCCESS) { + 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 -- cgit v1.1-32-gdbae From 0d6dba35a14197c387548116239982100f51402a Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 17 Apr 2009 15:30:03 +0200 Subject: damn typo --- iphone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iphone.c b/iphone.c index c57df61..ea8d3a3 100644 --- a/iphone.c +++ b/iphone.c @@ -1116,7 +1116,7 @@ int iphone_mux_pullbulk(iphone_device_t phone) // perhaps this is too general, == IPHONE_E_ECONNRESET // might be a better check here - if (client->error != IPHONE_E SUCCESS) { + if (client->error != IPHONE_E_SUCCESS) { pthread_mutex_lock(&client->mutex); if (client->cleanup) { pthread_mutex_unlock(&client->mutex); -- cgit v1.1-32-gdbae From 8743112105e2f5d1539a266f9e174c9895c7c2c5 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 17 Apr 2009 17:42:50 +0200 Subject: redirected some debugging output through log_debug_msg instead of printf --- iphone.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/iphone.c b/iphone.c index ea8d3a3..21b8281 100644 --- a/iphone.c +++ b/iphone.c @@ -474,28 +474,28 @@ int send_to_phone(iphone_device_t phone, char *data, int datalen) #endif do { if (retrycount > 3) { - fprintf(stderr, "EPIC FAIL! aborting on retry count overload.\n"); + log_debug_msg("EPIC FAIL! aborting on retry count overload.\n"); return -1; } bytes = usb_bulk_write(phone->device, BULKOUT, data, datalen, timeout); if (bytes == -ETIMEDOUT) { // timed out waiting for write. - fprintf(stderr, "usb_bulk_write timeout error.\n"); + log_debug_msg("usb_bulk_write timeout error.\n"); return bytes; } else if (bytes < 0) { - fprintf(stderr, "usb_bulk_write failed with error. err:%d (%s)(%s)\n", bytes, usb_strerror(), strerror(-bytes)); + log_debug_msg("usb_bulk_write failed with error. err:%d (%s)(%s)\n", bytes, usb_strerror(), strerror(-bytes)); return -1; } else if (bytes == 0) { - fprintf(stderr, "usb_bulk_write sent nothing. retrying.\n"); + log_debug_msg("usb_bulk_write sent nothing. retrying.\n"); timeout = timeout * 4; retrycount++; continue; } else if (bytes < datalen) { - fprintf(stderr, "usb_bulk_write failed to send full dataload. %d of %d\n", 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; @@ -946,20 +946,20 @@ uint32_t append_receive_buffer(iphone_umux_client_t client, char* packet) switch(data[0]) { case 0: // this is not an error, it's just a status message. - fprintf(stdout, "received status message: %s\n", e_msg); + log_debug_msg("received status message: %s\n", e_msg); datalen = 0; break; case 1: - fprintf(stderr, "received error message: %s\n", e_msg); + log_debug_msg("received error message: %s\n", e_msg); datalen = 0; break; default: - fprintf(stderr, "received unknown message (type 0x%02x): %s\n", data[0], e_msg); + 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 { - fprintf(stderr, "peer sent connection reset. setting error: %d\n", client->error); + log_debug_msg("peer sent connection reset. setting error: %d\n", client->error); } } @@ -1056,10 +1056,8 @@ iphone_umux_client_t find_client(usbmux_tcp_header* recv_header) */ int iphone_mux_pullbulk(iphone_device_t phone) { - if (!phone) { - fprintf(stderr, "iphone_mux_pullbulk: invalid argument\n"); + if (!phone) return -EINVAL; - } int res = 0; static const int DEFAULT_CAPACITY = 128*1024; @@ -1142,7 +1140,7 @@ int iphone_mux_pullbulk(iphone_device_t phone) // if there are no leftovers, we just leave the datastructure as is, // and re-use the block next time. if (phone->usbReceive.leftover > 0 && cursor != phone->usbReceive.buffer) { - fprintf(stderr, "%s: we got a leftover, so handle it\n", __func__); + log_debug_msg("%s: we got a leftover, so handle it\n", __func__); char* newbuff = malloc(DEFAULT_CAPACITY); memcpy(newbuff, cursor, phone->usbReceive.leftover); free(phone->usbReceive.buffer); -- cgit v1.1-32-gdbae From d54c5f4f0d87f76cf2a11fd88ec18cdbd67edaa2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 17 Apr 2009 17:43:59 +0200 Subject: Drop privileges after startup --- main.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index 157ecbb..8fb36ef 100644 --- a/main.c +++ b/main.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "usbmuxd-proto.h" #include "sock_stuff.h" @@ -1018,7 +1019,27 @@ int main(int argc, char **argv) lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; - fcntl(fileno(lfd), F_SETLK, &lock); + if (fcntl(fileno(lfd), F_SETLK, &lock) == -1) { + logmsg(LOG_ERR, "ERROR: lockfile locking failed!"); + } + } + + // drop elevated privileges + if (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 @@ -1137,7 +1158,7 @@ int main(int argc, char **argv) // unlock lock file and close it. if (lfd) { lock.l_type = F_UNLCK; - fcntl(fileno(lfd), F_SETLK, lock); + fcntl(fileno(lfd), F_SETLK, &lock); fclose(lfd); } -- cgit v1.1-32-gdbae From f88d5a5124b36f798f05f5524b54db4713d4beda Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 17 Apr 2009 18:14:03 +0200 Subject: more warning options --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 13a9914..cd3a0a0 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ TARGETS=usbmuxd libusbmuxd.so iproxy -CFLAGS=-I. -Wall -g -DDEBUG -fPIC +CFLAGS=-I. -g -DDEBUG -fPIC -Wall -Wextra -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter LIBS=-lpthread -lusb -lrt LDFLAGS=-L. INSTALL_PREFIX=/usr/local -- cgit v1.1-32-gdbae From 966872a569c7082b46fc94f9c446f24fb1969a2a Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 17 Apr 2009 18:14:16 +0200 Subject: removed some compiler warnings --- iphone.c | 45 +++++---------------------------------------- libusbmuxd.c | 6 +++--- main.c | 6 +++--- sock_stuff.c | 2 ++ 4 files changed, 13 insertions(+), 46 deletions(-) diff --git a/iphone.c b/iphone.c index 21b8281..c759899 100644 --- a/iphone.c +++ b/iphone.c @@ -314,7 +314,7 @@ iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_device_t // Set the device configuration for (bus = usb_get_busses(); bus; bus = bus->next) - if (bus->location == bus_n) + //if (bus->location == bus_n) for (dev = bus->devices; dev != NULL; dev = dev->next) if (dev->devnum == dev_n) { phone->__device = dev; @@ -374,41 +374,6 @@ iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_device_t return IPHONE_E_UNKNOWN_ERROR; // if it got to this point it's gotta be bad } - -/** - * Scans all USB busses and devices for a known AFC-compatible device and - * returns a handle to the first such device it finds. Known devices include - * those with vendor ID 0x05ac and product ID between 0x1290 and 0x1293 - * inclusive. - * - * This function is convenient, but on systems where higher-level abstractions - * (such as HAL) are available it may be preferable to use - * iphone_get_specific_device instead, because it can deal with multiple - * connected devices as well as devices not known to libiphone. - * - * @param device Upon calling this function, a pointer to a location of type - * iphone_device_t, which must have the value NULL. On return, this location - * will be filled with a handle to the device. - * @return IPHONE_E_SUCCESS if ok, otherwise an error code. - */ -iphone_error_t iphone_get_device(iphone_device_t * device) -{ - struct usb_bus *bus; - struct usb_device *dev; - - usb_init(); - usb_find_busses(); - usb_find_devices(); - - for (bus = usb_get_busses(); bus != NULL; bus = bus->next) - for (dev = bus->devices; dev != NULL; dev = dev->next) - if (dev->descriptor.idVendor == 0x05ac - && dev->descriptor.idProduct >= 0x1290 && dev->descriptor.idProduct <= 0x1293) - return iphone_get_specific_device(bus->location, dev->devnum, device); - - return IPHONE_E_NO_DEVICE; -} - /** Cleans up an iPhone structure, then frees the structure itself. * This is a library-level function; deals directly with the iPhone to tear * down relations, but otherwise is mostly internal. @@ -845,7 +810,7 @@ iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, ui ntoh_header(client->header); // update counts ONLY if the send succeeded. - if (sendresult == blocksize) { + if ((uint32_t)sendresult == blocksize) { // Re-calculate scnt client->header->scnt += datalen; client->wr_window -= blocksize; @@ -863,7 +828,7 @@ iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, ui else if (sendresult < 0) { return IPHONE_E_UNKNOWN_ERROR; } - else if (sendresult == blocksize) { + else if ((uint32_t)sendresult == blocksize) { // actual number of data bytes sent. *sent_bytes = sendresult - HEADERLEN; return IPHONE_E_SUCCESS; @@ -1097,7 +1062,7 @@ int iphone_mux_pullbulk(iphone_device_t phone) // 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 (phone->usbReceive.leftover < packetlen) { + if ((uint32_t)phone->usbReceive.leftover < packetlen) { fprintf(stderr, "%s: not enough data to construct a full packet\n", __func__); break; } @@ -1205,7 +1170,7 @@ iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, *recv_bytes = 0; if (client->recv_buffer != NULL && client->r_len > 0) { uint32_t foolen = datalen; - if (foolen > client->r_len) foolen = client->r_len; + if ((int)foolen > client->r_len) foolen = client->r_len; memcpy(data, client->recv_buffer, foolen); *recv_bytes = foolen; diff --git a/libusbmuxd.c b/libusbmuxd.c index c12a7c0..edd585c 100644 --- a/libusbmuxd.c +++ b/libusbmuxd.c @@ -28,7 +28,7 @@ static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result) return -errno; } else { if ((recv_len == sizeof(res)) - && (res.header.length == recv_len) + && (res.header.length == (uint32_t)recv_len) && (res.header.reserved == 0) && (res.header.type == USBMUXD_RESULT) ) { @@ -68,7 +68,7 @@ int usbmuxd_scan(usbmuxd_scan_result **available_devices) s_req.header.tag = 2; // send scan request packet - if (send_buf(sfd, &s_req, s_req.header.length) == s_req.header.length) { + 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)) { @@ -99,7 +99,7 @@ int usbmuxd_scan(usbmuxd_scan_result **available_devices) if (recv_len <= 0) { fprintf(stderr, "%s: Error when receiving device info record\n", __func__); break; - } else if (recv_len < pktlen) { + } 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); diff --git a/main.c b/main.c index 8fb36ef..c9bf884 100644 --- a/main.c +++ b/main.c @@ -95,7 +95,7 @@ static pthread_mutex_t usb_mutex = PTHREAD_MUTEX_INITIALIZER; * @param prio The logging priority. * @param format The message to be printed. */ -static void logmsg(int prio, char *format, ...) +static void logmsg(int prio, const char *format, ...) { va_list args; va_start(args, format); @@ -179,7 +179,7 @@ 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)) < sizeof(pktlen)) { + if (peek_buf(fd, &pktlen, sizeof(pktlen)) < (int)sizeof(pktlen)) { return -errno; } @@ -193,7 +193,7 @@ static int usbmuxd_get_request(int fd, void **data, size_t len) } recv_len = recv_buf(fd, *data, pktlen); - if ((recv_len > 0) && (recv_len < 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); } diff --git a/sock_stuff.c b/sock_stuff.c index 8a06135..43fdf0e 100644 --- a/sock_stuff.c +++ b/sock_stuff.c @@ -224,6 +224,8 @@ int check_fd(int fd, fd_mode fdm, unsigned int timeout) case FD_EXCEPT: sret = select(fd+1,NULL,NULL,&fds,&to); break; + default: + return -1; } if (sret < 0) { -- cgit v1.1-32-gdbae From f7a7b349947235a0fac57159e3883b05dd51db29 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 17 Apr 2009 18:43:22 +0200 Subject: removed unused function --- iphone.c | 13 +++---------- iphone.h | 1 - 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/iphone.c b/iphone.c index c759899..cd91b2e 100644 --- a/iphone.c +++ b/iphone.c @@ -1133,22 +1133,15 @@ iphone_error_t iphone_mux_get_error(iphone_umux_client_t client) return client->error; } -/** This is a higher-level USBMuxTCP-like function +/** This function reads from the client's recv_buffer. * - * @param connection The connection to receive data on. + * @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 IPHONE_E_SUCCESS or error code if failure. */ -iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes) -{ - return iphone_mux_recv_timeout(client, data, datalen, recv_bytes, 0); -} - -/** - @param timeout - */ iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout) { diff --git a/iphone.h b/iphone.h index fcef32a..9900b99 100644 --- a/iphone.h +++ b/iphone.h @@ -70,7 +70,6 @@ iphone_error_t iphone_mux_free_client ( iphone_umux_client_t client ); iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, uint32_t datalen, uint32_t * sent_bytes); -iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes); iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout); int iphone_mux_pullbulk(iphone_device_t phone); -- cgit v1.1-32-gdbae From 25273957cbfa16dc908c4a56f48f2c847d5e7ab2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 24 Apr 2009 18:40:11 +0200 Subject: 1. renamed iphone.c to usbmux.c and iphone.h to usbmux.h 2. renamed iphone* function to usbmux* 3. got rid of iphone_error_t type and constants 4. indentation adjustments --- Makefile | 6 +- iphone.c | 1190 -------------------------------------------------------------- iphone.h | 79 ----- main.c | 42 ++- usbmux.c | 1181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ usbmux.h | 51 +++ 6 files changed, 1255 insertions(+), 1294 deletions(-) delete mode 100644 iphone.c delete mode 100644 iphone.h create mode 100644 usbmux.c create mode 100644 usbmux.h diff --git a/Makefile b/Makefile index cd3a0a0..535e028 100644 --- a/Makefile +++ b/Makefile @@ -6,8 +6,8 @@ INSTALL_PREFIX=/usr/local all: $(TARGETS) -main.o: main.c usbmuxd-proto.h sock_stuff.h iphone.h -iphone.o: iphone.c iphone.h usbmuxd.h sock_stuff.h +main.o: main.c usbmuxd-proto.h sock_stuff.h usbmux.h +usbmux.o: usbmux.c usbmux.h usbmuxd.h sock_stuff.h sock_stuff.o: sock_stuff.c sock_stuff.h libusbmuxd.o: libusbmuxd.c usbmuxd.h usbmuxd-proto.h iproxy.o: iproxy.c sock_stuff.h @@ -19,7 +19,7 @@ libusbmuxd.so: libusbmuxd.o sock_stuff.o %.o: %.c $(CC) -o $@ $(CFLAGS) -c $< -usbmuxd: main.o sock_stuff.o iphone.o +usbmuxd: main.o sock_stuff.o usbmux.o $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) iproxy: iproxy.o diff --git a/iphone.c b/iphone.c deleted file mode 100644 index cd91b2e..0000000 --- a/iphone.c +++ /dev/null @@ -1,1190 +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 -#include -#include -#include -#include -#include -#include -#include -#include -#include "iphone.h" - -#define BULKIN 0x85 -#define BULKOUT 0x04 -#define HEADERLEN 28 - -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 iPhone. It keeps sending back 512 and seems to drop off a cliff -// when the phone gets overwhelmed. In addition, the phone 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 phone 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 iphone_device_int { - char *buffer; - struct usb_dev_handle *device; - struct usb_device *__device; - receivebuf_t usbReceive; -}; - -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 iphone_umux_client_int { - usbmux_tcp_header *header; - iphone_device_t phone; - - 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 phone. - 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. - iphone_error_t error; - - int cleanup; -}; - - -static pthread_mutex_t iphonemutex = PTHREAD_MUTEX_INITIALIZER; -static iphone_umux_client_t *connlist = NULL; -static int clients = 0; - - -/** - */ -int toto_debug = 0; - -void iphone_set_debug(int e) -{ - toto_debug = e; -} - -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) - vfprintf(stderr, format, args); - - va_end(args); - -#endif -} - -#ifdef DEBUG -/** - * for debugging purposes. - */ -static void print_buffer(const char *data, const int length) -{ - if (toto_debug > 0) { - int i; - int j; - unsigned char c; - - for(i=0; i= 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"); - } -} -#endif - -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); - } -} - -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 - */ -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 phone which device to configure - */ -static iphone_error_t iphone_config_usb_device(iphone_device_t phone) -{ - int ret; - int bytes; - char buf[512]; - -#if 0 - log_debug_msg("checking configuration...\n"); - if (phone->__device->config->bConfigurationValue != 3) { - log_debug_msg("WARNING: usb device configuration is not 3 as expected!\n"); - } - - log_debug_msg("setting configuration...\n"); - ret = usb_set_configuration(phone->device, 3); - if (ret != 0) { - log_debug_msg("Hm, usb_set_configuration returned %d: %s\n", ret, strerror(-ret)); -#if LIBUSB_HAS_GET_DRIVER_NP - log_debug_msg("trying to fix:\n"); - log_debug_msg("-> detaching kernel driver... "); - ret = usb_detach_kernel_driver_np(phone->device, phone->__device->config->interface->altsetting->bInterfaceNumber); - if (ret != 0) { - log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", ret, strerror(-ret)); - } else { - log_debug_msg("done.\n"); - log_debug_msg("setting configuration again... "); - ret = usb_set_configuration(phone->device, 3); - if (ret != 0) { - log_debug_msg("Error: usb_set_configuration returned %d: %s\n", ret, strerror(-ret)); - log_debug_msg("--> trying to continue anyway...\n"); - } else { - log_debug_msg("done.\n"); - } - } -#else - log_debug_msg("--> trying to continue anyway...\n"); -#endif - } else { - log_debug_msg("done.\n"); - } -#endif - - log_debug_msg("claiming interface... "); - ret = usb_claim_interface(phone->device, 1); - if (ret != 0) { - log_debug_msg("Error: usb_claim_interface returned %d: %s\n", ret, strerror(-ret)); - return IPHONE_E_NO_DEVICE; - } else { - log_debug_msg("done.\n"); - } - - do { - bytes = usb_bulk_read(phone->device, BULKIN, buf, 512, 800); - } while (bytes > 0); - - return IPHONE_E_SUCCESS; -} - -/** - * Given a USB bus and device number, returns a device handle to the iPhone 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 - * iphone_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 iphone_device_t, which must be set to NULL upon - * calling iphone_get_specific_device, which will be filled with a device - * descriptor on return. - * @return IPHONE_E_SUCCESS if ok, otherwise an error code. - */ -iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_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 IPHONE_E_INVALID_ARG; - - iphone_device_t phone = (iphone_device_t) malloc(sizeof(struct iphone_device_int)); - - // Initialize the struct - phone->device = NULL; - phone->__device = NULL; - phone->buffer = NULL; - - // don't forget these: - phone->usbReceive.buffer = NULL; - phone->usbReceive.leftover = 0; - phone->usbReceive.capacity = 0; - - // Initialize libusb - usb_init(); - usb_find_busses(); - usb_find_devices(); - - // Set the device configuration - for (bus = usb_get_busses(); bus; bus = bus->next) - //if (bus->location == bus_n) - for (dev = bus->devices; dev != NULL; dev = dev->next) - if (dev->devnum == dev_n) { - phone->__device = dev; - phone->device = usb_open(phone->__device); - if (iphone_config_usb_device(phone) == IPHONE_E_SUCCESS) { - goto found; - } - } - - iphone_free_device(phone); - - log_debug_msg("iphone_get_specific_device: iPhone not found\n"); - return IPHONE_E_NO_DEVICE; - - found: - // Send the version command to the phone - version = version_header(); - bytes = usb_bulk_write(phone->device, BULKOUT, (char *) version, sizeof(*version), 800); - if (bytes < 20) { - log_debug_msg("get_iPhone(): libusb did NOT send enough!\n"); - if (bytes < 0) { - log_debug_msg("get_iPhone(): libusb gave me the error %d: %s (%s)\n", - bytes, usb_strerror(), strerror(-bytes)); - } - } - // Read the phone's response - bytes = usb_bulk_read(phone->device, BULKIN, (char *) version, sizeof(*version), 800); - - // Check for bad response - if (bytes < 20) { - free(version); - iphone_free_device(phone); - log_debug_msg("get_iPhone(): Invalid version message -- header too short.\n"); - if (bytes < 0) - log_debug_msg("get_iPhone(): libusb error message %d: %s (%s)\n", bytes, usb_strerror(), strerror(-bytes)); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Check for correct version - if (ntohl(version->major) == 1 && ntohl(version->minor) == 0) { - // We're all ready to roll. - log_debug_msg("get_iPhone() success\n"); - free(version); - *device = phone; - return IPHONE_E_SUCCESS; - } else { - // Bad header - iphone_free_device(phone); - free(version); - log_debug_msg("get_iPhone(): Received a bad header/invalid version number."); - return IPHONE_E_BAD_HEADER; - } - - // If it got to this point it's gotta be bad - log_debug_msg("get_iPhone(): Unknown error.\n"); - iphone_free_device(phone); - free(version); - return IPHONE_E_UNKNOWN_ERROR; // if it got to this point it's gotta be bad -} - -/** Cleans up an iPhone structure, then frees the structure itself. - * This is a library-level function; deals directly with the iPhone to tear - * down relations, but otherwise is mostly internal. - * - * @param phone A pointer to an iPhone structure. - */ -iphone_error_t iphone_free_device(iphone_device_t device) -{ - char buf[512]; - int bytes; - - if (!device) - return IPHONE_E_INVALID_ARG; - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - - if (device->device) { - do { - bytes = usb_bulk_read(device->device, BULKIN, buf, 512, 800); - } while (bytes > 0); - } - - if (device->buffer) { - free(device->buffer); - } - if (device->usbReceive.buffer) { - free(device->usbReceive.buffer); - } - if (device->device) { - usb_release_interface(device->device, 1); - usb_close(device->device); - ret = IPHONE_E_SUCCESS; - } - free(device); - - return ret; -} - - - -/** Sends data to the phone - * This is a low-level (i.e. directly to phone) function. - * - * @param phone The iPhone to send data to - * @param data The data to send to the iPhone - * @param datalen The length of the data - * @return The number of bytes sent, or -ERRNO on error - */ -int send_to_phone(iphone_device_t phone, char *data, int datalen) -{ - if (!phone) - return -1; - - int timeout = 1000; - int retrycount = 0; - int bytes = 0; - -#ifdef DEBUG - #ifdef DEBUG_MORE - printf("===============================\n%s: trying to send\n", __func__); - print_buffer(data, datalen); - printf("===============================\n"); - #endif -#endif - do { - if (retrycount > 3) { - log_debug_msg("EPIC FAIL! aborting on retry count overload.\n"); - return -1; - } - - bytes = usb_bulk_write(phone->device, 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 -1; - } - 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; - } - } - while(0); // fall out - -#ifdef DEBUG - if (bytes > 0) { - if (toto_debug > 0) { - printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); - printf("%s: sent to phone\n", __func__); - print_buffer(data, bytes); - printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); - } - } -#endif - return bytes; -} - -/** Receives data from the phone - * This function is a low-level (i.e. direct from iPhone) function. - * - * @param phone The iPhone 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. - */ -int recv_from_phone_timeout(iphone_device_t phone, char *data, int datalen, int timeoutmillis) -{ - if (!phone) - return -EINVAL; - //log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen); - - int bytes = usb_bulk_read(phone->device, 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, "recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), strerror(-bytes)); - log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), strerror(-bytes)); - } - return bytes; - } - -#ifdef DEBUG - if (bytes > 0) { - if (toto_debug > 0) { - printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); - printf("%s: received from phone:\n", __func__); - print_buffer(data, bytes); - printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); - } - } -#endif - - 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 - */ -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 = HEADERLEN; - 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 = HEADERLEN; - 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(iphone_umux_client_t connection) -{ - iphone_umux_client_t *newlist = NULL; - - pthread_mutex_lock(&iphonemutex); - - // update the global list of connections - if (clients > 1) { - newlist = (iphone_umux_client_t *) malloc(sizeof(iphone_umux_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); - if (connection->header) - free(connection->header); - connection->r_len = 0; - pthread_mutex_unlock(&connection->mutex); - pthread_mutex_destroy(&connection->mutex); - free(connection); - - pthread_mutex_unlock(&iphonemutex); -} - -/** 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(iphone_umux_client_t connection) -{ - pthread_mutex_lock(&iphonemutex); - iphone_umux_client_t *newlist = - (iphone_umux_client_t *) realloc(connlist, sizeof(iphone_umux_client_t) * (clients + 1)); - newlist[clients] = connection; - connlist = newlist; - clients++; - pthread_mutex_unlock(&iphonemutex); -} - -/** - * 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(&iphonemutex); - 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(&iphonemutex); - - return newport; -} - -/** Initializes a connection on phone, with source port s_port and destination port d_port - * - * @param device The iPhone 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 IPHONE_E_SUCCESS on success, an error code otherwise. - */ -iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port, uint16_t dst_port, - iphone_umux_client_t * client) -{ - if (!device || !dst_port) - return IPHONE_E_INVALID_ARG; - - 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 - iphone_umux_client_t new_connection = (iphone_umux_client_t) malloc(sizeof(struct iphone_umux_client_int)); - new_connection->header = new_mux_packet(src_port, dst_port); - - // send TCP syn - if (new_connection && new_connection->header) { - 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->phone = 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 = IPHONE_E_SUCCESS; - new_connection->cleanup = 0; - hton_header(new_connection->header); - log_debug_msg("%s: send_to_phone (%d --> %d)\n", __func__, ntohs(new_connection->header->sport), ntohs(new_connection->header->dport)); - if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) { - *client = new_connection; - return IPHONE_E_SUCCESS; - } else { - delete_connection(new_connection); - return IPHONE_E_NOT_ENOUGH_DATA; - } - } - // if we get to this point it's probably bad - return IPHONE_E_UNKNOWN_ERROR; -} - -/** 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 IPHONE_E_SUCCESS on success. - */ -iphone_error_t iphone_mux_free_client(iphone_umux_client_t client) -{ - if (!client || !client->phone) - return IPHONE_E_INVALID_ARG; - - iphone_error_t result = IPHONE_E_SUCCESS; - pthread_mutex_lock(&client->mutex); - client->header->tcp_flags = TCP_FIN; - client->header->length = 0x1C; - client->header->window = 0; - client->header->length16 = 0x1C; - hton_header(client->header); - - if (send_to_phone(client->phone, (char*)client->header, sizeof(usbmux_tcp_header)) < 0) { - log_debug_msg("%s: error sending TCP_FIN\n", __func__); - result = IPHONE_E_UNKNOWN_ERROR; - } - - 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 phone The iPhone to send to. - * @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 IPHONE_E_SUCCESS on success. - */ -iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, uint32_t datalen, uint32_t * sent_bytes) -{ - if (!client->phone || !client || !sent_bytes) - return IPHONE_E_INVALID_ARG; - - if (client->error != IPHONE_E_SUCCESS) { - 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) { - // timd 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_phone(%d --> %d)\n", __func__, ntohs(client->header->sport), ntohs(client->header->dport)); - sendresult = send_to_phone(client->phone, 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 IPHONE_E_TIMEOUT; - } - else if (sendresult < 0) { - return IPHONE_E_UNKNOWN_ERROR; - } - else if ((uint32_t)sendresult == blocksize) { - // actual number of data bytes sent. - *sent_bytes = sendresult - HEADERLEN; - return IPHONE_E_SUCCESS; - } - else { - fprintf(stderr, "usbsend managed to dump a packet that is not full size. %d of %d\n", - sendresult, blocksize); - return IPHONE_E_UNKNOWN_ERROR; - } -} - -/** 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) - */ -uint32_t append_receive_buffer(iphone_umux_client_t client, char* packet) -{ - if (client == NULL || packet == NULL) return 0; - - usbmux_tcp_header *header = (usbmux_tcp_header *) packet; - char* data = &packet[HEADERLEN]; - uint32_t packetlen = ntohl(header->length); - uint32_t datalen = packetlen-HEADERLEN; - - 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_phone (%d --> %d)\n", __func__, ntohs(client->header->sport), ntohs(client->header->dport)); - if (send_to_phone(client->phone, (char *)client->header, sizeof(usbmux_tcp_header)) <= 0) { - log_debug_msg("%s: error when pushing to usb...\n", __func__); - } - // need to revert some of the fields back to host notation. - ntoh_header(client->header); - } - else { - client->error = IPHONE_E_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 = IPHONE_E_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 phone starts to drop below this number, we quickly fall - // into connection reset problems. Once we see the reported window size - // start falling off, cut 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. - */ -iphone_umux_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. - iphone_umux_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(&iphonemutex); - 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(&iphonemutex); - - return retval; -} - -/** pull in a big USB bulk packet and distribute it to queues appropriately. - */ -int iphone_mux_pullbulk(iphone_device_t phone) -{ - if (!phone) - return -EINVAL; - - int res = 0; - static const int DEFAULT_CAPACITY = 128*1024; - if (phone->usbReceive.buffer == NULL) { - phone->usbReceive.capacity = DEFAULT_CAPACITY; - phone->usbReceive.buffer = malloc(phone->usbReceive.capacity); - phone->usbReceive.leftover = 0; - } - - // start the cursor off just ahead of the leftover. - char* cursor = &phone->usbReceive.buffer[phone->usbReceive.leftover]; - // pull in content, note that the amount we can pull is capacity minus leftover - int readlen = recv_from_phone_timeout(phone, cursor, phone->usbReceive.capacity - phone->usbReceive.leftover, 3000); - if (readlen < 0) { - res = readlen; - //fprintf(stderr, "recv_from_phone_timeout gave us an error.\n"); - readlen = 0; - } - if (readlen > 0) { - //fprintf(stdout, "recv_from_phone_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 - phone->usbReceive.leftover += readlen; - - // reset the cursor to the front of that buffer and work through - // trying to decode packets out of them. - cursor = phone->usbReceive.buffer; - while (1) { - // check if there's even sufficient data to decode a header - if (phone->usbReceive.leftover < HEADERLEN) break; - usbmux_tcp_header *header = (usbmux_tcp_header *) cursor; - - log_debug_msg("%s: recv_from_phone_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)phone->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. - iphone_umux_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, == IPHONE_E_ECONNRESET - // might be a better check here - if (client->error != IPHONE_E_SUCCESS) { - 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; - phone->usbReceive.leftover -= packetlen; - } - - // now, we need to manage any leftovers. - // I'm going to manage the leftovers by alloc'ing a new block and copying - // the 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 (phone->usbReceive.leftover > 0 && cursor != phone->usbReceive.buffer) { - log_debug_msg("%s: we got a leftover, so handle it\n", __func__); - char* newbuff = malloc(DEFAULT_CAPACITY); - memcpy(newbuff, cursor, phone->usbReceive.leftover); - free(phone->usbReceive.buffer); - phone->usbReceive.buffer = newbuff; - phone->usbReceive.capacity = DEFAULT_CAPACITY; - } - - return res; -} - -/** - * return the error code stored in iphone_umux_client_t structure, - * e.g. non-zero when an usb read error occurs. - * - * @param client the umux client - * - * @return IPHONE_E_* error codes. - */ -iphone_error_t iphone_mux_get_error(iphone_umux_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 IPHONE_E_SUCCESS or error code if failure. - */ -iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout) -{ - - if (!client || !data || datalen == 0 || !recv_bytes) - return IPHONE_E_INVALID_ARG; - - if (client->error != IPHONE_E_SUCCESS) 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; //millis * 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 IPHONE_E_SUCCESS; -} diff --git a/iphone.h b/iphone.h deleted file mode 100644 index 9900b99..0000000 --- a/iphone.h +++ /dev/null @@ -1,79 +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 __IPHONE_H__ -#define __IPHONE_H__ - -#include -#include -#include - -//general errors -#define IPHONE_E_SUCCESS 0 -#define IPHONE_E_INVALID_ARG -1 -#define IPHONE_E_UNKNOWN_ERROR -2 -#define IPHONE_E_NO_DEVICE -3 -#define IPHONE_E_TIMEOUT -4 -#define IPHONE_E_NOT_ENOUGH_DATA -5 -#define IPHONE_E_BAD_HEADER -6 - -//lockdownd specific error -#define IPHONE_E_INVALID_CONF -7 -#define IPHONE_E_PAIRING_FAILED -8 -#define IPHONE_E_SSL_ERROR -9 -#define IPHONE_E_PLIST_ERROR -10 -#define IPHONE_E_DICT_ERROR -11 - -//afc specific error -#define IPHONE_E_NO_SUCH_FILE -12 - -//general TCP-style errors and conditions -#define IPHONE_E_ECONNABORTED -ECONNABORTED -#define IPHONE_E_ECONNRESET -ECONNRESET -#define IPHONE_E_ENOTCONN -ENOTCONN -#define IPHONE_E_ESHUTDOWN -ESHUTDOWN -#define IPHONE_E_ETIMEDOUT -ETIMEDOUT -#define IPHONE_E_ECONNREFUSED -ECONNREFUSED - -void iphone_set_debug(int e); - -typedef int16_t iphone_error_t; - -struct iphone_device_int; -typedef struct iphone_device_int *iphone_device_t; - -struct iphone_umux_client_int; -typedef struct iphone_umux_client_int *iphone_umux_client_t; - -iphone_error_t iphone_get_device ( iphone_device_t *device ); -iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_device_t * device); -iphone_error_t iphone_free_device ( iphone_device_t device ); - - -iphone_error_t iphone_mux_new_client ( iphone_device_t device, uint16_t src_port, uint16_t dst_port, iphone_umux_client_t *client ); -iphone_error_t iphone_mux_free_client ( iphone_umux_client_t client ); - -iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, uint32_t datalen, uint32_t * sent_bytes); - -iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout); - -int iphone_mux_pullbulk(iphone_device_t phone); - -iphone_error_t iphone_mux_get_error(iphone_umux_client_t client); - -#endif diff --git a/main.c b/main.c index c9bf884..43f0425 100644 --- a/main.c +++ b/main.c @@ -42,7 +42,7 @@ #include "usbmuxd-proto.h" #include "sock_stuff.h" -#include "iphone.h" +#include "usbmux.h" #define DEFAULT_TIMEOUT 4000 #define DEFAULT_CHILDREN_CAPACITY 10 @@ -60,11 +60,11 @@ static int exit_on_no_devices = 0; struct device_info { uint32_t device_id; - iphone_device_t phone; + usbmux_device_t phone; int use_count; pthread_t bulk_reader; pthread_mutex_t mutex; - /* mutex for mutual exclusion of calling the iphone_mux_send function + /* 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; }; @@ -80,7 +80,7 @@ struct client_data { int reader_dead; int handler_dead; int connected; - iphone_umux_client_t muxclient; + usbmux_client_t muxclient; struct device_info *dev; }; @@ -249,7 +249,7 @@ static void *usbmuxd_client_reader_thread(void *arg) char rbuffer[512]; uint32_t rbuffersize = 512; uint32_t rlen; - iphone_error_t err; + int err; char *cursor; ssize_t len; int result; @@ -276,7 +276,7 @@ static void *usbmuxd_client_reader_thread(void *arg) } rlen = 0; - err = iphone_mux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, &rlen, DEFAULT_TIMEOUT); + err = usbmux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, &rlen, DEFAULT_TIMEOUT); if (err != 0) { if (verbose >= 2) logmsg(LOG_ERR, "%s[%d:%d]: encountered USB read error: %d", __func__, cdata->dev->device_id, cdata->dev->use_count, err); break; @@ -327,7 +327,7 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) int err_code; ssize_t maxlen = 512; uint32_t rlen; - iphone_error_t err; + int err; if (!cdata) { if (verbose >= 2) logmsg(LOG_ERR, "%s: Invalid client_data provided!", __func__); @@ -342,8 +342,8 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) } } else { result = 0; - err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, 100); - if (err != 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; @@ -390,7 +390,7 @@ static void *usbmuxd_client_handler_thread(void *arg) ssize_t len; ssize_t maxlen = sizeof(buffer); uint32_t wlen; - iphone_error_t err; + int err; if (!arg) { if (verbose >= 2) logmsg(LOG_ERR, "%s: invalid client_data provided!", __func__); @@ -441,10 +441,10 @@ static void *usbmuxd_client_handler_thread(void *arg) pthread_mutex_lock(&cdata->dev->writer_mutex); do { wlen = 0; - err = iphone_mux_send(cdata->muxclient, cursor, len, &wlen); - if (err == IPHONE_E_TIMEOUT) { + err = usbmux_send(cdata->muxclient, cursor, len, &wlen); + if (err == -ETIMEDOUT) { // some kind of timeout... just be patient and retry. - } else if (err != IPHONE_E_SUCCESS) { + } else if (err < 0) { if (verbose >= 2) logmsg(LOG_ERR, "%s[%d:%d]: USB write error: %d", __func__, cdata->dev->device_id, cdata->dev->use_count, err); len = -1; break; @@ -502,7 +502,7 @@ static void *usbmuxd_bulk_reader_thread(void *arg) } pthread_mutex_unlock(&cur_dev->mutex); - if ((err = iphone_mux_pullbulk(cur_dev->phone)) < 0) { + if ((err = usbmux_pullbulk(cur_dev->phone)) < 0) { if (verbose >= 1) logmsg(LOG_ERR, "%s: error %d when reading from device", __func__, err); break; } @@ -532,10 +532,8 @@ static void *usbmuxd_client_init_thread(void *arg) int found = 0; int res; int i; -// int sent_result; -// iphone_error_t err; - iphone_device_t phone = NULL; + usbmux_device_t phone = NULL; struct device_info *cur_dev = NULL; if (!arg) { @@ -667,7 +665,7 @@ connect: if (verbose >= 2) logmsg(LOG_NOTICE, "%s[%x]: creating new usb connection, device_id=%d", __func__, THREAD, c_req->device_id); pthread_mutex_lock(&usb_mutex); - if (iphone_get_specific_device(0, c_req->device_id, &phone) != IPHONE_E_SUCCESS) { + if (usbmux_get_specific_device(0, c_req->device_id, &phone) < 0) { pthread_mutex_unlock(&usb_mutex); pthread_mutex_unlock(&usbmux_mutex); if (verbose >= 1) logmsg(LOG_ERR, "%s[%x]: device_id %d could not be opened", __func__, THREAD, c_req->device_id); @@ -702,7 +700,7 @@ connect: // setup connection to iPhone/iPod // pthread_mutex_lock(&usbmux_mutex); - res = iphone_mux_new_client(cur_dev->phone, 0, ntohs(c_req->tcp_dport), &(cdata->muxclient)); + res = usbmux_new_client(cur_dev->phone, 0, ntohs(c_req->tcp_dport), &(cdata->muxclient)); // pthread_mutex_unlock(&usbmux_mutex); if (res != 0) { @@ -737,7 +735,7 @@ connect: // time to clean up if (cdata && cdata->muxclient) { // should be non-NULL - iphone_mux_free_client(cdata->muxclient); + usbmux_free_client(cdata->muxclient); } leave: @@ -768,7 +766,7 @@ leave: pthread_join(cur_dev->bulk_reader, NULL); } pthread_mutex_lock(&usb_mutex); - iphone_free_device(cur_dev->phone); + usbmux_free_device(cur_dev->phone); pthread_mutex_unlock(&usb_mutex); pthread_mutex_destroy(&cur_dev->writer_mutex); pthread_mutex_destroy(&cur_dev->mutex); @@ -1001,7 +999,7 @@ int main(int argc, char **argv) chmod(USBMUXD_SOCKET_FILE, 0666); - if (verbose >= 3) iphone_set_debug(1); + if (verbose >= 3) usbmux_set_debug(1); if (!foreground) { if (daemonize() < 0) { diff --git a/usbmux.c b/usbmux.c new file mode 100644 index 0000000..0a175ed --- /dev/null +++ b/usbmux.c @@ -0,0 +1,1181 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "usbmux.h" + +#define BULKIN 0x85 +#define BULKOUT 0x04 +#define HEADERLEN 28 + +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 { + char *buffer; + struct usb_dev_handle *usbdev; + struct usb_device *__device; + receivebuf_t usbReceive; +}; + +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; +}; + + +static pthread_mutex_t usbmuxmutex = 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; +} + +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) + vfprintf(stderr, format, args); + + va_end(args); +#endif +} + +#ifdef DEBUG +/** + * 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) { + 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"); +} +#endif + +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); + } +} + +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 + */ +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]; + +#if 0 + log_debug_msg("checking configuration...\n"); + if (device->__device->config->bConfigurationValue != 3) { + log_debug_msg("WARNING: usb device configuration is not 3 as expected!\n"); + } + + log_debug_msg("setting configuration...\n"); + ret = usb_set_configuration(device->device, 3); + if (ret != 0) { + log_debug_msg("Hm, usb_set_configuration returned %d: %s\n", ret, strerror(-ret)); +#if LIBUSB_HAS_GET_DRIVER_NP + log_debug_msg("trying to fix:\n"); + log_debug_msg("-> detaching kernel driver... "); + ret = usb_detach_kernel_driver_np(device->device, device->__device->config->interface->altsetting->bInterfaceNumber); + if (ret != 0) { + log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", ret, strerror(-ret)); + } else { + log_debug_msg("done.\n"); + log_debug_msg("setting configuration again... "); + ret = usb_set_configuration(device->device, 3); + if (ret != 0) { + log_debug_msg("Error: usb_set_configuration returned %d: %s\n", ret, strerror(-ret)); + log_debug_msg("--> trying to continue anyway...\n"); + } else { + log_debug_msg("done.\n"); + } + } +#else + log_debug_msg("--> trying to continue anyway...\n"); +#endif + } else { + log_debug_msg("done.\n"); + } +#endif + + 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"); + } + + 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; + newdevice->buffer = NULL; + + // don't forget these: + newdevice->usbReceive.buffer = NULL; + newdevice->usbReceive.leftover = 0; + newdevice->usbReceive.capacity = 0; + + // Initialize libusb + usb_init(); + usb_find_busses(); + usb_find_devices(); + + // Set the device configuration + for (bus = usb_get_busses(); bus; bus = bus->next) + //if (bus->location == bus_n) + for (dev = bus->devices; dev != NULL; dev = dev->next) + if (dev->devnum == dev_n) { + newdevice->__device = dev; + newdevice->usbdev = usb_open(newdevice->__device); + 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; + + 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->buffer) { + free(device->buffer); + } + 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 + */ +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; + +#ifdef DEBUG + #ifdef DEBUG_MORE + printf("===============================\n%s: trying to send\n", __func__); + print_buffer(data, datalen); + printf("===============================\n"); + #endif +#endif + 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; + } + } while(0); // fall out + +#ifdef DEBUG + if (bytes > 0) { + if (toto_debug > 0) { + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + printf("%s: sent to device\n", __func__); + print_buffer(data, bytes); + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + } + } +#endif + 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. + */ +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; + } + +#ifdef DEBUG + if (bytes > 0) { + if (toto_debug > 0) { + printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + printf("%s: received from device:\n", __func__); + print_buffer(data, bytes); + printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + } + } +#endif + + 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 + */ +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 = HEADERLEN; + 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 = HEADERLEN; + 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); + if (connection->header) + free(connection->header); + 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; + 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_FIN; + 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 - HEADERLEN; + 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) + */ +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[HEADERLEN]; + uint32_t packetlen = ntohl(header->length); + uint32_t datalen = packetlen-HEADERLEN; + + 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__); + } + // 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. + */ +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 < HEADERLEN) + 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; +} diff --git a/usbmux.h b/usbmux.h new file mode 100644 index 0000000..2bcdb15 --- /dev/null +++ b/usbmux.h @@ -0,0 +1,51 @@ +/* + * 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 +#include +//#include + + +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); + +#endif -- cgit v1.1-32-gdbae From ce4b528e203a67cbc3c8c2950b237b8fd1a41bed Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 25 Apr 2009 06:24:05 +0200 Subject: indent -kr -ut --- libusbmuxd.c | 138 +++-- main.c | 1875 ++++++++++++++++++++++++++++++++-------------------------- sock_stuff.c | 470 ++++++++------- sock_stuff.h | 15 +- usbmux.c | 325 ++++++---- 5 files changed, 1559 insertions(+), 1264 deletions(-) diff --git a/libusbmuxd.c b/libusbmuxd.c index edd585c..c8acbf8 100644 --- a/libusbmuxd.c +++ b/libusbmuxd.c @@ -14,37 +14,37 @@ // socket utility functions #include "sock_stuff.h" -static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result) +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; + 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) +int usbmuxd_scan(usbmuxd_scan_result ** available_devices) { struct usbmuxd_scan_request s_req; int sfd; @@ -68,13 +68,16 @@ int usbmuxd_scan(usbmuxd_scan_result **available_devices) s_req.header.tag = 2; // send scan request packet - if (send_buf(sfd, &s_req, s_req.header.length) == (int)s_req.header.length) { + 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__); + fprintf(stderr, + "%s: Did not get response to scan request (with result=0)...\n", + __func__); close(sfd); return res; } @@ -91,29 +94,45 @@ int usbmuxd_scan(usbmuxd_scan_result **available_devices) 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); + 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__); + 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 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)); + 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)); + 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__); + fprintf(stderr, + "%s: ERROR: out of memory when trying to realloc!\n", + __func__); break; } } @@ -125,8 +144,11 @@ int usbmuxd_scan(usbmuxd_scan_result **available_devices) } // 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)); + 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; @@ -141,31 +163,33 @@ int usbmuxd_connect(const int handle, const unsigned short tcp_port) 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; + 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.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"); + 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); + // 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) { @@ -173,6 +197,6 @@ int usbmuxd_connect(const int handle, const unsigned short tcp_port) } close(sfd); - + return -1; } diff --git a/main.c b/main.c index 43f0425..e7292cc 100644 --- a/main.c +++ b/main.c @@ -59,29 +59,29 @@ static int foreground = 0; static int exit_on_no_devices = 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; + 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; + 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; @@ -97,69 +97,77 @@ static pthread_mutex_t usb_mutex = PTHREAD_MUTEX_INITIALIZER; */ 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; + 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); } - strcpy(msgbuf, "usbmuxd: "); - vsnprintf(msgbuf+9, 244, format, args); - strcat(msgbuf, "\n"); - fputs(msgbuf, lfp); - } - va_end(args); + va_end(args); } #ifdef DEBUG /** * for debugging purposes. */ -static void print_buffer(FILE *fp, const char *data, const int length) +static void print_buffer(FILE * fp, const char *data, const int length) { - int i; + int i; int j; unsigned char c; - for(i=0; i= 4) fprintf(fp, "%04x: ", i); - for (j=0;j<16;j++) { - if (i+j >= length) { - if (verbose >= 4) fprintf(fp, " "); + 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, "%02hhx ", *(data + i + j)); } - if (verbose >= 4) fprintf(fp, " | "); - for(j=0;j<16;j++) { - if (i+j >= length) + if (verbose >= 4) + fprintf(fp, " | "); + for (j = 0; j < 16; j++) { + if (i + j >= length) break; - c = *(data+i+j); + c = *(data + i + j); if ((c < 32) || (c > 127)) { - if (verbose >= 4) fprintf(fp, "."); + if (verbose >= 4) + fprintf(fp, "."); continue; } - if (verbose >= 4) fprintf(fp, "%c", c); + if (verbose >= 4) + fprintf(fp, "%c", c); } - if (verbose >= 4) fprintf(fp, "\n"); + if (verbose >= 4) + fprintf(fp, "\n"); } - if (verbose >= 4) fprintf(fp, "\n"); + if (verbose >= 4) + fprintf(fp, "\n"); } #endif @@ -176,35 +184,40 @@ static void print_buffer(FILE *fp, const char *data, const int length) */ 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); - } + 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); - } + if (*data && (recv_len > 0) && verbose >= 4) { + fprintf(stderr, "%s: received:\n", __func__); + print_buffer(stderr, *data, recv_len); + } #endif - return recv_len; + return recv_len; } /** @@ -218,20 +231,22 @@ static int usbmuxd_get_request(int fd, void **data, size_t len) */ 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; + 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; } /** @@ -244,69 +259,84 @@ static int usbmuxd_send_result(int fd, uint32_t tag, uint32_t result_code) */ 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; - } + 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 = (struct client_data *) arg; - cdata->reader_dead = 0; + cdata->reader_dead = 0; - if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%d:%d]: started", __func__, cdata->dev->device_id, cdata->dev->use_count); + if (verbose >= 3) + logmsg(LOG_NOTICE, "%s[%d:%d]: started", __func__, + cdata->dev->device_id, 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; - } + 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[%d:%d]: encountered USB read error: %d", __func__, cdata->dev->device_id, cdata->dev->use_count, err); - break; - } + rlen = 0; + err = + usbmux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, + &rlen, DEFAULT_TIMEOUT); + if (err != 0) { + if (verbose >= 2) + logmsg(LOG_ERR, + "%s[%d:%d]: encountered USB read error: %d", + __func__, cdata->dev->device_id, + cdata->dev->use_count, 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; + 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); } - fsync(cdata->socket); - } - if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%d:%d]: terminated", __func__, cdata->dev->device_id, cdata->dev->use_count); + if (verbose >= 3) + logmsg(LOG_NOTICE, "%s[%d:%d]: terminated", __func__, + cdata->dev->device_id, cdata->dev->use_count); - cdata->reader_dead = 1; + cdata->reader_dead = 1; - return NULL; + return NULL; } /** @@ -321,60 +351,73 @@ static void *usbmuxd_client_reader_thread(void *arg) */ 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; + 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; } - } 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; + + 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 { - 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; - } + 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 { - // send success result - usbmuxd_send_result(cdata->socket, cdata->tag, 0); - // and the server greeting message - send_buf(cdata->socket, buffer, rlen); + 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); + } } - } else { - // no server greeting? this seems to be ok. send success. - usbmuxd_send_result(cdata->socket, cdata->tag, 0); - } + //fsync(cdata->socket); } - //fsync(cdata->socket); - } - return result; + return result; } /** @@ -383,96 +426,115 @@ static int usbmuxd_handleConnectResult(struct client_data *cdata) */ static void *usbmuxd_client_handler_thread(void *arg) { - struct client_data *cdata; - int result; - char *cursor; - char buffer[65536]; - 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[%d:%d]: started", __func__, cdata->dev->device_id,cdata->dev->use_count); + struct client_data *cdata; + int result; + char *cursor; + char buffer[65536]; + 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; + } - if (usbmuxd_handleConnectResult(cdata)) { - if (verbose >= 3) logmsg(LOG_ERR, "handleConnectResult: Error"); - goto leave; - } else { - if (verbose >= 3) logmsg(LOG_NOTICE, "handleConnectResult: Success"); - } + cdata = (struct client_data *) arg; - // 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; - } + if (verbose >= 3) + logmsg(LOG_NOTICE, "%s[%d:%d]: started", __func__, + cdata->dev->device_id, cdata->dev->use_count); - 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: Error: checkfd: %s", __func__, strerror(errno)); - } - continue; + if (usbmuxd_handleConnectResult(cdata)) { + if (verbose >= 3) + logmsg(LOG_ERR, "handleConnectResult: Error"); + goto leave; + } else { + if (verbose >= 3) + logmsg(LOG_NOTICE, "handleConnectResult: Success"); } - // 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[%d:%d]: Error: recv: %s", __func__, cdata->dev->device_id, cdata->dev->use_count, strerror(errno)); - break; + // 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; } - 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[%d:%d]: USB write error: %d", __func__, cdata->dev->device_id, cdata->dev->use_count, 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; + 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: Error: checkfd: %s", __func__, + 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[%d:%d]: Error: recv: %s", __func__, + cdata->dev->device_id, cdata->dev->use_count, + 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[%d:%d]: USB write error: %d", + __func__, cdata->dev->device_id, + cdata->dev->use_count, 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[%d:%d]: terminating", __func__, cdata->dev->device_id, cdata->dev->use_count); - if (cdata->reader != 0) { - cdata->reader_quit = 1; - pthread_join(cdata->reader, NULL); - } + leave: + // cleanup + if (verbose >= 3) + logmsg(LOG_NOTICE, "%s[%d:%d]: terminating", __func__, + cdata->dev->device_id, cdata->dev->use_count); + if (cdata->reader != 0) { + cdata->reader_quit = 1; + pthread_join(cdata->reader, NULL); + } - cdata->handler_dead = 1; + cdata->handler_dead = 1; - if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%d:%d]: terminated", __func__, cdata->dev->device_id, cdata->dev->use_count); - return NULL; + if (verbose >= 3) + logmsg(LOG_NOTICE, "%s[%d:%d]: terminated", __func__, + cdata->dev->device_id, cdata->dev->use_count); + return NULL; } /** @@ -481,36 +543,41 @@ leave: */ static void *usbmuxd_bulk_reader_thread(void *arg) { - struct device_info *cur_dev; - int err; + struct device_info *cur_dev; + int err; - if (!arg) { - if (verbose >= 2) logmsg(LOG_ERR, "%s: Invalid client_data provided", __func__); - return NULL; - } + if (!arg) { + if (verbose >= 2) + logmsg(LOG_ERR, "%s: Invalid client_data provided", __func__); + return NULL; + } - cur_dev = (struct device_info*)arg; + cur_dev = (struct device_info *) arg; - if (verbose >= 3) logmsg(LOG_NOTICE, "%s: started", __func__); + if (verbose >= 3) + logmsg(LOG_NOTICE, "%s: started", __func__); - while (!quit_flag && cur_dev) { + 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); + 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 ((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__); + if (verbose >= 3) + logmsg(LOG_NOTICE, "%s: terminated", __func__); - return NULL; + return NULL; } /** @@ -520,286 +587,374 @@ static void *usbmuxd_bulk_reader_thread(void *arg) */ static void *usbmuxd_client_init_thread(void *arg) { - struct client_data *cdata; - struct usbmuxd_scan_request *s_req = NULL; - struct usbmuxd_device_info_record dev_info_rec; - struct usbmuxd_connect_request *c_req = NULL; + struct client_data *cdata; + struct usbmuxd_scan_request *s_req = NULL; + 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; + } - struct usb_bus *bus; - struct usb_device *dev; + cdata = (struct client_data *) arg; + cdata->dead = 0; - int recv_len; - int found = 0; - int res; - int i; + if (verbose >= 3) + logmsg(LOG_NOTICE, "%s[%x]: started (fd=%d)", __func__, THREAD, + cdata->socket); - usbmux_device_t phone = NULL; - struct device_info *cur_dev = NULL; + 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 (!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 <= 0x1293) - { - if (verbose >= 1) logmsg(LOG_NOTICE, "%s[%x]: Found device on bus %d, id %d", __func__, THREAD, bus->location, dev->devnum); - 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; - dev_info_rec.device.device_id = dev->devnum; - 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); - } - //pthread_mutex_unlock(&usbmux_mutex); - } + 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 <= 0x1293) { + if (verbose >= 1) + logmsg(LOG_NOTICE, + "%s[%x]: Found device on bus %d, id %d", + __func__, THREAD, bus->location, dev->devnum); + 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; + dev_info_rec.device.device_id = dev->devnum; + 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); + } + //pthread_mutex_unlock(&usbmux_mutex); + } #ifdef DEBUG - if (verbose >= 4) print_buffer(stderr, (char*)&dev_info_rec, sizeof(dev_info_rec)); + 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--; + // 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); - 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 on port %d", __func__, THREAD, c_req->device_id, 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; - } - } + pthread_mutex_unlock(&usb_mutex); + + if (found <= 0) { + if (verbose >= 1) + logmsg(LOG_NOTICE, + "%s[%x]: No attached iPhone/iPod devices found.", + __func__, THREAD); + goto leave; } - } - if (!phone) { - // if not found, make a new connection - if (verbose >= 2) logmsg(LOG_NOTICE, "%s[%x]: creating new usb connection, device_id=%d", __func__, THREAD, c_req->device_id); - pthread_mutex_lock(&usb_mutex); - if (usbmux_get_specific_device(0, c_req->device_id, &phone) < 0) { - pthread_mutex_unlock(&usb_mutex); - pthread_mutex_unlock(&usbmux_mutex); - if (verbose >= 1) logmsg(LOG_ERR, "%s[%x]: device_id %d could not be opened", __func__, THREAD, c_req->device_id); - usbmuxd_send_result(cdata->socket, c_req->header.tag, ENODEV); - 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; } - 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)); + + 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 on port %d", + __func__, THREAD, c_req->device_id, + 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) { - devices[device_count] = cur_dev; - device_count++; + 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_id=%d", + __func__, THREAD, c_req->device_id); + + pthread_mutex_lock(&usb_mutex); + if (usbmux_get_specific_device(0, c_req->device_id, &phone) < 0) { + pthread_mutex_unlock(&usb_mutex); + pthread_mutex_unlock(&usbmux_mutex); + if (verbose >= 1) + logmsg(LOG_ERR, "%s[%x]: device_id %d could not be opened", + __func__, THREAD, c_req->device_id); + 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_id=%d", + __func__, THREAD, c_req->device_id); } - } else { - if (verbose >= 2) logmsg(LOG_NOTICE, "%s[%x]: reusing usb connection, device_id=%d", __func__, THREAD, c_req->device_id); - } - pthread_mutex_unlock(&usbmux_mutex); + pthread_mutex_unlock(&usbmux_mutex); - // setup connection to iPhone/iPod + // setup connection to iPhone/iPod // pthread_mutex_lock(&usbmux_mutex); - res = usbmux_new_client(cur_dev->phone, 0, ntohs(c_req->tcp_dport), &(cdata->muxclient)); + res = + usbmux_new_client(cur_dev->phone, 0, ntohs(c_req->tcp_dport), + &(cdata->muxclient)); // pthread_mutex_unlock(&usbmux_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); - - // 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 - usbmux_free_client(cdata->muxclient); - } - -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) { + 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->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; - - 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]; - } + 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); + + // 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 + usbmux_free_client(cdata->muxclient); + } + + 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; + + 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; + } } - free(devices); - devices = newlist; - device_count--; - } else { - free(devices); - devices = NULL; - device_count = 0; - } } - } - pthread_mutex_unlock(&usbmux_mutex); + pthread_mutex_unlock(&usbmux_mutex); + + cdata->dead = 1; + close(cdata->socket); - cdata->dead = 1; - close(cdata->socket); - - if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%x]: terminated", __func__, THREAD); + if (verbose >= 3) + logmsg(LOG_NOTICE, "%s[%x]: terminated", __func__, THREAD); - return NULL; + return NULL; } /** @@ -807,44 +962,42 @@ leave: */ static int daemonize() { - pid_t pid; - pid_t sid; + pid_t pid; + pid_t sid; - // already a daemon - if (getppid() == 1) return 0; + // 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); + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } - // Create a new SID for the child process - sid = setsid(); - if (sid < 0) { - return -1; - } + if (pid > 0) { + // exit parent process + exit(EXIT_SUCCESS); + } + // At this point we are executing as the child process - // Change the current working directory. - if ((chdir("/")) < 0) { - return -2; - } + // Change the file mode mask + umask(0); - // Redirect standard files to /dev/null - freopen("/dev/null", "r", stdin); - freopen("/dev/null", "w", stdout); - freopen("/dev/null", "w", stderr); + // 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 + freopen("/dev/null", "r", stdin); + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); - return 0; + return 0; } /** @@ -852,56 +1005,57 @@ static int daemonize() */ static void clean_exit(int sig) { - if (sig == SIGINT) { - if (verbose >= 1) fprintf(stderr, "CTRL+C pressed\n"); - } - quit_flag = 1; + if (sig == SIGINT) { + if (verbose >= 1) + fprintf(stderr, "CTRL+C pressed\n"); + } + quit_flag = 1; } static void usage() { - printf("usage: usbmuxd [options]\n"); - printf("\t-h|--help print this message.\n"); - printf("\t-v|--verbose be verbose\n"); - printf("\t-f|--foreground do not daemonize\n"); - printf("\n"); + printf("usage: usbmuxd [options]\n"); + printf("\t-h|--help print this message.\n"); + printf("\t-v|--verbose be verbose\n"); + printf("\t-f|--foreground do not daemonize\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' }, - { NULL, 0, NULL, 0} - }; - int c; - - while (1) { - c = getopt_long(argc, argv, "hfve", longopts, (int *) 0); - if (c == -1) { - break; - } + static struct option longopts[] = { + {"help", 0, NULL, 'h'}, + {"foreground", 0, NULL, 'f'}, + {"verbose", 0, NULL, 'v'}, + {"exit-on-no-devices", 0, NULL, 'e'}, + {NULL, 0, NULL, 0} + }; + int c; + + while (1) { + c = getopt_long(argc, argv, "hfve", 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; - default: - usage(); - exit(2); + 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; + default: + usage(); + exit(2); + } } - } } /** @@ -911,26 +1065,25 @@ static void parse_opts(int argc, char **argv) */ 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 <= 0x1293) - { - res++; - } + 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 <= 0x1293) { + res++; + } + } } - } - return res; + return res; } /** @@ -938,233 +1091,261 @@ static int devices_attached() */ 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 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 >= 2) logmsg(LOG_NOTICE, "starting"); - - // signal(SIGHUP, reload_conf); // none yet - signal(SIGINT, clean_exit); - signal(SIGQUIT, clean_exit); - signal(SIGTERM, clean_exit); - 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) { - logmsg(LOG_NOTICE, "another instance is already running. exiting."); - return -1; + 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 cnt = 0; + FILE *lfd = NULL; + struct flock lock; + + parse_opts(argc, argv); + + argc -= optind; + argv += optind; + + if (!foreground) { + openlog("usbmuxd", LOG_PID, 0); } - } - if (exit_on_no_devices) { - if (devices_attached() <= 0) { - logmsg(LOG_NOTICE, "no devices attached. exiting."); - return 0; + if (verbose >= 2) + logmsg(LOG_NOTICE, "starting"); + + // signal(SIGHUP, reload_conf); // none yet + signal(SIGINT, clean_exit); + signal(SIGQUIT, clean_exit); + signal(SIGTERM, clean_exit); + 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) { + logmsg(LOG_NOTICE, + "another instance is already running. exiting."); + return -1; + } } - } - fsock = create_unix_socket(USBMUXD_SOCKET_FILE); - if (fsock < 0) { - logmsg(LOG_ERR, "Could not create socket, exiting"); - if (!foreground) { - closelog(); + if (exit_on_no_devices) { + if (devices_attached() <= 0) { + logmsg(LOG_NOTICE, "no devices attached. exiting."); + return 0; + } } - return -1; - } - chmod(USBMUXD_SOCKET_FILE, 0666); + fsock = create_unix_socket(USBMUXD_SOCKET_FILE); + if (fsock < 0) { + logmsg(LOG_ERR, "Could not create socket, exiting"); + if (!foreground) { + closelog(); + } + return -1; + } - if (verbose >= 3) usbmux_set_debug(1); + chmod(USBMUXD_SOCKET_FILE, 0666); - 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!"); - } - } + if (verbose >= 3) + usbmux_set_debug(1); - // drop elevated privileges - if (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); + 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!"); + } + } + // drop elevated privileges + if (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); + // 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"); } - 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(); + // 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); } - 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++; + 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 { - cnt = 0; + if (verbose >= 3) + logmsg(LOG_ERR, "usbmuxd: select error: %s", + strerror(errno)); + continue; } - } 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); + 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; } - 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; - } - } + 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"); + 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; } - } - 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"); + 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]); - } - } + // 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]); + } + } - // delete the children set. - free(children); - children = NULL; + // delete the children set. + free(children); + children = NULL; - if (fsock >= 0) { - close(fsock); - } + if (fsock >= 0) { + close(fsock); + } - unlink(USBMUXD_SOCKET_FILE); + 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); - } + // unlock lock file and close it. + if (lfd) { + lock.l_type = F_UNLCK; + fcntl(fileno(lfd), F_SETLK, &lock); + fclose(lfd); + } - if (verbose >= 1) logmsg(LOG_NOTICE, "usbmuxd: terminated"); - if (!foreground) { - closelog(); - } + if (verbose >= 1) + logmsg(LOG_NOTICE, "usbmuxd: terminated"); + if (!foreground) { + closelog(); + } - return 0; + return 0; } - diff --git a/sock_stuff.c b/sock_stuff.c index 43fdf0e..b51d6ba 100644 --- a/sock_stuff.c +++ b/sock_stuff.c @@ -17,270 +17,282 @@ static int verbose = 0; void sock_stuff_set_verbose(int level) { - verbose = level; + verbose = level; } -int create_unix_socket (const char *filename) +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; + 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; + 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 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 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: + 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; } - - 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; + 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); + 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); + 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 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 -1; - } - return result; + 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 -1; + } + return result; } int send_buf(int fd, void *data, size_t length) { - return send(fd, data, length, 0); + return send(fd, data, length, 0); } - diff --git a/sock_stuff.h b/sock_stuff.h index b9766ba..190f7e1 100644 --- a/sock_stuff.h +++ b/sock_stuff.h @@ -3,11 +3,10 @@ #include -enum fd_mode -{ - FD_READ, - FD_WRITE, - FD_EXCEPT +enum fd_mode { + FD_READ, + FD_WRITE, + FD_EXCEPT }; typedef enum fd_mode fd_mode; @@ -19,11 +18,11 @@ 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 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 */ - +#endif /* __SOCK_STUFF_H */ diff --git a/usbmux.c b/usbmux.c index 0a175ed..106c5ff 100644 --- a/usbmux.c +++ b/usbmux.c @@ -50,7 +50,7 @@ static const uint32_t WINDOW_MAX = 5 * 1024; static const uint32_t WINDOW_INCREMENT = 512; typedef struct { - char* buffer; + char *buffer; int leftover; int capacity; } receivebuf_t; @@ -145,20 +145,20 @@ static void print_buffer(const char *data, const int length) int j; unsigned char c; - for(i=0; i= length) { + for (j = 0; j < 16; j++) { + if (i + j >= length) { printf(" "); continue; } - printf("%02hhx ", *(data+i+j)); + printf("%02hhx ", *(data + i + j)); } printf(" | "); - for(j=0;j<16;j++) { - if (i+j >= length) + for (j = 0; j < 16; j++) { + if (i + j >= length) break; - c = *(data+i+j); + c = *(data + i + j); if ((c < 32) || (c > 127)) { printf("."); continue; @@ -171,7 +171,7 @@ static void print_buffer(const char *data, const int length) } #endif -void hton_header(usbmux_tcp_header *hdr) +void hton_header(usbmux_tcp_header * hdr) { if (hdr) { hdr->length = htonl(hdr->length); @@ -181,7 +181,7 @@ void hton_header(usbmux_tcp_header *hdr) } } -void ntoh_header(usbmux_tcp_header *hdr) +void ntoh_header(usbmux_tcp_header * hdr) { if (hdr) { hdr->length = ntohl(hdr->length); @@ -197,7 +197,8 @@ void ntoh_header(usbmux_tcp_header *hdr) */ usbmux_version_header *version_header() { - usbmux_version_header *version = (usbmux_version_header *) malloc(sizeof(usbmux_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); @@ -222,25 +223,34 @@ static int usbmux_config_usb_device(usbmux_device_t device) #if 0 log_debug_msg("checking configuration...\n"); if (device->__device->config->bConfigurationValue != 3) { - log_debug_msg("WARNING: usb device configuration is not 3 as expected!\n"); + log_debug_msg + ("WARNING: usb device configuration is not 3 as expected!\n"); } log_debug_msg("setting configuration...\n"); ret = usb_set_configuration(device->device, 3); if (ret != 0) { - log_debug_msg("Hm, usb_set_configuration returned %d: %s\n", ret, strerror(-ret)); + log_debug_msg("Hm, usb_set_configuration returned %d: %s\n", ret, + strerror(-ret)); #if LIBUSB_HAS_GET_DRIVER_NP log_debug_msg("trying to fix:\n"); log_debug_msg("-> detaching kernel driver... "); - ret = usb_detach_kernel_driver_np(device->device, device->__device->config->interface->altsetting->bInterfaceNumber); + ret = + usb_detach_kernel_driver_np(device->device, + device->__device->config-> + interface->altsetting-> + bInterfaceNumber); if (ret != 0) { - log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", ret, strerror(-ret)); + log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", + ret, strerror(-ret)); } else { log_debug_msg("done.\n"); log_debug_msg("setting configuration again... "); ret = usb_set_configuration(device->device, 3); if (ret != 0) { - log_debug_msg("Error: usb_set_configuration returned %d: %s\n", ret, strerror(-ret)); + log_debug_msg + ("Error: usb_set_configuration returned %d: %s\n", ret, + strerror(-ret)); log_debug_msg("--> trying to continue anyway...\n"); } else { log_debug_msg("done.\n"); @@ -257,7 +267,8 @@ static int usbmux_config_usb_device(usbmux_device_t device) 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)); + log_debug_msg("Error: usb_claim_interface returned %d: %s\n", ret, + strerror(-ret)); return -ENODEV; } else { log_debug_msg("done.\n"); @@ -266,7 +277,7 @@ static int usbmux_config_usb_device(usbmux_device_t device) do { bytes = usb_bulk_read(device->usbdev, BULKIN, buf, 512, 800); } while (bytes > 0); - + return 0; } @@ -283,7 +294,8 @@ static int usbmux_config_usb_device(usbmux_device_t 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) +int usbmux_get_specific_device(int bus_n, int dev_n, + usbmux_device_t * device) { struct usb_bus *bus; struct usb_device *dev; @@ -294,7 +306,8 @@ int usbmux_get_specific_device(int bus_n, int dev_n, usbmux_device_t * device) if (!device || (device && *device)) return -EINVAL; - usbmux_device_t newdevice = (usbmux_device_t) malloc(sizeof(struct usbmux_device_int)); + usbmux_device_t newdevice = + (usbmux_device_t) malloc(sizeof(struct usbmux_device_int)); // Initialize the struct newdevice->usbdev = NULL; @@ -314,40 +327,49 @@ int usbmux_get_specific_device(int bus_n, int dev_n, usbmux_device_t * device) // Set the device configuration for (bus = usb_get_busses(); bus; bus = bus->next) //if (bus->location == bus_n) - for (dev = bus->devices; dev != NULL; dev = dev->next) - if (dev->devnum == dev_n) { - newdevice->__device = dev; - newdevice->usbdev = usb_open(newdevice->__device); - if (usbmux_config_usb_device(newdevice) == 0) { - goto found; - } + for (dev = bus->devices; dev != NULL; dev = dev->next) + if (dev->devnum == dev_n) { + newdevice->__device = dev; + newdevice->usbdev = usb_open(newdevice->__device); + 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: + found: // Send the version command to the device version = version_header(); - bytes = usb_bulk_write(newdevice->usbdev, BULKOUT, (char *) version, sizeof(*version), 800); + 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)); + 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); + 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__); + 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)); + log_debug_msg("%s: libusb error message %d: %s (%s)\n", + __func__, bytes, usb_strerror(), + strerror(-bytes)); return bytes; } return -EBADMSG; @@ -363,7 +385,8 @@ found: // Bad header usbmux_free_device(newdevice); free(version); - log_debug_msg("%s: Received a bad header/invalid version number.", __func__); + log_debug_msg("%s: Received a bad header/invalid version number.", + __func__); return -EBADMSG; } @@ -371,7 +394,7 @@ found: 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 + 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. @@ -435,25 +458,31 @@ int send_to_device(usbmux_device_t device, char *data, int datalen) int bytes = 0; #ifdef DEBUG - #ifdef DEBUG_MORE - printf("===============================\n%s: trying to send\n", __func__); +#ifdef DEBUG_MORE + printf("===============================\n%s: trying to send\n", + __func__); print_buffer(data, datalen); printf("===============================\n"); - #endif +#endif #endif do { if (retrycount > 3) { - log_debug_msg("EPIC FAIL! aborting on retry count overload.\n"); + log_debug_msg + ("EPIC FAIL! aborting on retry count overload.\n"); return -ECOMM; } - bytes = usb_bulk_write(device->usbdev, BULKOUT, data, datalen, timeout); + 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)); + 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"); @@ -461,22 +490,24 @@ int send_to_device(usbmux_device_t device, char *data, int datalen) retrycount++; continue; } else if (bytes < datalen) { - log_debug_msg("usb_bulk_write failed to send full dataload. %d of %d\n", 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; } - } while(0); // fall out + } while (0); // fall out #ifdef DEBUG if (bytes > 0) { if (toto_debug > 0) { - printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); - printf("%s: sent to device\n", __func__); - print_buffer(data, bytes); - printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + printf("%s: sent to device\n", __func__); + print_buffer(data, bytes); + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); } } #endif @@ -493,13 +524,16 @@ int send_to_device(usbmux_device_t device, char *data, int datalen) * * @return How many bytes were read in, or -1 on error. */ -int recv_from_device_timeout(usbmux_device_t device, char *data, int datalen, int timeoutmillis) +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); + 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. @@ -509,12 +543,14 @@ int recv_from_device_timeout(usbmux_device_t device, char *data, int datalen, in // 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)); + 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; } - #ifdef DEBUG if (bytes > 0) { if (toto_debug > 0) { @@ -538,7 +574,8 @@ int recv_from_device_timeout(usbmux_device_t device, char *data, int datalen, in */ 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)); + usbmux_tcp_header *conn = + (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header)); conn->type = htonl(6); conn->length = HEADERLEN; conn->sport = htons(s_port); @@ -566,7 +603,9 @@ static void delete_connection(usbmux_client_t connection) // update the global list of connections if (clients > 1) { - newlist = (usbmux_client_t *) malloc(sizeof(usbmux_client_t) * (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) @@ -607,7 +646,9 @@ 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)); + (usbmux_client_t *) realloc(connlist, + sizeof(usbmux_client_t) * (clients + + 1)); newlist[clients] = connection; connlist = newlist; clients++; @@ -661,7 +702,8 @@ static uint16_t get_free_port() * @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) +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; @@ -670,11 +712,11 @@ int usbmux_new_client(usbmux_device_t device, uint16_t src_port, uint16_t dst_po if (!src_port) { // this is a special case, if we get 0, this is not good, so - return -EISCONN; // TODO: error code suitable? + return -EISCONN; // TODO: error code suitable? } - // Initialize connection stuff - usbmux_client_t new_connection = (usbmux_client_t) malloc(sizeof(struct usbmux_client_int)); + 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 @@ -682,7 +724,8 @@ int usbmux_new_client(usbmux_device_t device, uint16_t src_port, uint16_t dst_po 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->length16 = + new_connection->header->length16; new_connection->header->scnt = 0; new_connection->header->ocnt = 0; new_connection->device = device; @@ -697,8 +740,12 @@ int usbmux_new_client(usbmux_device_t device, uint16_t src_port, uint16_t dst_po new_connection->error = 0; new_connection->cleanup = 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)); + 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; @@ -732,7 +779,9 @@ int usbmux_free_client(usbmux_client_t client) client->header->length16 = 0x1C; hton_header(client->header); - err = send_to_device(client->device, (char*)client->header, sizeof(usbmux_tcp_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; @@ -762,7 +811,8 @@ int usbmux_free_client(usbmux_client_t client) * * @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) +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; @@ -781,7 +831,8 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, uint clock_gettime(CLOCK_REALTIME, &ts); //ts.tv_sec += 1; ts.tv_nsec += 750 * 1000; - if (pthread_cond_timedwait(&client->wait, &client->mutex, &ts) == ETIMEDOUT) { + 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; } @@ -791,7 +842,7 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, uint // 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 + char *buffer = (char *) malloc(blocksize + 2); // allow 2 bytes of safety padding // Set the length client->header->length = blocksize; client->header->length16 = blocksize; @@ -802,7 +853,9 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, uint 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)); + 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) @@ -812,7 +865,7 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, uint ntoh_header(client->header); // update counts ONLY if the send succeeded. - if ((uint32_t)sendresult == blocksize) { + if ((uint32_t) sendresult == blocksize) { // Re-calculate scnt client->header->scnt += datalen; client->wr_window -= blocksize; @@ -826,12 +879,14 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, uint return -ETIMEDOUT; } else if (sendresult < 0) { return sendresult; - } else if ((uint32_t)sendresult == blocksize) { + } else if ((uint32_t) sendresult == blocksize) { // actual number of data bytes sent. *sent_bytes = sendresult - HEADERLEN; return 0; } else { - fprintf(stderr, "usbsend managed to dump a packet that is not full size. %d of %d\n", sendresult, blocksize); + fprintf(stderr, + "usbsend managed to dump a packet that is not full size. %d of %d\n", + sendresult, blocksize); return -EBADMSG; } } @@ -844,14 +899,15 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, uint * * @return number of bytes consumed (header + data) */ -uint32_t append_receive_buffer(usbmux_client_t client, char* packet) +uint32_t append_receive_buffer(usbmux_client_t client, char *packet) { - if (client == NULL || packet == NULL) return 0; + if (client == NULL || packet == NULL) + return 0; usbmux_tcp_header *header = (usbmux_tcp_header *) packet; - char* data = &packet[HEADERLEN]; + char *data = &packet[HEADERLEN]; uint32_t packetlen = ntohl(header->length); - uint32_t datalen = packetlen-HEADERLEN; + uint32_t datalen = packetlen - HEADERLEN; int dobroadcast = 0; @@ -860,7 +916,7 @@ uint32_t append_receive_buffer(usbmux_client_t client, char* packet) // 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 ) { + 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"); @@ -872,9 +928,14 @@ uint32_t append_receive_buffer(usbmux_client_t client, char* packet) 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__); + 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__); } // need to revert some of the fields back to host notation. ntoh_header(client->header); @@ -885,7 +946,6 @@ uint32_t append_receive_buffer(usbmux_client_t client, char* packet) 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. @@ -899,30 +959,33 @@ uint32_t append_receive_buffer(usbmux_client_t client, char* packet) char e_msg[128]; e_msg[0] = 0; if (datalen > 1) { - memcpy(e_msg, data+1, datalen-1); - e_msg[datalen-1] = 0; + 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; + 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); + 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 @@ -930,7 +993,7 @@ uint32_t append_receive_buffer(usbmux_client_t client, char* packet) // 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) + if (ntohs(header->window) < 256) client->wr_window = 0; // check what just got acked. @@ -938,21 +1001,24 @@ uint32_t append_receive_buffer(usbmux_client_t client, char* packet) // 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 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); + log_debug_msg("%s: putting %d bytes into client's recv_buffer\n", + __func__, datalen); if (client->r_len == 0) dobroadcast = 1; @@ -960,7 +1026,8 @@ uint32_t append_receive_buffer(usbmux_client_t client, char* packet) client->recv_buffer = malloc(datalen); client->r_len = 0; } else { - client->recv_buffer = realloc(client->recv_buffer, client->r_len + datalen); + client->recv_buffer = + realloc(client->recv_buffer, client->r_len + datalen); } memcpy(&client->recv_buffer[client->r_len], data, datalen); @@ -982,7 +1049,7 @@ uint32_t append_receive_buffer(usbmux_client_t client, char* packet) * because we're only called from one location, pullbulk, where the lock * is already held. */ -usbmux_client_t find_client(usbmux_tcp_header* recv_header) +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 @@ -1017,17 +1084,19 @@ int usbmux_pullbulk(usbmux_device_t device) return -EINVAL; int res = 0; - static const int DEFAULT_CAPACITY = 128*1024; + 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]; + 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); + 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"); @@ -1036,7 +1105,6 @@ int usbmux_pullbulk(usbmux_device_t device) 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; @@ -1050,23 +1118,29 @@ int usbmux_pullbulk(usbmux_device_t device) 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)); + 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__); + 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"); + 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__); + log_debug_msg + ("%s: found client, calling append_receive_buffer\n", + __func__); append_receive_buffer(client, cursor); // perhaps this is too general, == -ECONNRESET @@ -1075,7 +1149,9 @@ int usbmux_pullbulk(usbmux_device_t device) 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)); + 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); @@ -1096,9 +1172,10 @@ int usbmux_pullbulk(usbmux_device_t device) // // 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) { + 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); + char *newbuff = malloc(DEFAULT_CAPACITY); memcpy(newbuff, cursor, device->usbReceive.leftover); free(device->usbReceive.buffer); device->usbReceive.buffer = newbuff; @@ -1133,7 +1210,9 @@ int usbmux_get_error(usbmux_client_t client) * * @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) +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) @@ -1147,15 +1226,15 @@ int usbmux_recv_timeout(usbmux_client_t client, char *data, uint32_t datalen, ui 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; + 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) + if ((int) foolen > client->r_len) foolen = client->r_len; memcpy(data, client->recv_buffer, foolen); *recv_bytes = foolen; @@ -1163,7 +1242,7 @@ int usbmux_recv_timeout(usbmux_client_t client, char *data, uint32_t datalen, ui // preserve any left-over unread amounts. int remainder = client->r_len - foolen; if (remainder > 0) { - char* newbuf = malloc(remainder); + char *newbuf = malloc(remainder); memcpy(newbuf, client->recv_buffer + foolen, remainder); client->r_len = remainder; free(client->recv_buffer); -- cgit v1.1-32-gdbae From cae80628faeeb19a88a28d7fb058e74f8b2743ed Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 25 Apr 2009 15:14:39 +0200 Subject: removed unused buffer variable from usbmux_device_t --- usbmux.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/usbmux.c b/usbmux.c index 106c5ff..e86e3bc 100644 --- a/usbmux.c +++ b/usbmux.c @@ -56,7 +56,6 @@ typedef struct { } receivebuf_t; struct usbmux_device_int { - char *buffer; struct usb_dev_handle *usbdev; struct usb_device *__device; receivebuf_t usbReceive; @@ -312,7 +311,6 @@ int usbmux_get_specific_device(int bus_n, int dev_n, // Initialize the struct newdevice->usbdev = NULL; newdevice->__device = NULL; - newdevice->buffer = NULL; // don't forget these: newdevice->usbReceive.buffer = NULL; @@ -422,9 +420,6 @@ int usbmux_free_device(usbmux_device_t device) ret = bytes; } - if (device->buffer) { - free(device->buffer); - } if (device->usbReceive.buffer) { free(device->usbReceive.buffer); } @@ -624,10 +619,14 @@ static void delete_connection(usbmux_client_t connection) // free up this connection pthread_mutex_lock(&connection->mutex); - if (connection->recv_buffer) + if (connection->recv_buffer) { free(connection->recv_buffer); - if (connection->header) + 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); -- cgit v1.1-32-gdbae From 7364e09f6849076c710ac9ce52a5d5fd2445e19c Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Mon, 4 May 2009 18:18:40 +0200 Subject: Use autotools build system and add license Signed-off-by: Nikias Bassen --- 85-usbmuxd.rules | 37 -- COPYING | 340 +++++++++++++ Makefile | 696 +++++++++++++++++++++++-- Makefile.am | 6 + autogen.sh | 6 + configure.ac | 28 + iproxy.c | 241 --------- libusbmuxd.c | 202 -------- main.c | 1351 ------------------------------------------------- sock_stuff.c | 298 ----------- sock_stuff.h | 28 - src/Makefile.am | 31 ++ src/libusbmuxd.c | 202 ++++++++ src/main.c | 1351 +++++++++++++++++++++++++++++++++++++++++++++++++ src/sock_stuff.c | 298 +++++++++++ src/sock_stuff.h | 28 + src/usbmux.c | 1259 +++++++++++++++++++++++++++++++++++++++++++++ src/usbmux.h | 51 ++ src/usbmuxd-proto.h | 52 ++ src/usbmuxd.h | 45 ++ tools/Makefile.am | 5 + tools/iproxy.c | 241 +++++++++ udev/85-usbmuxd.rules | 37 ++ udev/Makefile.am | 4 + usbmux.c | 1259 --------------------------------------------- usbmux.h | 51 -- usbmuxd-proto.h | 52 -- usbmuxd.h | 45 -- 28 files changed, 4625 insertions(+), 3619 deletions(-) delete mode 100644 85-usbmuxd.rules create mode 100644 COPYING create mode 100644 Makefile.am create mode 100755 autogen.sh create mode 100644 configure.ac delete mode 100644 iproxy.c delete mode 100644 libusbmuxd.c delete mode 100644 main.c delete mode 100644 sock_stuff.c delete mode 100644 sock_stuff.h create mode 100644 src/Makefile.am create mode 100644 src/libusbmuxd.c create mode 100644 src/main.c create mode 100644 src/sock_stuff.c create mode 100644 src/sock_stuff.h create mode 100644 src/usbmux.c create mode 100644 src/usbmux.h create mode 100644 src/usbmuxd-proto.h create mode 100644 src/usbmuxd.h create mode 100644 tools/Makefile.am create mode 100644 tools/iproxy.c create mode 100644 udev/85-usbmuxd.rules create mode 100644 udev/Makefile.am delete mode 100644 usbmux.c delete mode 100644 usbmux.h delete mode 100644 usbmuxd-proto.h delete mode 100644 usbmuxd.h diff --git a/85-usbmuxd.rules b/85-usbmuxd.rules deleted file mode 100644 index 69ddef8..0000000 --- a/85-usbmuxd.rules +++ /dev/null @@ -1,37 +0,0 @@ -# usbmuxd (iPhone "Apple Mobile Device" MUXer listening on /var/run/usbmuxd) -#if -#SUBSYSTEMS=="usb_interface", SYMLINK+="usbmux/interface" - -#SUBSYSTEMS!="usb", GOTO="usbmuxd_rules_end" # stops the whole script working -ATTR{idVendor}!="05ac", GOTO="usbmuxd_rules_end" - -# If it's plug insertion, flip it into dual "PTP + Apple Mobile Device" configuration -# This allows another application to switch it later without it getting switched back (hopefully) -# TODO: check iPod Touch/3G -SUBSYSTEM=="usb", ACTION=="add", ATTR{product}=="iPhone", ATTR{bConfigurationValue}!="3", ATTR{bConfigurationValue}="3", GOTO="usbmuxd_rules_end" - -# SYMLINK the usbmux endpoints, if we get them -# TODO: Multiple devices -# TODO: work out how to make nice, incrementing usbmux/{0,1,2,3}-in for -LABEL="usbmuxd_rules_usbmux" - -# ff/fe/02 == usbmux -# -#ACTION=="add", - -# Try to symlink the interface, containing the endpoints. -# ...But it doesn't work -#KERNELS=="7-3:3.1", SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="01", ATTRS{bAlternateSetting}==" 0", ATTRS{bNumEndpoints}=="02", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="fe", ATTRS{bInterfaceProtocol}=="02", SYMLINK+="usbmux/prettyplease", RUN+="/bin/ls -l /dev/usbmux/prettyplease" - -#ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="fe", ATTRS{bInterfaceProtocol}=="02", SYMLINK+="usbmux/interface" - -# Cute names, really they should have nice numerically increasing names. -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", SYMLINK+="usbmux/in" -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbmux/out" - -# Start and stop 'usbmuxd' as required. -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec /usr/local/sbin/usbmuxd" -ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 2 --exec /usr/local/sbin/usbmuxd" - -# skip -LABEL="usbmuxd_rules_end" diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..08ddefd --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + diff --git a/Makefile b/Makefile index 535e028..d933bd2 100644 --- a/Makefile +++ b/Makefile @@ -1,55 +1,641 @@ -TARGETS=usbmuxd libusbmuxd.so iproxy -CFLAGS=-I. -g -DDEBUG -fPIC -Wall -Wextra -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -LIBS=-lpthread -lusb -lrt -LDFLAGS=-L. -INSTALL_PREFIX=/usr/local - -all: $(TARGETS) - -main.o: main.c usbmuxd-proto.h sock_stuff.h usbmux.h -usbmux.o: usbmux.c usbmux.h usbmuxd.h sock_stuff.h -sock_stuff.o: sock_stuff.c sock_stuff.h -libusbmuxd.o: libusbmuxd.c usbmuxd.h usbmuxd-proto.h -iproxy.o: iproxy.c sock_stuff.h -libusbmuxd.so: libusbmuxd.o sock_stuff.o - -%.so: %.o - $(CC) -o $@ -shared -Wl,-soname,$@.1 $^ - -%.o: %.c - $(CC) -o $@ $(CFLAGS) -c $< - -usbmuxd: main.o sock_stuff.o usbmux.o - $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) - -iproxy: iproxy.o - $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) -lusbmuxd - -clean: - rm -f *.o *.so $(TARGETS) - -realclean: clean - rm -f *~ - -install: all - install -m 755 usbmuxd $(INSTALL_PREFIX)/sbin/ - # udev crack - #install -D -m 644 85-usbmuxd.rules $(INSTALL_PREFIX)/lib/udev/rules.d/85-usbmuxd.rules - install -m 644 85-usbmuxd.rules /etc/udev/rules.d/85-usbmuxd.rules - # protocol - install -m 644 usbmuxd-proto.h $(INSTALL_PREFIX)/include/ - # iproxy - install -m 644 libusbmuxd.so $(INSTALL_PREFIX)/lib/ - install -m 644 usbmuxd.h $(INSTALL_PREFIX)/include/ - install -m 755 iproxy $(INSTALL_PREFIX)/bin/ - -uninstall: - -rm $(INSTALL_PREFIX)/sbin/usbmuxd - #-rm $(INSTALL_PREFIX)/lib/udev/rules.d/85-usbmuxd.rules - -rm /etc/udev/rules.d/85-usbmuxd.rules - -rm $(INSTALL_PREFIX)/include/usbmuxd-proto.h - -rm $(INSTALL_PREFIX)/lib/libusbmuxd.so - -rm $(INSTALL_PREFIX)/include/usbmuxd.h - -rm $(INSTALL_PREFIX)/bin/iproxy - -.PHONY: all clean realclean +# Makefile.in generated by automake 1.10.2 from Makefile.am. +# Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +pkgdatadir = $(datadir)/usbmuxd +pkglibdir = $(libdir)/usbmuxd +pkgincludedir = $(includedir)/usbmuxd +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = i686-pc-linux-gnu +host_triplet = i686-pc-linux-gnu +subdir = . +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/config.h.in \ + $(top_srcdir)/configure AUTHORS COPYING compile config.guess \ + config.sub depcomp install-sh ltmain.sh missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = ${SHELL} /home/nikias/coding/usbmuxd/missing --run aclocal-1.10 +AMTAR = ${SHELL} /home/nikias/coding/usbmuxd/missing --run tar +AR = ar +AUTOCONF = ${SHELL} /home/nikias/coding/usbmuxd/missing --run autoconf +AUTOHEADER = ${SHELL} /home/nikias/coding/usbmuxd/missing --run autoheader +AUTOMAKE = ${SHELL} /home/nikias/coding/usbmuxd/missing --run automake-1.10 +AWK = gawk +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CPP = gcc -E +CPPFLAGS = +CYGPATH_W = echo +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DSYMUTIL = +DUMPBIN = +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +EXEEXT = +FGREP = /bin/grep -F +GREP = /bin/grep +INSTALL = /usr/bin/install -c +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +LD = /usr/bin/ld +LDFLAGS = +LIBOBJS = +LIBS = +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LIPO = +LN_S = ln -s +LTLIBOBJS = +MAKEINFO = ${SHELL} /home/nikias/coding/usbmuxd/missing --run makeinfo +MKDIR_P = /bin/mkdir -p +NM = /usr/bin/nm -B +NMEDIT = +OBJDUMP = objdump +OBJEXT = o +OTOOL = +OTOOL64 = +PACKAGE = usbmuxd +PACKAGE_BUGREPORT = nikias@gmx.li +PACKAGE_NAME = usbmuxd +PACKAGE_STRING = usbmuxd 0.1.0 +PACKAGE_TARNAME = usbmuxd +PACKAGE_VERSION = 0.1.0 +PATH_SEPARATOR = : +PKG_CONFIG = /usr/bin/pkg-config +RANLIB = ranlib +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = strip +VERSION = 0.1.0 +abs_builddir = /home/nikias/coding/usbmuxd +abs_srcdir = /home/nikias/coding/usbmuxd +abs_top_builddir = /home/nikias/coding/usbmuxd +abs_top_srcdir = /home/nikias/coding/usbmuxd +ac_ct_CC = gcc +ac_ct_DUMPBIN = +am__include = include +am__leading_dot = . +am__quote = +am__tar = ${AMTAR} chof - "$$tardir" +am__untar = ${AMTAR} xf - +bindir = ${exec_prefix}/bin +build = i686-pc-linux-gnu +build_alias = +build_cpu = i686 +build_os = linux-gnu +build_vendor = pc +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +host = i686-pc-linux-gnu +host_alias = +host_cpu = i686 +host_os = linux-gnu +host_vendor = pc +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = $(SHELL) /home/nikias/coding/usbmuxd/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +libusb_CFLAGS = +libusb_LIBS = -lusb +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +lt_ECHO = echo +mandir = ${datarootdir}/man +mkdir_p = /bin/mkdir -p +oldincludedir = /usr/include +pdfdir = ${docdir} +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +sysconfdir = /etc +target_alias = +top_build_prefix = +top_builddir = . +top_srcdir = . +SUBDIRS = src udev tools +EXTRA_DIST = README.devel +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ + cd $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: $(am__configure_deps) + cd $(top_srcdir) && $(AUTOHEADER) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d $(distdir) || mkdir $(distdir) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile config.h +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr \ + distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-exec-am: + +install-html: install-html-recursive + +install-info: install-info-recursive + +install-man: + +install-pdf: install-pdf-recursive + +install-ps: install-ps-recursive + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ + install-strip + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ + dist-gzip dist-lzma dist-shar dist-tarZ dist-zip distcheck \ + distclean distclean-generic distclean-hdr distclean-libtool \ + distclean-tags distcleancheck distdir distuninstallcheck dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am + + +indent: + indent -kr -ut -ts4 -l120 src/*.c src/*.h tools/*.c +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..43dc592 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,6 @@ +SUBDIRS = src udev tools + +indent: + indent -kr -ut -ts4 -l120 src/*.c src/*.h tools/*.c + +EXTRA_DIST = README.devel diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..90f6046 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,6 @@ +#!/bin/sh +aclocal -I m4 || exit 1 +libtoolize || exit 1 +autoheader || exit 1 +automake --add-missing || exit 1 +autoconf || exit 1 diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..7c54416 --- /dev/null +++ b/configure.ac @@ -0,0 +1,28 @@ +# Inital configuration + +AC_PREREQ(2.61) + +AC_INIT([usbmuxd], [0.1.0], [nikias@gmx.li]) +AM_INIT_AUTOMAKE([-Wall -Werror foreign dist-bzip2]) + +AC_CONFIG_HEADERS([config.h]) + +# Check for programs + +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_LIBTOOL +AC_PROG_INSTALL + +# Check for libraries + +PKG_CHECK_MODULES(libusb, libusb >= 0.1.12) + +# Output files + +AC_OUTPUT([ +Makefile +src/Makefile +tools/Makefile +udev/Makefile +]) diff --git a/iproxy.c b/iproxy.c deleted file mode 100644 index 3cb2894..0000000 --- a/iproxy.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * iproxy -- proxy that enables tcp service access to iPhone/iPod - * via USB cable - * TODO: improve code... - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sock_stuff.h" -#include "usbmuxd.h" - -static uint16_t listen_port = 0; -static uint16_t device_port = 0; - -pthread_mutex_t smutex = PTHREAD_MUTEX_INITIALIZER; - -struct client_data { - int fd; - int sfd; - volatile int stop_ctos; - volatile int stop_stoc; -}; - -void *run_stoc_loop(void *arg) -{ - struct client_data *cdata = (struct client_data*)arg; - int recv_len; - int sent; - char buffer[131072]; - - printf("%s: fd = %d\n", __func__, cdata->fd); - - while (!cdata->stop_stoc && cdata->fd>0 && cdata->sfd>0) { - recv_len = recv_buf_timeout(cdata->sfd, buffer, sizeof(buffer), 0, 5000); - if (recv_len <= 0) { - if (recv_len == 0) { - // try again - continue; - } else { - fprintf(stderr, "recv failed: %s\n", strerror(errno)); - break; - } - } else { -// printf("received %d bytes from server\n", recv_len); - // send to socket - sent = send_buf(cdata->fd, buffer, recv_len); - if (sent < recv_len) { - if (sent <= 0) { - fprintf(stderr, "send failed: %s\n", strerror(errno)); - break; - } else { - fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len); - } - } else { - // sending succeeded, receive from device -// printf("pushed %d bytes to client\n", sent); - } - } - } - close(cdata->fd); - cdata->fd = -1; - cdata->stop_ctos = 1; - - return NULL; -} - -void *run_ctos_loop(void *arg) -{ - struct client_data *cdata = (struct client_data*)arg; - int recv_len; - int sent; - char buffer[131072]; - pthread_t stoc = 0; - - printf("%s: fd = %d\n", __func__, cdata->fd); - - cdata->stop_stoc = 0; - pthread_create(&stoc, NULL, run_stoc_loop, cdata); - - while (!cdata->stop_ctos && cdata->fd>0 && cdata->sfd>0) { - recv_len = recv_buf_timeout(cdata->fd, buffer, sizeof(buffer), 0, 5000); - if (recv_len <= 0) { - if (recv_len == 0) { - // try again - continue; - } else { - fprintf(stderr, "recv failed: %s\n", strerror(errno)); - break; - } - } else { -// printf("pulled %d bytes from client\n", recv_len); - // send to local socket - sent = send_buf(cdata->sfd, buffer, recv_len); - if (sent < recv_len) { - if (sent <= 0) { - fprintf(stderr, "send failed: %s\n", strerror(errno)); - break; - } else { - fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len); - } - } else { - // sending succeeded, receive from device -// printf("sent %d bytes to server\n", sent); - } - } - } - close(cdata->fd); - cdata->fd = -1; - cdata->stop_stoc = 1; - - pthread_join(stoc, NULL); - - return NULL; -} - -void *acceptor_thread(void *arg) -{ - struct client_data *cdata; - usbmuxd_scan_result *dev_list = NULL; - pthread_t ctos; - int count; - - if (!arg) { - fprintf(stderr, "invalid client_data provided!\n"); - return NULL; - } - - cdata = (struct client_data*)arg; - - if ((count = usbmuxd_scan(&dev_list)) < 0) { - printf("Connecting to usbmuxd failed, terminating.\n"); - free(dev_list); - return NULL; - } - - fprintf(stdout, "Number of available devices == %d\n", count); - - if (dev_list == NULL || dev_list[0].handle == 0) { - printf("No connected device found, terminating.\n"); - free(dev_list); - return NULL; - } - - fprintf(stdout, "Requesting connecion to device handle == %d (serial: %s), port %d\n", dev_list[0].handle, dev_list[0].serial_number, device_port); - - cdata->sfd = usbmuxd_connect(dev_list[0].handle, device_port); - free(dev_list); - if (cdata->sfd < 0) { - fprintf(stderr, "Error connecting to device!\n"); - } else { - cdata->stop_ctos = 0; - pthread_create(&ctos, NULL, run_ctos_loop, cdata); - pthread_join(ctos, NULL); - } - - if (cdata->fd > 0) { - close(cdata->fd); - } - if (cdata->sfd > 0) { - close(cdata->sfd); - } - - return NULL; -} - -int main(int argc, char **argv) -{ - int mysock = -1; - - if (argc != 3) { - printf("usage: %s LOCAL_TCP_PORT DEVICE_TCP_PORT\n", argv[0]); - return 0; - } - - listen_port = atoi(argv[1]); - device_port = atoi(argv[2]); - - if (!listen_port) { - fprintf(stderr, "Invalid listen_port specified!\n"); - return -EINVAL; - } - - if (!device_port) { - fprintf(stderr, "Invalid device_port specified!\n"); - return -EINVAL; - } - - // first create the listening socket endpoint waiting for connections. - mysock = create_socket(listen_port); - if (mysock < 0) { - fprintf(stderr, "Error creating socket: %s\n", strerror(errno)); - return -errno; - } else { - pthread_t acceptor; - struct sockaddr_in c_addr; - socklen_t len = sizeof(struct sockaddr_in); - struct client_data cdata; - int c_sock; - while (1) { - printf("waiting for connection\n"); - c_sock = accept(mysock, (struct sockaddr*)&c_addr, &len); - if (c_sock) { - printf("accepted connection, fd = %d\n", c_sock); - cdata.fd = c_sock; - pthread_create(&acceptor, NULL, acceptor_thread, &cdata); - pthread_join(acceptor, NULL); - } else { - break; - } - } - close(c_sock); - close(mysock); - } - - return 0; -} diff --git a/libusbmuxd.c b/libusbmuxd.c deleted file mode 100644 index c8acbf8..0000000 --- a/libusbmuxd.c +++ /dev/null @@ -1,202 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -// usbmuxd public interface -#include -// usbmuxd protocol -#include -// 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; -} diff --git a/main.c b/main.c deleted file mode 100644 index e7292cc..0000000 --- a/main.c +++ /dev/null @@ -1,1351 +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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; - -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[%d:%d]: started", __func__, - cdata->dev->device_id, 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[%d:%d]: encountered USB read error: %d", - __func__, cdata->dev->device_id, - cdata->dev->use_count, 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[%d:%d]: terminated", __func__, - cdata->dev->device_id, cdata->dev->use_count); - - 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[65536]; - 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[%d:%d]: started", __func__, - cdata->dev->device_id, 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: Error: checkfd: %s", __func__, - 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[%d:%d]: Error: recv: %s", __func__, - cdata->dev->device_id, cdata->dev->use_count, - 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[%d:%d]: USB write error: %d", - __func__, cdata->dev->device_id, - cdata->dev->use_count, 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[%d:%d]: terminating", __func__, - cdata->dev->device_id, cdata->dev->use_count); - if (cdata->reader != 0) { - cdata->reader_quit = 1; - pthread_join(cdata->reader, NULL); - } - - cdata->handler_dead = 1; - - if (verbose >= 3) - logmsg(LOG_NOTICE, "%s[%d:%d]: terminated", __func__, - cdata->dev->device_id, cdata->dev->use_count); - 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 = NULL; - 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 <= 0x1293) { - if (verbose >= 1) - logmsg(LOG_NOTICE, - "%s[%x]: Found device on bus %d, id %d", - __func__, THREAD, bus->location, dev->devnum); - 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; - dev_info_rec.device.device_id = dev->devnum; - 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); - } - //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); - 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 on port %d", - __func__, THREAD, c_req->device_id, - 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_id=%d", - __func__, THREAD, c_req->device_id); - - pthread_mutex_lock(&usb_mutex); - if (usbmux_get_specific_device(0, c_req->device_id, &phone) < 0) { - pthread_mutex_unlock(&usb_mutex); - pthread_mutex_unlock(&usbmux_mutex); - if (verbose >= 1) - logmsg(LOG_ERR, "%s[%x]: device_id %d could not be opened", - __func__, THREAD, c_req->device_id); - 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_id=%d", - __func__, THREAD, c_req->device_id); - } - pthread_mutex_unlock(&usbmux_mutex); - - // setup connection to iPhone/iPod -// pthread_mutex_lock(&usbmux_mutex); - res = - usbmux_new_client(cur_dev->phone, 0, ntohs(c_req->tcp_dport), - &(cdata->muxclient)); -// pthread_mutex_unlock(&usbmux_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); - - // 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 - usbmux_free_client(cdata->muxclient); - } - - 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; - - 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 - freopen("/dev/null", "r", stdin); - freopen("/dev/null", "w", stdout); - freopen("/dev/null", "w", stderr); - - return 0; -} - -/** - * signal handler function for cleaning up properly - */ -static void clean_exit(int sig) -{ - if (sig == SIGINT) { - if (verbose >= 1) - fprintf(stderr, "CTRL+C pressed\n"); - } - quit_flag = 1; -} - -static void usage() -{ - printf("usage: usbmuxd [options]\n"); - printf("\t-h|--help print this message.\n"); - printf("\t-v|--verbose be verbose\n"); - printf("\t-f|--foreground do not daemonize\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'}, - {NULL, 0, NULL, 0} - }; - int c; - - while (1) { - c = getopt_long(argc, argv, "hfve", 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; - default: - usage(); - exit(2); - } - } -} - -/** - * 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 <= 0x1293) { - res++; - } - } - } - - return res; -} - -/** - * 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 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 >= 2) - logmsg(LOG_NOTICE, "starting"); - - // signal(SIGHUP, reload_conf); // none yet - signal(SIGINT, clean_exit); - signal(SIGQUIT, clean_exit); - signal(SIGTERM, clean_exit); - 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) { - logmsg(LOG_NOTICE, - "another instance is already running. exiting."); - return -1; - } - } - - 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 >= 3) - 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!"); - } - } - // drop elevated privileges - if (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]); - } - } - - // 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); - } - - if (verbose >= 1) - logmsg(LOG_NOTICE, "usbmuxd: terminated"); - if (!foreground) { - closelog(); - } - - return 0; -} diff --git a/sock_stuff.c b/sock_stuff.c deleted file mode 100644 index b51d6ba..0000000 --- a/sock_stuff.c +++ /dev/null @@ -1,298 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 -1; - } - return result; -} - -int send_buf(int fd, void *data, size_t length) -{ - return send(fd, data, length, 0); -} diff --git a/sock_stuff.h b/sock_stuff.h deleted file mode 100644 index 190f7e1..0000000 --- a/sock_stuff.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __SOCK_STUFF_H -#define __SOCK_STUFF_H - -#include - -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/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..547870e --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,31 @@ +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 new file mode 100644 index 0000000..c8acbf8 --- /dev/null +++ b/src/libusbmuxd.c @@ -0,0 +1,202 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +// usbmuxd public interface +#include +// usbmuxd protocol +#include +// 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; +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..e7292cc --- /dev/null +++ b/src/main.c @@ -0,0 +1,1351 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + +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[%d:%d]: started", __func__, + cdata->dev->device_id, 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[%d:%d]: encountered USB read error: %d", + __func__, cdata->dev->device_id, + cdata->dev->use_count, 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[%d:%d]: terminated", __func__, + cdata->dev->device_id, cdata->dev->use_count); + + 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[65536]; + 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[%d:%d]: started", __func__, + cdata->dev->device_id, 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: Error: checkfd: %s", __func__, + 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[%d:%d]: Error: recv: %s", __func__, + cdata->dev->device_id, cdata->dev->use_count, + 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[%d:%d]: USB write error: %d", + __func__, cdata->dev->device_id, + cdata->dev->use_count, 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[%d:%d]: terminating", __func__, + cdata->dev->device_id, cdata->dev->use_count); + if (cdata->reader != 0) { + cdata->reader_quit = 1; + pthread_join(cdata->reader, NULL); + } + + cdata->handler_dead = 1; + + if (verbose >= 3) + logmsg(LOG_NOTICE, "%s[%d:%d]: terminated", __func__, + cdata->dev->device_id, cdata->dev->use_count); + 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 = NULL; + 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 <= 0x1293) { + if (verbose >= 1) + logmsg(LOG_NOTICE, + "%s[%x]: Found device on bus %d, id %d", + __func__, THREAD, bus->location, dev->devnum); + 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; + dev_info_rec.device.device_id = dev->devnum; + 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); + } + //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); + 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 on port %d", + __func__, THREAD, c_req->device_id, + 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_id=%d", + __func__, THREAD, c_req->device_id); + + pthread_mutex_lock(&usb_mutex); + if (usbmux_get_specific_device(0, c_req->device_id, &phone) < 0) { + pthread_mutex_unlock(&usb_mutex); + pthread_mutex_unlock(&usbmux_mutex); + if (verbose >= 1) + logmsg(LOG_ERR, "%s[%x]: device_id %d could not be opened", + __func__, THREAD, c_req->device_id); + 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_id=%d", + __func__, THREAD, c_req->device_id); + } + pthread_mutex_unlock(&usbmux_mutex); + + // setup connection to iPhone/iPod +// pthread_mutex_lock(&usbmux_mutex); + res = + usbmux_new_client(cur_dev->phone, 0, ntohs(c_req->tcp_dport), + &(cdata->muxclient)); +// pthread_mutex_unlock(&usbmux_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); + + // 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 + usbmux_free_client(cdata->muxclient); + } + + 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; + + 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 + freopen("/dev/null", "r", stdin); + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); + + return 0; +} + +/** + * signal handler function for cleaning up properly + */ +static void clean_exit(int sig) +{ + if (sig == SIGINT) { + if (verbose >= 1) + fprintf(stderr, "CTRL+C pressed\n"); + } + quit_flag = 1; +} + +static void usage() +{ + printf("usage: usbmuxd [options]\n"); + printf("\t-h|--help print this message.\n"); + printf("\t-v|--verbose be verbose\n"); + printf("\t-f|--foreground do not daemonize\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'}, + {NULL, 0, NULL, 0} + }; + int c; + + while (1) { + c = getopt_long(argc, argv, "hfve", 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; + default: + usage(); + exit(2); + } + } +} + +/** + * 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 <= 0x1293) { + res++; + } + } + } + + return res; +} + +/** + * 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 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 >= 2) + logmsg(LOG_NOTICE, "starting"); + + // signal(SIGHUP, reload_conf); // none yet + signal(SIGINT, clean_exit); + signal(SIGQUIT, clean_exit); + signal(SIGTERM, clean_exit); + 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) { + logmsg(LOG_NOTICE, + "another instance is already running. exiting."); + return -1; + } + } + + 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 >= 3) + 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!"); + } + } + // drop elevated privileges + if (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]); + } + } + + // 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); + } + + if (verbose >= 1) + logmsg(LOG_NOTICE, "usbmuxd: terminated"); + if (!foreground) { + closelog(); + } + + return 0; +} diff --git a/src/sock_stuff.c b/src/sock_stuff.c new file mode 100644 index 0000000..b51d6ba --- /dev/null +++ b/src/sock_stuff.c @@ -0,0 +1,298 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 -1; + } + 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 new file mode 100644 index 0000000..190f7e1 --- /dev/null +++ b/src/sock_stuff.h @@ -0,0 +1,28 @@ +#ifndef __SOCK_STUFF_H +#define __SOCK_STUFF_H + +#include + +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 new file mode 100644 index 0000000..e86e3bc --- /dev/null +++ b/src/usbmux.c @@ -0,0 +1,1259 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "usbmux.h" + +#define BULKIN 0x85 +#define BULKOUT 0x04 +#define HEADERLEN 28 + +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; +}; + +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; +}; + + +static pthread_mutex_t usbmuxmutex = 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; +} + +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) + vfprintf(stderr, format, args); + + va_end(args); +#endif +} + +#ifdef DEBUG +/** + * 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"); +} +#endif + +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); + } +} + +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 + */ +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]; + +#if 0 + log_debug_msg("checking configuration...\n"); + if (device->__device->config->bConfigurationValue != 3) { + log_debug_msg + ("WARNING: usb device configuration is not 3 as expected!\n"); + } + + log_debug_msg("setting configuration...\n"); + ret = usb_set_configuration(device->device, 3); + if (ret != 0) { + log_debug_msg("Hm, usb_set_configuration returned %d: %s\n", ret, + strerror(-ret)); +#if LIBUSB_HAS_GET_DRIVER_NP + log_debug_msg("trying to fix:\n"); + log_debug_msg("-> detaching kernel driver... "); + ret = + usb_detach_kernel_driver_np(device->device, + device->__device->config-> + interface->altsetting-> + bInterfaceNumber); + if (ret != 0) { + log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", + ret, strerror(-ret)); + } else { + log_debug_msg("done.\n"); + log_debug_msg("setting configuration again... "); + ret = usb_set_configuration(device->device, 3); + if (ret != 0) { + log_debug_msg + ("Error: usb_set_configuration returned %d: %s\n", ret, + strerror(-ret)); + log_debug_msg("--> trying to continue anyway...\n"); + } else { + log_debug_msg("done.\n"); + } + } +#else + log_debug_msg("--> trying to continue anyway...\n"); +#endif + } else { + log_debug_msg("done.\n"); + } +#endif + + 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"); + } + + 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; + + // Initialize libusb + usb_init(); + usb_find_busses(); + usb_find_devices(); + + // Set the device configuration + for (bus = usb_get_busses(); bus; bus = bus->next) + //if (bus->location == bus_n) + for (dev = bus->devices; dev != NULL; dev = dev->next) + if (dev->devnum == dev_n) { + newdevice->__device = dev; + newdevice->usbdev = usb_open(newdevice->__device); + 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; + + 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 + */ +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; + +#ifdef DEBUG +#ifdef DEBUG_MORE + printf("===============================\n%s: trying to send\n", + __func__); + print_buffer(data, datalen); + printf("===============================\n"); +#endif +#endif + 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; + } + } while (0); // fall out + +#ifdef DEBUG + if (bytes > 0) { + if (toto_debug > 0) { + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + printf("%s: sent to device\n", __func__); + print_buffer(data, bytes); + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + } + } +#endif + 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. + */ +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; + } +#ifdef DEBUG + if (bytes > 0) { + if (toto_debug > 0) { + printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + printf("%s: received from device:\n", __func__); + print_buffer(data, bytes); + printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + } + } +#endif + + 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 + */ +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 = HEADERLEN; + 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 = HEADERLEN; + 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; + 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_FIN; + 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 - HEADERLEN; + 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) + */ +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[HEADERLEN]; + uint32_t packetlen = ntohl(header->length); + uint32_t datalen = packetlen - HEADERLEN; + + 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__); + } + // 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. + */ +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 < HEADERLEN) + 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; +} diff --git a/src/usbmux.h b/src/usbmux.h new file mode 100644 index 0000000..2bcdb15 --- /dev/null +++ b/src/usbmux.h @@ -0,0 +1,51 @@ +/* + * 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 +#include +//#include + + +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); + +#endif diff --git a/src/usbmuxd-proto.h b/src/usbmuxd-proto.h new file mode 100644 index 0000000..7f8c2d6 --- /dev/null +++ b/src/usbmuxd-proto.h @@ -0,0 +1,52 @@ +/* Protocol defintion for usbmuxd proxy protocol */ + +#ifndef __USBMUXD_PROTO_H +#define __USBMUXD_PROTO_H + +#include + +#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 new file mode 100644 index 0000000..15e97ee --- /dev/null +++ b/src/usbmuxd.h @@ -0,0 +1,45 @@ +#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); + +#endif /* __USBMUXD_H */ diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 0000000..5d20bbf --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,5 @@ +bin_PROGRAMS = iproxy + +iproxy_SOURCES = iproxy.c +iproxy_CFLAGS = -I$(top_srcdir)/src +iproxy_LDADD = ../src/libusbmuxd.la diff --git a/tools/iproxy.c b/tools/iproxy.c new file mode 100644 index 0000000..3cb2894 --- /dev/null +++ b/tools/iproxy.c @@ -0,0 +1,241 @@ +/* + * iproxy -- proxy that enables tcp service access to iPhone/iPod + * via USB cable + * TODO: improve code... + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sock_stuff.h" +#include "usbmuxd.h" + +static uint16_t listen_port = 0; +static uint16_t device_port = 0; + +pthread_mutex_t smutex = PTHREAD_MUTEX_INITIALIZER; + +struct client_data { + int fd; + int sfd; + volatile int stop_ctos; + volatile int stop_stoc; +}; + +void *run_stoc_loop(void *arg) +{ + struct client_data *cdata = (struct client_data*)arg; + int recv_len; + int sent; + char buffer[131072]; + + printf("%s: fd = %d\n", __func__, cdata->fd); + + while (!cdata->stop_stoc && cdata->fd>0 && cdata->sfd>0) { + recv_len = recv_buf_timeout(cdata->sfd, buffer, sizeof(buffer), 0, 5000); + if (recv_len <= 0) { + if (recv_len == 0) { + // try again + continue; + } else { + fprintf(stderr, "recv failed: %s\n", strerror(errno)); + break; + } + } else { +// printf("received %d bytes from server\n", recv_len); + // send to socket + sent = send_buf(cdata->fd, buffer, recv_len); + if (sent < recv_len) { + if (sent <= 0) { + fprintf(stderr, "send failed: %s\n", strerror(errno)); + break; + } else { + fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len); + } + } else { + // sending succeeded, receive from device +// printf("pushed %d bytes to client\n", sent); + } + } + } + close(cdata->fd); + cdata->fd = -1; + cdata->stop_ctos = 1; + + return NULL; +} + +void *run_ctos_loop(void *arg) +{ + struct client_data *cdata = (struct client_data*)arg; + int recv_len; + int sent; + char buffer[131072]; + pthread_t stoc = 0; + + printf("%s: fd = %d\n", __func__, cdata->fd); + + cdata->stop_stoc = 0; + pthread_create(&stoc, NULL, run_stoc_loop, cdata); + + while (!cdata->stop_ctos && cdata->fd>0 && cdata->sfd>0) { + recv_len = recv_buf_timeout(cdata->fd, buffer, sizeof(buffer), 0, 5000); + if (recv_len <= 0) { + if (recv_len == 0) { + // try again + continue; + } else { + fprintf(stderr, "recv failed: %s\n", strerror(errno)); + break; + } + } else { +// printf("pulled %d bytes from client\n", recv_len); + // send to local socket + sent = send_buf(cdata->sfd, buffer, recv_len); + if (sent < recv_len) { + if (sent <= 0) { + fprintf(stderr, "send failed: %s\n", strerror(errno)); + break; + } else { + fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len); + } + } else { + // sending succeeded, receive from device +// printf("sent %d bytes to server\n", sent); + } + } + } + close(cdata->fd); + cdata->fd = -1; + cdata->stop_stoc = 1; + + pthread_join(stoc, NULL); + + return NULL; +} + +void *acceptor_thread(void *arg) +{ + struct client_data *cdata; + usbmuxd_scan_result *dev_list = NULL; + pthread_t ctos; + int count; + + if (!arg) { + fprintf(stderr, "invalid client_data provided!\n"); + return NULL; + } + + cdata = (struct client_data*)arg; + + if ((count = usbmuxd_scan(&dev_list)) < 0) { + printf("Connecting to usbmuxd failed, terminating.\n"); + free(dev_list); + return NULL; + } + + fprintf(stdout, "Number of available devices == %d\n", count); + + if (dev_list == NULL || dev_list[0].handle == 0) { + printf("No connected device found, terminating.\n"); + free(dev_list); + return NULL; + } + + fprintf(stdout, "Requesting connecion to device handle == %d (serial: %s), port %d\n", dev_list[0].handle, dev_list[0].serial_number, device_port); + + cdata->sfd = usbmuxd_connect(dev_list[0].handle, device_port); + free(dev_list); + if (cdata->sfd < 0) { + fprintf(stderr, "Error connecting to device!\n"); + } else { + cdata->stop_ctos = 0; + pthread_create(&ctos, NULL, run_ctos_loop, cdata); + pthread_join(ctos, NULL); + } + + if (cdata->fd > 0) { + close(cdata->fd); + } + if (cdata->sfd > 0) { + close(cdata->sfd); + } + + return NULL; +} + +int main(int argc, char **argv) +{ + int mysock = -1; + + if (argc != 3) { + printf("usage: %s LOCAL_TCP_PORT DEVICE_TCP_PORT\n", argv[0]); + return 0; + } + + listen_port = atoi(argv[1]); + device_port = atoi(argv[2]); + + if (!listen_port) { + fprintf(stderr, "Invalid listen_port specified!\n"); + return -EINVAL; + } + + if (!device_port) { + fprintf(stderr, "Invalid device_port specified!\n"); + return -EINVAL; + } + + // first create the listening socket endpoint waiting for connections. + mysock = create_socket(listen_port); + if (mysock < 0) { + fprintf(stderr, "Error creating socket: %s\n", strerror(errno)); + return -errno; + } else { + pthread_t acceptor; + struct sockaddr_in c_addr; + socklen_t len = sizeof(struct sockaddr_in); + struct client_data cdata; + int c_sock; + while (1) { + printf("waiting for connection\n"); + c_sock = accept(mysock, (struct sockaddr*)&c_addr, &len); + if (c_sock) { + printf("accepted connection, fd = %d\n", c_sock); + cdata.fd = c_sock; + pthread_create(&acceptor, NULL, acceptor_thread, &cdata); + pthread_join(acceptor, NULL); + } else { + break; + } + } + close(c_sock); + close(mysock); + } + + return 0; +} diff --git a/udev/85-usbmuxd.rules b/udev/85-usbmuxd.rules new file mode 100644 index 0000000..69ddef8 --- /dev/null +++ b/udev/85-usbmuxd.rules @@ -0,0 +1,37 @@ +# usbmuxd (iPhone "Apple Mobile Device" MUXer listening on /var/run/usbmuxd) +#if +#SUBSYSTEMS=="usb_interface", SYMLINK+="usbmux/interface" + +#SUBSYSTEMS!="usb", GOTO="usbmuxd_rules_end" # stops the whole script working +ATTR{idVendor}!="05ac", GOTO="usbmuxd_rules_end" + +# If it's plug insertion, flip it into dual "PTP + Apple Mobile Device" configuration +# This allows another application to switch it later without it getting switched back (hopefully) +# TODO: check iPod Touch/3G +SUBSYSTEM=="usb", ACTION=="add", ATTR{product}=="iPhone", ATTR{bConfigurationValue}!="3", ATTR{bConfigurationValue}="3", GOTO="usbmuxd_rules_end" + +# SYMLINK the usbmux endpoints, if we get them +# TODO: Multiple devices +# TODO: work out how to make nice, incrementing usbmux/{0,1,2,3}-in for +LABEL="usbmuxd_rules_usbmux" + +# ff/fe/02 == usbmux +# +#ACTION=="add", + +# Try to symlink the interface, containing the endpoints. +# ...But it doesn't work +#KERNELS=="7-3:3.1", SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="01", ATTRS{bAlternateSetting}==" 0", ATTRS{bNumEndpoints}=="02", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="fe", ATTRS{bInterfaceProtocol}=="02", SYMLINK+="usbmux/prettyplease", RUN+="/bin/ls -l /dev/usbmux/prettyplease" + +#ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="fe", ATTRS{bInterfaceProtocol}=="02", SYMLINK+="usbmux/interface" + +# Cute names, really they should have nice numerically increasing names. +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", SYMLINK+="usbmux/in" +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbmux/out" + +# Start and stop 'usbmuxd' as required. +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec /usr/local/sbin/usbmuxd" +ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 2 --exec /usr/local/sbin/usbmuxd" + +# skip +LABEL="usbmuxd_rules_end" diff --git a/udev/Makefile.am b/udev/Makefile.am new file mode 100644 index 0000000..321008a --- /dev/null +++ b/udev/Makefile.am @@ -0,0 +1,4 @@ +udevdir=$(sysconfdir)/udev/rules.d/ +udev_DATA=85-usbmuxd.rules + +EXTRA_DIST = 85-usbmuxd.rules diff --git a/usbmux.c b/usbmux.c deleted file mode 100644 index e86e3bc..0000000 --- a/usbmux.c +++ /dev/null @@ -1,1259 +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 -#include -#include -#include -#include -#include -#include -#include -#include -#include "usbmux.h" - -#define BULKIN 0x85 -#define BULKOUT 0x04 -#define HEADERLEN 28 - -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; -}; - -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; -}; - - -static pthread_mutex_t usbmuxmutex = 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; -} - -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) - vfprintf(stderr, format, args); - - va_end(args); -#endif -} - -#ifdef DEBUG -/** - * 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"); -} -#endif - -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); - } -} - -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 - */ -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]; - -#if 0 - log_debug_msg("checking configuration...\n"); - if (device->__device->config->bConfigurationValue != 3) { - log_debug_msg - ("WARNING: usb device configuration is not 3 as expected!\n"); - } - - log_debug_msg("setting configuration...\n"); - ret = usb_set_configuration(device->device, 3); - if (ret != 0) { - log_debug_msg("Hm, usb_set_configuration returned %d: %s\n", ret, - strerror(-ret)); -#if LIBUSB_HAS_GET_DRIVER_NP - log_debug_msg("trying to fix:\n"); - log_debug_msg("-> detaching kernel driver... "); - ret = - usb_detach_kernel_driver_np(device->device, - device->__device->config-> - interface->altsetting-> - bInterfaceNumber); - if (ret != 0) { - log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", - ret, strerror(-ret)); - } else { - log_debug_msg("done.\n"); - log_debug_msg("setting configuration again... "); - ret = usb_set_configuration(device->device, 3); - if (ret != 0) { - log_debug_msg - ("Error: usb_set_configuration returned %d: %s\n", ret, - strerror(-ret)); - log_debug_msg("--> trying to continue anyway...\n"); - } else { - log_debug_msg("done.\n"); - } - } -#else - log_debug_msg("--> trying to continue anyway...\n"); -#endif - } else { - log_debug_msg("done.\n"); - } -#endif - - 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"); - } - - 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; - - // Initialize libusb - usb_init(); - usb_find_busses(); - usb_find_devices(); - - // Set the device configuration - for (bus = usb_get_busses(); bus; bus = bus->next) - //if (bus->location == bus_n) - for (dev = bus->devices; dev != NULL; dev = dev->next) - if (dev->devnum == dev_n) { - newdevice->__device = dev; - newdevice->usbdev = usb_open(newdevice->__device); - 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; - - 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 - */ -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; - -#ifdef DEBUG -#ifdef DEBUG_MORE - printf("===============================\n%s: trying to send\n", - __func__); - print_buffer(data, datalen); - printf("===============================\n"); -#endif -#endif - 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; - } - } while (0); // fall out - -#ifdef DEBUG - if (bytes > 0) { - if (toto_debug > 0) { - printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); - printf("%s: sent to device\n", __func__); - print_buffer(data, bytes); - printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); - } - } -#endif - 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. - */ -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; - } -#ifdef DEBUG - if (bytes > 0) { - if (toto_debug > 0) { - printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); - printf("%s: received from device:\n", __func__); - print_buffer(data, bytes); - printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); - } - } -#endif - - 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 - */ -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 = HEADERLEN; - 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 = HEADERLEN; - 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; - 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_FIN; - 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 - HEADERLEN; - 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) - */ -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[HEADERLEN]; - uint32_t packetlen = ntohl(header->length); - uint32_t datalen = packetlen - HEADERLEN; - - 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__); - } - // 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. - */ -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 < HEADERLEN) - 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; -} diff --git a/usbmux.h b/usbmux.h deleted file mode 100644 index 2bcdb15..0000000 --- a/usbmux.h +++ /dev/null @@ -1,51 +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 -#include -//#include - - -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); - -#endif diff --git a/usbmuxd-proto.h b/usbmuxd-proto.h deleted file mode 100644 index 7f8c2d6..0000000 --- a/usbmuxd-proto.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Protocol defintion for usbmuxd proxy protocol */ - -#ifndef __USBMUXD_PROTO_H -#define __USBMUXD_PROTO_H - -#include - -#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/usbmuxd.h b/usbmuxd.h deleted file mode 100644 index 15e97ee..0000000 --- a/usbmuxd.h +++ /dev/null @@ -1,45 +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); - -#endif /* __USBMUXD_H */ -- cgit v1.1-32-gdbae From e4ee9af3ee1c7dbd25d5ca183cc35fa6e48469eb Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 4 May 2009 18:23:52 +0200 Subject: null children[i] pointers after freeing them and check for errors when calling freopen (prevents compiler warnings). --- src/main.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main.c b/src/main.c index e7292cc..b4b5283 100644 --- a/src/main.c +++ b/src/main.c @@ -993,9 +993,15 @@ static int daemonize() return -2; } // Redirect standard files to /dev/null - freopen("/dev/null", "r", stdin); - freopen("/dev/null", "w", stdout); - freopen("/dev/null", "w", stderr); + 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; } @@ -1320,6 +1326,7 @@ int main(int argc, char **argv) if (children[i] != NULL) { pthread_join(children[i]->thread, NULL); free(children[i]); + children[i] = NULL; } } -- cgit v1.1-32-gdbae From f64eb1f01fe21819e6e9c43aa97830460b32a1f9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 5 May 2009 15:04:52 +0200 Subject: README updated --- README | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README b/README index 42ca40a..ff28e19 100644 --- a/README +++ b/README @@ -20,6 +20,8 @@ libiphone compatible with the 'usbmuxd' infrastructure is called Building ======== + ./autogen.sh + ./configure --sysconfdir=/etc make sudo make install -- cgit v1.1-32-gdbae From b8d58d4a9b10f35ff0b72c7348eb329eb4465feb Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 5 May 2009 18:59:35 +0200 Subject: Makefile removed. --- Makefile | 641 --------------------------------------------------------------- 1 file changed, 641 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index d933bd2..0000000 --- a/Makefile +++ /dev/null @@ -1,641 +0,0 @@ -# Makefile.in generated by automake 1.10.2 from Makefile.am. -# Makefile. Generated from Makefile.in by configure. - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - - - -pkgdatadir = $(datadir)/usbmuxd -pkglibdir = $(libdir)/usbmuxd -pkgincludedir = $(includedir)/usbmuxd -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = i686-pc-linux-gnu -host_triplet = i686-pc-linux-gnu -subdir = . -DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in $(srcdir)/config.h.in \ - $(top_srcdir)/configure AUTHORS COPYING compile config.guess \ - config.sub depcomp install-sh ltmain.sh missing -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno config.status.lineno -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = config.h -CONFIG_CLEAN_FILES = -SOURCES = -DIST_SOURCES = -RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ - html-recursive info-recursive install-data-recursive \ - install-dvi-recursive install-exec-recursive \ - install-html-recursive install-info-recursive \ - install-pdf-recursive install-ps-recursive install-recursive \ - installcheck-recursive installdirs-recursive pdf-recursive \ - ps-recursive uninstall-recursive -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -ETAGS = etags -CTAGS = ctags -DIST_SUBDIRS = $(SUBDIRS) -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -distdir = $(PACKAGE)-$(VERSION) -top_distdir = $(distdir) -am__remove_distdir = \ - { test ! -d $(distdir) \ - || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ - && rm -fr $(distdir); }; } -DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 -GZIP_ENV = --best -distuninstallcheck_listfiles = find . -type f -print -distcleancheck_listfiles = find . -type f -print -ACLOCAL = ${SHELL} /home/nikias/coding/usbmuxd/missing --run aclocal-1.10 -AMTAR = ${SHELL} /home/nikias/coding/usbmuxd/missing --run tar -AR = ar -AUTOCONF = ${SHELL} /home/nikias/coding/usbmuxd/missing --run autoconf -AUTOHEADER = ${SHELL} /home/nikias/coding/usbmuxd/missing --run autoheader -AUTOMAKE = ${SHELL} /home/nikias/coding/usbmuxd/missing --run automake-1.10 -AWK = gawk -CC = gcc -CCDEPMODE = depmode=gcc3 -CFLAGS = -g -O2 -CPP = gcc -E -CPPFLAGS = -CYGPATH_W = echo -DEFS = -DHAVE_CONFIG_H -DEPDIR = .deps -DSYMUTIL = -DUMPBIN = -ECHO_C = -ECHO_N = -n -ECHO_T = -EGREP = /bin/grep -E -EXEEXT = -FGREP = /bin/grep -F -GREP = /bin/grep -INSTALL = /usr/bin/install -c -INSTALL_DATA = ${INSTALL} -m 644 -INSTALL_PROGRAM = ${INSTALL} -INSTALL_SCRIPT = ${INSTALL} -INSTALL_STRIP_PROGRAM = $(install_sh) -c -s -LD = /usr/bin/ld -LDFLAGS = -LIBOBJS = -LIBS = -LIBTOOL = $(SHELL) $(top_builddir)/libtool -LIPO = -LN_S = ln -s -LTLIBOBJS = -MAKEINFO = ${SHELL} /home/nikias/coding/usbmuxd/missing --run makeinfo -MKDIR_P = /bin/mkdir -p -NM = /usr/bin/nm -B -NMEDIT = -OBJDUMP = objdump -OBJEXT = o -OTOOL = -OTOOL64 = -PACKAGE = usbmuxd -PACKAGE_BUGREPORT = nikias@gmx.li -PACKAGE_NAME = usbmuxd -PACKAGE_STRING = usbmuxd 0.1.0 -PACKAGE_TARNAME = usbmuxd -PACKAGE_VERSION = 0.1.0 -PATH_SEPARATOR = : -PKG_CONFIG = /usr/bin/pkg-config -RANLIB = ranlib -SED = /bin/sed -SET_MAKE = -SHELL = /bin/bash -STRIP = strip -VERSION = 0.1.0 -abs_builddir = /home/nikias/coding/usbmuxd -abs_srcdir = /home/nikias/coding/usbmuxd -abs_top_builddir = /home/nikias/coding/usbmuxd -abs_top_srcdir = /home/nikias/coding/usbmuxd -ac_ct_CC = gcc -ac_ct_DUMPBIN = -am__include = include -am__leading_dot = . -am__quote = -am__tar = ${AMTAR} chof - "$$tardir" -am__untar = ${AMTAR} xf - -bindir = ${exec_prefix}/bin -build = i686-pc-linux-gnu -build_alias = -build_cpu = i686 -build_os = linux-gnu -build_vendor = pc -builddir = . -datadir = ${datarootdir} -datarootdir = ${prefix}/share -docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} -dvidir = ${docdir} -exec_prefix = ${prefix} -host = i686-pc-linux-gnu -host_alias = -host_cpu = i686 -host_os = linux-gnu -host_vendor = pc -htmldir = ${docdir} -includedir = ${prefix}/include -infodir = ${datarootdir}/info -install_sh = $(SHELL) /home/nikias/coding/usbmuxd/install-sh -libdir = ${exec_prefix}/lib -libexecdir = ${exec_prefix}/libexec -libusb_CFLAGS = -libusb_LIBS = -lusb -localedir = ${datarootdir}/locale -localstatedir = ${prefix}/var -lt_ECHO = echo -mandir = ${datarootdir}/man -mkdir_p = /bin/mkdir -p -oldincludedir = /usr/include -pdfdir = ${docdir} -prefix = /usr/local -program_transform_name = s,x,x, -psdir = ${docdir} -sbindir = ${exec_prefix}/sbin -sharedstatedir = ${prefix}/com -srcdir = . -sysconfdir = /etc -target_alias = -top_build_prefix = -top_builddir = . -top_srcdir = . -SUBDIRS = src udev tools -EXTRA_DIST = README.devel -all: config.h - $(MAKE) $(AM_MAKEFLAGS) all-recursive - -.SUFFIXES: -am--refresh: - @: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ - cd $(srcdir) && $(AUTOMAKE) --foreign \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --foreign Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - echo ' $(SHELL) ./config.status'; \ - $(SHELL) ./config.status;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) - -config.h: stamp-h1 - @if test ! -f $@; then \ - rm -f stamp-h1; \ - $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ - else :; fi - -stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status - @rm -f stamp-h1 - cd $(top_builddir) && $(SHELL) ./config.status config.h -$(srcdir)/config.h.in: $(am__configure_deps) - cd $(top_srcdir) && $(AUTOHEADER) - rm -f stamp-h1 - touch $@ - -distclean-hdr: - -rm -f config.h stamp-h1 - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -distclean-libtool: - -rm -f libtool config.lt - -# This directory's subdirectories are mostly independent; you can cd -# into them and run `make' without going through this Makefile. -# To change the values of `make' variables: instead of editing Makefiles, -# (1) if the variable is set in `config.status', edit `config.status' -# (which will cause the Makefiles to be regenerated when you run `make'); -# (2) otherwise, pass the desired values on the `make' command line. -$(RECURSIVE_TARGETS): - @failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -$(RECURSIVE_CLEAN_TARGETS): - @failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ - dot_seen=no; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - rev=''; for subdir in $$list; do \ - if test "$$subdir" = "."; then :; else \ - rev="$$subdir $$rev"; \ - fi; \ - done; \ - rev="$$rev ."; \ - target=`echo $@ | sed s/-recursive//`; \ - for subdir in $$rev; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done && test -z "$$fail" -tags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ - done -ctags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ - done - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ - fi -ctags: CTAGS -CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - $(am__remove_distdir) - test -d $(distdir) || mkdir $(distdir) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ - fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ - else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ - || exit 1; \ - fi; \ - done - list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - distdir=`$(am__cd) $(distdir) && pwd`; \ - top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ - (cd $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$top_distdir" \ - distdir="$$distdir/$$subdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - distdir) \ - || exit 1; \ - fi; \ - done - -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ - ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ - || chmod -R a+r $(distdir) -dist-gzip: distdir - tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - $(am__remove_distdir) -dist-bzip2: distdir - tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 - $(am__remove_distdir) - -dist-lzma: distdir - tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma - $(am__remove_distdir) - -dist-tarZ: distdir - tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z - $(am__remove_distdir) - -dist-shar: distdir - shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz - $(am__remove_distdir) - -dist-zip: distdir - -rm -f $(distdir).zip - zip -rq $(distdir).zip $(distdir) - $(am__remove_distdir) - -dist dist-all: distdir - tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 - $(am__remove_distdir) - -# This target untars the dist file and tries a VPATH configuration. Then -# it guarantees that the distribution is self-contained by making another -# tarfile. -distcheck: dist - case '$(DIST_ARCHIVES)' in \ - *.tar.gz*) \ - GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ - *.tar.bz2*) \ - bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ - *.tar.lzma*) \ - unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ - *.tar.Z*) \ - uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ - *.shar.gz*) \ - GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ - *.zip*) \ - unzip $(distdir).zip ;;\ - esac - chmod -R a-w $(distdir); chmod a+w $(distdir) - mkdir $(distdir)/_build - mkdir $(distdir)/_inst - chmod a-w $(distdir) - dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ - && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ - && cd $(distdir)/_build \ - && ../configure --srcdir=.. --prefix="$$dc_install_base" \ - $(DISTCHECK_CONFIGURE_FLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ - && $(MAKE) $(AM_MAKEFLAGS) check \ - && $(MAKE) $(AM_MAKEFLAGS) install \ - && $(MAKE) $(AM_MAKEFLAGS) installcheck \ - && $(MAKE) $(AM_MAKEFLAGS) uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ - distuninstallcheck \ - && chmod -R a-w "$$dc_install_base" \ - && ({ \ - (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ - distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ - } || { rm -rf "$$dc_destdir"; exit 1; }) \ - && rm -rf "$$dc_destdir" \ - && $(MAKE) $(AM_MAKEFLAGS) dist \ - && rm -rf $(DIST_ARCHIVES) \ - && $(MAKE) $(AM_MAKEFLAGS) distcleancheck - $(am__remove_distdir) - @(echo "$(distdir) archives ready for distribution: "; \ - list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ - sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' -distuninstallcheck: - @cd $(distuninstallcheck_dir) \ - && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ - || { echo "ERROR: files left after uninstall:" ; \ - if test -n "$(DESTDIR)"; then \ - echo " (check DESTDIR support)"; \ - fi ; \ - $(distuninstallcheck_listfiles) ; \ - exit 1; } >&2 -distcleancheck: distclean - @if test '$(srcdir)' = . ; then \ - echo "ERROR: distcleancheck can only run from a VPATH build" ; \ - exit 1 ; \ - fi - @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left in build directory after distclean:" ; \ - $(distcleancheck_listfiles) ; \ - exit 1; } >&2 -check-am: all-am -check: check-recursive -all-am: Makefile config.h -installdirs: installdirs-recursive -installdirs-am: -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-recursive - -clean-am: clean-generic clean-libtool mostlyclean-am - -distclean: distclean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-hdr \ - distclean-libtool distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -info: info-recursive - -info-am: - -install-data-am: - -install-dvi: install-dvi-recursive - -install-exec-am: - -install-html: install-html-recursive - -install-info: install-info-recursive - -install-man: - -install-pdf: install-pdf-recursive - -install-ps: install-ps-recursive - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: - -.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ - install-strip - -.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ - all all-am am--refresh check check-am clean clean-generic \ - clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ - dist-gzip dist-lzma dist-shar dist-tarZ dist-zip distcheck \ - distclean distclean-generic distclean-hdr distclean-libtool \ - distclean-tags distcleancheck distdir distuninstallcheck dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man install-pdf \ - install-pdf-am install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs installdirs-am \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags tags-recursive uninstall uninstall-am - - -indent: - indent -kr -ut -ts4 -l120 src/*.c src/*.h tools/*.c -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: -- cgit v1.1-32-gdbae From a04c396a21d29da832de21c693da18e6cbf56a13 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 18 May 2009 00:39:11 +0200 Subject: mall change to recv_buf_timeout for easier debugging. --- src/sock_stuff.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sock_stuff.c b/src/sock_stuff.c index b51d6ba..137375d 100644 --- a/src/sock_stuff.c +++ b/src/sock_stuff.c @@ -287,7 +287,10 @@ int recv_buf_timeout(int fd, void *data, size_t length, int flags, // but this is an error condition if (verbose >= 3) fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd); - return -1; + return -EAGAIN; + } + if (result < 0) { + return -errno; } return result; } -- cgit v1.1-32-gdbae From ce97f25e9ab038f8a96b6d9c9f1b9d247aeec11c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 18 May 2009 00:39:41 +0200 Subject: Added usbmuxd_recv, usbmuxd_recv_timeout, usbmuxd_send, and usbmuxd_disconnect --- src/libusbmuxd.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/usbmuxd.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/src/libusbmuxd.c b/src/libusbmuxd.c index c8acbf8..4cd0a6d 100644 --- a/src/libusbmuxd.c +++ b/src/libusbmuxd.c @@ -200,3 +200,49 @@ int usbmuxd_connect(const int handle, const unsigned short tcp_port) 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/usbmuxd.h b/src/usbmuxd.h index 15e97ee..ba45ec3 100644 --- a/src/usbmuxd.h +++ b/src/usbmuxd.h @@ -42,4 +42,50 @@ int usbmuxd_scan(usbmuxd_scan_result **available_devices); */ 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 */ -- cgit v1.1-32-gdbae From a90a7fc0a4ff4ceacc3cb1319151f594eb376315 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 18 May 2009 01:46:58 +0200 Subject: Added pkgconfig file for usbmuxd. --- Makefile.am | 3 +++ configure.ac | 1 + libusbmuxd-1.0.pc.in | 12 ++++++++++++ 3 files changed, 16 insertions(+) create mode 100644 libusbmuxd-1.0.pc.in diff --git a/Makefile.am b/Makefile.am index 43dc592..12e6a35 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,8 @@ SUBDIRS = src udev tools +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libusbmuxd-1.0.pc + indent: indent -kr -ut -ts4 -l120 src/*.c src/*.h tools/*.c diff --git a/configure.ac b/configure.ac index 7c54416..ef9cbdd 100644 --- a/configure.ac +++ b/configure.ac @@ -25,4 +25,5 @@ Makefile src/Makefile tools/Makefile udev/Makefile +libusbmuxd-1.0.pc ]) diff --git a/libusbmuxd-1.0.pc.in b/libusbmuxd-1.0.pc.in new file mode 100644 index 0000000..84c5027 --- /dev/null +++ b/libusbmuxd-1.0.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libusbmuxd +Description: A library to communicate with the usbmux daemon +Version: @VERSION@ +Requires: libusb >= 0.1.12 +Libs: -L${libdir} -lusbmuxd +Cflags: -I${includedir} + -- cgit v1.1-32-gdbae From 5027da9381f64bfa321132e6cbd570db379062e1 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 18 May 2009 01:55:51 +0200 Subject: renamed libusbmuxd-1.0.pc.in to libusbmuxd.pc.in --- Makefile.am | 2 +- configure.ac | 2 +- libusbmuxd-1.0.pc.in | 12 ------------ libusbmuxd.pc.in | 12 ++++++++++++ 4 files changed, 14 insertions(+), 14 deletions(-) delete mode 100644 libusbmuxd-1.0.pc.in create mode 100644 libusbmuxd.pc.in diff --git a/Makefile.am b/Makefile.am index 12e6a35..403981d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS = src udev tools pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libusbmuxd-1.0.pc +pkgconfig_DATA = libusbmuxd.pc indent: indent -kr -ut -ts4 -l120 src/*.c src/*.h tools/*.c diff --git a/configure.ac b/configure.ac index ef9cbdd..03d207f 100644 --- a/configure.ac +++ b/configure.ac @@ -25,5 +25,5 @@ Makefile src/Makefile tools/Makefile udev/Makefile -libusbmuxd-1.0.pc +libusbmuxd.pc ]) diff --git a/libusbmuxd-1.0.pc.in b/libusbmuxd-1.0.pc.in deleted file mode 100644 index 84c5027..0000000 --- a/libusbmuxd-1.0.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libusbmuxd -Description: A library to communicate with the usbmux daemon -Version: @VERSION@ -Requires: libusb >= 0.1.12 -Libs: -L${libdir} -lusbmuxd -Cflags: -I${includedir} - diff --git a/libusbmuxd.pc.in b/libusbmuxd.pc.in new file mode 100644 index 0000000..84c5027 --- /dev/null +++ b/libusbmuxd.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libusbmuxd +Description: A library to communicate with the usbmux daemon +Version: @VERSION@ +Requires: libusb >= 0.1.12 +Libs: -L${libdir} -lusbmuxd +Cflags: -I${includedir} + -- cgit v1.1-32-gdbae From 85de7aa6bd214aa5303f31f078acfe6e4d7a89c0 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 19 May 2009 07:32:39 +0200 Subject: Create m4 directory if not present. --- autogen.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/autogen.sh b/autogen.sh index 90f6046..e1f46a0 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,4 +1,5 @@ #!/bin/sh +if [ ! -d m4 ]; then echo mkdir m4; fi aclocal -I m4 || exit 1 libtoolize || exit 1 autoheader || exit 1 -- cgit v1.1-32-gdbae From e1efbba597356f068b5cf90b16527170ad625b41 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 19 May 2009 11:35:25 +0200 Subject: WTF?! echo mkdir m4 --> mkdir m4. Now it's correct. --- autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index e1f46a0..440c1e2 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,5 +1,5 @@ #!/bin/sh -if [ ! -d m4 ]; then echo mkdir m4; fi +if [ ! -d m4 ]; then mkdir m4; fi aclocal -I m4 || exit 1 libtoolize || exit 1 autoheader || exit 1 -- cgit v1.1-32-gdbae From 5d34c2e7c70de039c75c7a39933b98d14a659176 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 19 May 2009 14:00:28 +0200 Subject: modified udev rules file to reflect autoconf prefix specification --- configure.ac | 1 + udev/85-usbmuxd.rules | 37 ------------------------------------- udev/85-usbmuxd.rules.in | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 37 deletions(-) delete mode 100644 udev/85-usbmuxd.rules create mode 100644 udev/85-usbmuxd.rules.in diff --git a/configure.ac b/configure.ac index 03d207f..55ce7af 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,7 @@ AC_OUTPUT([ Makefile src/Makefile tools/Makefile +udev/85-usbmuxd.rules udev/Makefile libusbmuxd.pc ]) diff --git a/udev/85-usbmuxd.rules b/udev/85-usbmuxd.rules deleted file mode 100644 index 69ddef8..0000000 --- a/udev/85-usbmuxd.rules +++ /dev/null @@ -1,37 +0,0 @@ -# usbmuxd (iPhone "Apple Mobile Device" MUXer listening on /var/run/usbmuxd) -#if -#SUBSYSTEMS=="usb_interface", SYMLINK+="usbmux/interface" - -#SUBSYSTEMS!="usb", GOTO="usbmuxd_rules_end" # stops the whole script working -ATTR{idVendor}!="05ac", GOTO="usbmuxd_rules_end" - -# If it's plug insertion, flip it into dual "PTP + Apple Mobile Device" configuration -# This allows another application to switch it later without it getting switched back (hopefully) -# TODO: check iPod Touch/3G -SUBSYSTEM=="usb", ACTION=="add", ATTR{product}=="iPhone", ATTR{bConfigurationValue}!="3", ATTR{bConfigurationValue}="3", GOTO="usbmuxd_rules_end" - -# SYMLINK the usbmux endpoints, if we get them -# TODO: Multiple devices -# TODO: work out how to make nice, incrementing usbmux/{0,1,2,3}-in for -LABEL="usbmuxd_rules_usbmux" - -# ff/fe/02 == usbmux -# -#ACTION=="add", - -# Try to symlink the interface, containing the endpoints. -# ...But it doesn't work -#KERNELS=="7-3:3.1", SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="01", ATTRS{bAlternateSetting}==" 0", ATTRS{bNumEndpoints}=="02", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="fe", ATTRS{bInterfaceProtocol}=="02", SYMLINK+="usbmux/prettyplease", RUN+="/bin/ls -l /dev/usbmux/prettyplease" - -#ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="fe", ATTRS{bInterfaceProtocol}=="02", SYMLINK+="usbmux/interface" - -# Cute names, really they should have nice numerically increasing names. -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", SYMLINK+="usbmux/in" -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbmux/out" - -# Start and stop 'usbmuxd' as required. -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec /usr/local/sbin/usbmuxd" -ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 2 --exec /usr/local/sbin/usbmuxd" - -# skip -LABEL="usbmuxd_rules_end" diff --git a/udev/85-usbmuxd.rules.in b/udev/85-usbmuxd.rules.in new file mode 100644 index 0000000..e661ccd --- /dev/null +++ b/udev/85-usbmuxd.rules.in @@ -0,0 +1,37 @@ +# usbmuxd (iPhone "Apple Mobile Device" MUXer listening on /var/run/usbmuxd) +#if +#SUBSYSTEMS=="usb_interface", SYMLINK+="usbmux/interface" + +#SUBSYSTEMS!="usb", GOTO="usbmuxd_rules_end" # stops the whole script working +ATTR{idVendor}!="05ac", GOTO="usbmuxd_rules_end" + +# If it's plug insertion, flip it into dual "PTP + Apple Mobile Device" configuration +# This allows another application to switch it later without it getting switched back (hopefully) +# TODO: check iPod Touch/3G +SUBSYSTEM=="usb", ACTION=="add", ATTR{product}=="iPhone", ATTR{bConfigurationValue}!="3", ATTR{bConfigurationValue}="3", GOTO="usbmuxd_rules_end" + +# SYMLINK the usbmux endpoints, if we get them +# TODO: Multiple devices +# TODO: work out how to make nice, incrementing usbmux/{0,1,2,3}-in for +LABEL="usbmuxd_rules_usbmux" + +# ff/fe/02 == usbmux +# +#ACTION=="add", + +# Try to symlink the interface, containing the endpoints. +# ...But it doesn't work +#KERNELS=="7-3:3.1", SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="01", ATTRS{bAlternateSetting}==" 0", ATTRS{bNumEndpoints}=="02", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="fe", ATTRS{bInterfaceProtocol}=="02", SYMLINK+="usbmux/prettyplease", RUN+="/bin/ls -l /dev/usbmux/prettyplease" + +#ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="fe", ATTRS{bInterfaceProtocol}=="02", SYMLINK+="usbmux/interface" + +# Cute names, really they should have nice numerically increasing names. +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", SYMLINK+="usbmux/in" +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbmux/out" + +# Start and stop 'usbmuxd' as required. +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec @prefix@/sbin/usbmuxd" +ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 2 --exec @prefix@/sbin/usbmuxd" + +# skip +LABEL="usbmuxd_rules_end" -- cgit v1.1-32-gdbae From 0c55afdb315f12b0f2a37f37a3ec711c75507c0d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 19 May 2009 16:44:39 +0200 Subject: Let the daemon terminate only when no more device is attached --- src/main.c | 45 ++++++++++++++++++++++++++++++--------------- udev/85-usbmuxd.rules.in | 2 +- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/main.c b/src/main.c index b4b5283..3617e14 100644 --- a/src/main.c +++ b/src/main.c @@ -1006,18 +1006,6 @@ static int daemonize() return 0; } -/** - * signal handler function for cleaning up properly - */ -static void clean_exit(int sig) -{ - if (sig == SIGINT) { - if (verbose >= 1) - fprintf(stderr, "CTRL+C pressed\n"); - } - quit_flag = 1; -} - static void usage() { printf("usage: usbmuxd [options]\n"); @@ -1092,6 +1080,33 @@ static int devices_attached() 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. */ @@ -1121,9 +1136,9 @@ int main(int argc, char **argv) logmsg(LOG_NOTICE, "starting"); // signal(SIGHUP, reload_conf); // none yet - signal(SIGINT, clean_exit); - signal(SIGQUIT, clean_exit); - signal(SIGTERM, clean_exit); + signal(SIGINT, handle_signal); + signal(SIGQUIT, handle_signal); + signal(SIGTERM, handle_signal); signal(SIGPIPE, SIG_IGN); // check for other running instance diff --git a/udev/85-usbmuxd.rules.in b/udev/85-usbmuxd.rules.in index e661ccd..7820a36 100644 --- a/udev/85-usbmuxd.rules.in +++ b/udev/85-usbmuxd.rules.in @@ -31,7 +31,7 @@ ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbm # Start and stop 'usbmuxd' as required. ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec @prefix@/sbin/usbmuxd" -ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 2 --exec @prefix@/sbin/usbmuxd" +ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 3 --exec @prefix@/sbin/usbmuxd" # skip LABEL="usbmuxd_rules_end" -- cgit v1.1-32-gdbae From f8141b55b230dd4c66b39cee843149bdabe13580 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 21 May 2009 22:25:21 +0200 Subject: Added parameter -p to prevent usbmuxd from dropping privileges (see this as a workaround for systems where the usb device access is restricted) --- src/main.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main.c b/src/main.c index 3617e14..9e99c1b 100644 --- a/src/main.c +++ b/src/main.c @@ -57,6 +57,7 @@ static int fsock = -1; static int verbose = DEBUG_LEVEL; static int foreground = 0; static int exit_on_no_devices = 0; +static int preserve_privileges = 0; struct device_info { uint32_t device_id; @@ -1009,9 +1010,11 @@ static int daemonize() static void usage() { printf("usage: usbmuxd [options]\n"); - printf("\t-h|--help print this message.\n"); - printf("\t-v|--verbose be verbose\n"); - printf("\t-f|--foreground do not daemonize\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-p|--preserve-privileges do not drop privileges\n"); printf("\n"); } @@ -1022,12 +1025,13 @@ static void parse_opts(int argc, char **argv) {"foreground", 0, NULL, 'f'}, {"verbose", 0, NULL, 'v'}, {"exit-on-no-devices", 0, NULL, 'e'}, + {"preserve-privileges", 0, NULL, 'p'}, {NULL, 0, NULL, 0} }; int c; while (1) { - c = getopt_long(argc, argv, "hfve", longopts, (int *) 0); + c = getopt_long(argc, argv, "hfvep", longopts, (int *) 0); if (c == -1) { break; } @@ -1045,6 +1049,9 @@ static void parse_opts(int argc, char **argv) case 'e': exit_on_no_devices = 1; break; + case 'p': + preserve_privileges = 1; + break; default: usage(); exit(2); @@ -1198,7 +1205,7 @@ int main(int argc, char **argv) } } // drop elevated privileges - if (getuid() == 0 || geteuid() == 0) { + if (!preserve_privileges && (getuid() == 0 || geteuid() == 0)) { struct passwd *pw = getpwnam("nobody"); if (pw) { setuid(pw->pw_uid); -- cgit v1.1-32-gdbae From f6c4deed001629a408cca62cbf8e82bf303554db Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 23 May 2009 13:01:56 +0200 Subject: Debugging: print correct usb bus location and dev filename. --- src/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.c b/src/main.c index 9e99c1b..7b4fa57 100644 --- a/src/main.c +++ b/src/main.c @@ -674,8 +674,8 @@ static void *usbmuxd_client_init_thread(void *arg) && dev->descriptor.idProduct <= 0x1293) { if (verbose >= 1) logmsg(LOG_NOTICE, - "%s[%x]: Found device on bus %d, id %d", - __func__, THREAD, bus->location, dev->devnum); + "%s[%x]: Found device on bus %s, id %s", + __func__, THREAD, bus->dirname, dev->filename); found++; // construct packet @@ -1182,7 +1182,7 @@ int main(int argc, char **argv) chmod(USBMUXD_SOCKET_FILE, 0666); - if (verbose >= 3) + if (verbose >= 4) usbmux_set_debug(1); if (!foreground) { -- cgit v1.1-32-gdbae From e6de508029e3db03eb295b466d18f2ccf790902b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 23 May 2009 13:15:05 +0200 Subject: Some debugging output for usb_open(). --- src/main.c | 11 +++++------ src/usbmux.c | 3 +++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main.c b/src/main.c index 7b4fa57..f377b82 100644 --- a/src/main.c +++ b/src/main.c @@ -690,13 +690,12 @@ static void *usbmuxd_client_init_thread(void *arg) 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); + 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); } diff --git a/src/usbmux.c b/src/usbmux.c index e86e3bc..90aeb84 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -329,6 +329,9 @@ int usbmux_get_specific_device(int bus_n, int dev_n, if (dev->devnum == 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; } -- cgit v1.1-32-gdbae From 6070107e7c8b27844e7e15d0c7e4ef4f7d0076b0 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 23 May 2009 13:20:49 +0200 Subject: Enable libusb debugging when verbose is >= 2 --- src/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main.c b/src/main.c index f377b82..1eb7af3 100644 --- a/src/main.c +++ b/src/main.c @@ -1181,6 +1181,9 @@ int main(int argc, char **argv) chmod(USBMUXD_SOCKET_FILE, 0666); + if (verbose >= 2) + usb_set_debug(verbose); + if (verbose >= 4) usbmux_set_debug(1); -- cgit v1.1-32-gdbae From fca059d76626a18b086e793f9283ee3070e853d8 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 23 May 2009 22:11:39 +0200 Subject: Make usb enumeration work properly. --- src/main.c | 57 +++++++++++++++++++++++++-------------------------------- src/usbmux.c | 22 +++++++++++----------- 2 files changed, 36 insertions(+), 43 deletions(-) diff --git a/src/main.c b/src/main.c index 1eb7af3..f672231 100644 --- a/src/main.c +++ b/src/main.c @@ -282,8 +282,8 @@ static void *usbmuxd_client_reader_thread(void *arg) cdata->reader_dead = 0; if (verbose >= 3) - logmsg(LOG_NOTICE, "%s[%d:%d]: started", __func__, - cdata->dev->device_id, cdata->dev->use_count); + 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); @@ -303,9 +303,8 @@ static void *usbmuxd_client_reader_thread(void *arg) if (err != 0) { if (verbose >= 2) logmsg(LOG_ERR, - "%s[%d:%d]: encountered USB read error: %d", - __func__, cdata->dev->device_id, - cdata->dev->use_count, err); + "%s[%x]: encountered USB read error: %d", + __func__, THREAD, err); break; } @@ -332,8 +331,7 @@ static void *usbmuxd_client_reader_thread(void *arg) } if (verbose >= 3) - logmsg(LOG_NOTICE, "%s[%d:%d]: terminated", __func__, - cdata->dev->device_id, cdata->dev->use_count); + logmsg(LOG_NOTICE, "%s[%x]: terminated", __func__, THREAD); cdata->reader_dead = 1; @@ -445,8 +443,8 @@ static void *usbmuxd_client_handler_thread(void *arg) cdata = (struct client_data *) arg; if (verbose >= 3) - logmsg(LOG_NOTICE, "%s[%d:%d]: started", __func__, - cdata->dev->device_id, cdata->dev->use_count); + 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) @@ -473,8 +471,7 @@ static void *usbmuxd_client_handler_thread(void *arg) if (result <= 0) { if (result < 0) { if (verbose >= 3) - logmsg(LOG_ERR, "%s: Error: checkfd: %s", __func__, - strerror(errno)); + logmsg(LOG_ERR, "%s[%x]: Error: checkfd: %s", __func__, THREAD, strerror(errno)); } continue; } @@ -486,9 +483,7 @@ static void *usbmuxd_client_handler_thread(void *arg) } if (len < 0) { if (verbose >= 2) - logmsg(LOG_ERR, "%s[%d:%d]: Error: recv: %s", __func__, - cdata->dev->device_id, cdata->dev->use_count, - strerror(errno)); + logmsg(LOG_ERR, "%s[%x]: Error: recv: %s", __func__, THREAD, strerror(errno)); break; } @@ -502,9 +497,7 @@ static void *usbmuxd_client_handler_thread(void *arg) // some kind of timeout... just be patient and retry. } else if (err < 0) { if (verbose >= 2) - logmsg(LOG_ERR, "%s[%d:%d]: USB write error: %d", - __func__, cdata->dev->device_id, - cdata->dev->use_count, err); + logmsg(LOG_ERR, "%s[%x]: USB write error: %d", __func__, THREAD, err); len = -1; break; } @@ -523,8 +516,7 @@ static void *usbmuxd_client_handler_thread(void *arg) leave: // cleanup if (verbose >= 3) - logmsg(LOG_NOTICE, "%s[%d:%d]: terminating", __func__, - cdata->dev->device_id, cdata->dev->use_count); + logmsg(LOG_NOTICE, "%s[%x]: terminating", __func__, THREAD); if (cdata->reader != 0) { cdata->reader_quit = 1; pthread_join(cdata->reader, NULL); @@ -533,8 +525,7 @@ static void *usbmuxd_client_handler_thread(void *arg) cdata->handler_dead = 1; if (verbose >= 3) - logmsg(LOG_NOTICE, "%s[%d:%d]: terminated", __func__, - cdata->dev->device_id, cdata->dev->use_count); + logmsg(LOG_NOTICE, "%s[%x]: terminated", __func__, THREAD); return NULL; } @@ -682,7 +673,10 @@ static void *usbmuxd_client_init_thread(void *arg) 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; - dev_info_rec.device.device_id = dev->devnum; + 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; @@ -755,9 +749,8 @@ static void *usbmuxd_client_init_thread(void *arg) if (verbose >= 3) logmsg(LOG_NOTICE, - "%s[%x]: Setting up connection to usb device #%d on port %d", - __func__, THREAD, c_req->device_id, - ntohs(c_req->tcp_dport)); + "%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); @@ -780,16 +773,16 @@ static void *usbmuxd_client_init_thread(void *arg) // if not found, make a new connection if (verbose >= 2) logmsg(LOG_NOTICE, - "%s[%x]: creating new usb connection, device_id=%d", - __func__, THREAD, c_req->device_id); + "%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(0, c_req->device_id, &phone) < 0) { + 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_id %d could not be opened", - __func__, THREAD, c_req->device_id); + 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; } @@ -825,8 +818,8 @@ static void *usbmuxd_client_init_thread(void *arg) } else { if (verbose >= 2) logmsg(LOG_NOTICE, - "%s[%x]: reusing usb connection, device_id=%d", - __func__, THREAD, c_req->device_id); + "%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); diff --git a/src/usbmux.c b/src/usbmux.c index 90aeb84..c64d1a0 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -324,18 +324,18 @@ int usbmux_get_specific_device(int bus_n, int dev_n, // Set the device configuration for (bus = usb_get_busses(); bus; bus = bus->next) - //if (bus->location == bus_n) - for (dev = bus->devices; dev != NULL; dev = dev->next) - if (dev->devnum == 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 (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; + } } - if (usbmux_config_usb_device(newdevice) == 0) { - goto found; - } - } usbmux_free_device(newdevice); -- cgit v1.1-32-gdbae From 7feced9e014c6478eca0391685c57d4c3ae2fc91 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Sun, 24 May 2009 13:33:16 +0200 Subject: Make udev rules set the right usb config and create pretty usbmux symlinks Signed-off-by: Nikias Bassen --- udev/85-usbmuxd.rules.in | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/udev/85-usbmuxd.rules.in b/udev/85-usbmuxd.rules.in index 7820a36..8aca2ce 100644 --- a/udev/85-usbmuxd.rules.in +++ b/udev/85-usbmuxd.rules.in @@ -1,35 +1,21 @@ # usbmuxd (iPhone "Apple Mobile Device" MUXer listening on /var/run/usbmuxd) -#if -#SUBSYSTEMS=="usb_interface", SYMLINK+="usbmux/interface" -#SUBSYSTEMS!="usb", GOTO="usbmuxd_rules_end" # stops the whole script working -ATTR{idVendor}!="05ac", GOTO="usbmuxd_rules_end" +# Skip anything non Apple +ACTION=="add|remove", SUBSYSTEM!="usb|usb_endpoint", ATTRS{idVendor}!="05ac", GOTO="usbmuxd_rules_end" -# If it's plug insertion, flip it into dual "PTP + Apple Mobile Device" configuration -# This allows another application to switch it later without it getting switched back (hopefully) -# TODO: check iPod Touch/3G -SUBSYSTEM=="usb", ACTION=="add", ATTR{product}=="iPhone", ATTR{bConfigurationValue}!="3", ATTR{bConfigurationValue}="3", GOTO="usbmuxd_rules_end" +# Forces iPhone 1.0, 3G and iPodTouch 1 and 2 to USB configuration 3 +ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="1290|1291|1292|1293", ATTR{bConfigurationValue}!="3", ATTR{bConfigurationValue}="3", GOTO="usbmuxd_rules_end" -# SYMLINK the usbmux endpoints, if we get them -# TODO: Multiple devices -# TODO: work out how to make nice, incrementing usbmux/{0,1,2,3}-in for LABEL="usbmuxd_rules_usbmux" -# ff/fe/02 == usbmux -# -#ACTION=="add", +# Only apply to usb endpoints +ACTION=="add|remove", SUBSYSTEM!="usb_endpoint", GOTO="usbmuxd_rules_end" -# Try to symlink the interface, containing the endpoints. -# ...But it doesn't work -#KERNELS=="7-3:3.1", SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="01", ATTRS{bAlternateSetting}==" 0", ATTRS{bNumEndpoints}=="02", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="fe", ATTRS{bInterfaceProtocol}=="02", SYMLINK+="usbmux/prettyplease", RUN+="/bin/ls -l /dev/usbmux/prettyplease" +# Setup cute names for the endpoints +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", SYMLINK+="usbmux/%s{serial}/%s{direction}" +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbmux/%s{serial}/%s{direction}" -#ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="fe", ATTRS{bInterfaceProtocol}=="02", SYMLINK+="usbmux/interface" - -# Cute names, really they should have nice numerically increasing names. -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", SYMLINK+="usbmux/in" -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbmux/out" - -# Start and stop 'usbmuxd' as required. +# Start and stop 'usbmuxd' as required ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec @prefix@/sbin/usbmuxd" ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 3 --exec @prefix@/sbin/usbmuxd" -- cgit v1.1-32-gdbae From ada0443d5c2a71ba580b1ae122d7212e4fb12078 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 24 May 2009 13:35:35 +0200 Subject: Removed parameter -p and added parameter -d to allow to drop privileges. Default is to NOT drop the privileges as is causes permission problems on some systems. --- src/main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main.c b/src/main.c index f672231..99d2a5c 100644 --- a/src/main.c +++ b/src/main.c @@ -57,7 +57,7 @@ static int fsock = -1; static int verbose = DEBUG_LEVEL; static int foreground = 0; static int exit_on_no_devices = 0; -static int preserve_privileges = 0; +static int drop_privileges = 0; struct device_info { uint32_t device_id; @@ -1006,7 +1006,7 @@ static void usage() 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-p|--preserve-privileges do not drop privileges\n"); + printf("\t-d|--drop-privileges drop privileges after startup\n"); printf("\n"); } @@ -1017,13 +1017,13 @@ static void parse_opts(int argc, char **argv) {"foreground", 0, NULL, 'f'}, {"verbose", 0, NULL, 'v'}, {"exit-on-no-devices", 0, NULL, 'e'}, - {"preserve-privileges", 0, NULL, 'p'}, + {"drop-privileges", 0, NULL, 'd'}, {NULL, 0, NULL, 0} }; int c; while (1) { - c = getopt_long(argc, argv, "hfvep", longopts, (int *) 0); + c = getopt_long(argc, argv, "hfved", longopts, (int *) 0); if (c == -1) { break; } @@ -1041,8 +1041,8 @@ static void parse_opts(int argc, char **argv) case 'e': exit_on_no_devices = 1; break; - case 'p': - preserve_privileges = 1; + case 'd': + drop_privileges = 1; break; default: usage(); @@ -1200,7 +1200,7 @@ int main(int argc, char **argv) } } // drop elevated privileges - if (!preserve_privileges && (getuid() == 0 || geteuid() == 0)) { + if (drop_privileges && (getuid() == 0 || geteuid() == 0)) { struct passwd *pw = getpwnam("nobody"); if (pw) { setuid(pw->pw_uid); -- cgit v1.1-32-gdbae From 12c244a76cc6a75a385ddfc5dc44734825383fe2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 24 May 2009 18:20:54 +0200 Subject: Make udev symlink rules work with recent udev by using usb_id --- udev/85-usbmuxd.rules.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/udev/85-usbmuxd.rules.in b/udev/85-usbmuxd.rules.in index 8aca2ce..3acc944 100644 --- a/udev/85-usbmuxd.rules.in +++ b/udev/85-usbmuxd.rules.in @@ -12,8 +12,8 @@ LABEL="usbmuxd_rules_usbmux" ACTION=="add|remove", SUBSYSTEM!="usb_endpoint", GOTO="usbmuxd_rules_end" # Setup cute names for the endpoints -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", SYMLINK+="usbmux/%s{serial}/%s{direction}" -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbmux/%s{serial}/%s{direction}" +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", IMPORT{program}="usb_id %p --export", SYMLINK+="usbmux/$env{ID_SERIAL_SHORT}/%s{direction}" +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", IMPORT{program}="usb_id %p --export", SYMLINK+="usbmux/$env{ID_SERIAL_SHORT}/%s{direction}" # Start and stop 'usbmuxd' as required ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec @prefix@/sbin/usbmuxd" -- cgit v1.1-32-gdbae From b45560b1a982aab1063eb6fbd65122650efafe9d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 15 Jun 2009 05:11:56 +0200 Subject: Additional mutex when writing to device. --- src/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index 99d2a5c..1ee2480 100644 --- a/src/main.c +++ b/src/main.c @@ -824,11 +824,11 @@ static void *usbmuxd_client_init_thread(void *arg) pthread_mutex_unlock(&usbmux_mutex); // setup connection to iPhone/iPod -// pthread_mutex_lock(&usbmux_mutex); + 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(&usbmux_mutex); + pthread_mutex_unlock(&cur_dev->writer_mutex); if (res != 0) { usbmuxd_send_result(cdata->socket, c_req->header.tag, res); @@ -870,7 +870,9 @@ static void *usbmuxd_client_init_thread(void *arg) // 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: -- cgit v1.1-32-gdbae From 2417678145a801bd311f64e55a07378dab6f3ba0 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 15 Jun 2009 13:02:10 +0200 Subject: removed some #ifdefs to make debugging output more verbose --- src/usbmux.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/usbmux.c b/src/usbmux.c index c64d1a0..87cdede 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -131,7 +131,6 @@ void log_debug_msg(const char *format, ...) #endif } -#ifdef DEBUG /** * for debugging purposes. */ @@ -168,7 +167,6 @@ static void print_buffer(const char *data, const int length) } printf("\n"); } -#endif void hton_header(usbmux_tcp_header * hdr) { @@ -455,14 +453,13 @@ int send_to_device(usbmux_device_t device, char *data, int datalen) int retrycount = 0; int bytes = 0; -#ifdef DEBUG -#ifdef DEBUG_MORE +if (toto_debug > 0) { printf("===============================\n%s: trying to send\n", __func__); print_buffer(data, datalen); printf("===============================\n"); -#endif -#endif +} + do { if (retrycount > 3) { log_debug_msg @@ -499,7 +496,6 @@ int send_to_device(usbmux_device_t device, char *data, int datalen) } } while (0); // fall out -#ifdef DEBUG if (bytes > 0) { if (toto_debug > 0) { printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); @@ -508,7 +504,6 @@ int send_to_device(usbmux_device_t device, char *data, int datalen) printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); } } -#endif return bytes; } @@ -549,7 +544,6 @@ int recv_from_device_timeout(usbmux_device_t device, char *data, } return bytes; } -#ifdef DEBUG if (bytes > 0) { if (toto_debug > 0) { printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); @@ -558,7 +552,6 @@ int recv_from_device_timeout(usbmux_device_t device, char *data, printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); } } -#endif return bytes; } -- cgit v1.1-32-gdbae From bb33ccdf06f261dca033d70772bc256c890c76f7 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Fri, 19 Jun 2009 14:34:16 +0200 Subject: Add product ids to support iPhone 3GS Signed-off-by: Nikias Bassen --- src/main.c | 4 ++-- udev/85-usbmuxd.rules.in | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.c b/src/main.c index 1ee2480..1a62f17 100644 --- a/src/main.c +++ b/src/main.c @@ -662,7 +662,7 @@ static void *usbmuxd_client_init_thread(void *arg) for (dev = bus->devices; dev; dev = dev->next) { if (dev->descriptor.idVendor == 0x05ac && dev->descriptor.idProduct >= 0x1290 - && dev->descriptor.idProduct <= 0x1293) { + && dev->descriptor.idProduct <= 0x1294) { if (verbose >= 1) logmsg(LOG_NOTICE, "%s[%x]: Found device on bus %s, id %s", @@ -1072,7 +1072,7 @@ static int devices_attached() for (dev = bus->devices; dev; dev = dev->next) { if (dev->descriptor.idVendor == 0x05ac && dev->descriptor.idProduct >= 0x1290 - && dev->descriptor.idProduct <= 0x1293) { + && dev->descriptor.idProduct <= 0x1294) { res++; } } diff --git a/udev/85-usbmuxd.rules.in b/udev/85-usbmuxd.rules.in index 3acc944..4f28cdf 100644 --- a/udev/85-usbmuxd.rules.in +++ b/udev/85-usbmuxd.rules.in @@ -3,8 +3,8 @@ # Skip anything non Apple ACTION=="add|remove", SUBSYSTEM!="usb|usb_endpoint", ATTRS{idVendor}!="05ac", GOTO="usbmuxd_rules_end" -# Forces iPhone 1.0, 3G and iPodTouch 1 and 2 to USB configuration 3 -ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="1290|1291|1292|1293", ATTR{bConfigurationValue}!="3", ATTR{bConfigurationValue}="3", GOTO="usbmuxd_rules_end" +# Forces iPhone 1.0, 3G, 3GS and iPodTouch 1 and 2 to USB configuration 3 +ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="1290|1291|1292|1293|1294", ATTR{bConfigurationValue}!="3", ATTR{bConfigurationValue}="3", GOTO="usbmuxd_rules_end" LABEL="usbmuxd_rules_usbmux" -- cgit v1.1-32-gdbae From 94d700159d010176a57640d6f59476aaf43875fc Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 20 Jun 2009 04:29:23 +0200 Subject: hopefully fixed race condition on connection setup --- src/main.c | 22 ++++++++++++++++++++++ src/usbmux.c | 13 +++++++++++++ src/usbmux.h | 2 ++ 3 files changed, 37 insertions(+) diff --git a/src/main.c b/src/main.c index 1a62f17..8e27d8f 100644 --- a/src/main.c +++ b/src/main.c @@ -719,6 +719,7 @@ static void *usbmuxd_client_init_thread(void *arg) 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; } @@ -846,6 +847,27 @@ static void *usbmuxd_client_init_thread(void *arg) } pthread_mutex_unlock(&cur_dev->mutex); + // wait for the initial handshake (SYN->SYN+ACK->ACKto complete + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + + i = 0; + printf("waiting for handshake to complete...\n"); + while (i < 10000) { + if (usbmux_is_connected(cdata->muxclient)) { + printf("handshake done\n"); + break; + } + nanosleep(&ts, NULL); + i+=100; + } + if (!usbmux_is_connected(cdata->muxclient)) { + printf("handshake failed\n"); + 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; diff --git a/src/usbmux.c b/src/usbmux.c index 87cdede..927928e 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -100,6 +100,8 @@ struct usbmux_client_int { int error; int cleanup; + + int connected; }; @@ -734,6 +736,7 @@ int usbmux_new_client(usbmux_device_t device, uint16_t src_port, 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), @@ -931,6 +934,8 @@ uint32_t append_receive_buffer(usbmux_client_t client, char *packet) 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); @@ -1253,3 +1258,11 @@ int usbmux_recv_timeout(usbmux_client_t client, char *data, 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 index 2bcdb15..155316a 100644 --- a/src/usbmux.h +++ b/src/usbmux.h @@ -48,4 +48,6 @@ int usbmux_pullbulk(usbmux_device_t device); int usbmux_get_error(usbmux_client_t client); +int usbmux_is_connected(usbmux_client_t client); + #endif -- cgit v1.1-32-gdbae From 23a07f6bc7e14b325f7b3ea29ebe0eeb1d5635b4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 20 Jun 2009 04:30:44 +0200 Subject: removed debugging output --- src/main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main.c b/src/main.c index 8e27d8f..8f1eeec 100644 --- a/src/main.c +++ b/src/main.c @@ -847,23 +847,20 @@ static void *usbmuxd_client_init_thread(void *arg) } pthread_mutex_unlock(&cur_dev->mutex); - // wait for the initial handshake (SYN->SYN+ACK->ACKto complete + // wait for the initial handshake (SYN->SYN+ACK->ACK) to complete) struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000000; i = 0; - printf("waiting for handshake to complete...\n"); while (i < 10000) { if (usbmux_is_connected(cdata->muxclient)) { - printf("handshake done\n"); break; } nanosleep(&ts, NULL); i+=100; } if (!usbmux_is_connected(cdata->muxclient)) { - printf("handshake failed\n"); usbmuxd_send_result(cdata->socket, c_req->header.tag, -ENOTCONN); goto leave; } -- cgit v1.1-32-gdbae From 296c7764942bc7dac55b631cf17539742b54bf59 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 20 Jun 2009 04:45:47 +0200 Subject: Do not wait for connection request after scan request --- src/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index 8f1eeec..cd87632 100644 --- a/src/main.c +++ b/src/main.c @@ -723,7 +723,9 @@ static void *usbmuxd_client_init_thread(void *arg) goto leave; } - if (verbose >= 3) + goto leave; + +/* if (verbose >= 3) logmsg(LOG_NOTICE, "%s[%x]: Waiting for connect request", __func__, THREAD); @@ -736,7 +738,7 @@ static void *usbmuxd_client_init_thread(void *arg) "%s[%x]: Did not receive any connect request.", __func__, THREAD); goto leave; - } + }*/ connect: -- cgit v1.1-32-gdbae From 96149556f89f4250621f5892a0684f96f8c7c5e5 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 29 Jun 2009 02:54:16 +0200 Subject: use TCP_RST instead of TCP_FIN when closing the connection so the device does not complain with messages like handleMuxTCPInput th.th_flags = 0x1, not TH_ACK(0x10) --- src/usbmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usbmux.c b/src/usbmux.c index 927928e..d7f0710 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -771,7 +771,7 @@ int usbmux_free_client(usbmux_client_t client) int err = 0; int result = 0; pthread_mutex_lock(&client->mutex); - client->header->tcp_flags = TCP_FIN; + client->header->tcp_flags = TCP_RST; client->header->length = 0x1C; client->header->window = 0; client->header->length16 = 0x1C; -- cgit v1.1-32-gdbae From 2bff11cdd189745dd044c759afec9ce9c6ceb9fa Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 13 Jul 2009 14:30:23 +0200 Subject: Added support for PTP + Apple Mobile Device + Apple USB Ethernet interfaces by setting to the highest configuration value available(thanks Martin). --- udev/85-usbmuxd.rules.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/udev/85-usbmuxd.rules.in b/udev/85-usbmuxd.rules.in index 4f28cdf..4e35f7e 100644 --- a/udev/85-usbmuxd.rules.in +++ b/udev/85-usbmuxd.rules.in @@ -4,7 +4,7 @@ ACTION=="add|remove", SUBSYSTEM!="usb|usb_endpoint", ATTRS{idVendor}!="05ac", GOTO="usbmuxd_rules_end" # Forces iPhone 1.0, 3G, 3GS and iPodTouch 1 and 2 to USB configuration 3 -ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="1290|1291|1292|1293|1294", ATTR{bConfigurationValue}!="3", ATTR{bConfigurationValue}="3", GOTO="usbmuxd_rules_end" +ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="1290|1291|1292|1293|1294", ATTR{bConfigurationValue}!="$attr{bNumConfigurations}", ATTR{bConfigurationValue}="$attr{bNumConfigurations}", GOTO="usbmuxd_rules_end" LABEL="usbmuxd_rules_usbmux" -- cgit v1.1-32-gdbae From 50a85a4c8b50a9884ddd5530132995dc962ebb13 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 2 Aug 2009 06:32:22 +0200 Subject: Replaced HEADERLEN with sizeof(usbmux_tcp_header) --- src/usbmux.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/usbmux.c b/src/usbmux.c index d7f0710..1d6497e 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -28,7 +28,6 @@ #define BULKIN 0x85 #define BULKOUT 0x04 -#define HEADERLEN 28 static const uint8_t TCP_FIN = 1; static const uint8_t TCP_SYN = 1 << 1; @@ -570,7 +569,7 @@ 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 = HEADERLEN; + conn->length = sizeof(usbmux_tcp_header); conn->sport = htons(s_port); conn->dport = htons(d_port); conn->scnt = 0; @@ -578,7 +577,7 @@ usbmux_tcp_header *new_mux_packet(uint16_t s_port, uint16_t d_port) conn->offset = 0x50; conn->window = htons(0x0200); conn->nullnull = 0x0000; - conn->length16 = HEADERLEN; + conn->length16 = sizeof(usbmux_tcp_header); return conn; } @@ -879,7 +878,7 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, return sendresult; } else if ((uint32_t) sendresult == blocksize) { // actual number of data bytes sent. - *sent_bytes = sendresult - HEADERLEN; + *sent_bytes = sendresult - sizeof(usbmux_tcp_header); return 0; } else { fprintf(stderr, @@ -903,9 +902,9 @@ uint32_t append_receive_buffer(usbmux_client_t client, char *packet) return 0; usbmux_tcp_header *header = (usbmux_tcp_header *) packet; - char *data = &packet[HEADERLEN]; + char *data = &packet[sizeof(usbmux_tcp_header)]; uint32_t packetlen = ntohl(header->length); - uint32_t datalen = packetlen - HEADERLEN; + uint32_t datalen = packetlen - sizeof(usbmux_tcp_header); int dobroadcast = 0; @@ -1114,7 +1113,7 @@ int usbmux_pullbulk(usbmux_device_t device) cursor = device->usbReceive.buffer; while (1) { // check if there's even sufficient data to decode a header - if (device->usbReceive.leftover < HEADERLEN) + if (device->usbReceive.leftover < sizeof(usbmux_tcp_header)) break; usbmux_tcp_header *header = (usbmux_tcp_header *) cursor; -- cgit v1.1-32-gdbae From 3d517f6879b0c476a2e1ac9a55bb7d436977e3b6 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 2 Aug 2009 06:42:00 +0200 Subject: Workaround for usb communication issue aka 'N*128 problem' or 'N*512 problem' For some strange reason packets that are N*128 bytes long via USB 1.1, or N*512 bytes long via USB 2.0, the device will not send an answer and any following packet will cause a connection reset. See this as a workaround until the usb issue has been resolved. --- src/usbmux.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/src/usbmux.c b/src/usbmux.c index 1d6497e..2157e05 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -822,6 +822,7 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, pthread_mutex_lock(&client->mutex); int sendresult = 0; + int fullsendresult = 0; uint32_t blocksize = 0; if (client->wr_window <= 0) { struct timespec ts; @@ -840,20 +841,67 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t 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 + const char *dataptr = data; + uint32_t curlen = datalen; + uint32_t packetsize = blocksize; + + // BEGIN HACK + if ((blocksize % 128) == 0) { + int cutoff = 28; + // HACK: we need to split up the packet because of an unresolved + // usb communication issue aka 'N*128 problem' or 'N*512 problem' + log_debug_msg("%s: HACK: splitting packet, two send_to_device calls will follow\n"); + packetsize = blocksize - cutoff; + curlen = datalen - cutoff; + client->header->length = packetsize; + client->header->length16 = packetsize; + hton_header(client->header); + memcpy(buffer, client->header, sizeof(usbmux_tcp_header)); + memcpy(buffer + sizeof(usbmux_tcp_header), dataptr, curlen); + + log_debug_msg("%s: send_to_device(%d --> %d) window = %d\n", __func__, + ntohs(client->header->sport), + ntohs(client->header->dport), + ntohs(client->header->window)); + sendresult = send_to_device(client->device, buffer, packetsize); + fullsendresult = sendresult; + + // 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 == packetsize) { + // Re-calculate scnt + client->header->scnt += curlen; + client->wr_window -= packetsize; + } else { + goto err_cond; + } + + dataptr += curlen; + curlen = cutoff; + packetsize = sizeof(usbmux_tcp_header) + curlen; + // fix fullsendresult to not include the header length to make + // setting *sent_bytes work properly + fullsendresult -= sizeof(usbmux_tcp_header); + } + // END HACK + // Set the length - client->header->length = blocksize; - client->header->length16 = blocksize; + client->header->length = packetsize; + client->header->length16 = packetsize; // 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); + memcpy(buffer + sizeof(usbmux_tcp_header), dataptr, curlen); 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); + sendresult = send_to_device(client->device, buffer, packetsize); + fullsendresult += sendresult; // Now that we've sent it off, we can clean up after our sloppy selves. if (buffer) free(buffer); @@ -862,12 +910,13 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, ntoh_header(client->header); // update counts ONLY if the send succeeded. - if ((uint32_t) sendresult == blocksize) { + if ((uint32_t) sendresult == packetsize) { // Re-calculate scnt - client->header->scnt += datalen; - client->wr_window -= blocksize; + client->header->scnt += curlen; + client->wr_window -= packetsize; } +err_cond: pthread_mutex_unlock(&client->mutex); if (sendresult == -ETIMEDOUT || sendresult == 0) { @@ -876,14 +925,14 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, return -ETIMEDOUT; } else if (sendresult < 0) { return sendresult; - } else if ((uint32_t) sendresult == blocksize) { + } else if ((uint32_t) fullsendresult == blocksize) { // actual number of data bytes sent. - *sent_bytes = sendresult - sizeof(usbmux_tcp_header); + *sent_bytes = fullsendresult - 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); + sendresult, packetsize); return -EBADMSG; } } -- cgit v1.1-32-gdbae From a4ef4325ec1b6cddd4212a6fec954cba270cebb4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 2 Aug 2009 07:29:37 +0200 Subject: Automatically execute configure from inside autogen.sh --- autogen.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/autogen.sh b/autogen.sh index 440c1e2..82cc273 100755 --- a/autogen.sh +++ b/autogen.sh @@ -5,3 +5,7 @@ libtoolize || exit 1 autoheader || exit 1 automake --add-missing || exit 1 autoconf || exit 1 +echo +echo Executing ./configure $@ +echo +./configure "$@" -- cgit v1.1-32-gdbae From 6fbd2a72122d6bcd70edbf599baa7465e3e9acb6 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 2 Aug 2009 07:35:00 +0200 Subject: include config.h and defined ENABLE_HACKS Use --disable-hacks to NOT enable hacks like the N*128/N*512 hack when running configure. Hacks are enabled by default. --- configure.ac | 14 ++++++++++++++ src/usbmux.c | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/configure.ac b/configure.ac index 55ce7af..d8c10f8 100644 --- a/configure.ac +++ b/configure.ac @@ -18,6 +18,20 @@ AC_PROG_INSTALL PKG_CHECK_MODULES(libusb, libusb >= 0.1.12) +# check for options +AC_ARG_ENABLE([hacks], + [AS_HELP_STRING([--disable-hacks], + [disable hacks that provide workarounds for certain problems])], + [enable_hacks=no], + [enable_hacks=yes]) +if test "x$enable_hacks" = xyes; then + AC_DEFINE(ENABLE_HACKS, 1, [Define if you want hacks enabled]) + echo "Note: hacks are enabled." +else + echo "Note: hacks are DISABLED." +fi +AM_CONDITIONAL(ENABLE_HACKS, test "x$enable_hacks" = xyes) + # Output files AC_OUTPUT([ diff --git a/src/usbmux.c b/src/usbmux.c index 2157e05..37538da 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -15,6 +15,9 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifdef HAVE_CONFIG_H +#include +#endif #include #include #include @@ -845,6 +848,7 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, uint32_t curlen = datalen; uint32_t packetsize = blocksize; +#ifdef ENABLE_HACKS // BEGIN HACK if ((blocksize % 128) == 0) { int cutoff = 28; @@ -886,6 +890,7 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, fullsendresult -= sizeof(usbmux_tcp_header); } // END HACK +#endif // Set the length client->header->length = packetsize; -- cgit v1.1-32-gdbae From c62271b8a872803f2cbf9ba233a5197bd0289ea4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 2 Aug 2009 16:58:11 +0200 Subject: Bump version to 0.1.1 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d8c10f8..21b69e3 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.61) -AC_INIT([usbmuxd], [0.1.0], [nikias@gmx.li]) +AC_INIT([usbmuxd], [0.1.1], [nikias@gmx.li]) AM_INIT_AUTOMAKE([-Wall -Werror foreign dist-bzip2]) AC_CONFIG_HEADERS([config.h]) -- cgit v1.1-32-gdbae From 843db538ed4b75d0d5943f0df5ba7ab1ce4e65f9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 2 Aug 2009 16:58:48 +0200 Subject: Added missing __func__ to printf --- src/usbmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usbmux.c b/src/usbmux.c index 37538da..a695f27 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -854,7 +854,7 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, int cutoff = 28; // HACK: we need to split up the packet because of an unresolved // usb communication issue aka 'N*128 problem' or 'N*512 problem' - log_debug_msg("%s: HACK: splitting packet, two send_to_device calls will follow\n"); + log_debug_msg("%s: HACK: splitting packet, two send_to_device calls will follow\n", __func__); packetsize = blocksize - cutoff; curlen = datalen - cutoff; client->header->length = packetsize; -- cgit v1.1-32-gdbae From 50c536e4b97f0eb5e4991b97d86564ed2f1d0ebe Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 3 Aug 2009 18:51:10 +0200 Subject: Revert "Added missing __func__ to printf" This reverts commit 843db538ed4b75d0d5943f0df5ba7ab1ce4e65f9. --- src/usbmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usbmux.c b/src/usbmux.c index a695f27..37538da 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -854,7 +854,7 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, int cutoff = 28; // HACK: we need to split up the packet because of an unresolved // usb communication issue aka 'N*128 problem' or 'N*512 problem' - log_debug_msg("%s: HACK: splitting packet, two send_to_device calls will follow\n", __func__); + log_debug_msg("%s: HACK: splitting packet, two send_to_device calls will follow\n"); packetsize = blocksize - cutoff; curlen = datalen - cutoff; client->header->length = packetsize; -- cgit v1.1-32-gdbae From 3441c7a73f138efaa6037746e69f060fc0c3796e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 3 Aug 2009 18:51:31 +0200 Subject: Revert "include config.h and defined ENABLE_HACKS" This reverts commit 6fbd2a72122d6bcd70edbf599baa7465e3e9acb6. --- configure.ac | 14 -------------- src/usbmux.c | 5 ----- 2 files changed, 19 deletions(-) diff --git a/configure.ac b/configure.ac index 21b69e3..b277f73 100644 --- a/configure.ac +++ b/configure.ac @@ -18,20 +18,6 @@ AC_PROG_INSTALL PKG_CHECK_MODULES(libusb, libusb >= 0.1.12) -# check for options -AC_ARG_ENABLE([hacks], - [AS_HELP_STRING([--disable-hacks], - [disable hacks that provide workarounds for certain problems])], - [enable_hacks=no], - [enable_hacks=yes]) -if test "x$enable_hacks" = xyes; then - AC_DEFINE(ENABLE_HACKS, 1, [Define if you want hacks enabled]) - echo "Note: hacks are enabled." -else - echo "Note: hacks are DISABLED." -fi -AM_CONDITIONAL(ENABLE_HACKS, test "x$enable_hacks" = xyes) - # Output files AC_OUTPUT([ diff --git a/src/usbmux.c b/src/usbmux.c index 37538da..2157e05 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -15,9 +15,6 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifdef HAVE_CONFIG_H -#include -#endif #include #include #include @@ -848,7 +845,6 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, uint32_t curlen = datalen; uint32_t packetsize = blocksize; -#ifdef ENABLE_HACKS // BEGIN HACK if ((blocksize % 128) == 0) { int cutoff = 28; @@ -890,7 +886,6 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, fullsendresult -= sizeof(usbmux_tcp_header); } // END HACK -#endif // Set the length client->header->length = packetsize; -- cgit v1.1-32-gdbae From dcc304e88a4d1e2261871a5d4a66bdc8fe4b5339 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 3 Aug 2009 18:51:48 +0200 Subject: Revert "Workaround for usb communication issue aka 'N*128 problem' or 'N*512 problem'" This reverts commit 3d517f6879b0c476a2e1ac9a55bb7d436977e3b6. --- src/usbmux.c | 69 +++++++++--------------------------------------------------- 1 file changed, 10 insertions(+), 59 deletions(-) diff --git a/src/usbmux.c b/src/usbmux.c index 2157e05..1d6497e 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -822,7 +822,6 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, pthread_mutex_lock(&client->mutex); int sendresult = 0; - int fullsendresult = 0; uint32_t blocksize = 0; if (client->wr_window <= 0) { struct timespec ts; @@ -841,67 +840,20 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t 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 - const char *dataptr = data; - uint32_t curlen = datalen; - uint32_t packetsize = blocksize; - - // BEGIN HACK - if ((blocksize % 128) == 0) { - int cutoff = 28; - // HACK: we need to split up the packet because of an unresolved - // usb communication issue aka 'N*128 problem' or 'N*512 problem' - log_debug_msg("%s: HACK: splitting packet, two send_to_device calls will follow\n"); - packetsize = blocksize - cutoff; - curlen = datalen - cutoff; - client->header->length = packetsize; - client->header->length16 = packetsize; - hton_header(client->header); - memcpy(buffer, client->header, sizeof(usbmux_tcp_header)); - memcpy(buffer + sizeof(usbmux_tcp_header), dataptr, curlen); - - log_debug_msg("%s: send_to_device(%d --> %d) window = %d\n", __func__, - ntohs(client->header->sport), - ntohs(client->header->dport), - ntohs(client->header->window)); - sendresult = send_to_device(client->device, buffer, packetsize); - fullsendresult = sendresult; - - // 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 == packetsize) { - // Re-calculate scnt - client->header->scnt += curlen; - client->wr_window -= packetsize; - } else { - goto err_cond; - } - - dataptr += curlen; - curlen = cutoff; - packetsize = sizeof(usbmux_tcp_header) + curlen; - // fix fullsendresult to not include the header length to make - // setting *sent_bytes work properly - fullsendresult -= sizeof(usbmux_tcp_header); - } - // END HACK - // Set the length - client->header->length = packetsize; - client->header->length16 = packetsize; + 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), dataptr, curlen); + 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, packetsize); - fullsendresult += sendresult; + 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); @@ -910,13 +862,12 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, ntoh_header(client->header); // update counts ONLY if the send succeeded. - if ((uint32_t) sendresult == packetsize) { + if ((uint32_t) sendresult == blocksize) { // Re-calculate scnt - client->header->scnt += curlen; - client->wr_window -= packetsize; + client->header->scnt += datalen; + client->wr_window -= blocksize; } -err_cond: pthread_mutex_unlock(&client->mutex); if (sendresult == -ETIMEDOUT || sendresult == 0) { @@ -925,14 +876,14 @@ err_cond: return -ETIMEDOUT; } else if (sendresult < 0) { return sendresult; - } else if ((uint32_t) fullsendresult == blocksize) { + } else if ((uint32_t) sendresult == blocksize) { // actual number of data bytes sent. - *sent_bytes = fullsendresult - sizeof(usbmux_tcp_header); + *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, packetsize); + sendresult, blocksize); return -EBADMSG; } } -- cgit v1.1-32-gdbae From 1d006240c339dd950c5b4da8000289fba9105c0d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 3 Aug 2009 19:00:38 +0200 Subject: Fix usb communication problem To do this properly, we just have to send an additional zero length usb packet when we encounter a packet of size wMaxPacketSize or one of its multiplicants. --- src/usbmux.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/usbmux.c b/src/usbmux.c index 1d6497e..dd3ac1a 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -58,6 +58,7 @@ struct usbmux_device_int { struct usb_dev_handle *usbdev; struct usb_device *__device; receivebuf_t usbReceive; + int wMaxPacketSize; }; typedef struct { @@ -272,6 +273,24 @@ static int usbmux_config_usb_device(usbmux_device_t device) 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); @@ -316,6 +335,9 @@ int usbmux_get_specific_device(int bus_n, int dev_n, newdevice->usbReceive.leftover = 0; newdevice->usbReceive.capacity = 0; + // wMaxPacketSize + newdevice->wMaxPacketSize = 64; + // Initialize libusb usb_init(); usb_find_busses(); @@ -328,7 +350,7 @@ int usbmux_get_specific_device(int bus_n, int dev_n, if (strtol(dev->filename, NULL, 10) == dev_n) { newdevice->__device = dev; newdevice->usbdev = usb_open(newdevice->__device); - if (!newdevice->usbdev) { + if (!newdevice->usbdev) { fprintf(stderr, "%s: Error: usb_open(): %s\n", __func__, usb_strerror()); } if (usbmux_config_usb_device(newdevice) == 0) { @@ -495,6 +517,15 @@ if (toto_debug > 0) { 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) { -- cgit v1.1-32-gdbae From 9a66df47b0468aeac8dcd975e5991581627357b3 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 3 Aug 2009 19:20:07 +0200 Subject: Fix build warnings usbmux.c: In function ‘usbmux_free_device’: usbmux.c:412: warning: ‘bytes’ may be used uninitialized in this function main.c: In function ‘usbmuxd_client_init_thread’: main.c:197: warning: dereferencing pointer ‘s_req.55’ does break strict-aliasing rules main.c:613: note: initialized from here main.c:944: warning: ‘j’ may be used uninitialized in this function Signed-off-by: Nikias Bassen --- src/main.c | 4 ++-- src/usbmux.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.c b/src/main.c index cd87632..ee633b6 100644 --- a/src/main.c +++ b/src/main.c @@ -580,7 +580,7 @@ static void *usbmuxd_bulk_reader_thread(void *arg) static void *usbmuxd_client_init_thread(void *arg) { struct client_data *cdata; - struct usbmuxd_scan_request *s_req = NULL; + struct usbmuxd_scan_request *s_req; struct usbmuxd_device_info_record dev_info_rec; struct usbmuxd_connect_request *c_req = NULL; @@ -941,7 +941,7 @@ static void *usbmuxd_client_init_thread(void *arg) cur_dev = NULL; if (device_count > 1) { struct device_info **newlist; - int j; + int j = 0; newlist = (struct device_info **) diff --git a/src/usbmux.c b/src/usbmux.c index dd3ac1a..ed23278 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -428,7 +428,7 @@ int usbmux_get_specific_device(int bus_n, int dev_n, int usbmux_free_device(usbmux_device_t device) { char buf[512]; - int bytes; + int bytes = -1; if (!device) return -EINVAL; -- cgit v1.1-32-gdbae From 544f0420cd265194cd0c610f74ef928a60358e68 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 3 Aug 2009 21:18:15 +0200 Subject: Bump version to 0.1.2 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b277f73..23768c0 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.61) -AC_INIT([usbmuxd], [0.1.1], [nikias@gmx.li]) +AC_INIT([usbmuxd], [0.1.2], [nikias@gmx.li]) AM_INIT_AUTOMAKE([-Wall -Werror foreign dist-bzip2]) AC_CONFIG_HEADERS([config.h]) -- cgit v1.1-32-gdbae From b7d4f48d7e85c43f0dd1111619acf79aba535371 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 3 Aug 2009 21:22:37 +0200 Subject: Add udev mode of operation When starting up, force background operation when in udev mode and don't error out when already running. When disconnecting, check if there are any devices left-over, and exit if not. Signed-off-by: Nikias Bassen --- src/main.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main.c b/src/main.c index ee633b6..de68242 100644 --- a/src/main.c +++ b/src/main.c @@ -58,6 +58,7 @@ static int verbose = DEBUG_LEVEL; static int foreground = 0; static int exit_on_no_devices = 0; static int drop_privileges = 0; +static int udev = 0; struct device_info { uint32_t device_id; @@ -1030,6 +1031,7 @@ static void usage() 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 use udev mode of operations\n"); printf("\n"); } @@ -1041,12 +1043,13 @@ static void parse_opts(int argc, char **argv) {"verbose", 0, NULL, 'v'}, {"exit-on-no-devices", 0, NULL, 'e'}, {"drop-privileges", 0, NULL, 'd'}, + {"udev", 0, NULL, 'u'}, {NULL, 0, NULL, 0} }; int c; while (1) { - c = getopt_long(argc, argv, "hfved", longopts, (int *) 0); + c = getopt_long(argc, argv, "hfvedu", longopts, (int *) 0); if (c == -1) { break; } @@ -1067,11 +1070,17 @@ static void parse_opts(int argc, char **argv) case 'd': drop_privileges = 1; break; + case 'u': + udev = 1; + break; default: usage(); exit(2); } } + + if (udev) + foreground = 0; } /** @@ -1173,9 +1182,12 @@ int main(int argc, char **argv) fcntl(fileno(lfd), F_GETLK, &lock); fclose(lfd); if (lock.l_type != F_UNLCK) { - logmsg(LOG_NOTICE, - "another instance is already running. exiting."); - return -1; + if (!udev) { + logmsg(LOG_NOTICE, + "another instance is already running. exiting."); + return -1; + } + return 0; } } @@ -1265,6 +1277,7 @@ int main(int argc, char **argv) if (result <= 0) { if (result == 0) { // cleanup + int num_children = 0; for (i = 0; i < children_capacity; i++) { if (children[i]) { if (children[i]->dead != 0) { @@ -1277,6 +1290,7 @@ int main(int argc, char **argv) children[i] = NULL; cnt++; } else { + num_children++; cnt = 0; } } else { @@ -1284,6 +1298,9 @@ int main(int argc, char **argv) } } + if (num_children == 0 && udev) + break; + if ((children_capacity > DEFAULT_CHILDREN_CAPACITY) && ((children_capacity - cnt) <= DEFAULT_CHILDREN_CAPACITY)) { -- cgit v1.1-32-gdbae From 91fc30c3247dbc41ce2dfcedfd6086c513ffa80a Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 3 Aug 2009 21:23:25 +0200 Subject: Use udev mode in the udev rules Otherwise this only works on Debian-based systems. Signed-off-by: Nikias Bassen --- udev/85-usbmuxd.rules.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/udev/85-usbmuxd.rules.in b/udev/85-usbmuxd.rules.in index 4e35f7e..64f7c3f 100644 --- a/udev/85-usbmuxd.rules.in +++ b/udev/85-usbmuxd.rules.in @@ -16,8 +16,8 @@ ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", IMPORT{program ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", IMPORT{program}="usb_id %p --export", SYMLINK+="usbmux/$env{ID_SERIAL_SHORT}/%s{direction}" # Start and stop 'usbmuxd' as required -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec @prefix@/sbin/usbmuxd" -ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 3 --exec @prefix@/sbin/usbmuxd" +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="@prefix@/sbin/usbmuxd -u" +# usbmuxd will go away when the last device is removed, when in udev mode # skip LABEL="usbmuxd_rules_end" -- cgit v1.1-32-gdbae From 402191b92bcbd46293c2f7278eb4b52e0b4d4555 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 3 Aug 2009 22:00:33 +0200 Subject: Bump version to 0.1.3 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 23768c0..51c0866 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.61) -AC_INIT([usbmuxd], [0.1.2], [nikias@gmx.li]) +AC_INIT([usbmuxd], [0.1.3], [nikias@gmx.li]) AM_INIT_AUTOMAKE([-Wall -Werror foreign dist-bzip2]) AC_CONFIG_HEADERS([config.h]) -- cgit v1.1-32-gdbae From bfdcd3a071fb73ac43715a2900db292f88d7cc47 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 3 Aug 2009 22:12:29 +0200 Subject: Removed unused commented out code. --- src/usbmux.c | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/src/usbmux.c b/src/usbmux.c index ed23278..29f9879 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -219,50 +219,6 @@ static int usbmux_config_usb_device(usbmux_device_t device) int bytes; char buf[512]; -#if 0 - log_debug_msg("checking configuration...\n"); - if (device->__device->config->bConfigurationValue != 3) { - log_debug_msg - ("WARNING: usb device configuration is not 3 as expected!\n"); - } - - log_debug_msg("setting configuration...\n"); - ret = usb_set_configuration(device->device, 3); - if (ret != 0) { - log_debug_msg("Hm, usb_set_configuration returned %d: %s\n", ret, - strerror(-ret)); -#if LIBUSB_HAS_GET_DRIVER_NP - log_debug_msg("trying to fix:\n"); - log_debug_msg("-> detaching kernel driver... "); - ret = - usb_detach_kernel_driver_np(device->device, - device->__device->config-> - interface->altsetting-> - bInterfaceNumber); - if (ret != 0) { - log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", - ret, strerror(-ret)); - } else { - log_debug_msg("done.\n"); - log_debug_msg("setting configuration again... "); - ret = usb_set_configuration(device->device, 3); - if (ret != 0) { - log_debug_msg - ("Error: usb_set_configuration returned %d: %s\n", ret, - strerror(-ret)); - log_debug_msg("--> trying to continue anyway...\n"); - } else { - log_debug_msg("done.\n"); - } - } -#else - log_debug_msg("--> trying to continue anyway...\n"); -#endif - } else { - log_debug_msg("done.\n"); - } -#endif - log_debug_msg("claiming interface... "); ret = usb_claim_interface(device->usbdev, 1); if (ret != 0) { -- cgit v1.1-32-gdbae From f6ee6302f7d87294b7175b4b639b293aafb80424 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 4 Aug 2009 00:42:40 +0200 Subject: Revert "Add udev mode of operation" This reverts commit b7d4f48d7e85c43f0dd1111619acf79aba535371. Not working as expected. --- src/main.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/src/main.c b/src/main.c index de68242..ee633b6 100644 --- a/src/main.c +++ b/src/main.c @@ -58,7 +58,6 @@ static int verbose = DEBUG_LEVEL; static int foreground = 0; static int exit_on_no_devices = 0; static int drop_privileges = 0; -static int udev = 0; struct device_info { uint32_t device_id; @@ -1031,7 +1030,6 @@ static void usage() 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 use udev mode of operations\n"); printf("\n"); } @@ -1043,13 +1041,12 @@ static void parse_opts(int argc, char **argv) {"verbose", 0, NULL, 'v'}, {"exit-on-no-devices", 0, NULL, 'e'}, {"drop-privileges", 0, NULL, 'd'}, - {"udev", 0, NULL, 'u'}, {NULL, 0, NULL, 0} }; int c; while (1) { - c = getopt_long(argc, argv, "hfvedu", longopts, (int *) 0); + c = getopt_long(argc, argv, "hfved", longopts, (int *) 0); if (c == -1) { break; } @@ -1070,17 +1067,11 @@ static void parse_opts(int argc, char **argv) case 'd': drop_privileges = 1; break; - case 'u': - udev = 1; - break; default: usage(); exit(2); } } - - if (udev) - foreground = 0; } /** @@ -1182,12 +1173,9 @@ int main(int argc, char **argv) fcntl(fileno(lfd), F_GETLK, &lock); fclose(lfd); if (lock.l_type != F_UNLCK) { - if (!udev) { - logmsg(LOG_NOTICE, - "another instance is already running. exiting."); - return -1; - } - return 0; + logmsg(LOG_NOTICE, + "another instance is already running. exiting."); + return -1; } } @@ -1277,7 +1265,6 @@ int main(int argc, char **argv) if (result <= 0) { if (result == 0) { // cleanup - int num_children = 0; for (i = 0; i < children_capacity; i++) { if (children[i]) { if (children[i]->dead != 0) { @@ -1290,7 +1277,6 @@ int main(int argc, char **argv) children[i] = NULL; cnt++; } else { - num_children++; cnt = 0; } } else { @@ -1298,9 +1284,6 @@ int main(int argc, char **argv) } } - if (num_children == 0 && udev) - break; - if ((children_capacity > DEFAULT_CHILDREN_CAPACITY) && ((children_capacity - cnt) <= DEFAULT_CHILDREN_CAPACITY)) { -- cgit v1.1-32-gdbae From 29ab549b8bf981243efcc924bf6539a8170de3cc Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 4 Aug 2009 00:43:09 +0200 Subject: Revert "Use udev mode in the udev rules" This reverts commit 91fc30c3247dbc41ce2dfcedfd6086c513ffa80a. Not working as expected. --- udev/85-usbmuxd.rules.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/udev/85-usbmuxd.rules.in b/udev/85-usbmuxd.rules.in index 64f7c3f..4e35f7e 100644 --- a/udev/85-usbmuxd.rules.in +++ b/udev/85-usbmuxd.rules.in @@ -16,8 +16,8 @@ ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", IMPORT{program ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", IMPORT{program}="usb_id %p --export", SYMLINK+="usbmux/$env{ID_SERIAL_SHORT}/%s{direction}" # Start and stop 'usbmuxd' as required -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="@prefix@/sbin/usbmuxd -u" -# usbmuxd will go away when the last device is removed, when in udev mode +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec @prefix@/sbin/usbmuxd" +ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 3 --exec @prefix@/sbin/usbmuxd" # skip LABEL="usbmuxd_rules_end" -- cgit v1.1-32-gdbae From 6184b8e69890187a902b5bc4aa4c065ed9fd23c2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 4 Aug 2009 00:53:11 +0200 Subject: Bump version to 0.1.4 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 51c0866..c5922c3 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.61) -AC_INIT([usbmuxd], [0.1.3], [nikias@gmx.li]) +AC_INIT([usbmuxd], [0.1.4], [nikias@gmx.li]) AM_INIT_AUTOMAKE([-Wall -Werror foreign dist-bzip2]) AC_CONFIG_HEADERS([config.h]) -- cgit v1.1-32-gdbae From 679f6cd2904aa84f65a4f0fc38a353f5ac7b9e46 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 4 Aug 2009 13:11:34 +0200 Subject: udev operation mode; -x and -X options to exit a running instance In udev mode (-u|--udev) the return value is 0 if another instance is already running -x|--exit tells a running instance to exit by sending signal 3 (SIGQUIT) -X|--force-exit tells a running instance to exit even if devices are still connected by sending signal 15 (SIGTERM) --- src/main.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/src/main.c b/src/main.c index ee633b6..c567a66 100644 --- a/src/main.c +++ b/src/main.c @@ -58,6 +58,9 @@ 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; @@ -1030,6 +1033,10 @@ static void usage() 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"); } @@ -1041,12 +1048,15 @@ static void parse_opts(int argc, char **argv) {"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, "hfved", longopts, (int *) 0); + c = getopt_long(argc, argv, "hfveduxX", longopts, (int *) 0); if (c == -1) { break; } @@ -1067,11 +1077,24 @@ static void parse_opts(int argc, char **argv) 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; } /** @@ -1141,6 +1164,7 @@ int main(int argc, char **argv) int children_capacity = DEFAULT_CHILDREN_CAPACITY; int i; int result = 0; + int exit_val = 0; int cnt = 0; FILE *lfd = NULL; struct flock lock; @@ -1154,7 +1178,7 @@ int main(int argc, char **argv) openlog("usbmuxd", LOG_PID, 0); } - if (verbose >= 2) + if (verbose >= 1) logmsg(LOG_NOTICE, "starting"); // signal(SIGHUP, reload_conf); // none yet @@ -1173,12 +1197,35 @@ int main(int argc, char **argv) fcntl(fileno(lfd), F_GETLK, &lock); fclose(lfd); if (lock.l_type != F_UNLCK) { - logmsg(LOG_NOTICE, - "another instance is already running. exiting."); - return -1; + 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."); @@ -1220,6 +1267,7 @@ int main(int argc, char **argv) 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 @@ -1388,8 +1436,9 @@ int main(int argc, char **argv) fclose(lfd); } +terminate: if (verbose >= 1) - logmsg(LOG_NOTICE, "usbmuxd: terminated"); + logmsg(LOG_NOTICE, "terminated"); if (!foreground) { closelog(); } -- cgit v1.1-32-gdbae From ba107891b3ecb52fccc656bdd611142ffebef86d Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 4 Aug 2009 19:13:08 +0200 Subject: Fix compile-time warnings Signed-off-by: Nikias Bassen --- src/usbmux.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/usbmux.c b/src/usbmux.c index 29f9879..20c1298 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -119,7 +119,7 @@ void usbmux_set_debug(int e) toto_debug = e; } -void log_debug_msg(const char *format, ...) +static void log_debug_msg(const char *format, ...) { #ifndef STRIP_DEBUG_CODE va_list args; @@ -170,7 +170,7 @@ static void print_buffer(const char *data, const int length) printf("\n"); } -void hton_header(usbmux_tcp_header * hdr) +static void hton_header(usbmux_tcp_header * hdr) { if (hdr) { hdr->length = htonl(hdr->length); @@ -180,7 +180,7 @@ void hton_header(usbmux_tcp_header * hdr) } } -void ntoh_header(usbmux_tcp_header * hdr) +static void ntoh_header(usbmux_tcp_header * hdr) { if (hdr) { hdr->length = ntohl(hdr->length); @@ -194,7 +194,7 @@ void ntoh_header(usbmux_tcp_header * hdr) * * @return A USBMux header */ -usbmux_version_header *version_header() +static usbmux_version_header *version_header() { usbmux_version_header *version = (usbmux_version_header *) malloc(sizeof(usbmux_version_header)); @@ -423,7 +423,7 @@ int usbmux_free_device(usbmux_device_t device) * @param datalen The length of the data * @return The number of bytes sent, or -ERRNO on error */ -int send_to_device(usbmux_device_t device, char *data, int datalen) +static int send_to_device(usbmux_device_t device, char *data, int datalen) { if (!device) return -EINVAL; @@ -505,7 +505,7 @@ if (toto_debug > 0) { * * @return How many bytes were read in, or -1 on error. */ -int recv_from_device_timeout(usbmux_device_t device, char *data, +static int recv_from_device_timeout(usbmux_device_t device, char *data, int datalen, int timeoutmillis) { if (!device) @@ -551,7 +551,7 @@ int recv_from_device_timeout(usbmux_device_t device, char *data, * * @return A USBMux packet */ -usbmux_tcp_header *new_mux_packet(uint16_t s_port, uint16_t d_port) +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)); @@ -883,7 +883,7 @@ int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, * * @return number of bytes consumed (header + data) */ -uint32_t append_receive_buffer(usbmux_client_t client, char *packet) +static uint32_t append_receive_buffer(usbmux_client_t client, char *packet) { if (client == NULL || packet == NULL) return 0; @@ -1035,7 +1035,7 @@ uint32_t append_receive_buffer(usbmux_client_t client, char *packet) * because we're only called from one location, pullbulk, where the lock * is already held. */ -usbmux_client_t find_client(usbmux_tcp_header * recv_header) +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 -- cgit v1.1-32-gdbae From 8fc5311c3d1b9bcf39cd209004d92824b87d3883 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 4 Aug 2009 19:14:55 +0200 Subject: Use udev -x/-u in udev rules This will make them work on non-Debian distributions. Signed-off-by: Nikias Bassen --- udev/85-usbmuxd.rules.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/udev/85-usbmuxd.rules.in b/udev/85-usbmuxd.rules.in index 4e35f7e..82221d4 100644 --- a/udev/85-usbmuxd.rules.in +++ b/udev/85-usbmuxd.rules.in @@ -16,8 +16,8 @@ ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", IMPORT{program ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", IMPORT{program}="usb_id %p --export", SYMLINK+="usbmux/$env{ID_SERIAL_SHORT}/%s{direction}" # Start and stop 'usbmuxd' as required -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec @prefix@/sbin/usbmuxd" -ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 3 --exec @prefix@/sbin/usbmuxd" +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="@prefix@/sbin/usbmuxd -u" +ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="@prefix@/sbin/usbmuxd -x" # skip LABEL="usbmuxd_rules_end" -- cgit v1.1-32-gdbae From 0f2973702483e45a21283d74111b08bfdb95d6b4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 5 Aug 2009 23:57:05 +0200 Subject: Updated AUTHORS. --- AUTHORS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 5b8075b..f84e02b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,4 @@ Nikias Bassen +Bastien Nocera Paul Sladen +Martin Szulecki -- cgit v1.1-32-gdbae From 98a6295df6270145c995fa651eda8a2a3a015984 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 9 Aug 2009 19:24:00 +0200 Subject: Added mutex to prevent garbled debugging output (esp. packet data) --- src/usbmux.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/usbmux.c b/src/usbmux.c index 20c1298..c5e38dd 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -106,6 +106,7 @@ struct usbmux_client_int { 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; @@ -126,8 +127,11 @@ static void log_debug_msg(const char *format, ...) /* run the real fprintf */ va_start(args, format); - if (toto_debug) + if (toto_debug) { + pthread_mutex_lock(&printmutex); vfprintf(stderr, format, args); + pthread_mutex_unlock(&printmutex); + } va_end(args); #endif @@ -433,10 +437,12 @@ static int send_to_device(usbmux_device_t device, char *data, int datalen) 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 { @@ -486,10 +492,12 @@ if (toto_debug > 0) { 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; @@ -534,10 +542,12 @@ static int recv_from_device_timeout(usbmux_device_t device, char *data, } 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); } } -- cgit v1.1-32-gdbae From 67743b7bff776a176a0f4149f74dcf53a0c7192e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 9 Aug 2009 20:29:33 +0200 Subject: Reduce buffer size to prevent connection to freak out. There's a problem with packets larger than 65535 bytes, I suppose this has something to do with the length16 field in the usbmux_tcp_header. --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index c567a66..19649b1 100644 --- a/src/main.c +++ b/src/main.c @@ -431,7 +431,7 @@ static void *usbmuxd_client_handler_thread(void *arg) struct client_data *cdata; int result; char *cursor; - char buffer[65536]; + char buffer[32740]; ssize_t len; ssize_t maxlen = sizeof(buffer); uint32_t wlen; -- cgit v1.1-32-gdbae From 41e9221807f74f949a30f089a3bb4eac98bbb64e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 10 Aug 2009 00:04:12 +0200 Subject: Added missing LGPL license file. --- COPYING.LESSER | 502 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 502 insertions(+) create mode 100644 COPYING.LESSER diff --git a/COPYING.LESSER b/COPYING.LESSER new file mode 100644 index 0000000..732811e --- /dev/null +++ b/COPYING.LESSER @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! -- cgit v1.1-32-gdbae From 135e4c7baa6ddadbcfeaa74710371283a0c363e0 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 10 Aug 2009 00:12:05 +0200 Subject: Bump version to 0.1.5 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c5922c3..029eb1f 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.61) -AC_INIT([usbmuxd], [0.1.4], [nikias@gmx.li]) +AC_INIT([usbmuxd], [0.1.5], [nikias@gmx.li]) AM_INIT_AUTOMAKE([-Wall -Werror foreign dist-bzip2]) AC_CONFIG_HEADERS([config.h]) -- cgit v1.1-32-gdbae From f44dcbc5ec73baa3652627fc4b7a38875b2d496b Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Sat, 15 Aug 2009 14:52:13 +0200 Subject: Install udev rules in the correct location The ones in /etc are supposed to be configurable ones. Signed-off-by: Nikias Bassen --- udev/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/udev/Makefile.am b/udev/Makefile.am index 321008a..e44b077 100644 --- a/udev/Makefile.am +++ b/udev/Makefile.am @@ -1,4 +1,4 @@ -udevdir=$(sysconfdir)/udev/rules.d/ +udevdir=/lib/udev/rules.d/ udev_DATA=85-usbmuxd.rules EXTRA_DIST = 85-usbmuxd.rules -- cgit v1.1-32-gdbae From 79ca4d9a3c3a82bb5a3f9be1ac7a2533c7a89b05 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Sat, 15 Aug 2009 14:55:14 +0200 Subject: Port udev rules to newer kernels Remove use of usb_endpoint, it's gone in newer kernels. Signed-off-by: Nikias Bassen --- udev/85-usbmuxd.rules.in | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/udev/85-usbmuxd.rules.in b/udev/85-usbmuxd.rules.in index 82221d4..c0a3900 100644 --- a/udev/85-usbmuxd.rules.in +++ b/udev/85-usbmuxd.rules.in @@ -1,23 +1,7 @@ # usbmuxd (iPhone "Apple Mobile Device" MUXer listening on /var/run/usbmuxd) -# Skip anything non Apple -ACTION=="add|remove", SUBSYSTEM!="usb|usb_endpoint", ATTRS{idVendor}!="05ac", GOTO="usbmuxd_rules_end" +# Forces iPhone 1.0, 3G, 3GS and iPodTouch 1 and 2 to USB configuration 3 and run usbmuxd +ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="129[0-4]", ATTR{bConfigurationValue}!="$attr{bNumConfigurations}", ATTR{bConfigurationValue}="$attr{bNumConfigurations}", RUN+="@prefix@/sbin/usbmuxd -u" -# Forces iPhone 1.0, 3G, 3GS and iPodTouch 1 and 2 to USB configuration 3 -ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="1290|1291|1292|1293|1294", ATTR{bConfigurationValue}!="$attr{bNumConfigurations}", ATTR{bConfigurationValue}="$attr{bNumConfigurations}", GOTO="usbmuxd_rules_end" - -LABEL="usbmuxd_rules_usbmux" - -# Only apply to usb endpoints -ACTION=="add|remove", SUBSYSTEM!="usb_endpoint", GOTO="usbmuxd_rules_end" - -# Setup cute names for the endpoints -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", IMPORT{program}="usb_id %p --export", SYMLINK+="usbmux/$env{ID_SERIAL_SHORT}/%s{direction}" -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", IMPORT{program}="usb_id %p --export", SYMLINK+="usbmux/$env{ID_SERIAL_SHORT}/%s{direction}" - -# Start and stop 'usbmuxd' as required -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="@prefix@/sbin/usbmuxd -u" -ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="@prefix@/sbin/usbmuxd -x" - -# skip -LABEL="usbmuxd_rules_end" +# Exit usbmuxd when the last phone is removed +ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_VENDOR_ID}=="05ac", ENV{ID_MODEL_ID}=="129[0-4]", RUN+="@prefix@/sbin/usbmuxd -x" -- cgit v1.1-32-gdbae