summaryrefslogtreecommitdiffstats
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c1447
1 files changed, 0 insertions, 1447 deletions
diff --git a/src/main.c b/src/main.c
deleted file mode 100644
index 19649b1..0000000
--- a/src/main.c
+++ /dev/null
@@ -1,1447 +0,0 @@
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;
60static int drop_privileges = 0;
61static int opt_udev = 0;
62static int opt_exit = 0;
63static int exit_signal = 0;
64
65struct device_info {
66 uint32_t device_id;
67 usbmux_device_t phone;
68 int use_count;
69 pthread_t bulk_reader;
70 pthread_mutex_t mutex;
71 /* mutex for mutual exclusion of calling the usbmux_send function
72 * TODO: I don't know if we need really need this? */
73 pthread_mutex_t writer_mutex;
74};
75
76struct client_data {
77 volatile int dead;
78 int socket;
79 int tag;
80 pthread_t thread;
81 pthread_t handler;
82 pthread_t reader;
83 int reader_quit;
84 int reader_dead;
85 int handler_dead;
86 int connected;
87 usbmux_client_t muxclient;
88 struct device_info *dev;
89};
90
91static struct device_info **devices = NULL;
92static int device_count = 0;
93static pthread_mutex_t usbmux_mutex = PTHREAD_MUTEX_INITIALIZER;
94static pthread_mutex_t usb_mutex = PTHREAD_MUTEX_INITIALIZER;
95
96/**
97 * logs a message to syslog when running as daemon or to stdout/stderr when
98 * running in foreground.
99 * @param prio The logging priority.
100 * @param format The message to be printed.
101 */
102static void logmsg(int prio, const char *format, ...)
103{
104 va_list args;
105 va_start(args, format);
106
107 if (!foreground) {
108 // daemon. log using syslog.
109 vsyslog(prio, format, args);
110 } else {
111 // running in foreground. log to stdout/stderr.
112 char msgbuf[256];
113 FILE *lfp = stdout;
114 switch (prio) {
115 case LOG_EMERG:
116 case LOG_ALERT:
117 case LOG_CRIT:
118 case LOG_ERR:
119 case LOG_WARNING:
120 lfp = stderr;
121 break;
122 default:
123 lfp = stdout;
124 }
125 strcpy(msgbuf, "usbmuxd: ");
126 vsnprintf(msgbuf + 9, 244, format, args);
127 strcat(msgbuf, "\n");
128 fputs(msgbuf, lfp);
129 }
130
131 va_end(args);
132}
133
134#ifdef DEBUG
135/**
136 * for debugging purposes.
137 */
138static void print_buffer(FILE * fp, const char *data, const int length)
139{
140 int i;
141 int j;
142 unsigned char c;
143
144 for (i = 0; i < length; i += 16) {
145 if (verbose >= 4)
146 fprintf(fp, "%04x: ", i);
147 for (j = 0; j < 16; j++) {
148 if (i + j >= length) {
149 if (verbose >= 4)
150 fprintf(fp, " ");
151 continue;
152 }
153 if (verbose >= 4)
154 fprintf(fp, "%02hhx ", *(data + i + j));
155 }
156 if (verbose >= 4)
157 fprintf(fp, " | ");
158 for (j = 0; j < 16; j++) {
159 if (i + j >= length)
160 break;
161 c = *(data + i + j);
162 if ((c < 32) || (c > 127)) {
163 if (verbose >= 4)
164 fprintf(fp, ".");
165 continue;
166 }
167 if (verbose >= 4)
168 fprintf(fp, "%c", c);
169 }
170 if (verbose >= 4)
171 fprintf(fp, "\n");
172 }
173 if (verbose >= 4)
174 fprintf(fp, "\n");
175}
176#endif
177
178/**
179 * Read incoming usbmuxd packet. If the packet is larger than
180 * the size specified by len, the data will be truncated.
181 *
182 * @param fd the file descriptor to read from.
183 * @param data pointer to a buffer to store the read data to.
184 * @param len the length of the data to be read. The buffer
185 * pointed to by data should be at least len bytes in size.
186 *
187 * @return
188 */
189static int usbmuxd_get_request(int fd, void **data, size_t len)
190{
191 uint32_t pktlen;
192 int recv_len;
193
194 if (peek_buf(fd, &pktlen, sizeof(pktlen)) < (int) sizeof(pktlen)) {
195 return -errno;
196 }
197
198 if (len == 0) {
199 // allocate buffer space
200 *data = malloc(pktlen);
201 } else if (len < pktlen) {
202 // target buffer is to small to hold this packet! fix it!
203 if (verbose >= 2)
204 logmsg(LOG_WARNING,
205 "%s: WARNING -- packet (%d) is larger than target buffer (%d)! Truncating.",
206 __func__, pktlen, len);
207 pktlen = len;
208 }
209
210 recv_len = recv_buf(fd, *data, pktlen);
211 if ((recv_len > 0) && ((uint32_t) recv_len < pktlen)) {
212 if (verbose >= 2)
213 logmsg(LOG_WARNING,
214 "%s: Uh-oh, we got less than the packet's size, %d instead of %d...",
215 __func__, recv_len, pktlen);
216 }
217#ifdef DEBUG
218 if (*data && (recv_len > 0) && verbose >= 4) {
219 fprintf(stderr, "%s: received:\n", __func__);
220 print_buffer(stderr, *data, recv_len);
221 }
222#endif
223
224 return recv_len;
225}
226
227/**
228 * Send a usbmuxd result packet with given tag and result_code.
229 *
230 * @param fd the file descriptor to write to.
231 * @param tag the tag value that identifies where this message belongs to.
232 * @param result_code the error value (0 = Success, most likely errno values otherwise)
233 *
234 * @return the return value returned by send_buf (normally the number of bytes sent)
235 */
236static int usbmuxd_send_result(int fd, uint32_t tag, uint32_t result_code)
237{
238 struct usbmuxd_result res;
239 int ret;
240
241 res.header.length = sizeof(res);
242 res.header.reserved = 0;
243 res.header.type = USBMUXD_RESULT;
244 res.header.tag = tag;
245 res.result = result_code;
246
247 if (verbose >= 4)
248 logmsg(LOG_NOTICE, "%s: tag=%d result=%d", __func__,
249 res.header.tag, res.result);
250
251 ret = send_buf(fd, &res, sizeof(res));
252 fsync(fd); // let's get it sent
253 return ret;
254}
255
256/**
257 * this thread reads from the usb connection and writes the
258 * data to the connected client.
259 *
260 * @param arg pointer to a client_data structure.
261 *
262 * @return NULL in any case
263 */
264static void *usbmuxd_client_reader_thread(void *arg)
265{
266 struct client_data *cdata;
267
268 char rbuffer[512];
269 uint32_t rbuffersize = 512;
270 uint32_t rlen;
271 int err;
272 char *cursor;
273 ssize_t len;
274 int result;
275
276 if (!arg) {
277 if (verbose >= 2)
278 logmsg(LOG_ERR, "%s: invalid client_data supplied!", __func__);
279 cdata->reader_dead = 1;
280 return NULL;
281 }
282
283 cdata = (struct client_data *) arg;
284
285 cdata->reader_dead = 0;
286
287 if (verbose >= 3)
288 logmsg(LOG_NOTICE, "%s[%x]: started (device %d:%d, use_count=%d)", __func__, THREAD,
289 cdata->dev->device_id >> 16, cdata->dev->device_id & 0xFFFF, cdata->dev->use_count);
290
291 while (!quit_flag && !cdata->reader_quit) {
292 result = check_fd(cdata->socket, FD_WRITE, DEFAULT_TIMEOUT);
293 if (result <= 0) {
294 if (result < 0) {
295 if (verbose >= 2)
296 logmsg(LOG_ERR, "%s: select error: %s", __func__,
297 strerror(errno));
298 }
299 continue;
300 }
301
302 rlen = 0;
303 err =
304 usbmux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize,
305 &rlen, DEFAULT_TIMEOUT);
306 if (err != 0) {
307 if (verbose >= 2)
308 logmsg(LOG_ERR,
309 "%s[%x]: encountered USB read error: %d",
310 __func__, THREAD, err);
311 break;
312 }
313
314 cursor = rbuffer;
315 while (rlen > 0) {
316 len = send_buf(cdata->socket, cursor, rlen);
317 if (len <= 0) {
318 logmsg(LOG_ERR, "%s: Error: send returned %d", __func__,
319 len);
320 err = 1;
321 break;
322 }
323 // calculate remainder
324 rlen -= len;
325 // advance cursor
326 cursor += len;
327 }
328 if (err != 0) {
329 logmsg(LOG_ERR, "%s: Error when writing to client...",
330 __func__);
331 break;
332 }
333 fsync(cdata->socket);
334 }
335
336 if (verbose >= 3)
337 logmsg(LOG_NOTICE, "%s[%x]: terminated", __func__, THREAD);
338
339 cdata->reader_dead = 1;
340
341 return NULL;
342}
343
344/**
345 * This function handles the connecting procedure to a previously
346 * set up usbmux client.
347 * Sends a usbmuxd result packet denoting success or failure.
348 * A successful result is mandatory for later communication.
349 *
350 * @param cdata pointer to a previously initialized client_data structure
351 *
352 * @return
353 */
354static int usbmuxd_handleConnectResult(struct client_data *cdata)
355{
356 int result;
357 char buffer[512];
358 char err_type[64];
359 int err_code;
360 ssize_t maxlen = 512;
361 uint32_t rlen;
362 int err;
363
364 if (!cdata) {
365 if (verbose >= 2)
366 logmsg(LOG_ERR, "%s: Invalid client_data provided!", __func__);
367 return -EINVAL;
368 }
369
370 result = check_fd(cdata->socket, FD_WRITE, DEFAULT_TIMEOUT);
371 if (result <= 0) {
372 if (result < 0) {
373 if (verbose >= 2)
374 logmsg(LOG_ERR, "%s: select error: %s", __func__,
375 strerror(errno));
376 return result;
377 }
378 } else {
379 result = 0;
380 err =
381 usbmux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen,
382 100);
383 if (err < 0) {
384 if (verbose >= 2)
385 logmsg(LOG_ERR, "%s: encountered USB read error: %d",
386 __func__, err);
387 usbmuxd_send_result(cdata->socket, cdata->tag, -err);
388 return err;
389 } else {
390 if (rlen > 0) {
391 if ((buffer[0] == 1) && (rlen > 20)
392 && !memcmp(buffer + 1, "handleConnectResult:", 20)) {
393 // hm... we got an error message!
394 buffer[rlen] = 0;
395 if (verbose >= 1)
396 logmsg(LOG_ERR, "%s: %s\n", __func__, buffer + 22);
397
398 if (sscanf
399 (buffer + 22, "%s - %d\n", err_type, &err_code)
400 == 2) {
401 usbmuxd_send_result(cdata->socket, cdata->tag,
402 err_code);
403 return -err_code;
404 } else {
405 usbmuxd_send_result(cdata->socket, cdata->tag,
406 ENODATA);
407 return -ENODATA;
408 }
409 } else {
410 // send success result
411 usbmuxd_send_result(cdata->socket, cdata->tag, 0);
412 // and the server greeting message
413 send_buf(cdata->socket, buffer, rlen);
414 }
415 } else {
416 // no server greeting? this seems to be ok. send success.
417 usbmuxd_send_result(cdata->socket, cdata->tag, 0);
418 }
419 }
420 //fsync(cdata->socket);
421 }
422 return result;
423}
424
425/**
426 * This thread handles the communication between the connected iPhone/iPod
427 * and the client that created the connection.
428 */
429static void *usbmuxd_client_handler_thread(void *arg)
430{
431 struct client_data *cdata;
432 int result;
433 char *cursor;
434 char buffer[32740];
435 ssize_t len;
436 ssize_t maxlen = sizeof(buffer);
437 uint32_t wlen;
438 int err;
439
440 if (!arg) {
441 if (verbose >= 2)
442 logmsg(LOG_ERR, "%s: invalid client_data provided!", __func__);
443 return NULL;
444 }
445
446 cdata = (struct client_data *) arg;
447
448 if (verbose >= 3)
449 logmsg(LOG_NOTICE, "%s[%x]: started (device %d:%d, use_count=%d)", __func__, THREAD,
450 cdata->dev->device_id >> 16, cdata->dev->device_id & 0xFFFF, cdata->dev->use_count);
451
452 if (usbmuxd_handleConnectResult(cdata)) {
453 if (verbose >= 3)
454 logmsg(LOG_ERR, "handleConnectResult: Error");
455 goto leave;
456 } else {
457 if (verbose >= 3)
458 logmsg(LOG_NOTICE, "handleConnectResult: Success");
459 }
460
461 // starting mux reader thread
462 cdata->reader_quit = 0;
463 cdata->reader_dead = 0;
464 if (pthread_create
465 (&cdata->reader, NULL, usbmuxd_client_reader_thread, cdata) != 0) {
466 if (verbose >= 2)
467 logmsg(LOG_ERR, "%s: could not start client_reader thread",
468 __func__);
469 cdata->reader = 0;
470 }
471
472 while (!quit_flag && !cdata->reader_dead) {
473 result = check_fd(cdata->socket, FD_READ, DEFAULT_TIMEOUT);
474 if (result <= 0) {
475 if (result < 0) {
476 if (verbose >= 3)
477 logmsg(LOG_ERR, "%s[%x]: Error: checkfd: %s", __func__, THREAD, strerror(errno));
478 }
479 continue;
480 }
481 // check_fd told us there's data available, so read from client
482 // and push to USB device.
483 len = recv(cdata->socket, buffer, maxlen, 0);
484 if (len == 0) {
485 break;
486 }
487 if (len < 0) {
488 if (verbose >= 2)
489 logmsg(LOG_ERR, "%s[%x]: Error: recv: %s", __func__, THREAD, strerror(errno));
490 break;
491 }
492
493 cursor = buffer;
494
495 pthread_mutex_lock(&cdata->dev->writer_mutex);
496 do {
497 wlen = 0;
498 err = usbmux_send(cdata->muxclient, cursor, len, &wlen);
499 if (err == -ETIMEDOUT) {
500 // some kind of timeout... just be patient and retry.
501 } else if (err < 0) {
502 if (verbose >= 2)
503 logmsg(LOG_ERR, "%s[%x]: USB write error: %d", __func__, THREAD, err);
504 len = -1;
505 break;
506 }
507 // calculate remainder.
508 len -= wlen;
509 // advance cursor appropiately.
510 cursor += wlen;
511 }
512 while ((len > 0) && !quit_flag);
513 pthread_mutex_unlock(&cdata->dev->writer_mutex);
514 if (len < 0) {
515 break;
516 }
517 }
518
519 leave:
520 // cleanup
521 if (verbose >= 3)
522 logmsg(LOG_NOTICE, "%s[%x]: terminating", __func__, THREAD);
523 if (cdata->reader != 0) {
524 cdata->reader_quit = 1;
525 pthread_join(cdata->reader, NULL);
526 }
527
528 cdata->handler_dead = 1;
529
530 if (verbose >= 3)
531 logmsg(LOG_NOTICE, "%s[%x]: terminated", __func__, THREAD);
532 return NULL;
533}
534
535/**
536 * Thread performing usb_bulk_read from the connected device.
537 * One thread per device. Lives as long as the device is in use.
538 */
539static void *usbmuxd_bulk_reader_thread(void *arg)
540{
541 struct device_info *cur_dev;
542 int err;
543
544 if (!arg) {
545 if (verbose >= 2)
546 logmsg(LOG_ERR, "%s: Invalid client_data provided", __func__);
547 return NULL;
548 }
549
550 cur_dev = (struct device_info *) arg;
551
552 if (verbose >= 3)
553 logmsg(LOG_NOTICE, "%s: started", __func__);
554
555 while (!quit_flag && cur_dev) {
556
557 pthread_mutex_lock(&cur_dev->mutex);
558 if (cur_dev->use_count <= 0) {
559 pthread_mutex_unlock(&cur_dev->mutex);
560 break;
561 }
562 pthread_mutex_unlock(&cur_dev->mutex);
563
564 if ((err = usbmux_pullbulk(cur_dev->phone)) < 0) {
565 if (verbose >= 1)
566 logmsg(LOG_ERR, "%s: error %d when reading from device",
567 __func__, err);
568 break;
569 }
570 }
571
572 if (verbose >= 3)
573 logmsg(LOG_NOTICE, "%s: terminated", __func__);
574
575 return NULL;
576}
577
578/**
579 * This thread is started when a new connection is accepted.
580 * It performs the handshake, then waits for the connect packet and
581 * on success it starts the usbmuxd_client_handler thread.
582 */
583static void *usbmuxd_client_init_thread(void *arg)
584{
585 struct client_data *cdata;
586 struct usbmuxd_scan_request *s_req;
587 struct usbmuxd_device_info_record dev_info_rec;
588 struct usbmuxd_connect_request *c_req = NULL;
589
590 struct usb_bus *bus;
591 struct usb_device *dev;
592
593 int recv_len;
594 int found = 0;
595 int res;
596 int i;
597
598 usbmux_device_t phone = NULL;
599 struct device_info *cur_dev = NULL;
600
601 if (!arg) {
602 if (verbose >= 1)
603 logmsg(LOG_ERR, "%s[%x]: invalid client_data provided!",
604 __func__, THREAD);
605 return NULL;
606 }
607
608 cdata = (struct client_data *) arg;
609 cdata->dead = 0;
610
611 if (verbose >= 3)
612 logmsg(LOG_NOTICE, "%s[%x]: started (fd=%d)", __func__, THREAD,
613 cdata->socket);
614
615 if ((recv_len =
616 usbmuxd_get_request(cdata->socket, (void **) &s_req, 0)) <= 0) {
617 if (verbose >= 2)
618 logmsg(LOG_ERR, "%s[%x]: No scan packet received, error %s",
619 __func__, THREAD, strerror(errno));
620 goto leave;
621 }
622
623 if ((recv_len == sizeof(struct usbmuxd_scan_request))
624 && (s_req->header.length == sizeof(struct usbmuxd_scan_request))
625 && (s_req->header.reserved == 0)
626 && (s_req->header.type == USBMUXD_SCAN)) {
627 // send success response
628 if (verbose >= 3)
629 logmsg(LOG_NOTICE, "%s[%x]: Got scan packet!", __func__,
630 THREAD);
631 usbmuxd_send_result(cdata->socket, s_req->header.tag, 0);
632 } else if ((recv_len == sizeof(struct usbmuxd_connect_request))
633 && (s_req->header.type == USBMUXD_CONNECT)) {
634 c_req = (struct usbmuxd_connect_request *) s_req;
635 s_req = NULL;
636 goto connect;
637 } else {
638 // send error response and exit
639 if (verbose >= 2)
640 logmsg(LOG_ERR, "%s[%x]: Invalid scan packet received.",
641 __func__, THREAD);
642 // TODO is this required?!
643 usbmuxd_send_result(cdata->socket, s_req->header.tag, EINVAL);
644 goto leave;
645 }
646
647 pthread_mutex_lock(&usb_mutex);
648 // gather data about all iPhones/iPods attached
649
650 if (verbose >= 5)
651 logmsg(LOG_DEBUG, "%s[%x]: usb init", __func__, THREAD);
652 usb_init();
653 if (verbose >= 5)
654 logmsg(LOG_DEBUG, "%s[%x]: usb find busses", __func__, THREAD);
655 usb_find_busses();
656 if (verbose >= 5)
657 logmsg(LOG_DEBUG, "%s[%x]: usb find devices", __func__, THREAD);
658 usb_find_devices();
659
660 if (verbose >= 2)
661 logmsg(LOG_NOTICE, "%s[%x]: Looking for attached devices...",
662 __func__, THREAD);
663
664 for (bus = usb_get_busses(); bus; bus = bus->next) {
665 for (dev = bus->devices; dev; dev = dev->next) {
666 if (dev->descriptor.idVendor == 0x05ac
667 && dev->descriptor.idProduct >= 0x1290
668 && dev->descriptor.idProduct <= 0x1294) {
669 if (verbose >= 1)
670 logmsg(LOG_NOTICE,
671 "%s[%x]: Found device on bus %s, id %s",
672 __func__, THREAD, bus->dirname, dev->filename);
673 found++;
674
675 // construct packet
676 memset(&dev_info_rec, 0, sizeof(dev_info_rec));
677 dev_info_rec.header.length = sizeof(dev_info_rec);
678 dev_info_rec.header.type = USBMUXD_DEVICE_INFO;
679 uint32_t dev_id =
680 strtol(dev->filename, NULL, 10)
681 + (strtoul(bus->dirname, NULL, 10) << 16);
682 dev_info_rec.device.device_id = dev_id;
683 dev_info_rec.device.product_id = dev->descriptor.idProduct;
684 if (dev->descriptor.iSerialNumber) {
685 usb_dev_handle *udev;
686 //pthread_mutex_lock(&usbmux_mutex);
687 udev = usb_open(dev);
688 if (udev) {
689 usb_get_string_simple(udev,
690 dev->descriptor.iSerialNumber,
691 dev_info_rec.device.serial_number,
692 sizeof(dev_info_rec.device.serial_number) + 1);
693 usb_close(udev);
694 } else {
695 logmsg(LOG_ERR, "%s[%x]: Error: usb_open(): %s\n", __func__, THREAD, usb_strerror());
696 }
697 //pthread_mutex_unlock(&usbmux_mutex);
698 }
699#ifdef DEBUG
700 if (verbose >= 4)
701 print_buffer(stderr, (char *) &dev_info_rec,
702 sizeof(dev_info_rec));
703#endif
704
705 // send it
706 if (send_buf
707 (cdata->socket, &dev_info_rec,
708 sizeof(dev_info_rec)) <= 0) {
709 if (verbose >= 3)
710 logmsg(LOG_ERR,
711 "%s[%x]: Error: Could not send device info: %s",
712 __func__, THREAD, strerror(errno));
713 found--;
714 }
715 }
716 }
717 }
718 pthread_mutex_unlock(&usb_mutex);
719
720 if (found <= 0) {
721 if (verbose >= 1)
722 logmsg(LOG_NOTICE,
723 "%s[%x]: No attached iPhone/iPod devices found.",
724 __func__, THREAD);
725 usbmuxd_send_result(cdata->socket, s_req->header.tag, -ENODEV);
726 goto leave;
727 }
728
729 goto leave;
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:%d on port %d",
759 __func__, THREAD, c_req->device_id >> 16, c_req->device_id & 0xFFFF, ntohs(c_req->tcp_dport));
760
761 // find the device, and open usb connection
762 pthread_mutex_lock(&usbmux_mutex);
763 phone = NULL;
764 cur_dev = NULL;
765 // first check if we already have an open connection
766 if (devices) {
767 for (i = 0; i < device_count; i++) {
768 if (devices[i]) {
769 if (devices[i]->device_id == c_req->device_id) {
770 devices[i]->use_count++;
771 cur_dev = devices[i];
772 phone = cur_dev->phone;
773 break;
774 }
775 }
776 }
777 }
778 if (!phone) {
779 // if not found, make a new connection
780 if (verbose >= 2)
781 logmsg(LOG_NOTICE,
782 "%s[%x]: creating new usb connection, device %d:%d",
783 __func__, THREAD, c_req->device_id >> 16, c_req->device_id & 0xFFFF);
784
785 pthread_mutex_lock(&usb_mutex);
786 if (usbmux_get_specific_device(c_req->device_id >> 16, c_req->device_id & 0xFFFF, &phone) < 0) {
787 pthread_mutex_unlock(&usb_mutex);
788 pthread_mutex_unlock(&usbmux_mutex);
789 if (verbose >= 1)
790 logmsg(LOG_ERR, "%s[%x]: device %d:%d could not be opened",
791 __func__, THREAD, c_req->device_id >> 16, c_req->device_id & 0xFFFF);
792 usbmuxd_send_result(cdata->socket, c_req->header.tag, ENODEV);
793 goto leave;
794 }
795 pthread_mutex_unlock(&usb_mutex);
796
797 // create device object
798 if (verbose >= 3)
799 logmsg(LOG_DEBUG, "%s[%x]: add to device list", __func__,
800 THREAD);
801 cur_dev =
802 (struct device_info *) malloc(sizeof(struct device_info));
803 memset(cur_dev, 0, sizeof(struct device_info));
804 cur_dev->use_count = 1;
805 cur_dev->device_id = c_req->device_id;
806 cur_dev->phone = phone;
807 cur_dev->bulk_reader = 0;
808 pthread_mutex_init(&cur_dev->mutex, NULL);
809 pthread_mutex_init(&cur_dev->writer_mutex, NULL);
810
811 if (verbose >= 3)
812 logmsg(LOG_DEBUG, "%s[%x]: device_count = %d", __func__,
813 THREAD, device_count);
814
815 // add to list of devices
816 devices =
817 (struct device_info **) realloc(devices,
818 sizeof(struct device_info *) *
819 (device_count + 1));
820 if (devices) {
821 devices[device_count] = cur_dev;
822 device_count++;
823 }
824 } else {
825 if (verbose >= 2)
826 logmsg(LOG_NOTICE,
827 "%s[%x]: reusing usb connection, device %d:%d",
828 __func__, THREAD, c_req->device_id >> 16, c_req->device_id & 0xFFFF);
829 }
830 pthread_mutex_unlock(&usbmux_mutex);
831
832 // setup connection to iPhone/iPod
833 pthread_mutex_lock(&cur_dev->writer_mutex);
834 res =
835 usbmux_new_client(cur_dev->phone, 0, ntohs(c_req->tcp_dport),
836 &(cdata->muxclient));
837 pthread_mutex_unlock(&cur_dev->writer_mutex);
838
839 if (res != 0) {
840 usbmuxd_send_result(cdata->socket, c_req->header.tag, res);
841 if (verbose >= 1)
842 logmsg(LOG_ERR,
843 "%s[%x]: mux_new_client returned %d, aborting.",
844 __func__, THREAD, res);
845 goto leave;
846 }
847 // start bulk reader thread (once per device)
848 pthread_mutex_lock(&cur_dev->mutex);
849 if (cur_dev->bulk_reader == 0) {
850 pthread_create(&cur_dev->bulk_reader, NULL,
851 usbmuxd_bulk_reader_thread, cur_dev);
852 }
853 pthread_mutex_unlock(&cur_dev->mutex);
854
855 // wait for the initial handshake (SYN->SYN+ACK->ACK) to complete)
856 struct timespec ts;
857 ts.tv_sec = 0;
858 ts.tv_nsec = 100000000;
859
860 i = 0;
861 while (i < 10000) {
862 if (usbmux_is_connected(cdata->muxclient)) {
863 break;
864 }
865 nanosleep(&ts, NULL);
866 i+=100;
867 }
868 if (!usbmux_is_connected(cdata->muxclient)) {
869 usbmuxd_send_result(cdata->socket, c_req->header.tag, -ENOTCONN);
870 goto leave;
871 }
872
873 // start connection handler thread
874 cdata->handler_dead = 0;
875 cdata->tag = c_req->header.tag;
876 cdata->dev = cur_dev;
877 if (pthread_create
878 (&cdata->handler, NULL, usbmuxd_client_handler_thread, cdata) != 0)
879 {
880 if (verbose >= 1)
881 logmsg(LOG_ERR,
882 "%s[%x]: could not create usbmuxd_client_handler_thread!",
883 __func__, THREAD);
884 cdata->handler = 0;
885 goto leave;
886 }
887 // wait for handler thread to finish its work
888 if (cdata->handler != 0) {
889 pthread_join(cdata->handler, NULL);
890 }
891
892 if (verbose >= 2)
893 logmsg(LOG_NOTICE, "%s[%x]: closing connection", __func__, THREAD);
894
895 // time to clean up
896 if (cdata && cdata->muxclient) { // should be non-NULL
897 pthread_mutex_lock(&cdata->dev->writer_mutex);
898 usbmux_free_client(cdata->muxclient);
899 pthread_mutex_unlock(&cdata->dev->writer_mutex);
900 }
901
902 leave:
903 if (verbose >= 3)
904 logmsg(LOG_NOTICE, "%s[%x]: terminating", __func__, THREAD);
905
906 if (s_req) {
907 free(s_req);
908 }
909 if (c_req) {
910 free(c_req);
911 }
912 // this has to be freed only if it's not in use anymore as it closes
913 // the USB connection
914 pthread_mutex_lock(&usbmux_mutex);
915 if (cur_dev) {
916 pthread_mutex_lock(&cur_dev->mutex);
917 if (cur_dev->use_count > 1) {
918 if (verbose >= 2)
919 logmsg(LOG_NOTICE,
920 "%s[%x]: decreasing device use count (from %d to %d)",
921 __func__, THREAD, cur_dev->use_count,
922 cur_dev->use_count - 1);
923 cur_dev->use_count--;
924 pthread_mutex_unlock(&cur_dev->mutex);
925 } else {
926 if (verbose >= 2)
927 logmsg(LOG_NOTICE,
928 "%s[%x]: last client disconnected, cleaning up",
929 __func__, THREAD);
930 cur_dev->use_count = 0;
931 pthread_mutex_unlock(&cur_dev->mutex);
932 if (cur_dev->bulk_reader != 0) {
933 if (verbose >= 3)
934 logmsg(LOG_NOTICE, "%s[%x]: joining bulk_reader...",
935 __func__, THREAD);
936 pthread_join(cur_dev->bulk_reader, NULL);
937 }
938 pthread_mutex_lock(&usb_mutex);
939 usbmux_free_device(cur_dev->phone);
940 pthread_mutex_unlock(&usb_mutex);
941 pthread_mutex_destroy(&cur_dev->writer_mutex);
942 pthread_mutex_destroy(&cur_dev->mutex);
943 free(cur_dev);
944 cur_dev = NULL;
945 if (device_count > 1) {
946 struct device_info **newlist;
947 int j = 0;
948
949 newlist =
950 (struct device_info **)
951 malloc(sizeof(struct device_info *)
952 * device_count - 1);
953 for (i = 0; i < device_count; i++) {
954 if (devices[i] != NULL) {
955 newlist[j++] = devices[i];
956 }
957 }
958 free(devices);
959 devices = newlist;
960 device_count--;
961 } else {
962 free(devices);
963 devices = NULL;
964 device_count = 0;
965 }
966 }
967 }
968 pthread_mutex_unlock(&usbmux_mutex);
969
970 cdata->dead = 1;
971 close(cdata->socket);
972
973 if (verbose >= 3)
974 logmsg(LOG_NOTICE, "%s[%x]: terminated", __func__, THREAD);
975
976 return NULL;
977}
978
979/**
980 * make this program run detached from the current console
981 */
982static int daemonize()
983{
984 pid_t pid;
985 pid_t sid;
986
987 // already a daemon
988 if (getppid() == 1)
989 return 0;
990
991 pid = fork();
992 if (pid < 0) {
993 exit(EXIT_FAILURE);
994 }
995
996 if (pid > 0) {
997 // exit parent process
998 exit(EXIT_SUCCESS);
999 }
1000 // At this point we are executing as the child process
1001
1002 // Change the file mode mask
1003 umask(0);
1004
1005 // Create a new SID for the child process
1006 sid = setsid();
1007 if (sid < 0) {
1008 return -1;
1009 }
1010 // Change the current working directory.
1011 if ((chdir("/")) < 0) {
1012 return -2;
1013 }
1014 // Redirect standard files to /dev/null
1015 if (!freopen("/dev/null", "r", stdin)) {
1016 logmsg(LOG_ERR, "ERROR: redirection of stdin failed.\n");
1017 }
1018 if (!freopen("/dev/null", "w", stdout)) {
1019 logmsg(LOG_ERR, "ERROR: redirection of stdout failed.\n");
1020 }
1021 if (!freopen("/dev/null", "w", stderr)) {
1022 logmsg(LOG_ERR, "ERROR: redirection of stderr failed.\n");
1023 }
1024
1025 return 0;
1026}
1027
1028static void usage()
1029{
1030 printf("usage: usbmuxd [options]\n");
1031 printf("\t-h|--help print this message\n");
1032 printf("\t-v|--verbose be verbose (use twice or more to increase)\n");
1033 printf("\t-f|--foreground do not daemonize\n");
1034 printf("\t-e|--exit-on-no-devices exit if no device is attached\n");
1035 printf("\t-d|--drop-privileges drop privileges after startup\n");
1036 printf("\t-u|--udev udev operation mode\n");
1037 printf("\t-x|--exit tell a running instance to exit\n");
1038 printf("\t-X|--force-exit tell a running instance to exit, even if\n");
1039 printf("\t there are still devices connected\n");
1040 printf("\n");
1041}
1042
1043static void parse_opts(int argc, char **argv)
1044{
1045 static struct option longopts[] = {
1046 {"help", 0, NULL, 'h'},
1047 {"foreground", 0, NULL, 'f'},
1048 {"verbose", 0, NULL, 'v'},
1049 {"exit-on-no-devices", 0, NULL, 'e'},
1050 {"drop-privileges", 0, NULL, 'd'},
1051 {"udev", 0, NULL, 'u'},
1052 {"exit", 0, NULL, 'x'},
1053 {"force-exit", 0, NULL, 'X'},
1054 {NULL, 0, NULL, 0}
1055 };
1056 int c;
1057
1058 while (1) {
1059 c = getopt_long(argc, argv, "hfveduxX", longopts, (int *) 0);
1060 if (c == -1) {
1061 break;
1062 }
1063
1064 switch (c) {
1065 case 'h':
1066 usage();
1067 exit(0);
1068 case 'f':
1069 foreground = 1;
1070 break;
1071 case 'v':
1072 sock_stuff_set_verbose(++verbose);
1073 break;
1074 case 'e':
1075 exit_on_no_devices = 1;
1076 break;
1077 case 'd':
1078 drop_privileges = 1;
1079 break;
1080 case 'u':
1081 opt_udev = 1;
1082 break;
1083 case 'x':
1084 opt_exit = 1;
1085 exit_signal = SIGQUIT;
1086 break;
1087 case 'X':
1088 opt_exit = 1;
1089 exit_signal = SIGTERM;
1090 break;
1091 default:
1092 usage();
1093 exit(2);
1094 }
1095 }
1096 if (opt_udev)
1097 foreground = 0;
1098}
1099
1100/**
1101 * checks for attached devices
1102 *
1103 * @return number of devices found
1104 */
1105static int devices_attached()
1106{
1107 struct usb_bus *bus;
1108 struct usb_device *dev;
1109 int res = 0;
1110
1111 usb_init();
1112 usb_find_busses();
1113 usb_find_devices();
1114
1115 for (bus = usb_get_busses(); bus; bus = bus->next) {
1116 for (dev = bus->devices; dev; dev = dev->next) {
1117 if (dev->descriptor.idVendor == 0x05ac
1118 && dev->descriptor.idProduct >= 0x1290
1119 && dev->descriptor.idProduct <= 0x1294) {
1120 res++;
1121 }
1122 }
1123 }
1124
1125 return res;
1126}
1127
1128/**
1129 * signal handler function for cleaning up properly
1130 */
1131static void handle_signal(int sig)
1132{
1133 if (sig == SIGTERM) {
1134 quit_flag = 1;
1135 } else {
1136 if (sig == SIGINT) {
1137 if (verbose >= 1)
1138 fprintf(stderr, "CTRL+C pressed\n");
1139 }
1140
1141 if (verbose >= 1)
1142 fprintf(stderr, "Checking if we can terminate (no more devices attached)...\n");
1143
1144 if (devices_attached() > 0) {
1145 // we can't quit, there are still devices attached.
1146 if (verbose >= 1)
1147 fprintf(stderr, "Refusing to terminate, there are still devices attached. Kill me with signal 15 (TERM) to force quit.\n");
1148 } else {
1149 // it's safe to quit
1150 quit_flag = 1;
1151 }
1152 }
1153}
1154
1155/**
1156 * main function. Initializes all stuff and then loops waiting in accept.
1157 */
1158int main(int argc, char **argv)
1159{
1160 struct sockaddr_un c_addr;
1161 socklen_t len = sizeof(struct sockaddr_un);
1162 struct client_data *cdata = NULL;
1163 struct client_data **children = NULL;
1164 int children_capacity = DEFAULT_CHILDREN_CAPACITY;
1165 int i;
1166 int result = 0;
1167 int exit_val = 0;
1168 int cnt = 0;
1169 FILE *lfd = NULL;
1170 struct flock lock;
1171
1172 parse_opts(argc, argv);
1173
1174 argc -= optind;
1175 argv += optind;
1176
1177 if (!foreground) {
1178 openlog("usbmuxd", LOG_PID, 0);
1179 }
1180
1181 if (verbose >= 1)
1182 logmsg(LOG_NOTICE, "starting");
1183
1184 // signal(SIGHUP, reload_conf); // none yet
1185 signal(SIGINT, handle_signal);
1186 signal(SIGQUIT, handle_signal);
1187 signal(SIGTERM, handle_signal);
1188 signal(SIGPIPE, SIG_IGN);
1189
1190 // check for other running instance
1191 lfd = fopen(LOCKFILE, "r");
1192 if (lfd) {
1193 lock.l_type = 0;
1194 lock.l_whence = SEEK_SET;
1195 lock.l_start = 0;
1196 lock.l_len = 0;
1197 fcntl(fileno(lfd), F_GETLK, &lock);
1198 fclose(lfd);
1199 if (lock.l_type != F_UNLCK) {
1200 if (opt_exit) {
1201 if (lock.l_pid && !kill(lock.l_pid, 0)) {
1202 logmsg(LOG_NOTICE, "sending signal %d to instance with pid %d", exit_signal, lock.l_pid);
1203 if (kill(lock.l_pid, exit_signal) < 0) {
1204 logmsg(LOG_ERR, "Error: could not deliver signal %d to pid %d", exit_signal, lock.l_pid);
1205 }
1206 exit_val = 0;
1207 goto terminate;
1208 } else {
1209 logmsg(LOG_ERR, "Error: could not determine pid of the other running instance!");
1210 exit_val = -1;
1211 goto terminate;
1212 }
1213 } else {
1214 logmsg(LOG_NOTICE,
1215 "another instance is already running (pid %d). exiting.", lock.l_pid);
1216 if (!opt_udev) {
1217 exit_val = -1;
1218 }
1219 goto terminate;
1220 }
1221 }
1222 }
1223
1224 if (opt_exit) {
1225 logmsg(LOG_NOTICE, "no running instance found, none killed. exiting.");
1226 goto terminate;
1227 }
1228
1229 if (exit_on_no_devices) {
1230 if (devices_attached() <= 0) {
1231 logmsg(LOG_NOTICE, "no devices attached. exiting.");
1232 return 0;
1233 }
1234 }
1235
1236 fsock = create_unix_socket(USBMUXD_SOCKET_FILE);
1237 if (fsock < 0) {
1238 logmsg(LOG_ERR, "Could not create socket, exiting");
1239 if (!foreground) {
1240 closelog();
1241 }
1242 return -1;
1243 }
1244
1245 chmod(USBMUXD_SOCKET_FILE, 0666);
1246
1247 if (verbose >= 2)
1248 usb_set_debug(verbose);
1249
1250 if (verbose >= 4)
1251 usbmux_set_debug(1);
1252
1253 if (!foreground) {
1254 if (daemonize() < 0) {
1255 fprintf(stderr, "usbmuxd: FATAL: Could not daemonize!\n");
1256 syslog(LOG_ERR, "FATAL: Could not daemonize!");
1257 closelog();
1258 exit(EXIT_FAILURE);
1259 }
1260 }
1261 // now open the lockfile and place the lock
1262 lfd = fopen(LOCKFILE, "w");
1263 if (lfd) {
1264 lock.l_type = F_WRLCK;
1265 lock.l_whence = SEEK_SET;
1266 lock.l_start = 0;
1267 lock.l_len = 0;
1268 if (fcntl(fileno(lfd), F_SETLK, &lock) == -1) {
1269 logmsg(LOG_ERR, "ERROR: lockfile locking failed!");
1270 exit(EXIT_FAILURE);
1271 }
1272 }
1273 // drop elevated privileges
1274 if (drop_privileges && (getuid() == 0 || geteuid() == 0)) {
1275 struct passwd *pw = getpwnam("nobody");
1276 if (pw) {
1277 setuid(pw->pw_uid);
1278 } else {
1279 logmsg(LOG_ERR,
1280 "ERROR: Dropping privileges failed, check if user 'nobody' exists! Will now terminate.");
1281 exit(EXIT_FAILURE);
1282 }
1283
1284 // security check
1285 if (setuid(0) != -1) {
1286 logmsg(LOG_ERR, "ERROR: Failed to drop privileges properly!");
1287 exit(EXIT_FAILURE);
1288 }
1289 if (verbose >= 2)
1290 logmsg(LOG_NOTICE, "Successfully dropped privileges");
1291 }
1292 // Reserve space for 10 clients which should be enough. If not, the
1293 // buffer gets enlarged later.
1294 children =
1295 (struct client_data **) malloc(sizeof(struct client_data *) *
1296 children_capacity);
1297 if (!children) {
1298 logmsg(LOG_ERR,
1299 "Out of memory when allocating memory for child threads. Terminating.");
1300 if (!foreground) {
1301 closelog();
1302 }
1303 exit(EXIT_FAILURE);
1304 }
1305 memset(children, 0, sizeof(struct client_data *) * children_capacity);
1306
1307 if (verbose >= 2)
1308 logmsg(LOG_NOTICE, "waiting for connection");
1309 while (!quit_flag) {
1310 // Check the file descriptor before accepting a connection.
1311 // If no connection attempt is made, just repeat...
1312 result = check_fd(fsock, FD_READ, 1000);
1313 if (result <= 0) {
1314 if (result == 0) {
1315 // cleanup
1316 for (i = 0; i < children_capacity; i++) {
1317 if (children[i]) {
1318 if (children[i]->dead != 0) {
1319 pthread_join(children[i]->thread, NULL);
1320 if (verbose >= 3)
1321 logmsg(LOG_NOTICE,
1322 "reclaimed client thread (fd=%d)",
1323 children[i]->socket);
1324 free(children[i]);
1325 children[i] = NULL;
1326 cnt++;
1327 } else {
1328 cnt = 0;
1329 }
1330 } else {
1331 cnt++;
1332 }
1333 }
1334
1335 if ((children_capacity > DEFAULT_CHILDREN_CAPACITY)
1336 && ((children_capacity - cnt) <=
1337 DEFAULT_CHILDREN_CAPACITY)) {
1338 children_capacity = DEFAULT_CHILDREN_CAPACITY;
1339 children =
1340 realloc(children,
1341 sizeof(struct client_data *) *
1342 children_capacity);
1343 }
1344 continue;
1345 } else {
1346 if (verbose >= 3)
1347 logmsg(LOG_ERR, "usbmuxd: select error: %s",
1348 strerror(errno));
1349 continue;
1350 }
1351 }
1352
1353 cdata = (struct client_data *) malloc(sizeof(struct client_data));
1354 memset(cdata, 0, sizeof(struct client_data));
1355 if (!cdata) {
1356 quit_flag = 1;
1357 logmsg(LOG_ERR, "Error: Out of memory! Terminating.");
1358 break;
1359 }
1360
1361 cdata->socket = accept(fsock, (struct sockaddr *) &c_addr, &len);
1362 if (cdata->socket < 0) {
1363 free(cdata);
1364 if (errno == EINTR) {
1365 continue;
1366 } else {
1367 if (verbose >= 3)
1368 logmsg(LOG_ERR, "Error in accept: %s",
1369 strerror(errno));
1370 continue;
1371 }
1372 }
1373
1374 if (verbose >= 1)
1375 logmsg(LOG_NOTICE, "new client connected (fd=%d)",
1376 cdata->socket);
1377
1378 // create client thread:
1379 if (pthread_create
1380 (&cdata->thread, NULL, usbmuxd_client_init_thread, cdata) == 0)
1381 {
1382 for (i = 0; i < children_capacity; i++) {
1383 if (children[i] == NULL)
1384 break;
1385 }
1386 if (i == children_capacity) {
1387 // enlarge buffer
1388 children_capacity++;
1389 children =
1390 realloc(children,
1391 sizeof(struct client_data *) *
1392 children_capacity);
1393 if (!children) {
1394 logmsg(LOG_ERR,
1395 "Out of memory when enlarging child thread buffer");
1396 }
1397 }
1398 children[i] = cdata;
1399 } else {
1400 logmsg(LOG_ERR, "Failed to create client_init_thread.");
1401 close(cdata->socket);
1402 free(cdata);
1403 cdata = NULL;
1404 }
1405 }
1406
1407 if (verbose >= 3)
1408 logmsg(LOG_NOTICE, "terminating");
1409
1410 // preparing for shutdown: wait for child threads to terminate (if any)
1411 if (verbose >= 2)
1412 logmsg(LOG_NOTICE, "waiting for child threads to terminate...");
1413 for (i = 0; i < children_capacity; i++) {
1414 if (children[i] != NULL) {
1415 pthread_join(children[i]->thread, NULL);
1416 free(children[i]);
1417 children[i] = NULL;
1418 }
1419 }
1420
1421 // delete the children set.
1422 free(children);
1423 children = NULL;
1424
1425
1426 if (fsock >= 0) {
1427 close(fsock);
1428 }
1429
1430 unlink(USBMUXD_SOCKET_FILE);
1431
1432 // unlock lock file and close it.
1433 if (lfd) {
1434 lock.l_type = F_UNLCK;
1435 fcntl(fileno(lfd), F_SETLK, &lock);
1436 fclose(lfd);
1437 }
1438
1439terminate:
1440 if (verbose >= 1)
1441 logmsg(LOG_NOTICE, "terminated");
1442 if (!foreground) {
1443 closelog();
1444 }
1445
1446 return 0;
1447}