summaryrefslogtreecommitdiffstats
path: root/usbmuxd.c
diff options
context:
space:
mode:
Diffstat (limited to 'usbmuxd.c')
-rw-r--r--usbmuxd.c795
1 files changed, 795 insertions, 0 deletions
diff --git a/usbmuxd.c b/usbmuxd.c
new file mode 100644
index 0000000..37a7f9e
--- /dev/null
+++ b/usbmuxd.c
@@ -0,0 +1,795 @@
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 <sys/socket.h>
28#include <sys/un.h>
29#include <sys/stat.h>
30#include <arpa/inet.h>
31#include <unistd.h>
32#include <signal.h>
33#include <pthread.h>
34#include <stdint.h>
35#include <usb.h>
36
37#include "usbmuxd.h"
38#include "sock_stuff.h"
39
40#include "iphone.h"
41
42#define SOCKET_FILE "/var/run/usbmuxd"
43
44#define DEFAULT_TIMEOUT 4000
45#define DEFAULT_CHILDREN_CAPACITY 10
46
47static int quit_flag = 0;
48static int fsock = -1;
49
50struct client_data {
51 volatile int dead;
52 int socket;
53 int tag;
54 pthread_t thread;
55 pthread_t handler;
56 pthread_t reader;
57 int reader_quit;
58 int reader_dead;
59 int handler_dead;
60 iphone_umux_client_t muxclient;
61};
62
63struct device_use_info {
64 uint32_t device_id;
65 iphone_device_t phone;
66 int use_count;
67};
68
69static struct device_use_info **device_use_list = NULL;
70static int device_use_count = 0;
71static pthread_mutex_t usbmux_mutex = PTHREAD_MUTEX_INITIALIZER;
72
73static void print_buffer(const char *data, const int length)
74{
75 int i;
76 int j;
77 unsigned char c;
78
79 for(i=0; i<length; i+=16) {
80 printf("%04x: ", i);
81 for (j=0;j<16;j++) {
82 if (i+j >= length) {
83 printf(" ");
84 continue;
85 }
86 printf("%02hhx ", *(data+i+j));
87 }
88 printf(" | ");
89 for(j=0;j<16;j++) {
90 if (i+j >= length)
91 break;
92 c = *(data+i+j);
93 if ((c < 32) || (c > 127)) {
94 printf(".");
95 continue;
96 }
97 printf("%c", c);
98 }
99 printf("\n");
100 }
101 printf("\n");
102}
103
104static int usbmuxd_get_request(int fd, void *data, size_t len)
105{
106 uint32_t pktlen;
107 int recv_len;
108
109 if (peek_buf(fd, &pktlen, sizeof(pktlen)) < sizeof(pktlen)) {
110 return -errno;
111 }
112
113 if (len < pktlen) {
114 // target buffer is to small to hold this packet! fix it!
115 fprintf(stderr, "%s: WARNING -- packet (%d) is larger than target buffer (%d)! Truncating.\n", __func__, pktlen, len);
116 pktlen = len;
117 }
118
119 recv_len = recv_buf(fd, data, pktlen);
120 if (recv_len < pktlen) {
121 fprintf(stderr, "%s: Uh-oh, we got less than the packet's size, %d instead of %d...\n", __func__, recv_len, pktlen);
122 }
123
124 return recv_len;
125}
126
127static int usbmuxd_send_result(int fd, uint32_t tag, uint32_t result_code)
128{
129 struct usbmux_result res;
130
131 res.header.length = sizeof(res);
132 res.header.reserved = 0;
133 res.header.type = usbmux_result;
134 res.header.tag = tag;
135 res.result = result_code;
136
137 fprintf(stderr, "%s: tag=%d result=%d\n", __func__, res.header.tag, res.result);
138
139 return send_buf(fd, &res, sizeof(res));
140}
141
142/**
143 *
144 */
145static void *usbmuxd_client_reader_thread(void *arg)
146{
147 struct client_data *cdata;
148
149 char rbuffer[512];
150 uint32_t rbuffersize = 512;
151 uint32_t rlen;
152 iphone_error_t err;
153 char *cursor;
154 ssize_t len;
155 int result;
156
157 if (!arg) {
158 fprintf(stderr, "%s: invalid client_data supplied!\n", __func__);
159 cdata->reader_dead = 1;
160 return NULL;
161 }
162
163 cdata = (struct client_data*)arg;
164
165 cdata->reader_dead = 0;
166
167 fprintf(stdout, "%s: started\n", __func__);
168
169 while (!quit_flag && !cdata->reader_quit) {
170 result = check_fd(cdata->socket, fdwrite, DEFAULT_TIMEOUT);
171 if (result <= 0) {
172 if (result < 0) {
173 fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno));
174 }
175 continue;
176 }
177
178 rlen = 0;
179 err = iphone_mux_recv_timeout(cdata->muxclient, rbuffer, rbuffersize, &rlen, DEFAULT_TIMEOUT);
180 if (err != 0) {
181 fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err);
182 break;
183 }
184
185 cursor = rbuffer;
186 while (rlen > 0) {
187 //printf("%s: \n", __func__);
188 //print_buffer(cursor, rlen);
189 //if ((rlen > 4) && !cursor[3]) {
190 len = send_buf(cdata->socket, cursor, rlen);
191 /*} else if (cursor[0] == 1) {
192 fprintf(stderr, "%s: Error message received: %s\n", __func__, cursor+1);
193 // we got an error message and no data. don't send it.
194 // TODO parse the error code and put it in the right place!
195 len = rlen;
196 }*/
197 // calculate remainder
198 rlen -= len;
199 // advance cursor
200 cursor += len;
201 }
202 fsync(cdata->socket);
203 }
204
205 fprintf(stdout, "%s: terminated\n", __func__);
206
207 cdata->reader_dead = 1;
208
209 return NULL;
210}
211
212static int usbmuxd_handleConnectResult(struct client_data *cdata)
213{
214 int result;
215 char buffer[512];
216 char err_type[64];
217 int err_code;
218 ssize_t maxlen = 512;
219 uint32_t rlen;
220 iphone_error_t err;
221
222 // trigger connection attempt if ready to write to client
223 result = check_fd(cdata->socket, fdwrite, DEFAULT_TIMEOUT);
224 if (result <= 0) {
225 if (result < 0) {
226 fprintf(stderr, "%s: select error: %s\n", __func__, strerror(errno));
227 return result;
228 }
229 } else {
230 result = 0;
231 err = iphone_mux_recv_timeout(cdata->muxclient, buffer, maxlen, &rlen, DEFAULT_TIMEOUT);
232 if (err != 0) {
233 fprintf(stderr, "%s: encountered USB read error: %d\n", __func__, err);
234 usbmuxd_send_result(cdata->socket, cdata->tag, err);
235 } else {
236 if (rlen > 0) {
237 //print_buffer(buffer, rlen);
238 if ((buffer[0] == 1) && (rlen > 20) && !memcmp(buffer+1, "handleConnectResult:", 20)) {
239 // hm... we got an error message!
240 buffer[rlen] = 0;
241 fprintf(stderr, "%s: %s\n", __func__, buffer+22);
242
243 if (sscanf(buffer+22, "%s - %d\n", err_type, &err_code) == 2) {
244 usbmuxd_send_result(cdata->socket, cdata->tag, err_code);
245 } else {
246 usbmuxd_send_result(cdata->socket, cdata->tag, ENODATA);
247 }
248 return -2;
249 } else {
250 // send success result
251 usbmuxd_send_result(cdata->socket, cdata->tag, 0);
252 // and the server greeting message
253 send_buf(cdata->socket, buffer, rlen);
254 }
255 } else {
256 // no server greeting? this seems to be ok. send success.
257 usbmuxd_send_result(cdata->socket, cdata->tag, 0);
258 return 0;
259 }
260 }
261 //fsync(cdata->socket);
262 }
263 return 0;
264}
265
266/**
267 * This thread handles the communication between the connected iPhone/iPod
268 * and the client that created the connection.
269 */
270static void *usbmuxd_client_handler_thread(void *arg)
271{
272 struct client_data *cdata;
273 int result;
274 char *cursor;
275 char buffer[1024];
276 ssize_t len;
277 ssize_t maxlen = sizeof(buffer);
278 uint32_t wlen;
279 iphone_error_t err;
280
281 if (!arg) {
282 fprintf(stderr, "%s: invalid client_data provided!\n", __func__);
283 return NULL;
284 }
285
286 cdata = (struct client_data*)arg;
287
288 fprintf(stdout, "%s: started\n", __func__);
289
290 if (usbmuxd_handleConnectResult(cdata)) {
291 goto leave;
292 }
293
294 // starting mux reader thread
295 cdata->reader_quit = 0;
296 cdata->reader_dead = 0;
297 if (pthread_create(&cdata->reader, NULL, usbmuxd_client_reader_thread, cdata) != 0) {
298 fprintf(stderr, "%s: could not start client_reader thread\n", __func__);
299 cdata->reader = 0;
300 }
301
302 while (!quit_flag && !cdata->reader_dead) {
303 result = check_fd(cdata->socket, fdread, DEFAULT_TIMEOUT);
304 if (result <= 0) {
305 if (result < 0) {
306 fprintf(stderr, "%s: Error: checkfd: %s\n", __func__, strerror(errno));
307 }
308 continue;
309 }
310
311 // check_fd told us there's data available, so read from client
312 // and push to USB device.
313 len = recv(cdata->socket, buffer, maxlen, 0);
314 if (len == 0) {
315 break;
316 }
317 if (len < 0) {
318 fprintf(stderr, "%s: Error: recv: %s\n", __func__, strerror(errno));
319 break;
320 }
321
322 cursor = buffer;
323 do {
324 wlen = 0;
325 err = iphone_mux_send(cdata->muxclient, cursor, len, &wlen);
326 if (err == IPHONE_E_TIMEOUT) {
327 // some kind of timeout... just be patient and retry.
328 } else if (err != IPHONE_E_SUCCESS) {
329 fprintf(stderr, "%s: USB write error: %d\n", __func__, err);
330 len = -1;
331 break;
332 }
333
334 // calculate remainder.
335 len -= wlen;
336 // advance cursor appropiately.
337 cursor += wlen;
338 } while ((len > 0) && !quit_flag);
339 if (len < 0) {
340 break;
341 }
342 }
343
344leave:
345 // cleanup
346 fprintf(stdout, "%s: terminating\n", __func__);
347 if (cdata->reader != 0) {
348 cdata->reader_quit = 1;
349 pthread_join(cdata->reader, NULL);
350 }
351
352 cdata->handler_dead = 1;
353
354 fprintf(stdout, "%s: terminated\n", __func__);
355 return NULL;
356}
357
358/**
359 * This thread is started when a new connection is accepted.
360 * It performs the handshake, then waits for the connect packet and
361 * on success it starts the usbmuxd_client_handler thread.
362 */
363static void *usbmuxd_client_init_thread(void *arg)
364{
365 struct client_data *cdata;
366 struct usbmux_header hello;
367 struct usbmux_dev_info_request dev_info_req;
368 struct usbmux_connect_request c_req;
369
370 struct usb_bus *bus;
371 struct usb_device *dev;
372
373 int recv_len;
374 int found = 0;
375 int res;
376 int i;
377 int sent_result;
378 iphone_error_t err;
379
380 iphone_device_t phone;
381 struct device_use_info *cur_dev = NULL;
382
383 if (!arg) {
384 fprintf(stderr, "%s: invalid client_data provided!\n", __func__);
385 return NULL;
386 }
387
388 cdata = (struct client_data*)arg;
389 cdata->dead = 0;
390
391 fprintf(stdout, "%s: started (fd=%d)\n", __func__, cdata->socket);
392
393 if ((recv_len = usbmuxd_get_request(cdata->socket, &hello, sizeof(hello))) <= 0) {
394 fprintf(stderr, "%s: No Hello packet received, error %s\n", __func__, strerror(errno));
395 goto leave;
396 }
397
398 if ((recv_len == 16) && (hello.length == 16)
399 && (hello.reserved == 0) && (hello.type == usbmux_hello)) {
400 // send success response
401 usbmuxd_send_result(cdata->socket, hello.tag, 0);
402 } else {
403 // send error response and exit
404 fprintf(stderr, "%s: Invalid Hello packet received.\n", __func__);
405 // TODO is this required?!
406 usbmuxd_send_result(cdata->socket, hello.tag, EINVAL);
407 goto leave;
408 }
409
410 // gather data about all iPhones/iPods attached
411 usb_init();
412 usb_find_busses();
413 usb_find_devices();
414
415 for (bus = usb_get_busses(); bus; bus = bus->next) {
416 for (dev = bus->devices; dev; dev = dev->next) {
417 if (dev->descriptor.idVendor == 0x05ac
418 && dev->descriptor.idProduct >= 0x1290
419 && dev->descriptor.idProduct <= 0x1293)
420 {
421 fprintf(stdout, "%s: Found device on bus %d, id %d\n", __func__, bus->location, dev->devnum);
422 found++;
423
424 // construct packet
425 memset(&dev_info_req, 0, sizeof(dev_info_req));
426 dev_info_req.header.length = sizeof(dev_info_req);
427 dev_info_req.header.type = usbmux_device_info;
428 dev_info_req.dev_info.device_id = dev->devnum;
429 dev_info_req.dev_info.product_id = dev->descriptor.idProduct;
430 if (dev->descriptor.iSerialNumber) {
431 usb_dev_handle *udev;
432 //pthread_mutex_lock(&usbmux_mutex);
433 udev = usb_open(dev);
434 if (udev) {
435 usb_get_string_simple(udev, dev->descriptor.iSerialNumber, dev_info_req.dev_info.serial_number, sizeof(dev_info_req.dev_info.serial_number)+1);
436 usb_close(udev);
437 }
438 //pthread_mutex_unlock(&usbmux_mutex);
439 }
440
441 print_buffer((char*)&dev_info_req, sizeof(dev_info_req));
442
443 // send it
444 if (send_buf(cdata->socket, &dev_info_req, sizeof(dev_info_req)) <= 0) {
445 fprintf(stderr, "%s: Error: Could not send device info: %s\n", __func__, strerror(errno));
446 found--;
447 }
448 }
449 }
450 }
451
452 // now wait for connect request
453 if (found <= 0) {
454 fprintf(stderr, "%s: No attached iPhone/iPod devices found.\n", __func__);
455 goto leave;
456 }
457
458 memset(&c_req, 0, sizeof(c_req));
459 if ((recv_len = usbmuxd_get_request(cdata->socket, &c_req, sizeof(c_req))) <= 0) {
460 fprintf(stderr, "%s: Did not receive any connect request.\n", __func__);
461 goto leave;
462 }
463
464 if (c_req.header.type != usbmux_connect) {
465 fprintf(stderr, "%s: Unexpected packet of type %d received.\n", __func__, c_req.header.type);
466 goto leave;
467 }
468
469 fprintf(stdout, "%s: Setting up connection to usb device #%d on port %d\n", __func__, c_req.device_id, ntohs(c_req.port));
470
471 // find the device, and open usb connection
472 phone = NULL;
473 cur_dev = NULL;
474 // first check if we already have an open connection
475 if (device_use_list) {
476 pthread_mutex_lock(&usbmux_mutex);
477 for (i = 0; i < device_use_count; i++) {
478 if (device_use_list[i]) {
479 if (device_use_list[i]->device_id == c_req.device_id) {
480 device_use_list[i]->use_count++;
481 cur_dev = device_use_list[i];
482 phone = cur_dev->phone;
483 break;
484 }
485 }
486 }
487 pthread_mutex_unlock(&usbmux_mutex);
488 }
489 if (!phone) {
490 // if not found, make a new connection
491 if (iphone_get_specific_device(0, c_req.device_id, &phone) != IPHONE_E_SUCCESS) {
492 fprintf(stderr, "%s: device_id %d could not be opened\n", __func__, c_req.device_id);
493 usbmuxd_send_result(cdata->socket, c_req.header.tag, ENODEV);
494 goto leave;
495 }
496 // add to device list
497 cur_dev = (struct device_use_info*)malloc(sizeof(struct device_use_info));
498 memset(cur_dev, 0, sizeof(struct device_use_info));
499 cur_dev->use_count = 1;
500 cur_dev->device_id = c_req.device_id;
501 cur_dev->phone = phone;
502
503 pthread_mutex_lock(&usbmux_mutex);
504 device_use_list = (struct device_use_info**)realloc(device_use_list, sizeof(struct device_use_info*) * (device_use_count+1));
505 if (device_use_list) {
506 device_use_list[device_use_count] = cur_dev;
507 device_use_count++;
508 }
509 pthread_mutex_unlock(&usbmux_mutex);
510 } else {
511 fprintf(stdout, "%s: reusing usb connection device_id %d\n", __func__, c_req.device_id);
512 }
513
514 // setup connection to iPhone/iPod
515// pthread_mutex_lock(&usbmux_mutex);
516 res = iphone_mux_new_client(cur_dev->phone, 0, ntohs(c_req.port), &(cdata->muxclient));
517// pthread_mutex_unlock(&usbmux_mutex);
518
519 if (res != 0) {
520 usbmuxd_send_result(cdata->socket, c_req.header.tag, res);
521 fprintf(stderr, "%s: mux_new_client returned %d, aborting.\n", __func__, res);
522 goto leave;
523 }
524
525 // start connection handler thread
526 cdata->handler_dead = 0;
527 cdata->tag = c_req.header.tag;
528 if (pthread_create(&cdata->handler, NULL, usbmuxd_client_handler_thread, cdata) != 0) {
529 fprintf(stderr, "%s: could not create usbmuxd_client_handler_thread!\n", __func__);
530 cdata->handler = 0;
531 goto leave;
532 }
533
534 sent_result = 0;
535
536 // start reading data from the connected device
537 while (!quit_flag && !cdata->handler_dead) {
538 iphone_mux_pullbulk(cur_dev->phone);
539 err = iphone_mux_get_error(cdata->muxclient);
540 if (err != IPHONE_E_SUCCESS) {
541 break;
542 /*} else if (!sent_result) {
543 usbmuxd_send_result(cdata->socket, c_req.header.tag, 0);
544 sent_result = 1;*/
545 }
546 }
547
548 if (!sent_result) {
549 //fprintf(stderr, "Sending error message %d tag %d\n", err, c_req.header.tag);
550 err = iphone_mux_get_error(cdata->muxclient);
551 //usbmuxd_send_result(cdata->socket, c_req.header.tag, err);
552 }
553
554 fprintf(stdout, "%s: terminating\n", __func__);
555
556 // wait for handler thread to finish its work
557 if (cdata->handler != 0) {
558 pthread_join(cdata->handler, NULL);
559 }
560
561 // time to clean up
562 if (cdata && cdata->muxclient) { // should be non-NULL
563 iphone_mux_free_client(cdata->muxclient);
564 }
565
566leave:
567 // this has to be freed only if it's not in use anymore as it closes
568 // the USB connection
569 if (cur_dev) {
570 if (cur_dev->use_count > 1) {
571 cur_dev->use_count--;
572 } else {
573 iphone_free_device(cur_dev->phone);
574 cur_dev->use_count = 0;
575 free(cur_dev);
576 cur_dev = NULL;
577 pthread_mutex_lock(&usbmux_mutex);
578 if (device_use_count > 1) {
579 struct device_use_info **newlist;
580 int j;
581
582 newlist = (struct device_use_info**)malloc(sizeof(struct device_use_info*) * device_use_count-1);
583 for (i = 0; i < device_use_count; i++) {
584 if (device_use_list[i] != NULL) {
585 newlist[j++] = device_use_list[i];
586 }
587 }
588 free(device_use_list);
589 device_use_list = newlist;
590 } else {
591 free(device_use_list);
592 device_use_list = NULL;
593 }
594 pthread_mutex_unlock(&usbmux_mutex);
595 }
596 }
597
598 cdata->dead = 1;
599
600 fprintf(stdout, "%s: terminated\n", __func__);
601
602 return NULL;
603}
604
605/**
606 * make this program run detached from the current console
607 */
608static int daemonize()
609{
610 // TODO still to be implemented, also logging is missing!
611 return 0;
612}
613
614/**
615 * signal handler function for cleaning up stuff
616 */
617static void clean_exit(int sig)
618{
619 if (sig == SIGINT) {
620 fprintf(stdout, "CTRL+C pressed\n");
621 }
622 quit_flag = 1;
623}
624
625/**
626 * thread function that performs accept() and starts the required child
627 * threads to perform the rest of the communication stuff.
628 */
629static void *usbmuxd_accept_thread(void *arg)
630{
631 struct sockaddr_un c_addr;
632 socklen_t len = sizeof(struct sockaddr_un);
633 struct client_data *cdata;
634 struct client_data **children = NULL;
635 int children_capacity = DEFAULT_CHILDREN_CAPACITY;
636 int i = 0;
637 int result = 0;
638 int cnt;
639
640 // Reserve space for 10 clients which should be enough. If not, the
641 // buffer gets enlarged later.
642 children = (struct client_data**)malloc(sizeof(struct client_data*) * children_capacity);
643 if (!children) {
644 fprintf(stderr, "%s: Out of memory when allocating memory for child threads. Terminating.\n", __func__);
645 exit(EXIT_FAILURE);
646 }
647 memset(children, 0, sizeof(struct client_data*) * children_capacity);
648
649 fprintf(stdout, "%s: waiting for connection\n", __func__);
650 while (!quit_flag) {
651 // Check the file descriptor before accepting a connection.
652 // If no connection attempt is made, just repeat...
653 result = check_fd(fsock, fdread, DEFAULT_TIMEOUT);
654 if (result <= 0) {
655 if (result == 0) {
656 // cleanup
657 for (i = 0; i < children_capacity; i++) {
658 if (children[i]) {
659 if (children[i]->dead != 0) {
660 pthread_join(children[i]->thread, NULL);
661 fprintf(stdout, "%s: reclaimed client thread (fd=%d)\n", __func__, children[i]->socket);
662 free(children[i]);
663 children[i] = NULL;
664 cnt++;
665 } else {
666 cnt = 0;
667 }
668 } else {
669 cnt++;
670 }
671 }
672
673 if ((children_capacity > DEFAULT_CHILDREN_CAPACITY)
674 && ((children_capacity - cnt) <= DEFAULT_CHILDREN_CAPACITY)) {
675 children_capacity = DEFAULT_CHILDREN_CAPACITY;
676 children = realloc(children, sizeof(struct client_data*) * children_capacity);
677 }
678 continue;
679 } else {
680 fprintf(stderr, "select error: %s\n", strerror(errno));
681 continue;
682 }
683 }
684
685 cdata = (struct client_data*)malloc(sizeof(struct client_data));
686 memset(cdata, 0, sizeof(struct client_data));
687 if (!cdata) {
688 quit_flag = 1;
689 fprintf(stderr, "%s: Error: Out of memory! Terminating.\n", __func__);
690 break;
691 }
692
693 cdata->socket = accept(fsock, (struct sockaddr*)&c_addr, &len);
694 if (cdata->socket < 0) {
695 free(cdata);
696 if (errno == EINTR) {
697 continue;
698 } else {
699 fprintf(stderr, "%s: Error in accept: %s\n", __func__, strerror(errno));
700 continue;
701 }
702 }
703
704 fprintf(stdout, "%s: new client connected (fd=%d)\n", __func__, cdata->socket);
705
706 // create client thread:
707 if (pthread_create(&cdata->thread, NULL, usbmuxd_client_init_thread, cdata) == 0) {
708 for (i = 0; i < children_capacity; i++) {
709 if (children[i] == NULL) break;
710 }
711 if (i == children_capacity) {
712 // enlarge buffer
713 children_capacity++;
714 children = realloc(children, sizeof(struct client_data*) * children_capacity);
715 if (!children) {
716 fprintf(stderr, "%s: Out of memory when enlarging child thread buffer\n", __func__);
717 }
718 }
719 children[i] = cdata;
720 } else {
721 fprintf(stderr, "%s: Failed to create client_init_thread.\n", __func__);
722 close(cdata->socket);
723 free(cdata);
724 cdata = NULL;
725 }
726 }
727
728 fprintf(stdout, "%s: terminating\n", __func__);
729
730 // preparing for shutdown: wait for child threads to terminate (if any)
731 fprintf(stdout, "%s: waiting for child threads to terminate...\n", __func__);
732 for (i = 0; i < children_capacity; i++) {
733 if (children[i] != NULL) {
734 pthread_join(children[i]->thread, NULL);
735 free(children[i]);
736 }
737 }
738
739 // delete the children set.
740 free(children);
741 children = NULL;
742
743 fprintf(stdout, "%s: terminated.\n", __func__);
744
745 return NULL;
746}
747
748int main(int argc, char **argv)
749{
750 int foreground = 1;
751 pthread_t acceptor;
752
753 fprintf(stdout, "usbmuxd: starting\n");
754
755 // TODO: Parameter checking.
756
757 fsock = create_unix_socket(SOCKET_FILE);
758 if (fsock < 0) {
759 fprintf(stderr, "Could not create socket, exiting\n");
760 return -1;
761 }
762
763 chmod(SOCKET_FILE, 0666);
764
765 if (!foreground) {
766 if (daemonize() < 0) {
767 exit(EXIT_FAILURE);
768 }
769 }
770
771 // signal(SIGHUP, reload_conf); // none yet
772 signal(SIGINT, clean_exit);
773 signal(SIGQUIT, clean_exit);
774 signal(SIGTERM, clean_exit);
775 signal(SIGPIPE, SIG_IGN);
776
777 if (pthread_create(&acceptor, NULL, usbmuxd_accept_thread, NULL) != 0) {
778 fprintf(stderr, "Failed to create server thread.\n");
779 close(fsock);
780 return -1;
781 }
782
783 // Relax here. Just wait for the accept thread to terminate.
784 pthread_join(acceptor, NULL);
785
786 fprintf(stdout, "usbmuxd: terminating\n");
787 if (fsock >= 0) {
788 close(fsock);
789 }
790
791 unlink(SOCKET_FILE);
792
793 return 0;
794}
795