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