summaryrefslogtreecommitdiffstats
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c1351
1 files changed, 1351 insertions, 0 deletions
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}