summaryrefslogtreecommitdiffstats
path: root/iphone.c
diff options
context:
space:
mode:
Diffstat (limited to 'iphone.c')
-rw-r--r--iphone.c1089
1 files changed, 1089 insertions, 0 deletions
diff --git a/iphone.c b/iphone.c
new file mode 100644
index 0000000..9035be9
--- /dev/null
+++ b/iphone.c
@@ -0,0 +1,1089 @@
1/*
2 * Copyright (c) 2008 Jing Su. All Rights Reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#include <stdint.h>
19#include <stdarg.h>
20#include <stdlib.h>
21#include <string.h>
22#include <usb.h>
23#include <stdio.h>
24#include <arpa/inet.h>
25#include <errno.h>
26#include <pthread.h>
27#include "iphone.h"
28
29#define BULKIN 0x85
30#define BULKOUT 0x04
31#define HEADERLEN 28
32
33typedef uint16_t uint16;
34typedef uint32_t uint32;
35typedef uint8_t uint8;
36
37static const uint8 TCP_FIN = 1;
38static const uint8 TCP_SYN = 1 << 1;
39static const uint8 TCP_RST = 1 << 2;
40static const uint8 TCP_PSH = 1 << 3;
41static const uint8 TCP_ACK = 1 << 4;
42static const uint8 TCP_URG = 1 << 5;
43
44// I have trouble figuring out how to properly manage the windowing to
45// the iPhone. It keeps sending back 512 and seems to drop off a cliff
46// when the phone gets overwhelmed. In addition, the phone likes to
47// panic and send out RESETS before the window hits zero. Also, waiting
48// for responses seems to not be a winning strategy.
49//
50// Since I'm not sure how in the hell to interpret the window sizes that
51// the phone is sending back to us, I've figured out some magic number
52// constants which seem to work okay.
53static const uint32 WINDOW_MAX = 5 * 1024;
54static const uint32 WINDOW_INCREMENT = 512;
55
56
57struct iphone_device_int {
58 char *buffer;
59 struct usb_dev_handle *device;
60 struct usb_device *__device;
61};
62
63typedef struct {
64 uint32 type, length, major, minor, allnull;
65} usbmux_version_header;
66
67typedef struct {
68 uint32 type, length;
69 uint16 sport, dport;
70 uint32 scnt, ocnt;
71 uint8 offset, tcp_flags;
72 uint16 window, nullnull, length16;
73} usbmux_tcp_header;
74
75struct iphone_umux_client_int {
76 usbmux_tcp_header *header;
77 iphone_device_t phone;
78
79 char *recv_buffer;
80 int r_len;
81 pthread_cond_t wait;
82
83 // this contains a conditional variable which usb-writers can wait
84 // on while waiting for window updates from the phone.
85 pthread_cond_t wr_wait;
86 // I'm going to do something really cheesy here. We are going to
87 // just record the most recent scnt that we are expecting to hear
88 // back on. We will actually halt progress by limiting the number
89 // of outstanding un-acked bulk sends that we have beamed out.
90 uint32 wr_pending_scnt;
91 long wr_window;
92
93 pthread_mutex_t mutex;
94
95 // this variable is not protected by the mutex. This will always
96 // be E_SUCCESS, unless an error of some kind breaks this stream.
97 // this will then be set to the error that caused the broken stream.
98 // no further operations other than free_client will be allowed.
99 iphone_error_t error;
100};
101
102
103typedef struct {
104 char* buffer;
105 int leftover;
106 int capacity;
107} receivebuf_t;
108
109
110static pthread_mutex_t iphonemutex = PTHREAD_MUTEX_INITIALIZER;
111static iphone_umux_client_t *connlist = NULL;
112static int clients = 0;
113static receivebuf_t usbReceive = {NULL, 0, 0};
114
115
116/**
117 */
118int toto_debug = 0;
119void log_debug_msg(const char *format, ...)
120{
121#ifndef STRIP_DEBUG_CODE
122
123 va_list args;
124 /* run the real fprintf */
125 va_start(args, format);
126
127 if (toto_debug)
128 fprintf(stderr, format, args);
129
130 va_end(args);
131
132#endif
133}
134
135
136/** Creates a USBMux header containing version information
137 *
138 * @return A USBMux header
139 */
140usbmux_version_header *version_header()
141{
142 usbmux_version_header *version = (usbmux_version_header *) malloc(sizeof(usbmux_version_header));
143 version->type = 0;
144 version->length = htonl(20);
145 version->major = htonl(1);
146 version->minor = 0;
147 version->allnull = 0;
148 return version;
149}
150
151/**
152 * This function sets the configuration of the given device to 3
153 * and claims the interface 1. If usb_set_configuration fails, it detaches
154 * the kernel driver that blocks the device, and retries configuration.
155 *
156 * @param phone which device to configure
157 */
158static iphone_error_t iphone_config_usb_device(iphone_device_t phone)
159{
160 int ret;
161 int bytes;
162 char buf[512];
163
164 log_debug_msg("setting configuration...\n");
165 ret = usb_set_configuration(phone->device, 3);
166 if (ret != 0) {
167 log_debug_msg("Hm, usb_set_configuration returned %d: %s\n", ret, strerror(-ret));
168#if LIBUSB_HAS_GET_DRIVER_NP
169 log_debug_msg("trying to fix:\n");
170 log_debug_msg("-> detaching kernel driver... ");
171 ret = usb_detach_kernel_driver_np(phone->device, phone->__device->config->interface->altsetting->bInterfaceNumber);
172 if (ret != 0) {
173 log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", ret, strerror(-ret));
174 } else {
175 log_debug_msg("done.\n");
176 log_debug_msg("setting configuration again... ");
177 ret = usb_set_configuration(phone->device, 3);
178 if (ret != 0) {
179 log_debug_msg("Error: usb_set_configuration returned %d: %s\n", ret, strerror(-ret));
180 log_debug_msg("--> trying to continue anyway...\n");
181 } else {
182 log_debug_msg("done.\n");
183 }
184 }
185#else
186 log_debug_msg("--> trying to continue anyway...\n");
187#endif
188 } else {
189 log_debug_msg("done.\n");
190 }
191
192 log_debug_msg("claiming interface... ");
193 ret = usb_claim_interface(phone->device, 1);
194 if (ret != 0) {
195 log_debug_msg("Error: usb_claim_interface returned %d: %s\n", ret, strerror(-ret));
196 return IPHONE_E_NO_DEVICE;
197 } else {
198 log_debug_msg("done.\n");
199 }
200
201 do {
202 bytes = usb_bulk_read(phone->device, BULKIN, buf, 512, 800);
203 } while (bytes > 0);
204
205 return IPHONE_E_SUCCESS;
206}
207
208/**
209 * Given a USB bus and device number, returns a device handle to the iPhone on
210 * that bus. To aid compatibility with future devices, this function does not
211 * check the vendor and device IDs! To do that, you should use
212 * iphone_get_device() or a system-specific API (e.g. HAL).
213 *
214 * @param bus_n The USB bus number.
215 * @param dev_n The USB device number.
216 * @param device A pointer to a iphone_device_t, which must be set to NULL upon
217 * calling iphone_get_specific_device, which will be filled with a device
218 * descriptor on return.
219 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
220 */
221iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_device_t * device)
222{
223 struct usb_bus *bus, *busses;
224 struct usb_device *dev;
225 usbmux_version_header *version;
226 int bytes = 0;
227
228 //check we can actually write in device
229 if (!device || (device && *device))
230 return IPHONE_E_INVALID_ARG;
231
232 iphone_device_t phone = (iphone_device_t) malloc(sizeof(struct iphone_device_int));
233
234 // Initialize the struct
235 phone->device = NULL;
236 phone->__device = NULL;
237 phone->buffer = NULL;
238
239 // Initialize libusb
240 usb_init();
241 usb_find_busses();
242 usb_find_devices();
243 busses = usb_get_busses();
244
245 // Set the device configuration
246 for (bus = busses; bus; bus = bus->next)
247 if (bus->location == bus_n)
248 for (dev = bus->devices; dev != NULL; dev = dev->next)
249 if (dev->devnum == dev_n) {
250 phone->__device = dev;
251 phone->device = usb_open(phone->__device);
252 iphone_config_usb_device(phone);
253 goto found;
254 }
255
256 iphone_free_device(phone);
257
258 log_debug_msg("iphone_get_specific_device: iPhone not found\n");
259 return IPHONE_E_NO_DEVICE;
260
261 found:
262 // Send the version command to the phone
263 version = version_header();
264 bytes = usb_bulk_write(phone->device, BULKOUT, (char *) version, sizeof(*version), 800);
265 if (bytes < 20) {
266 log_debug_msg("get_iPhone(): libusb did NOT send enough!\n");
267 if (bytes < 0) {
268 log_debug_msg("get_iPhone(): libusb gave me the error %d: %s (%s)\n",
269 bytes, usb_strerror(), strerror(-bytes));
270 }
271 }
272 // Read the phone's response
273 bytes = usb_bulk_read(phone->device, BULKIN, (char *) version, sizeof(*version), 800);
274
275 // Check for bad response
276 if (bytes < 20) {
277 free(version);
278 iphone_free_device(phone);
279 log_debug_msg("get_iPhone(): Invalid version message -- header too short.\n");
280 if (bytes < 0)
281 log_debug_msg("get_iPhone(): libusb error message %d: %s (%s)\n", bytes, usb_strerror(), strerror(-bytes));
282 return IPHONE_E_NOT_ENOUGH_DATA;
283 }
284 // Check for correct version
285 if (ntohl(version->major) == 1 && ntohl(version->minor) == 0) {
286 // We're all ready to roll.
287 fprintf(stderr, "get_iPhone() success\n");
288 free(version);
289 *device = phone;
290 return IPHONE_E_SUCCESS;
291 } else {
292 // Bad header
293 iphone_free_device(phone);
294 free(version);
295 log_debug_msg("get_iPhone(): Received a bad header/invalid version number.");
296 return IPHONE_E_BAD_HEADER;
297 }
298
299 // If it got to this point it's gotta be bad
300 log_debug_msg("get_iPhone(): Unknown error.\n");
301 iphone_free_device(phone);
302 free(version);
303 return IPHONE_E_UNKNOWN_ERROR; // if it got to this point it's gotta be bad
304}
305
306
307/**
308 * Scans all USB busses and devices for a known AFC-compatible device and
309 * returns a handle to the first such device it finds. Known devices include
310 * those with vendor ID 0x05ac and product ID between 0x1290 and 0x1293
311 * inclusive.
312 *
313 * This function is convenient, but on systems where higher-level abstractions
314 * (such as HAL) are available it may be preferable to use
315 * iphone_get_specific_device instead, because it can deal with multiple
316 * connected devices as well as devices not known to libiphone.
317 *
318 * @param device Upon calling this function, a pointer to a location of type
319 * iphone_device_t, which must have the value NULL. On return, this location
320 * will be filled with a handle to the device.
321 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
322 */
323iphone_error_t iphone_get_device(iphone_device_t * device)
324{
325 struct usb_bus *bus;
326 struct usb_device *dev;
327
328 pthread_mutex_init(&iphonemutex, NULL);
329
330 usb_init();
331 usb_find_busses();
332 usb_find_devices();
333
334 for (bus = usb_get_busses(); bus != NULL; bus = bus->next)
335 for (dev = bus->devices; dev != NULL; dev = dev->next)
336 if (dev->descriptor.idVendor == 0x05ac
337 && dev->descriptor.idProduct >= 0x1290 && dev->descriptor.idProduct <= 0x1293)
338 return iphone_get_specific_device(bus->location, dev->devnum, device);
339
340 return IPHONE_E_NO_DEVICE;
341}
342
343/** Cleans up an iPhone structure, then frees the structure itself.
344 * This is a library-level function; deals directly with the iPhone to tear
345 * down relations, but otherwise is mostly internal.
346 *
347 * @param phone A pointer to an iPhone structure.
348 */
349iphone_error_t iphone_free_device(iphone_device_t device)
350{
351 char buf[512];
352 int bytes;
353
354 if (!device)
355 return IPHONE_E_INVALID_ARG;
356 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
357
358 do {
359 bytes = usb_bulk_read(device->device, BULKIN, buf, 512, 800);
360 } while (bytes > 0);
361
362 if (device->buffer) {
363 free(device->buffer);
364 }
365 if (device->device) {
366 usb_release_interface(device->device, 1);
367 usb_close(device->device);
368 ret = IPHONE_E_SUCCESS;
369 }
370 free(device);
371
372 pthread_mutex_destroy(&iphonemutex);
373
374 return ret;
375}
376
377
378
379/** Sends data to the phone
380 * This is a low-level (i.e. directly to phone) function.
381 *
382 * @param phone The iPhone to send data to
383 * @param data The data to send to the iPhone
384 * @param datalen The length of the data
385 * @return The number of bytes sent, or -ERRNO on error
386 */
387int send_to_phone(iphone_device_t phone, char *data, int datalen)
388{
389 if (!phone)
390 return -1;
391
392 int timeout = 1000;
393 int retrycount = 0;
394 int bytes = 0;
395 do {
396 if (retrycount > 3) {
397 fprintf(stderr, "EPIC FAIL! aborting on retry count overload.\n");
398 return -1;
399 }
400
401 bytes = usb_bulk_write(phone->device, BULKOUT, data, datalen, timeout);
402 if (bytes == -ETIMEDOUT) {
403 // timed out waiting for write.
404 fprintf(stderr, "usb_bulk_write timeout error.\n");
405 return bytes;
406 }
407 else if (bytes < 0) {
408 fprintf(stderr, "usb_bulk_write failed with error. err:%d (%s)(%s)\n",
409 bytes, usb_strerror(), strerror(-bytes));
410 return -1;
411 }
412 else if (bytes == 0) {
413 fprintf(stderr, "usb_bulk_write sent nothing. retrying.\n");
414 timeout = timeout * 4;
415 retrycount++;
416 continue;
417 }
418 else if (bytes < datalen) {
419 fprintf(stderr, "usb_bulk_write failed to send full dataload. %d of %d\n", bytes, datalen);
420 timeout = timeout * 4;
421 retrycount++;
422 data += bytes;
423 datalen -= bytes;
424 continue;
425 }
426 }
427 while(0); // fall out
428
429 return bytes;
430}
431
432/**
433 */
434int recv_from_phone_timeout(iphone_device_t phone, char *data, int datalen, int timeoutmillis)
435{
436 if (!phone)
437 return -1;
438 int bytes = 0;
439
440 if (!phone)
441 return -1;
442 log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen);
443
444 bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, timeoutmillis);
445 if (bytes < 0) {
446 // there are some things which are errors, others which are no problem.
447 // it's not documented in libUSB, but it seems that the error returns are
448 // just negated ERRNO values.
449 if (bytes == -ETIMEDOUT) {
450 // ignore this. it just means timeout reached before we
451 // picked up any data. no problem.
452 }
453 else {
454 fprintf(stderr, "recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(),
455 strerror(-bytes));
456 log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(),
457 strerror(-bytes));
458 }
459 return -1;
460 }
461
462 return bytes;
463}
464
465/** This function is a low-level (i.e. direct to iPhone) function.
466 *
467 * @param phone The iPhone to receive data from
468 * @param data Where to put data read
469 * @param datalen How much data to read in
470 *
471 * @return How many bytes were read in, or -1 on error.
472 */
473int recv_from_phone(iphone_device_t phone, char *data, int datalen) {
474 return recv_from_phone_timeout(phone, data, datalen, 100);
475}
476
477
478/** Creates a USBMux packet for the given set of ports.
479 *
480 * @param s_port The source port for the connection.
481 * @param d_port The destination port for the connection.
482 *
483 * @return A USBMux packet
484 */
485usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port)
486{
487 usbmux_tcp_header *conn = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header));
488 conn->type = htonl(6);
489 conn->length = HEADERLEN;
490 conn->sport = htons(s_port);
491 conn->dport = htons(d_port);
492 conn->scnt = 0;
493 conn->ocnt = 0;
494 conn->offset = 0x50;
495 conn->window = htons(0x0200);
496 conn->nullnull = 0x0000;
497 conn->length16 = HEADERLEN;
498 return conn;
499}
500
501
502/** Removes a connection from the list of connections made.
503 * The list of connections is necessary for buffering.
504 *
505 * @param connection The connection to delete from the tracking list.
506 */
507static void delete_connection(iphone_umux_client_t connection)
508{
509 pthread_mutex_lock(&iphonemutex);
510
511 // update the global list of connections
512 iphone_umux_client_t *newlist = (iphone_umux_client_t *) malloc(sizeof(iphone_umux_client_t) * (clients - 1));
513 int i = 0, j = 0;
514 for (i = 0; i < clients; i++) {
515 if (connlist[i] == connection)
516 continue;
517 else {
518 newlist[j] = connlist[i];
519 j++;
520 }
521 }
522 free(connlist);
523 connlist = newlist;
524 clients--;
525
526 // free up this connection
527 pthread_mutex_lock(&connection->mutex);
528 if (connection->recv_buffer)
529 free(connection->recv_buffer);
530 if (connection->header)
531 free(connection->header);
532 connection->r_len = 0;
533 pthread_mutex_unlock(&connection->mutex);
534 pthread_mutex_destroy(&connection->mutex);
535 free(connection);
536
537 pthread_mutex_unlock(&iphonemutex);
538}
539
540/** Adds a connection to the list of connections made.
541 * The connection list is necessary for buffering.
542 *
543 * @param connection The connection to add to the global list of connections.
544 */
545
546static void add_connection(iphone_umux_client_t connection)
547{
548 pthread_mutex_lock(&iphonemutex);
549 iphone_umux_client_t *newlist =
550 (iphone_umux_client_t *) realloc(connlist, sizeof(iphone_umux_client_t) * (clients + 1));
551 newlist[clients] = connection;
552 connlist = newlist;
553 clients++;
554 pthread_mutex_unlock(&iphonemutex);
555}
556
557/**
558 * Get a source port number that is not used by one of our connections
559 * This is needed for us to make sure we are not sending on another
560 * connection.
561 */
562static uint16_t get_free_port()
563{
564 int i;
565 uint16_t newport = 30000;
566 int cnt = 0;
567
568 pthread_mutex_lock(&iphonemutex);
569 while (1) {
570 cnt = 0;
571 for (i = 0; i < clients; i++) {
572 if (ntohs(connlist[i]->header->sport) == newport) {
573 cnt++;
574 }
575 }
576 if (cnt == 0) {
577 // newport is not used in our list of connections!
578 break;
579 } else {
580 newport++;
581 if (newport < 30000) {
582 // if all ports from 30000 to 65535 are in use,
583 // the value wraps (16-bit overflow)
584 // return 0, no port is available.
585 // This should not happen, but just in case ;)
586 newport = 0;
587 break;
588 }
589 }
590 }
591 pthread_mutex_unlock(&iphonemutex);
592
593 return newport;
594}
595
596/** Initializes a connection on phone, with source port s_port and destination port d_port
597 *
598 * @param device The iPhone to initialize a connection on.
599 * @param src_port The source port
600 * @param dst_port The destination port -- 0xf27e for lockdownd.
601 * @param client A mux TCP header for the connection which is used for tracking and data transfer.
602 * @return IPHONE_E_SUCCESS on success, an error code otherwise.
603 */
604iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port, uint16_t dst_port,
605 iphone_umux_client_t * client)
606{
607 if (!device || !dst_port)
608 return IPHONE_E_INVALID_ARG;
609
610 src_port = get_free_port();
611
612 if (!src_port) {
613 // this is a special case, if we get 0, this is not good, so
614 return -EISCONN; // TODO: error code suitable?
615 }
616
617 // Initialize connection stuff
618 iphone_umux_client_t new_connection = (iphone_umux_client_t) malloc(sizeof(struct iphone_umux_client_int));
619 new_connection->header = new_mux_packet(src_port, dst_port);
620
621 // send TCP syn
622 if (new_connection && new_connection->header) {
623 new_connection->header->tcp_flags = TCP_SYN;
624 new_connection->header->length = htonl(new_connection->header->length);
625 new_connection->header->length16 = htons(new_connection->header->length16);
626 new_connection->header->scnt = 0;
627 new_connection->header->ocnt = 0;
628 new_connection->phone = device;
629 new_connection->recv_buffer = NULL;
630 new_connection->r_len = 0;
631 pthread_cond_init(&new_connection->wait, NULL);
632 pthread_mutex_init(&new_connection->mutex, NULL);
633 pthread_cond_init(&new_connection->wr_wait, NULL);
634 new_connection->wr_pending_scnt = 0;
635 new_connection->wr_window = 0;
636 add_connection(new_connection);
637 new_connection->error = IPHONE_E_SUCCESS;
638 if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) {
639 *client = new_connection;
640 return IPHONE_E_SUCCESS;
641 } else {
642 delete_connection(new_connection);
643 return IPHONE_E_NOT_ENOUGH_DATA;
644 }
645 }
646 // if we get to this point it's probably bad
647 return IPHONE_E_UNKNOWN_ERROR;
648}
649
650/** Cleans up the given USBMux connection.
651 * @note Once a connection is closed it may not be used again.
652 *
653 * @param connection The connection to close.
654 *
655 * @return IPHONE_E_SUCCESS on success.
656 */
657iphone_error_t iphone_mux_free_client(iphone_umux_client_t client)
658{
659 if (!client || !client->phone)
660 return IPHONE_E_INVALID_ARG;
661
662 pthread_mutex_lock(&client->mutex);
663 client->header->tcp_flags = TCP_FIN;
664 client->header->length = htonl(0x1C);
665 client->header->scnt = htonl(client->header->scnt);
666 client->header->ocnt = htonl(client->header->ocnt);
667 client->header->window = 0;
668 client->header->length16 = htons(0x1C);
669 int bytes = 0;
670
671 bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800);
672 if (bytes < 0)
673 log_debug_msg("iphone_mux_free_client(): when writing, libusb gave me the error: %s\n", usb_strerror());
674
675 bytes = usb_bulk_read(client->phone->device, BULKIN, (char *) client->header, sizeof(usbmux_tcp_header), 800);
676 if (bytes < 0)
677 log_debug_msg("get_iPhone(): when reading, libusb gave me the error: %s\n", usb_strerror());
678
679 pthread_mutex_unlock(&client->mutex);
680 // make sure we don't have any last-minute laggards waiting on this.
681 // I put it after the mutex unlock because we have cases where the
682 // conditional wait is dependent on re-grabbing that mutex.
683 pthread_cond_broadcast(&client->wait);
684 pthread_cond_destroy(&client->wait);
685 pthread_cond_broadcast(&client->wr_wait);
686 pthread_cond_destroy(&client->wr_wait);
687
688 delete_connection(client);
689
690 return IPHONE_E_SUCCESS;
691}
692
693
694/** Sends the given data over the selected connection.
695 *
696 * @param phone The iPhone to send to.
697 * @param client The client we're sending data on.
698 * @param data A pointer to the data to send.
699 * @param datalen How much data we're sending.
700 * @param sent_bytes The number of bytes sent, minus the header (28)
701 *
702 * @return IPHONE_E_SUCCESS on success.
703 */
704iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, uint32_t datalen, uint32_t * sent_bytes)
705{
706 if (!client->phone || !client || !sent_bytes)
707 return IPHONE_E_INVALID_ARG;
708
709 if (client->error != IPHONE_E_SUCCESS) {
710 return client->error;
711 }
712
713 *sent_bytes = 0;
714 pthread_mutex_lock(&client->mutex);
715
716 int sendresult = 0;
717 uint32 blocksize = 0;
718 if (client->wr_window <= 0) {
719 struct timespec ts;
720 clock_gettime(CLOCK_REALTIME, &ts);
721 //ts.tv_sec += 1;
722 ts.tv_nsec += 750 * 1000;
723 if (pthread_cond_timedwait(&client->wait, &client->mutex, &ts) == ETIMEDOUT) {
724 // timd out. optimistically grow the window and try to make progress
725 client->wr_window += WINDOW_INCREMENT;
726 }
727 }
728
729 blocksize = sizeof(usbmux_tcp_header) + datalen;
730
731 // client->scnt and client->ocnt should already be in host notation...
732 // we don't need to change them juuuust yet.
733 char *buffer = (char *) malloc(blocksize + 2); // allow 2 bytes of safety padding
734 // Set the length and pre-emptively htonl/htons it
735 client->header->length = htonl(blocksize);
736 client->header->length16 = htons(blocksize);
737
738 // Put scnt and ocnt into big-endian notation
739 client->header->scnt = htonl(client->header->scnt);
740 client->header->ocnt = htonl(client->header->ocnt);
741 // Concatenation of stuff in the buffer.
742 memcpy(buffer, client->header, sizeof(usbmux_tcp_header));
743 memcpy(buffer + sizeof(usbmux_tcp_header), data, datalen);
744
745 sendresult = send_to_phone(client->phone, buffer, blocksize);
746 // Now that we've sent it off, we can clean up after our sloppy selves.
747 if (buffer)
748 free(buffer);
749
750 // update counts ONLY if the send succeeded.
751 if (sendresult == blocksize) {
752 // Re-calculate scnt and ocnt
753 client->header->scnt = ntohl(client->header->scnt) + datalen;
754 client->header->ocnt = ntohl(client->header->ocnt);
755 // Revert lengths
756 client->header->length = ntohl(client->header->length);
757 client->header->length16 = ntohs(client->header->length16);
758
759 client->wr_window -= blocksize;
760 }
761
762
763 pthread_mutex_unlock(&client->mutex);
764
765
766 if (sendresult == -ETIMEDOUT || sendresult == 0) {
767 // no problem for now...
768 *sent_bytes = 0;
769 return IPHONE_E_TIMEOUT;
770 }
771 else if (sendresult < 0) {
772 return IPHONE_E_UNKNOWN_ERROR;
773 }
774 else if (sendresult == blocksize) {
775 // actual number of data bytes sent.
776 *sent_bytes = sendresult - HEADERLEN;
777 return IPHONE_E_SUCCESS;
778 }
779 else {
780 fprintf(stderr, "usbsend managed to dump a packet that is not full size. %d of %d\n",
781 sendresult, blocksize);
782 return IPHONE_E_UNKNOWN_ERROR;
783 }
784}
785
786/** append the packet's DATA to the receive buffer for the client.
787 *
788 * this has a few other corner-case functions:
789 * 1. this will properly handle the handshake syn+ack.
790 * 2. for all receives, this will appropriately update the ocnt.
791 *
792 * @return number of bytes consumed (header + data)
793 */
794uint32 append_receive_buffer(iphone_umux_client_t client, char* packet)
795{
796 if (client == NULL || packet == NULL) return 0;
797
798 usbmux_tcp_header *header = (usbmux_tcp_header *) packet;
799 char* data = &packet[HEADERLEN];
800 uint32 packetlen = ntohl(header->length);
801 uint32 datalen = packetlen-HEADERLEN;
802
803 int dobroadcast = 0;
804
805 pthread_mutex_lock(&client->mutex);
806
807 // we need to handle a few corner case tasks and book-keeping which
808 // falls on our responsibility because we are the ones reading in
809 // feedback.
810 if (client->header->scnt == 0 && client->header->ocnt == 0 ) {
811 fprintf(stdout, "client is still waiting for handshake.\n");
812 if (header->tcp_flags == (TCP_SYN | TCP_ACK)) {
813 fprintf(stdout, "yes, got syn+ack ; replying with ack.\n");
814 client->header->tcp_flags = TCP_ACK;
815 client->header->length = htonl(sizeof(usbmux_tcp_header));
816 client->header->length16 = htons(sizeof(usbmux_tcp_header));
817 client->header->scnt = htonl(client->header->scnt + 1);
818 client->header->ocnt = header->ocnt;
819 // push it to USB
820 // TODO: need to check for error in the send here.... :(
821 if (send_to_phone(client->phone, (char *)client->header, sizeof(usbmux_tcp_header)) <= 0) {
822 fprintf(stdout, "%s: error when pushing to usb...\n", __func__);
823 }
824 // need to revert some of the fields back to host notation.
825 client->header->scnt = ntohl(client->header->scnt);
826 client->header->ocnt = ntohl(client->header->ocnt);
827 client->header->length = ntohl(client->header->length);
828 client->header->length16 = ntohs(client->header->length16);
829 }
830 else {
831 client->error = IPHONE_E_ECONNABORTED;
832 // woah... this connection failed us.
833 // TODO: somehow signal that this stream is a no-go.
834 fprintf(stderr, "WOAH! client failed to get proper syn+ack.\n");
835 }
836 }
837
838 // update TCP counters and windows.
839 //
840 // save the window that we're getting from the USB device.
841 // apparently the window is bigger than just the 512 that's typically
842 // advertised. iTunes apparently shifts this value by 8 to get a much
843 // larger number.
844 if (header->tcp_flags & TCP_RST) {
845 client->error = IPHONE_E_ECONNRESET;
846 fprintf(stderr, "peer sent connection reset. setting error: %d\n", client->error);
847 }
848
849 // the packet's ocnt tells us how much of our data the device has received.
850 if (header->tcp_flags & TCP_ACK) {
851
852 // this is a hacky magic number condition. it seems that once the window
853 // reported by the phone starts to drop below this number, we quickly fall
854 // into connection reset problems. Once we see the reported window size
855 // start falling off, cut off and wait for solid acks to come back.
856 if (ntohs(header->window) < 256)
857 client->wr_window = 0;
858
859 // check what just got acked.
860 if (ntohl(header->ocnt) < client->header->scnt) {
861 // we got some kind of ack, but it hasn't caught up with the
862 // pending that have been sent.
863 pthread_cond_broadcast(&client->wr_wait);
864 }
865 else if (ntohl(header->ocnt) > /*client->wr_pending_scnt*/ client->header->scnt) {
866 fprintf(stderr, "WTF?! acks overtook pending outstanding. %u,%u\n",
867 ntohl(header->ocnt), client->wr_pending_scnt);
868 }
869 else {
870 // reset the window
871 client->wr_window = WINDOW_MAX;
872 pthread_cond_broadcast(&client->wr_wait);
873 }
874 }
875
876 // the packet's scnt will be our new ocnt.
877 client->header->ocnt = ntohl(header->scnt);
878
879 // ensure there is enough space, either by first malloc or realloc
880 if (datalen > 0) {
881 if (client->r_len == 0) dobroadcast = 1;
882
883 if (client->recv_buffer == NULL) {
884 client->recv_buffer = malloc(datalen);
885 client->r_len = 0;
886 }
887 else {
888 client->recv_buffer = realloc(client->recv_buffer, client->r_len + datalen);
889 }
890
891 memcpy(&client->recv_buffer[client->r_len], data, datalen);
892 client->r_len += datalen;
893 }
894
895 pthread_mutex_unlock(&client->mutex);
896
897 // I put this outside the mutex unlock just so that when the threads
898 // wake, we don't have to do another round of unlock+try to grab.
899 if (dobroadcast)
900 pthread_cond_broadcast(&client->wait);
901
902
903 return packetlen;
904}
905
906/** NOTE! THERE IS NO MUTEX LOCK IN THIS FUNCTION!
907 because we're only called from one location, pullbulk, where the lock
908 is already held.
909 */
910iphone_umux_client_t find_client(usbmux_tcp_header* recv_header)
911{
912 // remember, as we're looking for the client, the receive header is
913 // coming from the USB into our client. This means that when we check
914 // the src/dst ports, we need to reverse them.
915 iphone_umux_client_t retval = NULL;
916
917 // just for debugging check, I'm going to convert the numbers to host-endian.
918 uint16 hsport = ntohs(recv_header->sport);
919 uint16 hdport = ntohs(recv_header->dport);
920
921 pthread_mutex_lock(&iphonemutex);
922 int i;
923 for (i = 0; i < clients; i++) {
924 uint16 csport = ntohs(connlist[i]->header->sport);
925 uint16 cdport = ntohs(connlist[i]->header->dport);
926
927 if (hsport == cdport && hdport == csport) {
928 retval = connlist[i];
929 break;
930 }
931 }
932 pthread_mutex_unlock(&iphonemutex);
933
934 return retval;
935}
936
937/** pull in a big USB bulk packet and distribute it to queues appropriately.
938 */
939void iphone_mux_pullbulk(iphone_device_t phone)
940{
941 static const int DEFAULT_CAPACITY = 128*1024;
942 if (usbReceive.buffer == NULL) {
943 usbReceive.capacity = DEFAULT_CAPACITY;
944 usbReceive.buffer = malloc(usbReceive.capacity);
945 usbReceive.leftover = 0;
946 }
947
948 // start the cursor off just ahead of the leftover.
949 char* cursor = &usbReceive.buffer[usbReceive.leftover];
950 // pull in content, note that the amount we can pull is capacity minus leftover
951 int readlen = recv_from_phone_timeout(phone, cursor, usbReceive.capacity - usbReceive.leftover, 5000);
952 if (readlen < 0) {
953 //fprintf(stderr, "recv_from_phone_timeout gave us an error.\n");
954 readlen = 0;
955 }
956 if (readlen > 0) {
957 //fprintf(stdout, "recv_from_phone_timeout pulled an extra %d bytes\n", readlen);
958 }
959
960 // the amount of content we have to work with is the remainder plus
961 // what we managed to read
962 usbReceive.leftover += readlen;
963
964 // reset the cursor to the front of that buffer and work through
965 // trying to decode packets out of them.
966 cursor = usbReceive.buffer;
967 while (1) {
968 // check if there's even sufficient data to decode a header
969 if (usbReceive.leftover < HEADERLEN) break;
970 usbmux_tcp_header *header = (usbmux_tcp_header *) cursor;
971
972 // now that we have a header, check if there is sufficient data
973 // to construct a full packet, including its data
974 uint32 packetlen = ntohl(header->length);
975 if (usbReceive.leftover < packetlen) {
976 break;
977 }
978
979 // ok... find the client this packet will get stuffed to.
980 iphone_umux_client_t client = find_client(header);
981 if (client == NULL) {
982 fprintf(stderr, "WARNING: client for packet cannot be found. dropping packet.\n");
983 }
984 else {
985 // stuff the data
986 append_receive_buffer(client, cursor);
987 }
988
989 // move the cursor and account for the consumption
990 cursor += packetlen;
991 usbReceive.leftover -= packetlen;
992 }
993
994 // now, we need to manage any leftovers.
995 // I'm going to manage the leftovers by alloc'ing a new block and copying
996 // the leftovers to it. This is just to prevent problems with memory
997 // moves where there may be overlap. Besides, the leftovers should be
998 // small enough that this copy is minimal in overhead.
999 //
1000 // if there are no leftovers, we just leave the datastructure as is,
1001 // and re-use the block next time.
1002 if (usbReceive.leftover > 0 && cursor != usbReceive.buffer) {
1003 char* newbuff = malloc(DEFAULT_CAPACITY);
1004 memcpy(newbuff, cursor, usbReceive.leftover);
1005 free(usbReceive.buffer);
1006 usbReceive.buffer = newbuff;
1007 usbReceive.capacity = DEFAULT_CAPACITY;
1008 }
1009}
1010
1011/**
1012 * return the error code stored in iphone_umux_client_t structure,
1013 * e.g. non-zero when an usb read error occurs.
1014 *
1015 * @param client the umux client
1016 *
1017 * @return IPHONE_E_* error codes.
1018 */
1019iphone_error_t iphone_mux_get_error(iphone_umux_client_t client)
1020{
1021 if (!client) {
1022 return 0;
1023 }
1024
1025 return client->error;
1026}
1027
1028/** This is a higher-level USBMuxTCP-like function
1029 *
1030 * @param connection The connection to receive data on.
1031 * @param data Where to put the data we receive.
1032 * @param datalen How much data to read.
1033 *
1034 * @return IPHONE_E_SUCCESS or error code if failure.
1035 */
1036iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes)
1037{
1038 return iphone_mux_recv_timeout(client, data, datalen, recv_bytes, 0);
1039}
1040
1041/**
1042 @param timeout
1043 */
1044iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout)
1045{
1046
1047 if (!client || !data || datalen == 0 || !recv_bytes)
1048 return IPHONE_E_INVALID_ARG;
1049
1050 if (client->error != IPHONE_E_SUCCESS) return client->error;
1051
1052 pthread_mutex_lock(&client->mutex);
1053
1054 if (timeout > 0 && (client->recv_buffer == NULL ||client->r_len == 0)) {
1055 struct timespec ts;
1056 clock_gettime(CLOCK_REALTIME, &ts);
1057 ts.tv_sec += timeout/1000;
1058 ts.tv_nsec += (timeout-((int)(timeout/1000))*1000)*1000; //millis * 1000;
1059 pthread_cond_timedwait(&client->wait, &client->mutex, &ts);
1060 }
1061
1062 *recv_bytes = 0;
1063 if (client->recv_buffer != NULL && client->r_len > 0) {
1064 uint32_t foolen = datalen;
1065 if (foolen > client->r_len) foolen = client->r_len;
1066 memcpy(data, client->recv_buffer, foolen);
1067 *recv_bytes = foolen;
1068
1069 // preserve any left-over unread amounts.
1070 int remainder = client->r_len - foolen;
1071 if (remainder > 0) {
1072 char* newbuf = malloc(remainder);
1073 memcpy(newbuf, client->recv_buffer + foolen, remainder);
1074 client->r_len = remainder;
1075 free(client->recv_buffer);
1076 client->recv_buffer = newbuf;
1077 }
1078 else {
1079 free(client->recv_buffer);
1080 client->recv_buffer = NULL;
1081 client->r_len = 0;
1082 }
1083 }
1084
1085 pthread_mutex_unlock(&client->mutex);
1086
1087
1088 return IPHONE_E_SUCCESS;
1089}