summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am31
-rw-r--r--src/libusbmuxd.c202
-rw-r--r--src/main.c1351
-rw-r--r--src/sock_stuff.c298
-rw-r--r--src/sock_stuff.h28
-rw-r--r--src/usbmux.c1259
-rw-r--r--src/usbmux.h51
-rw-r--r--src/usbmuxd-proto.h52
-rw-r--r--src/usbmuxd.h45
9 files changed, 3317 insertions, 0 deletions
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 @@
1AM_CFLAGS = $(GLOBAL_CFLAGS) $(libusb_CFLAGS)
2AM_LDFLAGS = $(libusb_LIBS) -lpthread -lrt
3
4# Libraries
5
6noinst_LTLIBRARIES = libusbmux.la libsock_stuff.la
7libsock_stuff_la_SOURCES = sock_stuff.c \
8 sock_stuff.h
9
10libusbmux_la_SOURCES = usbmux.c \
11 usbmux.h
12libusbmux_la_CFLAGS = $(AM_CFLAGS)
13libusbmux_la_LDFLAGS = $(AM_LDFLAGS)
14
15lib_LTLIBRARIES = libusbmuxd.la
16libusbmuxd_la_SOURCES = libusbmuxd.c \
17 usbmuxd.h \
18 usbmuxd-proto.h
19libusbmuxd_la_LIBADD = libsock_stuff.la
20
21include_HEADERS = usbmuxd.h \
22 usbmuxd-proto.h
23
24# Programs
25
26sbin_PROGRAMS = usbmuxd
27
28usbmuxd_SOURCES = main.c
29usbmuxd_LDADD = libusbmux.la \
30 libsock_stuff.la
31
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 @@
1#include <stdint.h>
2#include <stdlib.h>
3#include <errno.h>
4#include <stdio.h>
5#include <string.h>
6#include <sys/socket.h>
7#include <arpa/inet.h>
8#include <unistd.h>
9
10// usbmuxd public interface
11#include <usbmuxd.h>
12// usbmuxd protocol
13#include <usbmuxd-proto.h>
14// socket utility functions
15#include "sock_stuff.h"
16
17static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t * result)
18{
19 struct usbmuxd_result res;
20 int recv_len;
21
22 if (!result) {
23 return -EINVAL;
24 }
25
26 if ((recv_len = recv_buf(sfd, &res, sizeof(res))) <= 0) {
27 perror("recv");
28 return -errno;
29 } else {
30 if ((recv_len == sizeof(res))
31 && (res.header.length == (uint32_t) recv_len)
32 && (res.header.reserved == 0)
33 && (res.header.type == USBMUXD_RESULT)
34 ) {
35 *result = res.result;
36 if (res.header.tag == tag) {
37 return 1;
38 } else {
39 return 0;
40 }
41 }
42 }
43
44 return -1;
45}
46
47int usbmuxd_scan(usbmuxd_scan_result ** available_devices)
48{
49 struct usbmuxd_scan_request s_req;
50 int sfd;
51 int scan_success = 0;
52 uint32_t res;
53 uint32_t pktlen;
54 int recv_len;
55 usbmuxd_scan_result *newlist = NULL;
56 struct usbmuxd_device_info_record dev_info_pkt;
57 int dev_cnt = 0;
58
59 sfd = connect_unix_socket(USBMUXD_SOCKET_FILE);
60 if (sfd < 0) {
61 fprintf(stderr, "%s: error opening socket!\n", __func__);
62 return sfd;
63 }
64
65 s_req.header.length = sizeof(struct usbmuxd_scan_request);
66 s_req.header.reserved = 0;
67 s_req.header.type = USBMUXD_SCAN;
68 s_req.header.tag = 2;
69
70 // send scan request packet
71 if (send_buf(sfd, &s_req, s_req.header.length) ==
72 (int) s_req.header.length) {
73 res = -1;
74 // get response
75 if (usbmuxd_get_result(sfd, s_req.header.tag, &res) && (res == 0)) {
76 scan_success = 1;
77 } else {
78 fprintf(stderr,
79 "%s: Did not get response to scan request (with result=0)...\n",
80 __func__);
81 close(sfd);
82 return res;
83 }
84 }
85
86 if (!scan_success) {
87 fprintf(stderr, "%s: Could not send scan request!\n", __func__);
88 return -1;
89 }
90
91 *available_devices = NULL;
92 // receive device list
93 while (1) {
94 if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) {
95 if (pktlen != sizeof(dev_info_pkt)) {
96 // invalid packet size received!
97 fprintf(stderr,
98 "%s: Invalid packet size (%d) received when expecting a device info record.\n",
99 __func__, pktlen);
100 break;
101 }
102
103 recv_len = recv_buf(sfd, &dev_info_pkt, pktlen);
104 if (recv_len <= 0) {
105 fprintf(stderr,
106 "%s: Error when receiving device info record\n",
107 __func__);
108 break;
109 } else if ((uint32_t) recv_len < pktlen) {
110 fprintf(stderr,
111 "%s: received less data than specified in header!\n",
112 __func__);
113 } else {
114 //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);
115 newlist =
116 (usbmuxd_scan_result *) realloc(*available_devices,
117 sizeof
118 (usbmuxd_scan_result) *
119 (dev_cnt + 1));
120 if (newlist) {
121 newlist[dev_cnt].handle =
122 (int) dev_info_pkt.device.device_id;
123 newlist[dev_cnt].product_id =
124 dev_info_pkt.device.product_id;
125 memset(newlist[dev_cnt].serial_number, '\0',
126 sizeof(newlist[dev_cnt].serial_number));
127 memcpy(newlist[dev_cnt].serial_number,
128 dev_info_pkt.device.serial_number,
129 sizeof(dev_info_pkt.device.serial_number));
130 *available_devices = newlist;
131 dev_cnt++;
132 } else {
133 fprintf(stderr,
134 "%s: ERROR: out of memory when trying to realloc!\n",
135 __func__);
136 break;
137 }
138 }
139 } else {
140 // we _should_ have all of them now.
141 // or perhaps an error occured.
142 break;
143 }
144 }
145
146 // terminating zero record
147 newlist =
148 (usbmuxd_scan_result *) realloc(*available_devices,
149 sizeof(usbmuxd_scan_result) *
150 (dev_cnt + 1));
151 memset(newlist + dev_cnt, 0, sizeof(usbmuxd_scan_result));
152 *available_devices = newlist;
153
154 return dev_cnt;
155}
156
157int usbmuxd_connect(const int handle, const unsigned short tcp_port)
158{
159 int sfd;
160 struct usbmuxd_connect_request c_req;
161 int connected = 0;
162 uint32_t res = -1;
163
164 sfd = connect_unix_socket(USBMUXD_SOCKET_FILE);
165 if (sfd < 0) {
166 fprintf(stderr, "%s: Error: Connection to usbmuxd failed: %s\n",
167 __func__, strerror(errno));
168 return sfd;
169 }
170
171 c_req.header.length = sizeof(c_req);
172 c_req.header.reserved = 0;
173 c_req.header.type = USBMUXD_CONNECT;
174 c_req.header.tag = 3;
175 c_req.device_id = (uint32_t) handle;
176 c_req.tcp_dport = htons(tcp_port);
177 c_req.reserved = 0;
178
179 if (send_buf(sfd, &c_req, sizeof(c_req)) < 0) {
180 perror("send");
181 } else {
182 // read ACK
183 //fprintf(stderr, "%s: Reading connect result...\n", __func__);
184 if (usbmuxd_get_result(sfd, c_req.header.tag, &res)) {
185 if (res == 0) {
186 //fprintf(stderr, "%s: Connect success!\n", __func__);
187 connected = 1;
188 } else {
189 fprintf(stderr, "%s: Connect failed, Error code=%d\n",
190 __func__, res);
191 }
192 }
193 }
194
195 if (connected) {
196 return sfd;
197 }
198
199 close(sfd);
200
201 return -1;
202}
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 @@
1/*
2 * usbmuxd -- daemon for communication with iPhone/iPod via USB
3 *
4 * Copyright (c) 2009 Nikias Bassen. All Rights Reserved.
5 * Based upon iTunnel source code, Copyright (c) 2008 Jing Su.
6 * http://www.cs.toronto.edu/~jingsu/itunnel/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22#include <stddef.h>
23#include <stdio.h>
24#include <errno.h>
25#include <stdlib.h>
26#include <string.h>
27#include <getopt.h>
28#include <stdarg.h>
29#include <syslog.h>
30#include <fcntl.h>
31#include <sys/socket.h>
32#include <sys/un.h>
33#include <sys/stat.h>
34#include <arpa/inet.h>
35#include <unistd.h>
36#include <signal.h>
37#include <pthread.h>
38#include <stdint.h>
39#include <usb.h>
40#include <pwd.h>
41
42#include "usbmuxd-proto.h"
43#include "sock_stuff.h"
44
45#include "usbmux.h"
46
47#define DEFAULT_TIMEOUT 4000
48#define DEFAULT_CHILDREN_CAPACITY 10
49#define DEBUG_LEVEL 0
50
51#define LOCKFILE "/var/run/usbmuxd.lock"
52
53#define THREAD (unsigned int)pthread_self()
54
55static int quit_flag = 0;
56static int fsock = -1;
57static int verbose = DEBUG_LEVEL;
58static int foreground = 0;
59static int exit_on_no_devices = 0;
60
61struct device_info {
62 uint32_t device_id;
63 usbmux_device_t phone;
64 int use_count;
65 pthread_t bulk_reader;
66 pthread_mutex_t mutex;
67 /* mutex for mutual exclusion of calling the usbmux_send function
68 * TODO: I don't know if we need really need this? */
69 pthread_mutex_t writer_mutex;
70};
71
72struct client_data {
73 volatile int dead;
74 int socket;
75 int tag;
76 pthread_t thread;
77 pthread_t handler;
78 pthread_t reader;
79 int reader_quit;
80 int reader_dead;
81 int handler_dead;
82 int connected;
83 usbmux_client_t muxclient;
84 struct device_info *dev;
85};
86
87static struct device_info **devices = NULL;
88static int device_count = 0;
89static pthread_mutex_t usbmux_mutex = PTHREAD_MUTEX_INITIALIZER;
90static pthread_mutex_t usb_mutex = PTHREAD_MUTEX_INITIALIZER;
91
92/**
93 * logs a message to syslog when running as daemon or to stdout/stderr when
94 * running in foreground.
95 * @param prio The logging priority.
96 * @param format The message to be printed.
97 */
98static void logmsg(int prio, const char *format, ...)
99{
100 va_list args;
101 va_start(args, format);
102
103 if (!foreground) {
104 // daemon. log using syslog.
105 vsyslog(prio, format, args);
106 } else {
107 // running in foreground. log to stdout/stderr.
108 char msgbuf[256];
109 FILE *lfp = stdout;
110 switch (prio) {
111 case LOG_EMERG:
112 case LOG_ALERT:
113 case LOG_CRIT:
114 case LOG_ERR:
115 case LOG_WARNING:
116 lfp = stderr;
117 break;
118 default:
119 lfp = stdout;
120 }
121 strcpy(msgbuf, "usbmuxd: ");
122 vsnprintf(msgbuf + 9, 244, format, args);
123 strcat(msgbuf, "\n");
124 fputs(msgbuf, lfp);
125 }
126
127 va_end(args);
128}
129
130#ifdef DEBUG
131/**
132 * for debugging purposes.
133 */
134static void print_buffer(FILE * fp, const char *data, const int length)
135{
136 int i;
137 int j;
138 unsigned char c;
139
140 for (i = 0; i < length; i += 16) {
141 if (verbose >= 4)
142 fprintf(fp, "%04x: ", i);
143 for (j = 0; j < 16; j++) {
144 if (i + j >= length) {
145 if (verbose >= 4)
146 fprintf(fp, " ");
147 continue;
148 }
149 if (verbose >= 4)
150 fprintf(fp, "%02hhx ", *(data + i + j));
151 }
152 if (verbose >= 4)
153 fprintf(fp, " | ");
154 for (j = 0; j < 16; j++) {
155 if (i + j >= length)
156 break;
157 c = *(data + i + j);
158 if ((c < 32) || (c > 127)) {
159 if (verbose >= 4)
160 fprintf(fp, ".");
161 continue;
162 }
163 if (verbose >= 4)
164 fprintf(fp, "%c", c);
165 }
166 if (verbose >= 4)
167 fprintf(fp, "\n");
168 }
169 if (verbose >= 4)
170 fprintf(fp, "\n");
171}
172#endif
173
174/**
175 * Read incoming usbmuxd packet. If the packet is larger than
176 * the size specified by len, the data will be truncated.
177 *
178 * @param fd the file descriptor to read from.
179 * @param data pointer to a buffer to store the read data to.
180 * @param len the length of the data to be read. The buffer
181 * pointed to by data should be at least len bytes in size.
182 *
183 * @return
184 */
185static int usbmuxd_get_request(int fd, void **data, size_t len)
186{
187 uint32_t pktlen;
188 int recv_len;
189
190 if (peek_buf(fd, &pktlen, sizeof(pktlen)) < (int) sizeof(pktlen)) {
191 return -errno;
192 }
193
194 if (len == 0) {
195 // allocate buffer space
196 *data = malloc(pktlen);
197 } else if (len < pktlen) {
198 // target buffer is to small to hold this packet! fix it!
199 if (verbose >= 2)
200 logmsg(LOG_WARNING,
201 "%s: WARNING -- packet (%d) is larger than target buffer (%d)! Truncating.",
202 __func__, pktlen, len);
203 pktlen = len;
204 }
205
206 recv_len = recv_buf(fd, *data, pktlen);
207 if ((recv_len > 0) && ((uint32_t) recv_len < pktlen)) {
208 if (verbose >= 2)
209 logmsg(LOG_WARNING,
210 "%s: Uh-oh, we got less than the packet's size, %d instead of %d...",
211 __func__, recv_len, pktlen);
212 }
213#ifdef DEBUG
214 if (*data && (recv_len > 0) && verbose >= 4) {
215 fprintf(stderr, "%s: received:\n", __func__);
216 print_buffer(stderr, *data, recv_len);
217 }
218#endif
219
220 return recv_len;
221}
222
223/**
224 * Send a usbmuxd result packet with given tag and result_code.
225 *
226 * @param fd the file descriptor to write to.
227 * @param tag the tag value that identifies where this message belongs to.
228 * @param result_code the error value (0 = Success, most likely errno values otherwise)
229 *
230 * @return the return value returned by send_buf (normally the number of bytes sent)
231 */
232static int usbmuxd_send_result(int fd, uint32_t tag, uint32_t result_code)
233{
234 struct usbmuxd_result res;
235 int ret;
236
237 res.header.length = sizeof(res);
238 res.header.reserved = 0;
239 res.header.type = USBMUXD_RESULT;
240 res.header.tag = tag;
241 res.result = result_code;
242
243 if (verbose >= 4)
244 logmsg(LOG_NOTICE, "%s: tag=%d result=%d", __func__,
245 res.header.tag, res.result);
246
247 ret = send_buf(fd, &res, sizeof(res));
248 fsync(fd); // let's get it sent
249 return ret;
250}
251
252/**
253 * this thread reads from the usb connection and writes the
254 * data to the connected client.
255 *
256 * @param arg pointer to a client_data structure.
257 *
258 * @return NULL in any case
259 */
260static void *usbmuxd_client_reader_thread(void *arg)
261{
262 struct client_data *cdata;
263
264 char rbuffer[512];
265 uint32_t rbuffersize = 512;
266 uint32_t rlen;
267 int err;
268 char *cursor;
269 ssize_t len;
270 int result;
271
272 if (!arg) {
273 if (verbose >= 2)
274 logmsg(LOG_ERR, "%s: invalid client_data supplied!", __func__);
275 cdata->reader_dead = 1;
276 return NULL;
277 }
278
279 cdata = (struct client_data *) arg;
280
281 cdata->reader_dead = 0;
282
283 if (verbose >= 3)
284 logmsg(LOG_NOTICE, "%s[%d:%d]: started", __func__,
285 cdata->dev->device_id, cdata->dev->use_count);
286
287 while (!quit_flag && !cdata->reader_quit) {
288 result = check_fd(cdata->socket, FD_WRITE, DEFAULT_TIMEOUT);
289 if (result <= 0) {
290 if (result < 0) {
291 if (verbose >= 2)
292 logmsg(LOG_ERR, "%s: select error: %s", __func__,
293 strerror(errno));
294 }
295 continue;
296 }
297
298 rlen = 0;
299 err =
300 usbmux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize,
301 &rlen, DEFAULT_TIMEOUT);
302 if (err != 0) {
303 if (verbose >= 2)
304 logmsg(LOG_ERR,
305 "%s[%d:%d]: encountered USB read error: %d",
306 __func__, cdata->dev->device_id,
307 cdata->dev->use_count, err);
308 break;
309 }
310
311 cursor = rbuffer;
312 while (rlen > 0) {
313 len = send_buf(cdata->socket, cursor, rlen);
314 if (len <= 0) {
315 logmsg(LOG_ERR, "%s: Error: send returned %d", __func__,
316 len);
317 err = 1;
318 break;
319 }
320 // calculate remainder
321 rlen -= len;
322 // advance cursor
323 cursor += len;
324 }
325 if (err != 0) {
326 logmsg(LOG_ERR, "%s: Error when writing to client...",
327 __func__);
328 break;
329 }
330 fsync(cdata->socket);
331 }
332
333 if (verbose >= 3)
334 logmsg(LOG_NOTICE, "%s[%d:%d]: terminated", __func__,
335 cdata->dev->device_id, cdata->dev->use_count);
336
337 cdata->reader_dead = 1;
338
339 return NULL;
340}
341
342/**
343 * This function handles the connecting procedure to a previously
344 * set up usbmux client.
345 * Sends a usbmuxd result packet denoting success or failure.
346 * A successful result is mandatory for later communication.
347 *
348 * @param cdata pointer to a previously initialized client_data structure
349 *
350 * @return
351 */
352static int usbmuxd_handleConnectResult(struct client_data *cdata)
353{
354 int result;
355 char buffer[512];
356 char err_type[64];
357 int err_code;
358 ssize_t maxlen = 512;
359 uint32_t rlen;
360 int err;
361
362 if (!cdata) {
363 if (verbose >= 2)
364 logmsg(LOG_ERR, "%s: Invalid client_data provided!", __func__);
365 return -EINVAL;
366 }
367
368 result = check_fd(cdata->socket, FD_WRITE, DEFAULT_TIMEOUT);
369 if (result <= 0) {
370 if (result < 0) {
371 if (verbose >= 2)
372 logmsg(LOG_ERR, "%s: select error: %s", __func__,
373 strerror(errno));
374 return result;
375 }
376 } else {
377 result = 0;
378 err =
379 usbmux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen,
380 100);
381 if (err < 0) {
382 if (verbose >= 2)
383 logmsg(LOG_ERR, "%s: encountered USB read error: %d",
384 __func__, err);
385 usbmuxd_send_result(cdata->socket, cdata->tag, -err);
386 return err;
387 } else {
388 if (rlen > 0) {
389 if ((buffer[0] == 1) && (rlen > 20)
390 && !memcmp(buffer + 1, "handleConnectResult:", 20)) {
391 // hm... we got an error message!
392 buffer[rlen] = 0;
393 if (verbose >= 1)
394 logmsg(LOG_ERR, "%s: %s\n", __func__, buffer + 22);
395
396 if (sscanf
397 (buffer + 22, "%s - %d\n", err_type, &err_code)
398 == 2) {
399 usbmuxd_send_result(cdata->socket, cdata->tag,
400 err_code);
401 return -err_code;
402 } else {
403 usbmuxd_send_result(cdata->socket, cdata->tag,
404 ENODATA);
405 return -ENODATA;
406 }
407 } else {
408 // send success result
409 usbmuxd_send_result(cdata->socket, cdata->tag, 0);
410 // and the server greeting message
411 send_buf(cdata->socket, buffer, rlen);
412 }
413 } else {
414 // no server greeting? this seems to be ok. send success.
415 usbmuxd_send_result(cdata->socket, cdata->tag, 0);
416 }
417 }
418 //fsync(cdata->socket);
419 }
420 return result;
421}
422
423/**
424 * This thread handles the communication between the connected iPhone/iPod
425 * and the client that created the connection.
426 */
427static void *usbmuxd_client_handler_thread(void *arg)
428{
429 struct client_data *cdata;
430 int result;
431 char *cursor;
432 char buffer[65536];
433 ssize_t len;
434 ssize_t maxlen = sizeof(buffer);
435 uint32_t wlen;
436 int err;
437
438 if (!arg) {
439 if (verbose >= 2)
440 logmsg(LOG_ERR, "%s: invalid client_data provided!", __func__);
441 return NULL;
442 }
443
444 cdata = (struct client_data *) arg;
445
446 if (verbose >= 3)
447 logmsg(LOG_NOTICE, "%s[%d:%d]: started", __func__,
448 cdata->dev->device_id, cdata->dev->use_count);
449
450 if (usbmuxd_handleConnectResult(cdata)) {
451 if (verbose >= 3)
452 logmsg(LOG_ERR, "handleConnectResult: Error");
453 goto leave;
454 } else {
455 if (verbose >= 3)
456 logmsg(LOG_NOTICE, "handleConnectResult: Success");
457 }
458
459 // starting mux reader thread
460 cdata->reader_quit = 0;
461 cdata->reader_dead = 0;
462 if (pthread_create
463 (&cdata->reader, NULL, usbmuxd_client_reader_thread, cdata) != 0) {
464 if (verbose >= 2)
465 logmsg(LOG_ERR, "%s: could not start client_reader thread",
466 __func__);
467 cdata->reader = 0;
468 }
469
470 while (!quit_flag && !cdata->reader_dead) {
471 result = check_fd(cdata->socket, FD_READ, DEFAULT_TIMEOUT);
472 if (result <= 0) {
473 if (result < 0) {
474 if (verbose >= 3)
475 logmsg(LOG_ERR, "%s: Error: checkfd: %s", __func__,
476 strerror(errno));
477 }
478 continue;
479 }
480 // check_fd told us there's data available, so read from client
481 // and push to USB device.
482 len = recv(cdata->socket, buffer, maxlen, 0);
483 if (len == 0) {
484 break;
485 }
486 if (len < 0) {
487 if (verbose >= 2)
488 logmsg(LOG_ERR, "%s[%d:%d]: Error: recv: %s", __func__,
489 cdata->dev->device_id, cdata->dev->use_count,
490 strerror(errno));
491 break;
492 }
493
494 cursor = buffer;
495
496 pthread_mutex_lock(&cdata->dev->writer_mutex);
497 do {
498 wlen = 0;
499 err = usbmux_send(cdata->muxclient, cursor, len, &wlen);
500 if (err == -ETIMEDOUT) {
501 // some kind of timeout... just be patient and retry.
502 } else if (err < 0) {
503 if (verbose >= 2)
504 logmsg(LOG_ERR, "%s[%d:%d]: USB write error: %d",
505 __func__, cdata->dev->device_id,
506 cdata->dev->use_count, err);
507 len = -1;
508 break;
509 }
510 // calculate remainder.
511 len -= wlen;
512 // advance cursor appropiately.
513 cursor += wlen;
514 }
515 while ((len > 0) && !quit_flag);
516 pthread_mutex_unlock(&cdata->dev->writer_mutex);
517 if (len < 0) {
518 break;
519 }
520 }
521
522 leave:
523 // cleanup
524 if (verbose >= 3)
525 logmsg(LOG_NOTICE, "%s[%d:%d]: terminating", __func__,
526 cdata->dev->device_id, cdata->dev->use_count);
527 if (cdata->reader != 0) {
528 cdata->reader_quit = 1;
529 pthread_join(cdata->reader, NULL);
530 }
531
532 cdata->handler_dead = 1;
533
534 if (verbose >= 3)
535 logmsg(LOG_NOTICE, "%s[%d:%d]: terminated", __func__,
536 cdata->dev->device_id, cdata->dev->use_count);
537 return NULL;
538}
539
540/**
541 * Thread performing usb_bulk_read from the connected device.
542 * One thread per device. Lives as long as the device is in use.
543 */
544static void *usbmuxd_bulk_reader_thread(void *arg)
545{
546 struct device_info *cur_dev;
547 int err;
548
549 if (!arg) {
550 if (verbose >= 2)
551 logmsg(LOG_ERR, "%s: Invalid client_data provided", __func__);
552 return NULL;
553 }
554
555 cur_dev = (struct device_info *) arg;
556
557 if (verbose >= 3)
558 logmsg(LOG_NOTICE, "%s: started", __func__);
559
560 while (!quit_flag && cur_dev) {
561
562 pthread_mutex_lock(&cur_dev->mutex);
563 if (cur_dev->use_count <= 0) {
564 pthread_mutex_unlock(&cur_dev->mutex);
565 break;
566 }
567 pthread_mutex_unlock(&cur_dev->mutex);
568
569 if ((err = usbmux_pullbulk(cur_dev->phone)) < 0) {
570 if (verbose >= 1)
571 logmsg(LOG_ERR, "%s: error %d when reading from device",
572 __func__, err);
573 break;
574 }
575 }
576
577 if (verbose >= 3)
578 logmsg(LOG_NOTICE, "%s: terminated", __func__);
579
580 return NULL;
581}
582
583/**
584 * This thread is started when a new connection is accepted.
585 * It performs the handshake, then waits for the connect packet and
586 * on success it starts the usbmuxd_client_handler thread.
587 */
588static void *usbmuxd_client_init_thread(void *arg)
589{
590 struct client_data *cdata;
591 struct usbmuxd_scan_request *s_req = NULL;
592 struct usbmuxd_device_info_record dev_info_rec;
593 struct usbmuxd_connect_request *c_req = NULL;
594
595 struct usb_bus *bus;
596 struct usb_device *dev;
597
598 int recv_len;
599 int found = 0;
600 int res;
601 int i;
602
603 usbmux_device_t phone = NULL;
604 struct device_info *cur_dev = NULL;
605
606 if (!arg) {
607 if (verbose >= 1)
608 logmsg(LOG_ERR, "%s[%x]: invalid client_data provided!",
609 __func__, THREAD);
610 return NULL;
611 }
612
613 cdata = (struct client_data *) arg;
614 cdata->dead = 0;
615
616 if (verbose >= 3)
617 logmsg(LOG_NOTICE, "%s[%x]: started (fd=%d)", __func__, THREAD,
618 cdata->socket);
619
620 if ((recv_len =
621 usbmuxd_get_request(cdata->socket, (void **) &s_req, 0)) <= 0) {
622 if (verbose >= 2)
623 logmsg(LOG_ERR, "%s[%x]: No scan packet received, error %s",
624 __func__, THREAD, strerror(errno));
625 goto leave;
626 }
627
628 if ((recv_len == sizeof(struct usbmuxd_scan_request))
629 && (s_req->header.length == sizeof(struct usbmuxd_scan_request))
630 && (s_req->header.reserved == 0)
631 && (s_req->header.type == USBMUXD_SCAN)) {
632 // send success response
633 if (verbose >= 3)
634 logmsg(LOG_NOTICE, "%s[%x]: Got scan packet!", __func__,
635 THREAD);
636 usbmuxd_send_result(cdata->socket, s_req->header.tag, 0);
637 } else if ((recv_len == sizeof(struct usbmuxd_connect_request))
638 && (s_req->header.type == USBMUXD_CONNECT)) {
639 c_req = (struct usbmuxd_connect_request *) s_req;
640 s_req = NULL;
641 goto connect;
642 } else {
643 // send error response and exit
644 if (verbose >= 2)
645 logmsg(LOG_ERR, "%s[%x]: Invalid scan packet received.",
646 __func__, THREAD);
647 // TODO is this required?!
648 usbmuxd_send_result(cdata->socket, s_req->header.tag, EINVAL);
649 goto leave;
650 }
651
652 pthread_mutex_lock(&usb_mutex);
653 // gather data about all iPhones/iPods attached
654
655 if (verbose >= 5)
656 logmsg(LOG_DEBUG, "%s[%x]: usb init", __func__, THREAD);
657 usb_init();
658 if (verbose >= 5)
659 logmsg(LOG_DEBUG, "%s[%x]: usb find busses", __func__, THREAD);
660 usb_find_busses();
661 if (verbose >= 5)
662 logmsg(LOG_DEBUG, "%s[%x]: usb find devices", __func__, THREAD);
663 usb_find_devices();
664
665 if (verbose >= 2)
666 logmsg(LOG_NOTICE, "%s[%x]: Looking for attached devices...",
667 __func__, THREAD);
668
669 for (bus = usb_get_busses(); bus; bus = bus->next) {
670 for (dev = bus->devices; dev; dev = dev->next) {
671 if (dev->descriptor.idVendor == 0x05ac
672 && dev->descriptor.idProduct >= 0x1290
673 && dev->descriptor.idProduct <= 0x1293) {
674 if (verbose >= 1)
675 logmsg(LOG_NOTICE,
676 "%s[%x]: Found device on bus %d, id %d",
677 __func__, THREAD, bus->location, dev->devnum);
678 found++;
679
680 // construct packet
681 memset(&dev_info_rec, 0, sizeof(dev_info_rec));
682 dev_info_rec.header.length = sizeof(dev_info_rec);
683 dev_info_rec.header.type = USBMUXD_DEVICE_INFO;
684 dev_info_rec.device.device_id = dev->devnum;
685 dev_info_rec.device.product_id = dev->descriptor.idProduct;
686 if (dev->descriptor.iSerialNumber) {
687 usb_dev_handle *udev;
688 //pthread_mutex_lock(&usbmux_mutex);
689 udev = usb_open(dev);
690 if (udev) {
691 usb_get_string_simple(udev,
692 dev->descriptor.
693 iSerialNumber,
694 dev_info_rec.device.
695 serial_number,
696 sizeof(dev_info_rec.device.
697 serial_number) + 1);
698 usb_close(udev);
699 }
700 //pthread_mutex_unlock(&usbmux_mutex);
701 }
702#ifdef DEBUG
703 if (verbose >= 4)
704 print_buffer(stderr, (char *) &dev_info_rec,
705 sizeof(dev_info_rec));
706#endif
707
708 // send it
709 if (send_buf
710 (cdata->socket, &dev_info_rec,
711 sizeof(dev_info_rec)) <= 0) {
712 if (verbose >= 3)
713 logmsg(LOG_ERR,
714 "%s[%x]: Error: Could not send device info: %s",
715 __func__, THREAD, strerror(errno));
716 found--;
717 }
718 }
719 }
720 }
721 pthread_mutex_unlock(&usb_mutex);
722
723 if (found <= 0) {
724 if (verbose >= 1)
725 logmsg(LOG_NOTICE,
726 "%s[%x]: No attached iPhone/iPod devices found.",
727 __func__, THREAD);
728 goto leave;
729 }
730
731 if (verbose >= 3)
732 logmsg(LOG_NOTICE, "%s[%x]: Waiting for connect request", __func__,
733 THREAD);
734
735 // now wait for connect request
736 //memset(&c_req, 0, sizeof(c_req));
737 if ((recv_len =
738 usbmuxd_get_request(cdata->socket, (void **) &c_req, 0)) <= 0) {
739 if (verbose >= 3)
740 logmsg(LOG_NOTICE,
741 "%s[%x]: Did not receive any connect request.",
742 __func__, THREAD);
743 goto leave;
744 }
745
746 connect:
747
748 if (c_req->header.type != USBMUXD_CONNECT) {
749 if (verbose >= 2)
750 logmsg(LOG_ERR,
751 "%s[%x]: Unexpected packet of type %d received.",
752 __func__, THREAD, c_req->header.type);
753 goto leave;
754 }
755
756 if (verbose >= 3)
757 logmsg(LOG_NOTICE,
758 "%s[%x]: Setting up connection to usb device #%d on port %d",
759 __func__, THREAD, c_req->device_id,
760 ntohs(c_req->tcp_dport));
761
762 // find the device, and open usb connection
763 pthread_mutex_lock(&usbmux_mutex);
764 phone = NULL;
765 cur_dev = NULL;
766 // first check if we already have an open connection
767 if (devices) {
768 for (i = 0; i < device_count; i++) {
769 if (devices[i]) {
770 if (devices[i]->device_id == c_req->device_id) {
771 devices[i]->use_count++;
772 cur_dev = devices[i];
773 phone = cur_dev->phone;
774 break;
775 }
776 }
777 }
778 }
779 if (!phone) {
780 // if not found, make a new connection
781 if (verbose >= 2)
782 logmsg(LOG_NOTICE,
783 "%s[%x]: creating new usb connection, device_id=%d",
784 __func__, THREAD, c_req->device_id);
785
786 pthread_mutex_lock(&usb_mutex);
787 if (usbmux_get_specific_device(0, c_req->device_id, &phone) < 0) {
788 pthread_mutex_unlock(&usb_mutex);
789 pthread_mutex_unlock(&usbmux_mutex);
790 if (verbose >= 1)
791 logmsg(LOG_ERR, "%s[%x]: device_id %d could not be opened",
792 __func__, THREAD, c_req->device_id);
793 usbmuxd_send_result(cdata->socket, c_req->header.tag, ENODEV);
794 goto leave;
795 }
796 pthread_mutex_unlock(&usb_mutex);
797
798 // create device object
799 if (verbose >= 3)
800 logmsg(LOG_DEBUG, "%s[%x]: add to device list", __func__,
801 THREAD);
802 cur_dev =
803 (struct device_info *) malloc(sizeof(struct device_info));
804 memset(cur_dev, 0, sizeof(struct device_info));
805 cur_dev->use_count = 1;
806 cur_dev->device_id = c_req->device_id;
807 cur_dev->phone = phone;
808 cur_dev->bulk_reader = 0;
809 pthread_mutex_init(&cur_dev->mutex, NULL);
810 pthread_mutex_init(&cur_dev->writer_mutex, NULL);
811
812 if (verbose >= 3)
813 logmsg(LOG_DEBUG, "%s[%x]: device_count = %d", __func__,
814 THREAD, device_count);
815
816 // add to list of devices
817 devices =
818 (struct device_info **) realloc(devices,
819 sizeof(struct device_info *) *
820 (device_count + 1));
821 if (devices) {
822 devices[device_count] = cur_dev;
823 device_count++;
824 }
825 } else {
826 if (verbose >= 2)
827 logmsg(LOG_NOTICE,
828 "%s[%x]: reusing usb connection, device_id=%d",
829 __func__, THREAD, c_req->device_id);
830 }
831 pthread_mutex_unlock(&usbmux_mutex);
832
833 // setup connection to iPhone/iPod
834// pthread_mutex_lock(&usbmux_mutex);
835 res =
836 usbmux_new_client(cur_dev->phone, 0, ntohs(c_req->tcp_dport),
837 &(cdata->muxclient));
838// pthread_mutex_unlock(&usbmux_mutex);
839
840 if (res != 0) {
841 usbmuxd_send_result(cdata->socket, c_req->header.tag, res);
842 if (verbose >= 1)
843 logmsg(LOG_ERR,
844 "%s[%x]: mux_new_client returned %d, aborting.",
845 __func__, THREAD, res);
846 goto leave;
847 }
848 // start bulk reader thread (once per device)
849 pthread_mutex_lock(&cur_dev->mutex);
850 if (cur_dev->bulk_reader == 0) {
851 pthread_create(&cur_dev->bulk_reader, NULL,
852 usbmuxd_bulk_reader_thread, cur_dev);
853 }
854 pthread_mutex_unlock(&cur_dev->mutex);
855
856 // start connection handler thread
857 cdata->handler_dead = 0;
858 cdata->tag = c_req->header.tag;
859 cdata->dev = cur_dev;
860 if (pthread_create
861 (&cdata->handler, NULL, usbmuxd_client_handler_thread, cdata) != 0)
862 {
863 if (verbose >= 1)
864 logmsg(LOG_ERR,
865 "%s[%x]: could not create usbmuxd_client_handler_thread!",
866 __func__, THREAD);
867 cdata->handler = 0;
868 goto leave;
869 }
870 // wait for handler thread to finish its work
871 if (cdata->handler != 0) {
872 pthread_join(cdata->handler, NULL);
873 }
874
875 if (verbose >= 2)
876 logmsg(LOG_NOTICE, "%s[%x]: closing connection", __func__, THREAD);
877
878 // time to clean up
879 if (cdata && cdata->muxclient) { // should be non-NULL
880 usbmux_free_client(cdata->muxclient);
881 }
882
883 leave:
884 if (verbose >= 3)
885 logmsg(LOG_NOTICE, "%s[%x]: terminating", __func__, THREAD);
886
887 if (s_req) {
888 free(s_req);
889 }
890 if (c_req) {
891 free(c_req);
892 }
893 // this has to be freed only if it's not in use anymore as it closes
894 // the USB connection
895 pthread_mutex_lock(&usbmux_mutex);
896 if (cur_dev) {
897 pthread_mutex_lock(&cur_dev->mutex);
898 if (cur_dev->use_count > 1) {
899 if (verbose >= 2)
900 logmsg(LOG_NOTICE,
901 "%s[%x]: decreasing device use count (from %d to %d)",
902 __func__, THREAD, cur_dev->use_count,
903 cur_dev->use_count - 1);
904 cur_dev->use_count--;
905 pthread_mutex_unlock(&cur_dev->mutex);
906 } else {
907 if (verbose >= 2)
908 logmsg(LOG_NOTICE,
909 "%s[%x]: last client disconnected, cleaning up",
910 __func__, THREAD);
911 cur_dev->use_count = 0;
912 pthread_mutex_unlock(&cur_dev->mutex);
913 if (cur_dev->bulk_reader != 0) {
914 if (verbose >= 3)
915 logmsg(LOG_NOTICE, "%s[%x]: joining bulk_reader...",
916 __func__, THREAD);
917 pthread_join(cur_dev->bulk_reader, NULL);
918 }
919 pthread_mutex_lock(&usb_mutex);
920 usbmux_free_device(cur_dev->phone);
921 pthread_mutex_unlock(&usb_mutex);
922 pthread_mutex_destroy(&cur_dev->writer_mutex);
923 pthread_mutex_destroy(&cur_dev->mutex);
924 free(cur_dev);
925 cur_dev = NULL;
926 if (device_count > 1) {
927 struct device_info **newlist;
928 int j;
929
930 newlist =
931 (struct device_info **)
932 malloc(sizeof(struct device_info *)
933 * device_count - 1);
934 for (i = 0; i < device_count; i++) {
935 if (devices[i] != NULL) {
936 newlist[j++] = devices[i];
937 }
938 }
939 free(devices);
940 devices = newlist;
941 device_count--;
942 } else {
943 free(devices);
944 devices = NULL;
945 device_count = 0;
946 }
947 }
948 }
949 pthread_mutex_unlock(&usbmux_mutex);
950
951 cdata->dead = 1;
952 close(cdata->socket);
953
954 if (verbose >= 3)
955 logmsg(LOG_NOTICE, "%s[%x]: terminated", __func__, THREAD);
956
957 return NULL;
958}
959
960/**
961 * make this program run detached from the current console
962 */
963static int daemonize()
964{
965 pid_t pid;
966 pid_t sid;
967
968 // already a daemon
969 if (getppid() == 1)
970 return 0;
971
972 pid = fork();
973 if (pid < 0) {
974 exit(EXIT_FAILURE);
975 }
976
977 if (pid > 0) {
978 // exit parent process
979 exit(EXIT_SUCCESS);
980 }
981 // At this point we are executing as the child process
982
983 // Change the file mode mask
984 umask(0);
985
986 // Create a new SID for the child process
987 sid = setsid();
988 if (sid < 0) {
989 return -1;
990 }
991 // Change the current working directory.
992 if ((chdir("/")) < 0) {
993 return -2;
994 }
995 // Redirect standard files to /dev/null
996 freopen("/dev/null", "r", stdin);
997 freopen("/dev/null", "w", stdout);
998 freopen("/dev/null", "w", stderr);
999
1000 return 0;
1001}
1002
1003/**
1004 * signal handler function for cleaning up properly
1005 */
1006static void clean_exit(int sig)
1007{
1008 if (sig == SIGINT) {
1009 if (verbose >= 1)
1010 fprintf(stderr, "CTRL+C pressed\n");
1011 }
1012 quit_flag = 1;
1013}
1014
1015static void usage()
1016{
1017 printf("usage: usbmuxd [options]\n");
1018 printf("\t-h|--help print this message.\n");
1019 printf("\t-v|--verbose be verbose\n");
1020 printf("\t-f|--foreground do not daemonize\n");
1021 printf("\n");
1022}
1023
1024static void parse_opts(int argc, char **argv)
1025{
1026 static struct option longopts[] = {
1027 {"help", 0, NULL, 'h'},
1028 {"foreground", 0, NULL, 'f'},
1029 {"verbose", 0, NULL, 'v'},
1030 {"exit-on-no-devices", 0, NULL, 'e'},
1031 {NULL, 0, NULL, 0}
1032 };
1033 int c;
1034
1035 while (1) {
1036 c = getopt_long(argc, argv, "hfve", longopts, (int *) 0);
1037 if (c == -1) {
1038 break;
1039 }
1040
1041 switch (c) {
1042 case 'h':
1043 usage();
1044 exit(0);
1045 case 'f':
1046 foreground = 1;
1047 break;
1048 case 'v':
1049 sock_stuff_set_verbose(++verbose);
1050 break;
1051 case 'e':
1052 exit_on_no_devices = 1;
1053 break;
1054 default:
1055 usage();
1056 exit(2);
1057 }
1058 }
1059}
1060
1061/**
1062 * checks for attached devices
1063 *
1064 * @return number of devices found
1065 */
1066static int devices_attached()
1067{
1068 struct usb_bus *bus;
1069 struct usb_device *dev;
1070 int res = 0;
1071
1072 usb_init();
1073 usb_find_busses();
1074 usb_find_devices();
1075
1076 for (bus = usb_get_busses(); bus; bus = bus->next) {
1077 for (dev = bus->devices; dev; dev = dev->next) {
1078 if (dev->descriptor.idVendor == 0x05ac
1079 && dev->descriptor.idProduct >= 0x1290
1080 && dev->descriptor.idProduct <= 0x1293) {
1081 res++;
1082 }
1083 }
1084 }
1085
1086 return res;
1087}
1088
1089/**
1090 * main function. Initializes all stuff and then loops waiting in accept.
1091 */
1092int main(int argc, char **argv)
1093{
1094 struct sockaddr_un c_addr;
1095 socklen_t len = sizeof(struct sockaddr_un);
1096 struct client_data *cdata = NULL;
1097 struct client_data **children = NULL;
1098 int children_capacity = DEFAULT_CHILDREN_CAPACITY;
1099 int i;
1100 int result = 0;
1101 int cnt = 0;
1102 FILE *lfd = NULL;
1103 struct flock lock;
1104
1105 parse_opts(argc, argv);
1106
1107 argc -= optind;
1108 argv += optind;
1109
1110 if (!foreground) {
1111 openlog("usbmuxd", LOG_PID, 0);
1112 }
1113
1114 if (verbose >= 2)
1115 logmsg(LOG_NOTICE, "starting");
1116
1117 // signal(SIGHUP, reload_conf); // none yet
1118 signal(SIGINT, clean_exit);
1119 signal(SIGQUIT, clean_exit);
1120 signal(SIGTERM, clean_exit);
1121 signal(SIGPIPE, SIG_IGN);
1122
1123 // check for other running instance
1124 lfd = fopen(LOCKFILE, "r");
1125 if (lfd) {
1126 lock.l_type = 0;
1127 lock.l_whence = SEEK_SET;
1128 lock.l_start = 0;
1129 lock.l_len = 0;
1130 fcntl(fileno(lfd), F_GETLK, &lock);
1131 fclose(lfd);
1132 if (lock.l_type != F_UNLCK) {
1133 logmsg(LOG_NOTICE,
1134 "another instance is already running. exiting.");
1135 return -1;
1136 }
1137 }
1138
1139 if (exit_on_no_devices) {
1140 if (devices_attached() <= 0) {
1141 logmsg(LOG_NOTICE, "no devices attached. exiting.");
1142 return 0;
1143 }
1144 }
1145
1146 fsock = create_unix_socket(USBMUXD_SOCKET_FILE);
1147 if (fsock < 0) {
1148 logmsg(LOG_ERR, "Could not create socket, exiting");
1149 if (!foreground) {
1150 closelog();
1151 }
1152 return -1;
1153 }
1154
1155 chmod(USBMUXD_SOCKET_FILE, 0666);
1156
1157 if (verbose >= 3)
1158 usbmux_set_debug(1);
1159
1160 if (!foreground) {
1161 if (daemonize() < 0) {
1162 fprintf(stderr, "usbmuxd: FATAL: Could not daemonize!\n");
1163 syslog(LOG_ERR, "FATAL: Could not daemonize!");
1164 closelog();
1165 exit(EXIT_FAILURE);
1166 }
1167 }
1168 // now open the lockfile and place the lock
1169 lfd = fopen(LOCKFILE, "w");
1170 if (lfd) {
1171 lock.l_type = F_WRLCK;
1172 lock.l_whence = SEEK_SET;
1173 lock.l_start = 0;
1174 lock.l_len = 0;
1175 if (fcntl(fileno(lfd), F_SETLK, &lock) == -1) {
1176 logmsg(LOG_ERR, "ERROR: lockfile locking failed!");
1177 }
1178 }
1179 // drop elevated privileges
1180 if (getuid() == 0 || geteuid() == 0) {
1181 struct passwd *pw = getpwnam("nobody");
1182 if (pw) {
1183 setuid(pw->pw_uid);
1184 } else {
1185 logmsg(LOG_ERR,
1186 "ERROR: Dropping privileges failed, check if user 'nobody' exists! Will now terminate.");
1187 exit(EXIT_FAILURE);
1188 }
1189
1190 // security check
1191 if (setuid(0) != -1) {
1192 logmsg(LOG_ERR, "ERROR: Failed to drop privileges properly!");
1193 exit(EXIT_FAILURE);
1194 }
1195 if (verbose >= 2)
1196 logmsg(LOG_NOTICE, "Successfully dropped privileges");
1197 }
1198 // Reserve space for 10 clients which should be enough. If not, the
1199 // buffer gets enlarged later.
1200 children =
1201 (struct client_data **) malloc(sizeof(struct client_data *) *
1202 children_capacity);
1203 if (!children) {
1204 logmsg(LOG_ERR,
1205 "Out of memory when allocating memory for child threads. Terminating.");
1206 if (!foreground) {
1207 closelog();
1208 }
1209 exit(EXIT_FAILURE);
1210 }
1211 memset(children, 0, sizeof(struct client_data *) * children_capacity);
1212
1213 if (verbose >= 2)
1214 logmsg(LOG_NOTICE, "waiting for connection");
1215 while (!quit_flag) {
1216 // Check the file descriptor before accepting a connection.
1217 // If no connection attempt is made, just repeat...
1218 result = check_fd(fsock, FD_READ, 1000);
1219 if (result <= 0) {
1220 if (result == 0) {
1221 // cleanup
1222 for (i = 0; i < children_capacity; i++) {
1223 if (children[i]) {
1224 if (children[i]->dead != 0) {
1225 pthread_join(children[i]->thread, NULL);
1226 if (verbose >= 3)
1227 logmsg(LOG_NOTICE,
1228 "reclaimed client thread (fd=%d)",
1229 children[i]->socket);
1230 free(children[i]);
1231 children[i] = NULL;
1232 cnt++;
1233 } else {
1234 cnt = 0;
1235 }
1236 } else {
1237 cnt++;
1238 }
1239 }
1240
1241 if ((children_capacity > DEFAULT_CHILDREN_CAPACITY)
1242 && ((children_capacity - cnt) <=
1243 DEFAULT_CHILDREN_CAPACITY)) {
1244 children_capacity = DEFAULT_CHILDREN_CAPACITY;
1245 children =
1246 realloc(children,
1247 sizeof(struct client_data *) *
1248 children_capacity);
1249 }
1250 continue;
1251 } else {
1252 if (verbose >= 3)
1253 logmsg(LOG_ERR, "usbmuxd: select error: %s",
1254 strerror(errno));
1255 continue;
1256 }
1257 }
1258
1259 cdata = (struct client_data *) malloc(sizeof(struct client_data));
1260 memset(cdata, 0, sizeof(struct client_data));
1261 if (!cdata) {
1262 quit_flag = 1;
1263 logmsg(LOG_ERR, "Error: Out of memory! Terminating.");
1264 break;
1265 }
1266
1267 cdata->socket = accept(fsock, (struct sockaddr *) &c_addr, &len);
1268 if (cdata->socket < 0) {
1269 free(cdata);
1270 if (errno == EINTR) {
1271 continue;
1272 } else {
1273 if (verbose >= 3)
1274 logmsg(LOG_ERR, "Error in accept: %s",
1275 strerror(errno));
1276 continue;
1277 }
1278 }
1279
1280 if (verbose >= 1)
1281 logmsg(LOG_NOTICE, "new client connected (fd=%d)",
1282 cdata->socket);
1283
1284 // create client thread:
1285 if (pthread_create
1286 (&cdata->thread, NULL, usbmuxd_client_init_thread, cdata) == 0)
1287 {
1288 for (i = 0; i < children_capacity; i++) {
1289 if (children[i] == NULL)
1290 break;
1291 }
1292 if (i == children_capacity) {
1293 // enlarge buffer
1294 children_capacity++;
1295 children =
1296 realloc(children,
1297 sizeof(struct client_data *) *
1298 children_capacity);
1299 if (!children) {
1300 logmsg(LOG_ERR,
1301 "Out of memory when enlarging child thread buffer");
1302 }
1303 }
1304 children[i] = cdata;
1305 } else {
1306 logmsg(LOG_ERR, "Failed to create client_init_thread.");
1307 close(cdata->socket);
1308 free(cdata);
1309 cdata = NULL;
1310 }
1311 }
1312
1313 if (verbose >= 3)
1314 logmsg(LOG_NOTICE, "terminating");
1315
1316 // preparing for shutdown: wait for child threads to terminate (if any)
1317 if (verbose >= 2)
1318 logmsg(LOG_NOTICE, "waiting for child threads to terminate...");
1319 for (i = 0; i < children_capacity; i++) {
1320 if (children[i] != NULL) {
1321 pthread_join(children[i]->thread, NULL);
1322 free(children[i]);
1323 }
1324 }
1325
1326 // delete the children set.
1327 free(children);
1328 children = NULL;
1329
1330
1331 if (fsock >= 0) {
1332 close(fsock);
1333 }
1334
1335 unlink(USBMUXD_SOCKET_FILE);
1336
1337 // unlock lock file and close it.
1338 if (lfd) {
1339 lock.l_type = F_UNLCK;
1340 fcntl(fileno(lfd), F_SETLK, &lock);
1341 fclose(lfd);
1342 }
1343
1344 if (verbose >= 1)
1345 logmsg(LOG_NOTICE, "usbmuxd: terminated");
1346 if (!foreground) {
1347 closelog();
1348 }
1349
1350 return 0;
1351}
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 @@
1#include <stdio.h>
2#include <stddef.h>
3#include <unistd.h>
4#include <errno.h>
5#include <sys/time.h>
6#include <sys/stat.h>
7#include <sys/socket.h>
8#include <sys/un.h>
9#include <netinet/in.h>
10#include <netdb.h>
11#include <arpa/inet.h>
12#include "sock_stuff.h"
13
14#define RECV_TIMEOUT 20000
15
16static int verbose = 0;
17
18void sock_stuff_set_verbose(int level)
19{
20 verbose = level;
21}
22
23int create_unix_socket(const char *filename)
24{
25 struct sockaddr_un name;
26 int sock;
27 size_t size;
28
29 // remove if still present
30 unlink(filename);
31
32 /* Create the socket. */
33 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
34 if (sock < 0) {
35 perror("socket");
36 return -1;
37 }
38
39 /* Bind a name to the socket. */
40 name.sun_family = AF_LOCAL;
41 strncpy(name.sun_path, filename, sizeof(name.sun_path));
42 name.sun_path[sizeof(name.sun_path) - 1] = '\0';
43
44 /* The size of the address is
45 the offset of the start of the filename,
46 plus its length,
47 plus one for the terminating null byte.
48 Alternatively you can just do:
49 size = SUN_LEN (&name);
50 */
51 size = (offsetof(struct sockaddr_un, sun_path)
52 + strlen(name.sun_path) + 1);
53
54 if (bind(sock, (struct sockaddr *) &name, size) < 0) {
55 perror("bind");
56 close(sock);
57 return -1;
58 }
59
60 if (listen(sock, 10) < 0) {
61 perror("listen");
62 close(sock);
63 return -1;
64 }
65
66 return sock;
67}
68
69int connect_unix_socket(const char *filename)
70{
71 struct sockaddr_un name;
72 int sfd = -1;
73 size_t size;
74 struct stat fst;
75
76 // check if socket file exists...
77 if (stat(filename, &fst) != 0) {
78 if (verbose >= 2)
79 fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename,
80 strerror(errno));
81 return -1;
82 }
83 // ... and if it is a unix domain socket
84 if (!S_ISSOCK(fst.st_mode)) {
85 if (verbose >= 2)
86 fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__,
87 filename);
88 return -1;
89 }
90 // make a new socket
91 if ((sfd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
92 if (verbose >= 2)
93 fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno));
94 return -1;
95 }
96 // and connect to 'filename'
97 name.sun_family = AF_LOCAL;
98 strncpy(name.sun_path, filename, sizeof(name.sun_path));
99 name.sun_path[sizeof(name.sun_path) - 1] = 0;
100
101 size = (offsetof(struct sockaddr_un, sun_path)
102 + strlen(name.sun_path) + 1);
103
104 if (connect(sfd, (struct sockaddr *) &name, size) < 0) {
105 close(sfd);
106 if (verbose >= 2)
107 fprintf(stderr, "%s: connect: %s\n", __func__,
108 strerror(errno));
109 return -1;
110 }
111
112 return sfd;
113}
114
115int create_socket(uint16_t port)
116{
117 int sfd = -1;
118 int yes = 1;
119 struct sockaddr_in saddr;
120
121 if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
122 perror("socket()");
123 return -1;
124 }
125
126 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
127 perror("setsockopt()");
128 close(sfd);
129 return -1;
130 }
131
132 memset((void *) &saddr, 0, sizeof(saddr));
133 saddr.sin_family = AF_INET;
134 saddr.sin_addr.s_addr = htonl(INADDR_ANY);
135 saddr.sin_port = htons(port);
136
137 if (0 > bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr))) {
138 perror("bind()");
139 close(sfd);
140 return -1;
141 }
142
143 if (listen(sfd, 1) == -1) {
144 perror("listen()");
145 close(sfd);
146 return -1;
147 }
148
149 return sfd;
150}
151
152int connect_socket(const char *addr, uint16_t port)
153{
154 int sfd = -1;
155 int yes = 1;
156 struct hostent *hp;
157 struct sockaddr_in saddr;
158
159 if (!addr) {
160 errno = EINVAL;
161 return -1;
162 }
163
164 if ((hp = gethostbyname(addr)) == NULL) {
165 if (verbose >= 2)
166 fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr);
167 return -1;
168 }
169
170 if (!hp->h_addr) {
171 if (verbose >= 2)
172 fprintf(stderr, "%s: gethostbyname returned NULL address!\n",
173 __func__);
174 return -1;
175 }
176
177 if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
178 perror("socket()");
179 return -1;
180 }
181
182 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
183 perror("setsockopt()");
184 close(sfd);
185 return -1;
186 }
187
188 memset((void *) &saddr, 0, sizeof(saddr));
189 saddr.sin_family = AF_INET;
190 saddr.sin_addr.s_addr = *(uint32_t *) hp->h_addr;
191 saddr.sin_port = htons(port);
192
193 if (connect(sfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
194 perror("connect");
195 close(sfd);
196 return -2;
197 }
198
199 return sfd;
200}
201
202int check_fd(int fd, fd_mode fdm, unsigned int timeout)
203{
204 fd_set fds;
205 int sret;
206 int eagain;
207 struct timeval to;
208
209 if (fd <= 0) {
210 if (verbose >= 2)
211 fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd);
212 return -1;
213 }
214
215 FD_ZERO(&fds);
216 FD_SET(fd, &fds);
217
218 to.tv_sec = (time_t) (timeout / 1000);
219 to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
220
221 sret = -1;
222
223 do {
224 eagain = 0;
225 switch (fdm) {
226 case FD_READ:
227 sret = select(fd + 1, &fds, NULL, NULL, &to);
228 break;
229 case FD_WRITE:
230 sret = select(fd + 1, NULL, &fds, NULL, &to);
231 break;
232 case FD_EXCEPT:
233 sret = select(fd + 1, NULL, NULL, &fds, &to);
234 break;
235 default:
236 return -1;
237 }
238
239 if (sret < 0) {
240 switch (errno) {
241 case EINTR:
242 // interrupt signal in select
243 if (verbose >= 2)
244 fprintf(stderr, "%s: EINTR\n", __func__);
245 eagain = 1;
246 break;
247 case EAGAIN:
248 if (verbose >= 2)
249 fprintf(stderr, "%s: EAGAIN\n", __func__);
250 break;
251 default:
252 if (verbose >= 2)
253 fprintf(stderr, "%s: select failed: %s\n", __func__,
254 strerror(errno));
255 return -1;
256 }
257 }
258 } while (eagain);
259
260 return sret;
261}
262
263int recv_buf(int fd, void *data, size_t length)
264{
265 return recv_buf_timeout(fd, data, length, 0, RECV_TIMEOUT);
266}
267
268int peek_buf(int fd, void *data, size_t length)
269{
270 return recv_buf_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT);
271}
272
273int recv_buf_timeout(int fd, void *data, size_t length, int flags,
274 unsigned int timeout)
275{
276 int res;
277 int result;
278
279 // check if data is available
280 res = check_fd(fd, FD_READ, timeout);
281 if (res <= 0) {
282 return res;
283 }
284 // if we get here, there _is_ data available
285 result = recv(fd, data, length, flags);
286 if (res > 0 && result == 0) {
287 // but this is an error condition
288 if (verbose >= 3)
289 fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
290 return -1;
291 }
292 return result;
293}
294
295int send_buf(int fd, void *data, size_t length)
296{
297 return send(fd, data, length, 0);
298}
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 @@
1#ifndef __SOCK_STUFF_H
2#define __SOCK_STUFF_H
3
4#include <stdint.h>
5
6enum fd_mode {
7 FD_READ,
8 FD_WRITE,
9 FD_EXCEPT
10};
11typedef enum fd_mode fd_mode;
12
13int create_unix_socket(const char *filename);
14int connect_unix_socket(const char *filename);
15int create_socket(uint16_t port);
16int connect_socket(const char *addr, uint16_t port);
17int check_fd(int fd, fd_mode fdm, unsigned int timeout);
18
19int recv_buf(int fd, void *data, size_t size);
20int peek_buf(int fd, void *data, size_t size);
21int recv_buf_timeout(int fd, void *data, size_t size, int flags,
22 unsigned int timeout);
23
24int send_buf(int fd, void *data, size_t size);
25
26void sock_stuff_set_verbose(int level);
27
28#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 @@
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 "usbmux.h"
28
29#define BULKIN 0x85
30#define BULKOUT 0x04
31#define HEADERLEN 28
32
33static const uint8_t TCP_FIN = 1;
34static const uint8_t TCP_SYN = 1 << 1;
35static const uint8_t TCP_RST = 1 << 2;
36static const uint8_t TCP_PSH = 1 << 3;
37static const uint8_t TCP_ACK = 1 << 4;
38static const uint8_t TCP_URG = 1 << 5;
39
40// I have trouble figuring out how to properly manage the windowing to
41// the device. It keeps sending back 512 and seems to drop off a cliff
42// when the device gets overwhelmed. In addition, the device likes to
43// panic and send out RESETS before the window hits zero. Also, waiting
44// for responses seems to not be a winning strategy.
45//
46// Since I'm not sure how in the hell to interpret the window sizes that
47// the device is sending back to us, I've figured out some magic number
48// constants which seem to work okay.
49static const uint32_t WINDOW_MAX = 5 * 1024;
50static const uint32_t WINDOW_INCREMENT = 512;
51
52typedef struct {
53 char *buffer;
54 int leftover;
55 int capacity;
56} receivebuf_t;
57
58struct usbmux_device_int {
59 struct usb_dev_handle *usbdev;
60 struct usb_device *__device;
61 receivebuf_t usbReceive;
62};
63
64typedef struct {
65 uint32_t type, length, major, minor, allnull;
66} usbmux_version_header;
67
68typedef struct {
69 uint32_t type, length;
70 uint16_t sport, dport;
71 uint32_t scnt, ocnt;
72 uint8_t offset, tcp_flags;
73 uint16_t window, nullnull, length16;
74} usbmux_tcp_header;
75
76struct usbmux_client_int {
77 usbmux_tcp_header *header;
78 usbmux_device_t device;
79
80 char *recv_buffer;
81 int r_len;
82 pthread_cond_t wait;
83
84 // this contains a conditional variable which usb-writers can wait
85 // on while waiting for window updates from the device.
86 pthread_cond_t wr_wait;
87 // I'm going to do something really cheesy here. We are going to
88 // just record the most recent scnt that we are expecting to hear
89 // back on. We will actually halt progress by limiting the number
90 // of outstanding un-acked bulk sends that we have beamed out.
91 uint32_t wr_pending_scnt;
92 long wr_window;
93
94 pthread_mutex_t mutex;
95
96 // this variable is not protected by the mutex. This will always
97 // be E_SUCCESS, unless an error of some kind breaks this stream.
98 // this will then be set to the error that caused the broken stream.
99 // no further operations other than free_client will be allowed.
100 int error;
101
102 int cleanup;
103};
104
105
106static pthread_mutex_t usbmuxmutex = PTHREAD_MUTEX_INITIALIZER;
107static usbmux_client_t *connlist = NULL;
108static int clients = 0;
109
110
111/**
112 */
113int toto_debug = 0;
114
115void usbmux_set_debug(int e)
116{
117 toto_debug = e;
118}
119
120void log_debug_msg(const char *format, ...)
121{
122#ifndef STRIP_DEBUG_CODE
123 va_list args;
124 /* run the real fprintf */
125 va_start(args, format);
126
127 if (toto_debug)
128 vfprintf(stderr, format, args);
129
130 va_end(args);
131#endif
132}
133
134#ifdef DEBUG
135/**
136 * for debugging purposes.
137 */
138static void print_buffer(const char *data, const int length)
139{
140 if (toto_debug <= 0) {
141 return;
142 }
143 int i;
144 int j;
145 unsigned char c;
146
147 for (i = 0; i < length; i += 16) {
148 printf("%04x: ", i);
149 for (j = 0; j < 16; j++) {
150 if (i + j >= length) {
151 printf(" ");
152 continue;
153 }
154 printf("%02hhx ", *(data + i + j));
155 }
156 printf(" | ");
157 for (j = 0; j < 16; j++) {
158 if (i + j >= length)
159 break;
160 c = *(data + i + j);
161 if ((c < 32) || (c > 127)) {
162 printf(".");
163 continue;
164 }
165 printf("%c", c);
166 }
167 printf("\n");
168 }
169 printf("\n");
170}
171#endif
172
173void hton_header(usbmux_tcp_header * hdr)
174{
175 if (hdr) {
176 hdr->length = htonl(hdr->length);
177 hdr->scnt = htonl(hdr->scnt);
178 hdr->ocnt = htonl(hdr->ocnt);
179 hdr->length16 = htons(hdr->length16);
180 }
181}
182
183void ntoh_header(usbmux_tcp_header * hdr)
184{
185 if (hdr) {
186 hdr->length = ntohl(hdr->length);
187 hdr->scnt = ntohl(hdr->scnt);
188 hdr->ocnt = ntohl(hdr->ocnt);
189 hdr->length16 = ntohs(hdr->length16);
190 }
191}
192
193/** Creates a USBMux header containing version information
194 *
195 * @return A USBMux header
196 */
197usbmux_version_header *version_header()
198{
199 usbmux_version_header *version =
200 (usbmux_version_header *) malloc(sizeof(usbmux_version_header));
201 version->type = 0;
202 version->length = htonl(20);
203 version->major = htonl(1);
204 version->minor = 0;
205 version->allnull = 0;
206 return version;
207}
208
209/**
210 * This function sets the configuration of the given device to 3
211 * and claims the interface 1. If usb_set_configuration fails, it detaches
212 * the kernel driver that blocks the device, and retries configuration.
213 *
214 * @param device which device to configure
215 */
216static int usbmux_config_usb_device(usbmux_device_t device)
217{
218 int ret;
219 int bytes;
220 char buf[512];
221
222#if 0
223 log_debug_msg("checking configuration...\n");
224 if (device->__device->config->bConfigurationValue != 3) {
225 log_debug_msg
226 ("WARNING: usb device configuration is not 3 as expected!\n");
227 }
228
229 log_debug_msg("setting configuration...\n");
230 ret = usb_set_configuration(device->device, 3);
231 if (ret != 0) {
232 log_debug_msg("Hm, usb_set_configuration returned %d: %s\n", ret,
233 strerror(-ret));
234#if LIBUSB_HAS_GET_DRIVER_NP
235 log_debug_msg("trying to fix:\n");
236 log_debug_msg("-> detaching kernel driver... ");
237 ret =
238 usb_detach_kernel_driver_np(device->device,
239 device->__device->config->
240 interface->altsetting->
241 bInterfaceNumber);
242 if (ret != 0) {
243 log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n",
244 ret, strerror(-ret));
245 } else {
246 log_debug_msg("done.\n");
247 log_debug_msg("setting configuration again... ");
248 ret = usb_set_configuration(device->device, 3);
249 if (ret != 0) {
250 log_debug_msg
251 ("Error: usb_set_configuration returned %d: %s\n", ret,
252 strerror(-ret));
253 log_debug_msg("--> trying to continue anyway...\n");
254 } else {
255 log_debug_msg("done.\n");
256 }
257 }
258#else
259 log_debug_msg("--> trying to continue anyway...\n");
260#endif
261 } else {
262 log_debug_msg("done.\n");
263 }
264#endif
265
266 log_debug_msg("claiming interface... ");
267 ret = usb_claim_interface(device->usbdev, 1);
268 if (ret != 0) {
269 log_debug_msg("Error: usb_claim_interface returned %d: %s\n", ret,
270 strerror(-ret));
271 return -ENODEV;
272 } else {
273 log_debug_msg("done.\n");
274 }
275
276 do {
277 bytes = usb_bulk_read(device->usbdev, BULKIN, buf, 512, 800);
278 } while (bytes > 0);
279
280 return 0;
281}
282
283/**
284 * Given a USB bus and device number, returns a device handle to the device on
285 * that bus. To aid compatibility with future devices, this function does not
286 * check the vendor and device IDs! To do that, you should use
287 * usbmux_get_device() or a system-specific API (e.g. HAL).
288 *
289 * @param bus_n The USB bus number.
290 * @param dev_n The USB device number.
291 * @param device A pointer to a usbmux_device_t, which must be set to NULL upon
292 * calling usbmux_get_specific_device, which will be filled with a device
293 * descriptor on return.
294 * @return 0 if ok, otherwise a negative errno value.
295 */
296int usbmux_get_specific_device(int bus_n, int dev_n,
297 usbmux_device_t * device)
298{
299 struct usb_bus *bus;
300 struct usb_device *dev;
301 usbmux_version_header *version;
302 int bytes = 0;
303
304 //check we can actually write in device
305 if (!device || (device && *device))
306 return -EINVAL;
307
308 usbmux_device_t newdevice =
309 (usbmux_device_t) malloc(sizeof(struct usbmux_device_int));
310
311 // Initialize the struct
312 newdevice->usbdev = NULL;
313 newdevice->__device = NULL;
314
315 // don't forget these:
316 newdevice->usbReceive.buffer = NULL;
317 newdevice->usbReceive.leftover = 0;
318 newdevice->usbReceive.capacity = 0;
319
320 // Initialize libusb
321 usb_init();
322 usb_find_busses();
323 usb_find_devices();
324
325 // Set the device configuration
326 for (bus = usb_get_busses(); bus; bus = bus->next)
327 //if (bus->location == bus_n)
328 for (dev = bus->devices; dev != NULL; dev = dev->next)
329 if (dev->devnum == dev_n) {
330 newdevice->__device = dev;
331 newdevice->usbdev = usb_open(newdevice->__device);
332 if (usbmux_config_usb_device(newdevice) == 0) {
333 goto found;
334 }
335 }
336
337 usbmux_free_device(newdevice);
338
339 log_debug_msg("usbmux_get_specific_device: device not found\n");
340 return -ENODEV;
341
342 found:
343 // Send the version command to the device
344 version = version_header();
345 bytes =
346 usb_bulk_write(newdevice->usbdev, BULKOUT, (char *) version,
347 sizeof(*version), 800);
348 if (bytes < 20) {
349 log_debug_msg("%s: libusb did NOT send enough!\n", __func__);
350 if (bytes < 0) {
351 log_debug_msg("%s: libusb gave me the error %d: %s (%s)\n",
352 __func__, bytes, usb_strerror(),
353 strerror(-bytes));
354 }
355 }
356 // Read the device's response
357 bytes =
358 usb_bulk_read(newdevice->usbdev, BULKIN, (char *) version,
359 sizeof(*version), 800);
360
361 // Check for bad response
362 if (bytes < 20) {
363 free(version);
364 usbmux_free_device(newdevice);
365 log_debug_msg("%s: Invalid version message -- header too short.\n",
366 __func__);
367 if (bytes < 0) {
368 log_debug_msg("%s: libusb error message %d: %s (%s)\n",
369 __func__, bytes, usb_strerror(),
370 strerror(-bytes));
371 return bytes;
372 }
373 return -EBADMSG;
374 }
375 // Check for correct version
376 if (ntohl(version->major) == 1 && ntohl(version->minor) == 0) {
377 // We're all ready to roll.
378 log_debug_msg("%s: success\n", __func__);
379 free(version);
380 *device = newdevice;
381 return 0;
382 } else {
383 // Bad header
384 usbmux_free_device(newdevice);
385 free(version);
386 log_debug_msg("%s: Received a bad header/invalid version number.",
387 __func__);
388 return -EBADMSG;
389 }
390
391 // If it got to this point it's gotta be bad
392 log_debug_msg("%s: Unknown error.\n", __func__);
393 usbmux_free_device(newdevice);
394 free(version);
395 return -EBADMSG; // if it got to this point it's gotta be bad
396}
397
398/** Cleans up an usbmux_device_t structure, then frees the structure itself.
399 * This is a library-level function; deals directly with the device to tear
400 * down relations, but otherwise is mostly internal.
401 *
402 * @param device A pointer to an usbmux_device_t structure.
403 */
404int usbmux_free_device(usbmux_device_t device)
405{
406 char buf[512];
407 int bytes;
408
409 if (!device)
410 return -EINVAL;
411 int ret = 0;
412
413 if (device->usbdev) {
414 do {
415 bytes = usb_bulk_read(device->usbdev, BULKIN, buf, 512, 800);
416 } while (bytes > 0);
417 }
418
419 if (bytes < 0) {
420 ret = bytes;
421 }
422
423 if (device->usbReceive.buffer) {
424 free(device->usbReceive.buffer);
425 }
426 if (device->usbdev) {
427 usb_release_interface(device->usbdev, 1);
428 usb_close(device->usbdev);
429 ret = 0;
430 }
431 free(device);
432
433 return ret;
434}
435
436
437
438/** Sends data to the device
439 * This is a low-level (i.e. directly to device) function.
440 *
441 * @param device The device to send data to
442 * @param data The data to send
443 * @param datalen The length of the data
444 * @return The number of bytes sent, or -ERRNO on error
445 */
446int send_to_device(usbmux_device_t device, char *data, int datalen)
447{
448 if (!device)
449 return -EINVAL;
450
451 int timeout = 1000;
452 int retrycount = 0;
453 int bytes = 0;
454
455#ifdef DEBUG
456#ifdef DEBUG_MORE
457 printf("===============================\n%s: trying to send\n",
458 __func__);
459 print_buffer(data, datalen);
460 printf("===============================\n");
461#endif
462#endif
463 do {
464 if (retrycount > 3) {
465 log_debug_msg
466 ("EPIC FAIL! aborting on retry count overload.\n");
467 return -ECOMM;
468 }
469
470 bytes =
471 usb_bulk_write(device->usbdev, BULKOUT, data, datalen,
472 timeout);
473 if (bytes == -ETIMEDOUT) {
474 // timed out waiting for write.
475 log_debug_msg("usb_bulk_write timeout error.\n");
476 return bytes;
477 } else if (bytes < 0) {
478 log_debug_msg
479 ("usb_bulk_write failed with error. err:%d (%s)(%s)\n",
480 bytes, usb_strerror(), strerror(-bytes));
481 return bytes;
482 } else if (bytes == 0) {
483 log_debug_msg("usb_bulk_write sent nothing. retrying.\n");
484 timeout = timeout * 4;
485 retrycount++;
486 continue;
487 } else if (bytes < datalen) {
488 log_debug_msg
489 ("usb_bulk_write failed to send full dataload. %d of %d\n",
490 bytes, datalen);
491 timeout = timeout * 4;
492 retrycount++;
493 data += bytes;
494 datalen -= bytes;
495 continue;
496 }
497 } while (0); // fall out
498
499#ifdef DEBUG
500 if (bytes > 0) {
501 if (toto_debug > 0) {
502 printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
503 printf("%s: sent to device\n", __func__);
504 print_buffer(data, bytes);
505 printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
506 }
507 }
508#endif
509 return bytes;
510}
511
512/** Receives data from the device
513 * This function is a low-level (i.e. direct from device) function.
514 *
515 * @param device The device to receive data from
516 * @param data Where to put data read
517 * @param datalen How much data to read in
518 * @param timeout How many milliseconds to wait for data
519 *
520 * @return How many bytes were read in, or -1 on error.
521 */
522int recv_from_device_timeout(usbmux_device_t device, char *data,
523 int datalen, int timeoutmillis)
524{
525 if (!device)
526 return -EINVAL;
527 //log_debug_msg("%s: attempting to receive %i bytes\n", __func__, datalen);
528
529 int bytes =
530 usb_bulk_read(device->usbdev, BULKIN, data, datalen,
531 timeoutmillis);
532 // There are some things which are errors, others which are no problem.
533 // It's not documented in libUSB, but it seems that the error values
534 // returned are just negated ERRNO values.
535 if (bytes < 0) {
536 if (bytes == -ETIMEDOUT) {
537 // ignore this. it just means timeout reached before we
538 // picked up any data. no problem.
539 return 0;
540 } else {
541 fprintf(stderr, "%s: libusb gave me the error %d: %s (%s)\n",
542 __func__, bytes, usb_strerror(), strerror(-bytes));
543 log_debug_msg("%s: libusb gave me the error %d: %s (%s)\n",
544 __func__, bytes, usb_strerror(),
545 strerror(-bytes));
546 }
547 return bytes;
548 }
549#ifdef DEBUG
550 if (bytes > 0) {
551 if (toto_debug > 0) {
552 printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
553 printf("%s: received from device:\n", __func__);
554 print_buffer(data, bytes);
555 printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
556 }
557 }
558#endif
559
560 return bytes;
561}
562
563/** Creates a USBMux packet for the given set of ports.
564 *
565 * @param s_port The source port for the connection.
566 * @param d_port The destination port for the connection.
567 *
568 * @return A USBMux packet
569 */
570usbmux_tcp_header *new_mux_packet(uint16_t s_port, uint16_t d_port)
571{
572 usbmux_tcp_header *conn =
573 (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header));
574 conn->type = htonl(6);
575 conn->length = HEADERLEN;
576 conn->sport = htons(s_port);
577 conn->dport = htons(d_port);
578 conn->scnt = 0;
579 conn->ocnt = 0;
580 conn->offset = 0x50;
581 conn->window = htons(0x0200);
582 conn->nullnull = 0x0000;
583 conn->length16 = HEADERLEN;
584 return conn;
585}
586
587
588/** Removes a connection from the list of connections made.
589 * The list of connections is necessary for buffering.
590 *
591 * @param connection The connection to delete from the tracking list.
592 */
593static void delete_connection(usbmux_client_t connection)
594{
595 usbmux_client_t *newlist = NULL;
596
597 pthread_mutex_lock(&usbmuxmutex);
598
599 // update the global list of connections
600 if (clients > 1) {
601 newlist =
602 (usbmux_client_t *) malloc(sizeof(usbmux_client_t) *
603 (clients - 1));
604 int i = 0, j = 0;
605 for (i = 0; i < clients; i++) {
606 if (connlist[i] == connection)
607 continue;
608 else {
609 newlist[j] = connlist[i];
610 j++;
611 }
612 }
613 }
614 if (connlist) {
615 free(connlist);
616 }
617 connlist = newlist;
618 clients--;
619
620 // free up this connection
621 pthread_mutex_lock(&connection->mutex);
622 if (connection->recv_buffer) {
623 free(connection->recv_buffer);
624 connection->recv_buffer = NULL;
625 }
626 if (connection->header) {
627 free(connection->header);
628 connection->header = NULL;
629 }
630 connection->r_len = 0;
631 pthread_mutex_unlock(&connection->mutex);
632 pthread_mutex_destroy(&connection->mutex);
633 free(connection);
634
635 pthread_mutex_unlock(&usbmuxmutex);
636}
637
638/** Adds a connection to the list of connections made.
639 * The connection list is necessary for buffering.
640 *
641 * @param connection The connection to add to the global list of connections.
642 */
643
644static void add_connection(usbmux_client_t connection)
645{
646 pthread_mutex_lock(&usbmuxmutex);
647 usbmux_client_t *newlist =
648 (usbmux_client_t *) realloc(connlist,
649 sizeof(usbmux_client_t) * (clients +
650 1));
651 newlist[clients] = connection;
652 connlist = newlist;
653 clients++;
654 pthread_mutex_unlock(&usbmuxmutex);
655}
656
657/**
658 * Get a source port number that is not used by one of our connections
659 * This is needed for us to make sure we are not sending on another
660 * connection.
661 */
662static uint16_t get_free_port()
663{
664 int i;
665 uint16_t newport = 30000;
666 int cnt = 0;
667
668 pthread_mutex_lock(&usbmuxmutex);
669 while (1) {
670 cnt = 0;
671 for (i = 0; i < clients; i++) {
672 if (ntohs(connlist[i]->header->sport) == newport) {
673 cnt++;
674 }
675 }
676 if (cnt == 0) {
677 // newport is not used in our list of connections!
678 break;
679 } else {
680 newport++;
681 if (newport < 30000) {
682 // if all ports from 30000 to 65535 are in use,
683 // the value wraps (16-bit overflow)
684 // return 0, no port is available.
685 // This should not happen, but just in case ;)
686 newport = 0;
687 break;
688 }
689 }
690 }
691 pthread_mutex_unlock(&usbmuxmutex);
692
693 return newport;
694}
695
696/** Initializes a connection to 'device' with source port s_port and destination port d_port
697 *
698 * @param device The device to initialize a connection on.
699 * @param src_port The source port
700 * @param dst_port The destination port -- 0xf27e for lockdownd.
701 * @param client A mux TCP header for the connection which is used for tracking and data transfer.
702 * @return 0 on success, a negative errno value otherwise.
703 */
704int usbmux_new_client(usbmux_device_t device, uint16_t src_port,
705 uint16_t dst_port, usbmux_client_t * client)
706{
707 if (!device || !dst_port)
708 return -EINVAL;
709
710 src_port = get_free_port();
711
712 if (!src_port) {
713 // this is a special case, if we get 0, this is not good, so
714 return -EISCONN; // TODO: error code suitable?
715 }
716 // Initialize connection stuff
717 usbmux_client_t new_connection =
718 (usbmux_client_t) malloc(sizeof(struct usbmux_client_int));
719 new_connection->header = new_mux_packet(src_port, dst_port);
720
721 // send TCP syn
722 if (new_connection && new_connection->header) {
723 int err = 0;
724 new_connection->header->tcp_flags = TCP_SYN;
725 new_connection->header->length = new_connection->header->length;
726 new_connection->header->length16 =
727 new_connection->header->length16;
728 new_connection->header->scnt = 0;
729 new_connection->header->ocnt = 0;
730 new_connection->device = device;
731 new_connection->recv_buffer = NULL;
732 new_connection->r_len = 0;
733 pthread_cond_init(&new_connection->wait, NULL);
734 pthread_mutex_init(&new_connection->mutex, NULL);
735 pthread_cond_init(&new_connection->wr_wait, NULL);
736 new_connection->wr_pending_scnt = 0;
737 new_connection->wr_window = 0;
738 add_connection(new_connection);
739 new_connection->error = 0;
740 new_connection->cleanup = 0;
741 hton_header(new_connection->header);
742 log_debug_msg("%s: send_to_device (%d --> %d)\n", __func__,
743 ntohs(new_connection->header->sport),
744 ntohs(new_connection->header->dport));
745 err =
746 send_to_device(device, (char *) new_connection->header,
747 sizeof(usbmux_tcp_header));
748 if (err >= 0) {
749 *client = new_connection;
750 return 0;
751 } else {
752 delete_connection(new_connection);
753 return err;
754 }
755 }
756 // if we get to this point it's probably bad
757 return -ENOMEM;
758}
759
760/** Cleans up the given USBMux connection.
761 * @note Once a connection is closed it may not be used again.
762 *
763 * @param connection The connection to close.
764 *
765 * @return 0 on success or a negative errno value on error.
766 */
767int usbmux_free_client(usbmux_client_t client)
768{
769 if (!client || !client->device)
770 return -EINVAL;
771
772 int err = 0;
773 int result = 0;
774 pthread_mutex_lock(&client->mutex);
775 client->header->tcp_flags = TCP_FIN;
776 client->header->length = 0x1C;
777 client->header->window = 0;
778 client->header->length16 = 0x1C;
779 hton_header(client->header);
780
781 err =
782 send_to_device(client->device, (char *) client->header,
783 sizeof(usbmux_tcp_header));
784 if (err < 0) {
785 log_debug_msg("%s: error sending TCP_FIN\n", __func__);
786 result = err;
787 }
788
789 client->cleanup = 1;
790
791 // make sure we don't have any last-minute laggards waiting on this.
792 // I put it after the mutex unlock because we have cases where the
793 // conditional wait is dependent on re-grabbing that mutex.
794 pthread_cond_broadcast(&client->wait);
795 pthread_cond_destroy(&client->wait);
796 pthread_cond_broadcast(&client->wr_wait);
797 pthread_cond_destroy(&client->wr_wait);
798
799 pthread_mutex_unlock(&client->mutex);
800
801 return result;
802}
803
804/** Sends the given data over the selected connection.
805 *
806 * @param client The client we're sending data on.
807 * @param data A pointer to the data to send.
808 * @param datalen How much data we're sending.
809 * @param sent_bytes The number of bytes sent, minus the header (28)
810 *
811 * @return 0 on success or a negative errno value on error.
812 */
813int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen,
814 uint32_t * sent_bytes)
815{
816 if (!client->device || !client || !sent_bytes)
817 return -EINVAL;
818
819 if (client->error < 0) {
820 return client->error;
821 }
822
823 *sent_bytes = 0;
824 pthread_mutex_lock(&client->mutex);
825
826 int sendresult = 0;
827 uint32_t blocksize = 0;
828 if (client->wr_window <= 0) {
829 struct timespec ts;
830 clock_gettime(CLOCK_REALTIME, &ts);
831 //ts.tv_sec += 1;
832 ts.tv_nsec += 750 * 1000;
833 if (pthread_cond_timedwait(&client->wait, &client->mutex, &ts) ==
834 ETIMEDOUT) {
835 // timed out. optimistically grow the window and try to make progress
836 client->wr_window += WINDOW_INCREMENT;
837 }
838 }
839
840 blocksize = sizeof(usbmux_tcp_header) + datalen;
841
842 // client->scnt and client->ocnt should already be in host notation...
843 // we don't need to change them juuuust yet.
844 char *buffer = (char *) malloc(blocksize + 2); // allow 2 bytes of safety padding
845 // Set the length
846 client->header->length = blocksize;
847 client->header->length16 = blocksize;
848
849 // Put header into big-endian notation
850 hton_header(client->header);
851 // Concatenation of stuff in the buffer.
852 memcpy(buffer, client->header, sizeof(usbmux_tcp_header));
853 memcpy(buffer + sizeof(usbmux_tcp_header), data, datalen);
854
855 log_debug_msg("%s: send_to_device(%d --> %d)\n", __func__,
856 ntohs(client->header->sport),
857 ntohs(client->header->dport));
858 sendresult = send_to_device(client->device, buffer, blocksize);
859 // Now that we've sent it off, we can clean up after our sloppy selves.
860 if (buffer)
861 free(buffer);
862
863 // revert header fields that have been swapped before trying to send
864 ntoh_header(client->header);
865
866 // update counts ONLY if the send succeeded.
867 if ((uint32_t) sendresult == blocksize) {
868 // Re-calculate scnt
869 client->header->scnt += datalen;
870 client->wr_window -= blocksize;
871 }
872
873 pthread_mutex_unlock(&client->mutex);
874
875 if (sendresult == -ETIMEDOUT || sendresult == 0) {
876 // no problem for now...
877 *sent_bytes = 0;
878 return -ETIMEDOUT;
879 } else if (sendresult < 0) {
880 return sendresult;
881 } else if ((uint32_t) sendresult == blocksize) {
882 // actual number of data bytes sent.
883 *sent_bytes = sendresult - HEADERLEN;
884 return 0;
885 } else {
886 fprintf(stderr,
887 "usbsend managed to dump a packet that is not full size. %d of %d\n",
888 sendresult, blocksize);
889 return -EBADMSG;
890 }
891}
892
893/** append the packet's DATA to the receive buffer for the client.
894 *
895 * this has a few other corner-case functions:
896 * 1. this will properly handle the handshake syn+ack.
897 * 2. for all receives, this will appropriately update the ocnt.
898 *
899 * @return number of bytes consumed (header + data)
900 */
901uint32_t append_receive_buffer(usbmux_client_t client, char *packet)
902{
903 if (client == NULL || packet == NULL)
904 return 0;
905
906 usbmux_tcp_header *header = (usbmux_tcp_header *) packet;
907 char *data = &packet[HEADERLEN];
908 uint32_t packetlen = ntohl(header->length);
909 uint32_t datalen = packetlen - HEADERLEN;
910
911 int dobroadcast = 0;
912
913 pthread_mutex_lock(&client->mutex);
914
915 // we need to handle a few corner case tasks and book-keeping which
916 // falls on our responsibility because we are the ones reading in
917 // feedback.
918 if (client->header->scnt == 0 && client->header->ocnt == 0) {
919 log_debug_msg("client is still waiting for handshake.\n");
920 if (header->tcp_flags == (TCP_SYN | TCP_ACK)) {
921 log_debug_msg("yes, got syn+ack ; replying with ack.\n");
922 client->header->tcp_flags = TCP_ACK;
923 client->header->length = sizeof(usbmux_tcp_header);
924 client->header->length16 = sizeof(usbmux_tcp_header);
925 client->header->scnt += 1;
926 client->header->ocnt = header->ocnt;
927 hton_header(client->header);
928 // push it to USB
929 // TODO: need to check for error in the send here.... :(
930 log_debug_msg("%s: send_to_device (%d --> %d)\n", __func__,
931 ntohs(client->header->sport),
932 ntohs(client->header->dport));
933 if (send_to_device
934 (client->device, (char *) client->header,
935 sizeof(usbmux_tcp_header)) <= 0) {
936 log_debug_msg("%s: error when pushing to usb...\n",
937 __func__);
938 }
939 // need to revert some of the fields back to host notation.
940 ntoh_header(client->header);
941 } else {
942 client->error = -ECONNABORTED;
943 // woah... this connection failed us.
944 // TODO: somehow signal that this stream is a no-go.
945 log_debug_msg("WOAH! client failed to get proper syn+ack.\n");
946 }
947 }
948 // update TCP counters and windows.
949 //
950 // save the window that we're getting from the USB device.
951 // apparently the window is bigger than just the 512 that's typically
952 // advertised. iTunes apparently shifts this value by 8 to get a much
953 // larger number.
954 if (header->tcp_flags & TCP_RST) {
955 client->error = -ECONNRESET;
956
957 if (datalen > 0) {
958 char e_msg[128];
959 e_msg[0] = 0;
960 if (datalen > 1) {
961 memcpy(e_msg, data + 1, datalen - 1);
962 e_msg[datalen - 1] = 0;
963 }
964 // fetch the message
965 switch (data[0]) {
966 case 0:
967 // this is not an error, it's just a status message.
968 log_debug_msg("received status message: %s\n", e_msg);
969 datalen = 0;
970 break;
971 case 1:
972 log_debug_msg("received error message: %s\n", e_msg);
973 datalen = 0;
974 break;
975 default:
976 log_debug_msg
977 ("received unknown message (type 0x%02x): %s\n",
978 data[0], e_msg);
979 //datalen = 0; // <-- we let this commented out for testing
980 break;
981 }
982 } else {
983 log_debug_msg
984 ("peer sent connection reset. setting error: %d\n",
985 client->error);
986 }
987 }
988 // the packet's ocnt tells us how much of our data the device has received.
989 if (header->tcp_flags & TCP_ACK) {
990 // this is a hacky magic number condition. it seems that once
991 // the window reported by the device starts to drop below this
992 // number, we quickly fall into connection reset problems.
993 // Once we see the reported window size start falling off,
994 // ut off and wait for solid acks to come back.
995 if (ntohs(header->window) < 256)
996 client->wr_window = 0;
997
998 // check what just got acked.
999 if (ntohl(header->ocnt) < client->header->scnt) {
1000 // we got some kind of ack, but it hasn't caught up
1001 // with the pending that have been sent.
1002 pthread_cond_broadcast(&client->wr_wait);
1003 } else if (ntohl(header->ocnt) >
1004 /*client->wr_pending_scnt */ client->header->scnt) {
1005 fprintf(stderr,
1006 "WTF?! acks overtook pending outstanding. %u,%u\n",
1007 ntohl(header->ocnt), client->wr_pending_scnt);
1008 } else {
1009 // reset the window
1010 client->wr_window = WINDOW_MAX;
1011 pthread_cond_broadcast(&client->wr_wait);
1012 }
1013 }
1014 // the packet's scnt will be our new ocnt.
1015 client->header->ocnt = ntohl(header->scnt);
1016
1017 // ensure there is enough space, either by first malloc or realloc
1018 if (datalen > 0) {
1019 log_debug_msg("%s: putting %d bytes into client's recv_buffer\n",
1020 __func__, datalen);
1021 if (client->r_len == 0)
1022 dobroadcast = 1;
1023
1024 if (client->recv_buffer == NULL) {
1025 client->recv_buffer = malloc(datalen);
1026 client->r_len = 0;
1027 } else {
1028 client->recv_buffer =
1029 realloc(client->recv_buffer, client->r_len + datalen);
1030 }
1031
1032 memcpy(&client->recv_buffer[client->r_len], data, datalen);
1033 client->r_len += datalen;
1034 }
1035
1036 pthread_mutex_unlock(&client->mutex);
1037
1038 // I put this outside the mutex unlock just so that when the threads
1039 // wake, we don't have to do another round of unlock+try to grab.
1040 if (dobroadcast)
1041 pthread_cond_broadcast(&client->wait);
1042
1043 return packetlen;
1044}
1045
1046/**
1047 * @note THERE IS NO MUTEX LOCK IN THIS FUNCTION!
1048 * because we're only called from one location, pullbulk, where the lock
1049 * is already held.
1050 */
1051usbmux_client_t find_client(usbmux_tcp_header * recv_header)
1052{
1053 // remember, as we're looking for the client, the receive header is
1054 // coming from the USB into our client. This means that when we check
1055 // the src/dst ports, we need to reverse them.
1056 usbmux_client_t retval = NULL;
1057
1058 // just for debugging check, I'm going to convert the numbers to host-endian.
1059 uint16_t hsport = ntohs(recv_header->sport);
1060 uint16_t hdport = ntohs(recv_header->dport);
1061
1062 pthread_mutex_lock(&usbmuxmutex);
1063 int i;
1064 for (i = 0; i < clients; i++) {
1065 uint16_t csport = ntohs(connlist[i]->header->sport);
1066 uint16_t cdport = ntohs(connlist[i]->header->dport);
1067
1068 if (hsport == cdport && hdport == csport) {
1069 retval = connlist[i];
1070 break;
1071 }
1072 }
1073 pthread_mutex_unlock(&usbmuxmutex);
1074
1075 return retval;
1076}
1077
1078/** pull in a big USB bulk packet and distribute it to queues appropriately.
1079 */
1080int usbmux_pullbulk(usbmux_device_t device)
1081{
1082 if (!device)
1083 return -EINVAL;
1084
1085 int res = 0;
1086 static const int DEFAULT_CAPACITY = 128 * 1024;
1087 if (device->usbReceive.buffer == NULL) {
1088 device->usbReceive.capacity = DEFAULT_CAPACITY;
1089 device->usbReceive.buffer = malloc(device->usbReceive.capacity);
1090 device->usbReceive.leftover = 0;
1091 }
1092 // start the cursor off just ahead of the leftover.
1093 char *cursor = &device->usbReceive.buffer[device->usbReceive.leftover];
1094 // pull in content, note that the amount we can pull is capacity minus leftover
1095 int readlen =
1096 recv_from_device_timeout(device, cursor,
1097 device->usbReceive.capacity -
1098 device->usbReceive.leftover, 3000);
1099 if (readlen < 0) {
1100 res = readlen;
1101 //fprintf(stderr, "recv_from_device_timeout gave us an error.\n");
1102 readlen = 0;
1103 }
1104 if (readlen > 0) {
1105 //fprintf(stdout, "recv_from_device_timeout pulled an extra %d bytes\n", readlen);
1106 }
1107 // the amount of content we have to work with is the remainder plus
1108 // what we managed to read
1109 device->usbReceive.leftover += readlen;
1110
1111 // reset the cursor to the front of that buffer and work through
1112 // trying to decode packets out of them.
1113 cursor = device->usbReceive.buffer;
1114 while (1) {
1115 // check if there's even sufficient data to decode a header
1116 if (device->usbReceive.leftover < HEADERLEN)
1117 break;
1118 usbmux_tcp_header *header = (usbmux_tcp_header *) cursor;
1119
1120 log_debug_msg("%s: recv_from_device_timeout (%d --> %d)\n",
1121 __func__, ntohs(header->sport),
1122 ntohs(header->dport));
1123
1124 // now that we have a header, check if there is sufficient data
1125 // to construct a full packet, including its data
1126 uint32_t packetlen = ntohl(header->length);
1127 if ((uint32_t) device->usbReceive.leftover < packetlen) {
1128 fprintf(stderr,
1129 "%s: not enough data to construct a full packet\n",
1130 __func__);
1131 break;
1132 }
1133 // ok... find the client this packet will get stuffed to.
1134 usbmux_client_t client = find_client(header);
1135 if (client == NULL) {
1136 log_debug_msg
1137 ("WARNING: client for packet cannot be found. dropping packet.\n");
1138 } else {
1139 // stuff the data
1140 log_debug_msg
1141 ("%s: found client, calling append_receive_buffer\n",
1142 __func__);
1143 append_receive_buffer(client, cursor);
1144
1145 // perhaps this is too general, == -ECONNRESET
1146 // might be a better check here
1147 if (client->error < 0) {
1148 pthread_mutex_lock(&client->mutex);
1149 if (client->cleanup) {
1150 pthread_mutex_unlock(&client->mutex);
1151 log_debug_msg("freeing up connection (%d->%d)\n",
1152 ntohs(client->header->sport),
1153 ntohs(client->header->dport));
1154 delete_connection(client);
1155 } else {
1156 pthread_mutex_unlock(&client->mutex);
1157 }
1158 }
1159 }
1160
1161 // move the cursor and account for the consumption
1162 cursor += packetlen;
1163 device->usbReceive.leftover -= packetlen;
1164 }
1165
1166 // now, we need to manage any leftovers.
1167 // I'm going to manage the leftovers by alloc'ing a new block and
1168 // copyingthe leftovers to it. This is just to prevent problems with
1169 // memory moves where there may be overlap. Besides, the leftovers
1170 // should be small enough that this copy is minimal in overhead.
1171 //
1172 // if there are no leftovers, we just leave the datastructure as is,
1173 // and re-use the block next time.
1174 if (device->usbReceive.leftover > 0
1175 && cursor != device->usbReceive.buffer) {
1176 log_debug_msg("%s: we got a leftover, so handle it\n", __func__);
1177 char *newbuff = malloc(DEFAULT_CAPACITY);
1178 memcpy(newbuff, cursor, device->usbReceive.leftover);
1179 free(device->usbReceive.buffer);
1180 device->usbReceive.buffer = newbuff;
1181 device->usbReceive.capacity = DEFAULT_CAPACITY;
1182 }
1183
1184 return res;
1185}
1186
1187/**
1188 * return the error code stored in usbmux_client_t structure,
1189 * e.g. non-zero when an usb read error occurs.
1190 *
1191 * @param client the usbmux client
1192 *
1193 * @return 0 or a negative errno value.
1194 */
1195int usbmux_get_error(usbmux_client_t client)
1196{
1197 if (!client) {
1198 return 0;
1199 }
1200 return client->error;
1201}
1202
1203/** This function reads from the client's recv_buffer.
1204 *
1205 * @param client The client to receive data from.
1206 * @param data Where to put the data we receive.
1207 * @param datalen How much data to read.
1208 * @param timeout How many milliseconds to wait for data
1209 *
1210 * @return 0 on success or a negative errno value on failure.
1211 */
1212int usbmux_recv_timeout(usbmux_client_t client, char *data,
1213 uint32_t datalen, uint32_t * recv_bytes,
1214 int timeout)
1215{
1216
1217 if (!client || !data || datalen == 0 || !recv_bytes)
1218 return -EINVAL;
1219
1220 if (client->error < 0)
1221 return client->error;
1222
1223 pthread_mutex_lock(&client->mutex);
1224
1225 if (timeout > 0 && (client->recv_buffer == NULL || client->r_len == 0)) {
1226 struct timespec ts;
1227 clock_gettime(CLOCK_REALTIME, &ts);
1228 ts.tv_sec += timeout / 1000;
1229 ts.tv_nsec += (timeout - ((int) (timeout / 1000)) * 1000) * 1000;
1230 pthread_cond_timedwait(&client->wait, &client->mutex, &ts);
1231 }
1232
1233 *recv_bytes = 0;
1234 if (client->recv_buffer != NULL && client->r_len > 0) {
1235 uint32_t foolen = datalen;
1236 if ((int) foolen > client->r_len)
1237 foolen = client->r_len;
1238 memcpy(data, client->recv_buffer, foolen);
1239 *recv_bytes = foolen;
1240
1241 // preserve any left-over unread amounts.
1242 int remainder = client->r_len - foolen;
1243 if (remainder > 0) {
1244 char *newbuf = malloc(remainder);
1245 memcpy(newbuf, client->recv_buffer + foolen, remainder);
1246 client->r_len = remainder;
1247 free(client->recv_buffer);
1248 client->recv_buffer = newbuf;
1249 } else {
1250 free(client->recv_buffer);
1251 client->recv_buffer = NULL;
1252 client->r_len = 0;
1253 }
1254 }
1255
1256 pthread_mutex_unlock(&client->mutex);
1257
1258 return 0;
1259}
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 @@
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
19#ifndef __USBMUX_H__
20#define __USBMUX_H__
21
22#include <stdint.h>
23#include <sys/types.h>
24//#include <sys/stat.h>
25
26
27void usbmux_set_debug(int e);
28
29struct usbmux_device_int;
30typedef struct usbmux_device_int *usbmux_device_t;
31
32struct usbmux_client_int;
33typedef struct usbmux_client_int *usbmux_client_t;
34
35int usbmux_get_device ( usbmux_device_t *device );
36int usbmux_get_specific_device(int bus_n, int dev_n, usbmux_device_t * device);
37int usbmux_free_device ( usbmux_device_t device );
38
39
40int usbmux_new_client ( usbmux_device_t device, uint16_t src_port, uint16_t dst_port, usbmux_client_t *client );
41int usbmux_free_client ( usbmux_client_t client );
42
43int usbmux_send(usbmux_client_t client, const char *data, uint32_t datalen, uint32_t * sent_bytes);
44
45int usbmux_recv_timeout(usbmux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout);
46
47int usbmux_pullbulk(usbmux_device_t device);
48
49int usbmux_get_error(usbmux_client_t client);
50
51#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 @@
1/* Protocol defintion for usbmuxd proxy protocol */
2
3#ifndef __USBMUXD_PROTO_H
4#define __USBMUXD_PROTO_H
5
6#include <stdint.h>
7
8#define USBMUXD_SOCKET_FILE "/var/run/usbmuxd"
9
10struct usbmuxd_header {
11 uint32_t length; // length of message, including header
12 uint32_t reserved; // always zero
13 uint32_t type; // message type
14 uint32_t tag; // responses to this query will echo back this tag
15} __attribute__((__packed__));
16
17struct usbmuxd_result {
18 struct usbmuxd_header header;
19 uint32_t result;
20} __attribute__((__packed__));
21
22struct usbmuxd_connect_request {
23 struct usbmuxd_header header;
24 uint32_t device_id;
25 uint16_t tcp_dport; // TCP port number
26 uint16_t reserved; // set to zero
27} __attribute__((__packed__));
28
29struct usbmuxd_device {
30 uint32_t device_id;
31 uint16_t product_id;
32 char serial_number[40];
33} __attribute__((__packed__));
34
35struct usbmuxd_device_info_record {
36 struct usbmuxd_header header;
37 struct usbmuxd_device device;
38 char padding[222];
39} __attribute__((__packed__));
40
41struct usbmuxd_scan_request {
42 struct usbmuxd_header header;
43} __attribute__((__packed__));
44
45enum {
46 USBMUXD_RESULT = 1,
47 USBMUXD_CONNECT = 2,
48 USBMUXD_SCAN = 3,
49 USBMUXD_DEVICE_INFO = 4,
50};
51
52#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 @@
1#ifndef __USBMUXD_H
2#define __USBMUXD_H
3
4/**
5 * Array entry returned by 'usbmuxd_scan()' scanning.
6 *
7 * If more than one device is available, 'product_id' and
8 * 'serial_number' and be analysed to help make a selection.
9 * The relevant 'handle' should be passed to 'usbmuxd_connect()', to
10 * start a proxy connection. The value 'handle' should be considered
11 * opaque and no presumption made about the meaning of its value.
12 */
13typedef struct {
14 int handle;
15 int product_id;
16 char serial_number[41];
17} usbmuxd_scan_result;
18
19/**
20 * Contacts usbmuxd and performs a scan for connected devices.
21 *
22 * @param available_devices pointer to array of usbmuxd_scan_result.
23 * Array of available devices. The required 'handle'
24 * should be passed to 'usbmuxd_connect()'. The returned array
25 * is zero-terminated for convenience; the final (unused)
26 * entry containing handle == 0. The returned array pointer
27 * should be freed by passing to 'free()' after use.
28 *
29 * @return number of available devices, zero on no devices, or negative on error
30 */
31int usbmuxd_scan(usbmuxd_scan_result **available_devices);
32
33/**
34 * Request proxy connect to
35 *
36 * @param handle returned by 'usbmuxd_scan()'
37 *
38 * @param tcp_port TCP port number on device, in range 0-65535.
39 * common values are 62078 for lockdown, and 22 for SSH.
40 *
41 * @return file descriptor socket of the connection, or -1 on error
42 */
43int usbmuxd_connect(const int handle, const unsigned short tcp_port);
44
45#endif /* __USBMUXD_H */