diff options
| author | 2009-02-25 18:09:19 +0100 | |
|---|---|---|
| committer | 2009-02-25 18:09:19 +0100 | |
| commit | 6e2946da89ce8c44ac2b78e49c8fc934974d021d (patch) | |
| tree | 33c63b8b7a008695df606190195b9baf4a59f350 | |
| parent | 97e6c8b7bb89c7f08ad46050598c15a55ea3f436 (diff) | |
| download | usbmuxd-6e2946da89ce8c44ac2b78e49c8fc934974d021d.tar.gz usbmuxd-6e2946da89ce8c44ac2b78e49c8fc934974d021d.tar.bz2 | |
big endian fix and some improvements, now multi-client capable
| -rw-r--r-- | iphone.c | 162 | ||||
| -rw-r--r-- | usbmuxd.c | 61 | 
2 files changed, 175 insertions, 48 deletions
| @@ -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; 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   *  @@ -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); @@ -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,12 +64,7 @@ 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; @@ -71,6 +72,18 @@ 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) @@ -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 | 
