summaryrefslogtreecommitdiffstats
path: root/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'daemon')
-rw-r--r--daemon/CMakeLists.txt23
-rw-r--r--daemon/client.c616
-rw-r--r--daemon/client.h47
-rw-r--r--daemon/device.c781
-rw-r--r--daemon/device.h52
-rw-r--r--daemon/log.c95
-rw-r--r--daemon/log.h44
-rw-r--r--daemon/main.c618
-rw-r--r--daemon/usb-linux.c589
-rw-r--r--daemon/usb.h66
10 files changed, 0 insertions, 2931 deletions
diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt
deleted file mode 100644
index c323f7b..0000000
--- a/daemon/CMakeLists.txt
+++ /dev/null
@@ -1,23 +0,0 @@
1find_package(USB REQUIRED)
2include_directories(${USB_INCLUDE_DIRS})
3include_directories(${OPT_INCLUDES})
4set(LIBS ${LIBS} ${USB_LIBRARIES} ${OPT_LIBS})
5if(HAVE_PLIST)
6 add_definitions("-DHAVE_PLIST")
7 message("-- usbmuxd will be built with protocol version 1 support")
8endif()
9include_directories (${CMAKE_SOURCE_DIR}/common)
10include_directories (${CMAKE_SOURCE_DIR}/daemon)
11include_directories (${CMAKE_SOURCE_DIR}/libusbmuxd)
12
13add_definitions(-DUSBMUXD_DAEMON -DUSBMUXD_VERSION="${USBMUXD_VERSION}")
14add_executable(usbmuxd main.c usb-linux.c log.c ${CMAKE_SOURCE_DIR}/common/utils.c device.c client.c)
15target_link_libraries(usbmuxd ${LIBS})
16
17install(TARGETS usbmuxd RUNTIME DESTINATION sbin)
18
19message("
20* REMINDER
21* Remember to add a user named 'usbmux' with USB access permissions
22* for the udev hotplugging feature to work out of the box.
23")
diff --git a/daemon/client.c b/daemon/client.c
deleted file mode 100644
index ac1045a..0000000
--- a/daemon/client.c
+++ /dev/null
@@ -1,616 +0,0 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 2 or version 3.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20*/
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#include <stdlib.h>
27#include <string.h>
28#include <errno.h>
29#include <unistd.h>
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/un.h>
33#include <arpa/inet.h>
34
35#ifdef HAVE_PLIST
36#include <plist/plist.h>
37#endif
38
39#include "log.h"
40#include "usb.h"
41#include "client.h"
42#include "device.h"
43
44#ifdef HAVE_PLIST
45#define CMD_BUF_SIZE 1024
46#else
47#define CMD_BUF_SIZE 256
48#endif
49#define REPLY_BUF_SIZE 1024
50
51enum client_state {
52 CLIENT_COMMAND, // waiting for command
53 CLIENT_LISTEN, // listening for devices
54 CLIENT_CONNECTING1, // issued connection request
55 CLIENT_CONNECTING2, // connection established, but waiting for response message to get sent
56 CLIENT_CONNECTED, // connected
57 CLIENT_DEAD
58};
59
60struct mux_client {
61 int fd;
62 unsigned char *ob_buf;
63 uint32_t ob_size;
64 uint32_t ob_capacity;
65 unsigned char *ib_buf;
66 uint32_t ib_size;
67 uint32_t ib_capacity;
68 short events, devents;
69 uint32_t connect_tag;
70 int connect_device;
71 enum client_state state;
72 uint32_t proto_version;
73};
74
75static struct collection client_list;
76
77int client_read(struct mux_client *client, void *buffer, uint32_t len)
78{
79 usbmuxd_log(LL_SPEW, "client_read fd %d buf %p len %d", client->fd, buffer, len);
80 if(client->state != CLIENT_CONNECTED) {
81 usbmuxd_log(LL_ERROR, "Attempted to read from client %d not in CONNECTED state", client->fd);
82 return -1;
83 }
84 return recv(client->fd, buffer, len, 0);
85}
86
87int client_write(struct mux_client *client, void *buffer, uint32_t len)
88{
89 usbmuxd_log(LL_SPEW, "client_write fd %d buf %p len %d", client->fd, buffer, len);
90 if(client->state != CLIENT_CONNECTED) {
91 usbmuxd_log(LL_ERROR, "Attempted to write to client %d not in CONNECTED state", client->fd);
92 return -1;
93 }
94 return send(client->fd, buffer, len, 0);
95}
96
97int client_set_events(struct mux_client *client, short events)
98{
99 if((client->state != CLIENT_CONNECTED) && (client->state != CLIENT_CONNECTING2)) {
100 usbmuxd_log(LL_ERROR, "client_set_events to client %d not in CONNECTED state", client->fd);
101 return -1;
102 }
103 client->devents = events;
104 if(client->state == CLIENT_CONNECTED)
105 client->events = events;
106 return 0;
107}
108
109int client_accept(int listenfd)
110{
111 struct sockaddr_un addr;
112 int cfd;
113 socklen_t len = sizeof(struct sockaddr_un);
114 cfd = accept(listenfd, (struct sockaddr *)&addr, &len);
115 if (cfd < 0) {
116 usbmuxd_log(LL_ERROR, "accept() failed (%s)", strerror(errno));
117 return cfd;
118 }
119
120 struct mux_client *client;
121 client = malloc(sizeof(struct mux_client));
122 memset(client, 0, sizeof(struct mux_client));
123
124 client->fd = cfd;
125 client->ob_buf = malloc(REPLY_BUF_SIZE);
126 client->ob_size = 0;
127 client->ob_capacity = REPLY_BUF_SIZE;
128 client->ib_buf = malloc(CMD_BUF_SIZE);
129 client->ib_size = 0;
130 client->ib_capacity = CMD_BUF_SIZE;
131 client->state = CLIENT_COMMAND;
132 client->events = POLLIN;
133
134 collection_add(&client_list, client);
135
136 usbmuxd_log(LL_INFO, "New client on fd %d", client->fd);
137 return client->fd;
138}
139
140void client_close(struct mux_client *client)
141{
142 usbmuxd_log(LL_INFO, "Disconnecting client fd %d", client->fd);
143 if(client->state == CLIENT_CONNECTING1 || client->state == CLIENT_CONNECTING2) {
144 usbmuxd_log(LL_INFO, "Client died mid-connect, aborting device %d connection", client->connect_device);
145 client->state = CLIENT_DEAD;
146 device_abort_connect(client->connect_device, client);
147 }
148 close(client->fd);
149 if(client->ob_buf)
150 free(client->ob_buf);
151 if(client->ib_buf)
152 free(client->ib_buf);
153 collection_remove(&client_list, client);
154 free(client);
155}
156
157void client_get_fds(struct fdlist *list)
158{
159 FOREACH(struct mux_client *client, &client_list) {
160 fdlist_add(list, FD_CLIENT, client->fd, client->events);
161 } ENDFOREACH
162}
163
164static int send_pkt(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtype msg, void *payload, int payload_length)
165{
166 struct usbmuxd_header hdr;
167 hdr.version = client->proto_version;
168 hdr.length = sizeof(hdr) + payload_length;
169 hdr.message = msg;
170 hdr.tag = tag;
171 usbmuxd_log(LL_DEBUG, "send_pkt fd %d tag %d msg %d payload_length %d", client->fd, tag, msg, payload_length);
172 if((client->ob_capacity - client->ob_size) < hdr.length) {
173 usbmuxd_log(LL_ERROR, "Client %d output buffer full (%d bytes) while sending message %d (%d bytes)", client->fd, client->ob_capacity, hdr.message, hdr.length);
174 client_close(client);
175 return -1;
176 }
177 memcpy(client->ob_buf + client->ob_size, &hdr, sizeof(hdr));
178 if(payload && payload_length)
179 memcpy(client->ob_buf + client->ob_size + sizeof(hdr), payload, payload_length);
180 client->ob_size += hdr.length;
181 client->events |= POLLOUT;
182 return hdr.length;
183}
184
185static int send_result(struct mux_client *client, uint32_t tag, uint32_t result)
186{
187 int res = -1;
188#ifdef HAVE_PLIST
189 if (client->proto_version == 1) {
190 /* XML plist packet */
191 char *xml = NULL;
192 uint32_t xmlsize = 0;
193 plist_t dict = plist_new_dict();
194 plist_dict_insert_item(dict, "MessageType", plist_new_string("Result"));
195 plist_dict_insert_item(dict, "Number", plist_new_uint(result));
196 plist_to_xml(dict, &xml, &xmlsize);
197 plist_free(dict);
198 if (xml) {
199 res = send_pkt(client, tag, MESSAGE_PLIST, xml, xmlsize);
200 free(xml);
201 } else {
202 usbmuxd_log(LL_ERROR, "%s: Could not convert plist to xml", __func__);
203 }
204 } else
205#endif
206 {
207 /* binary packet */
208 res = send_pkt(client, tag, MESSAGE_RESULT, &result, sizeof(uint32_t));
209 }
210 return res;
211}
212
213int client_notify_connect(struct mux_client *client, enum usbmuxd_result result)
214{
215 usbmuxd_log(LL_SPEW, "client_notify_connect fd %d result %d", client->fd, result);
216 if(client->state == CLIENT_DEAD)
217 return -1;
218 if(client->state != CLIENT_CONNECTING1) {
219 usbmuxd_log(LL_ERROR, "client_notify_connect when client %d is not in CONNECTING1 state", client->fd);
220 return -1;
221 }
222 if(send_result(client, client->connect_tag, result) < 0)
223 return -1;
224 if(result == RESULT_OK) {
225 client->state = CLIENT_CONNECTING2;
226 client->events = POLLOUT; // wait for the result packet to go through
227 // no longer need this
228 free(client->ib_buf);
229 client->ib_buf = NULL;
230 } else {
231 client->state = CLIENT_COMMAND;
232 }
233 return 0;
234}
235
236static int notify_device_add(struct mux_client *client, struct device_info *dev)
237{
238 int res = -1;
239#ifdef HAVE_PLIST
240 if (client->proto_version == 1) {
241 /* XML plist packet */
242 char *xml = NULL;
243 uint32_t xmlsize = 0;
244 plist_t dict = plist_new_dict();
245 plist_dict_insert_item(dict, "MessageType", plist_new_string("Attached"));
246 plist_t props = plist_new_dict();
247 // TODO: get current usb speed
248 plist_dict_insert_item(props, "ConnectionSpeed", plist_new_uint(480000000));
249 plist_dict_insert_item(props, "ConnectionType", plist_new_string("USB"));
250 plist_dict_insert_item(props, "DeviceID", plist_new_uint(dev->id));
251 plist_dict_insert_item(props, "LocationID", plist_new_uint(dev->location));
252 plist_dict_insert_item(props, "ProductID", plist_new_uint(dev->pid));
253 plist_dict_insert_item(props, "SerialNumber", plist_new_string(dev->serial));
254 plist_dict_insert_item(dict, "Properties", props);
255 plist_to_xml(dict, &xml, &xmlsize);
256 plist_free(dict);
257 if (xml) {
258 res = send_pkt(client, 0, MESSAGE_PLIST, xml, xmlsize);
259 free(xml);
260 } else {
261 usbmuxd_log(LL_ERROR, "%s: Could not convert plist to xml", __func__);
262 }
263 } else
264#endif
265 {
266 /* binary packet */
267 struct usbmuxd_device_record dmsg;
268 memset(&dmsg, 0, sizeof(dmsg));
269 dmsg.device_id = dev->id;
270 strncpy(dmsg.serial_number, dev->serial, 256);
271 dmsg.serial_number[255] = 0;
272 dmsg.location = dev->location;
273 dmsg.product_id = dev->pid;
274 res = send_pkt(client, 0, MESSAGE_DEVICE_ADD, &dmsg, sizeof(dmsg));
275 }
276 return res;
277}
278
279static int notify_device_remove(struct mux_client *client, uint32_t device_id)
280{
281 int res = -1;
282#ifdef HAVE_PLIST
283 if (client->proto_version == 1) {
284 /* XML plist packet */
285 char *xml = NULL;
286 uint32_t xmlsize = 0;
287 plist_t dict = plist_new_dict();
288 plist_dict_insert_item(dict, "MessageType", plist_new_string("Detached"));
289 plist_dict_insert_item(dict, "DeviceID", plist_new_uint(device_id));
290 plist_to_xml(dict, &xml, &xmlsize);
291 plist_free(dict);
292 if (xml) {
293 res = send_pkt(client, 0, MESSAGE_PLIST, xml, xmlsize);
294 free(xml);
295 } else {
296 usbmuxd_log(LL_ERROR, "%s: Could not convert plist to xml", __func__);
297 }
298 } else
299#endif
300 {
301 /* binary packet */
302 res = send_pkt(client, 0, MESSAGE_DEVICE_REMOVE, &device_id, sizeof(uint32_t));
303 }
304 return res;
305}
306
307static int start_listen(struct mux_client *client)
308{
309 struct device_info *devs;
310 struct device_info *dev;
311 int count, i;
312
313 client->state = CLIENT_LISTEN;
314 count = device_get_count();
315 if(!count)
316 return 0;
317 devs = malloc(sizeof(struct device_info) * count);
318 count = device_get_list(devs);
319
320 // going to need a larger buffer for many devices
321 int needed_buffer = count * (sizeof(struct usbmuxd_device_record) + sizeof(struct usbmuxd_header)) + REPLY_BUF_SIZE;
322 if(client->ob_capacity < needed_buffer) {
323 usbmuxd_log(LL_DEBUG, "Enlarging client %d reply buffer %d -> %d to make space for device notifications", client->fd, client->ob_capacity, needed_buffer);
324 client->ob_buf = realloc(client->ob_buf, needed_buffer);
325 client->ob_capacity = needed_buffer;
326 }
327 dev = devs;
328 for(i=0; i<count; i++) {
329 if(notify_device_add(client, dev++) < 0) {
330 free(devs);
331 return -1;
332 }
333 }
334 free(devs);
335 return count;
336}
337
338static int client_command(struct mux_client *client, struct usbmuxd_header *hdr)
339{
340 int res;
341 usbmuxd_log(LL_DEBUG, "Client command in fd %d len %d ver %d msg %d tag %d", client->fd, hdr->length, hdr->version, hdr->message, hdr->tag);
342
343 if(client->state != CLIENT_COMMAND) {
344 usbmuxd_log(LL_ERROR, "Client %d command received in the wrong state", client->fd);
345 if(send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
346 return -1;
347 client_close(client);
348 return -1;
349 }
350
351 struct usbmuxd_connect_request *ch;
352#ifdef HAVE_PLIST
353 char *payload;
354 uint32_t payload_size;
355#endif
356
357 switch(hdr->message) {
358#ifdef HAVE_PLIST
359 case MESSAGE_PLIST:
360 client->proto_version = 1;
361 payload = (char*)(hdr) + sizeof(struct usbmuxd_header);
362 payload_size = hdr->length - sizeof(struct usbmuxd_header);
363 plist_t dict = NULL;
364 plist_from_xml(payload, payload_size, &dict);
365 if (!dict) {
366 usbmuxd_log(LL_ERROR, "Could not parse plist from payload!");
367 return -1;
368 } else {
369 char *message = NULL;
370 plist_t node = plist_dict_get_item(dict, "MessageType");
371 plist_get_string_val(node, &message);
372 if (!message) {
373 usbmuxd_log(LL_ERROR, "Could not extract MessageType from plist!");
374 plist_free(dict);
375 return -1;
376 }
377 if (!strcmp(message, "Listen")) {
378 free(message);
379 plist_free(dict);
380 if (send_result(client, hdr->tag, 0) < 0)
381 return -1;
382 usbmuxd_log(LL_DEBUG, "Client %d now LISTENING", client->fd);
383 return start_listen(client);
384 } else if (!strcmp(message, "Connect")) {
385 uint64_t val;
386 uint16_t portnum = 0;
387 uint32_t device_id = 0;
388 free(message);
389 // get device id
390 node = plist_dict_get_item(dict, "DeviceID");
391 if (!node) {
392 usbmuxd_log(LL_ERROR, "Received connect request without device_id!");
393 plist_free(dict);
394 if (send_result(client, hdr->tag, RESULT_BADDEV) < 0)
395 return -1;
396 return 0;
397 }
398 val = 0;
399 plist_get_uint_val(node, &val);
400 device_id = (uint32_t)val;
401
402 // get port number
403 node = plist_dict_get_item(dict, "PortNumber");
404 if (!node) {
405 usbmuxd_log(LL_ERROR, "Received connect request without port number!");
406 plist_free(dict);
407 if (send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
408 return -1;
409 return 0;
410 }
411 val = 0;
412 plist_get_uint_val(node, &val);
413 portnum = (uint16_t)val;
414
415 usbmuxd_log(LL_DEBUG, "Client %d connection request to device %d port %d", client->fd, device_id, ntohs(portnum));
416 res = device_start_connect(device_id, ntohs(portnum), client);
417 if(res < 0) {
418 if (send_result(client, hdr->tag, -res) < 0)
419 return -1;
420 } else {
421 client->connect_tag = hdr->tag;
422 client->connect_device = device_id;
423 client->state = CLIENT_CONNECTING1;
424 }
425 return 0;
426 } else {
427 usbmuxd_log(LL_ERROR, "Unexpected command '%s' received!", message);
428 free(message);
429 plist_free(dict);
430 if (send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
431 return -1;
432 return 0;
433 }
434 }
435 // should not be reached?!
436 return -1;
437#endif
438 case MESSAGE_LISTEN:
439 if(send_result(client, hdr->tag, 0) < 0)
440 return -1;
441 usbmuxd_log(LL_DEBUG, "Client %d now LISTENING", client->fd);
442 return start_listen(client);
443 case MESSAGE_CONNECT:
444 ch = (void*)hdr;
445 usbmuxd_log(LL_DEBUG, "Client %d connection request to device %d port %d", client->fd, ch->device_id, ntohs(ch->port));
446 res = device_start_connect(ch->device_id, ntohs(ch->port), client);
447 if(res < 0) {
448 if(send_result(client, hdr->tag, -res) < 0)
449 return -1;
450 } else {
451 client->connect_tag = hdr->tag;
452 client->connect_device = ch->device_id;
453 client->state = CLIENT_CONNECTING1;
454 }
455 return 0;
456 default:
457 usbmuxd_log(LL_ERROR, "Client %d invalid command %d", client->fd, hdr->message);
458 if(send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
459 return -1;
460 return 0;
461 }
462 return -1;
463}
464
465static void process_send(struct mux_client *client)
466{
467 int res;
468 if(!client->ob_size) {
469 usbmuxd_log(LL_WARNING, "Client %d OUT process but nothing to send?", client->fd);
470 client->events &= ~POLLOUT;
471 return;
472 }
473 res = send(client->fd, client->ob_buf, client->ob_size, 0);
474 if(res <= 0) {
475 usbmuxd_log(LL_ERROR, "Send to client fd %d failed: %d %s", client->fd, res, strerror(errno));
476 client_close(client);
477 return;
478 }
479 if(res == client->ob_size) {
480 client->ob_size = 0;
481 client->events &= ~POLLOUT;
482 if(client->state == CLIENT_CONNECTING2) {
483 usbmuxd_log(LL_DEBUG, "Client %d switching to CONNECTED state", client->fd);
484 client->state = CLIENT_CONNECTED;
485 client->events = client->devents;
486 // no longer need this
487 free(client->ob_buf);
488 client->ob_buf = NULL;
489 }
490 } else {
491 client->ob_size -= res;
492 memmove(client->ob_buf, client->ob_buf + res, client->ob_size);
493 }
494}
495static void process_recv(struct mux_client *client)
496{
497 int res;
498 int did_read = 0;
499 if(client->ib_size < sizeof(struct usbmuxd_header)) {
500 res = recv(client->fd, client->ib_buf + client->ib_size, sizeof(struct usbmuxd_header) - client->ib_size, 0);
501 if(res <= 0) {
502 if(res < 0)
503 usbmuxd_log(LL_ERROR, "Receive from client fd %d failed: %s", client->fd, strerror(errno));
504 else
505 usbmuxd_log(LL_INFO, "Client %d connection closed", client->fd);
506 client_close(client);
507 return;
508 }
509 client->ib_size += res;
510 if(client->ib_size < sizeof(struct usbmuxd_header))
511 return;
512 did_read = 1;
513 }
514 struct usbmuxd_header *hdr = (void*)client->ib_buf;
515#ifdef HAVE_PLIST
516 if((hdr->version != 0) && (hdr->version != 1)) {
517 usbmuxd_log(LL_INFO, "Client %d version mismatch: expected 0 or 1, got %d", client->fd, hdr->version);
518#else
519 if(hdr->version != USBMUXD_PROTOCOL_VERSION) {
520 usbmuxd_log(LL_INFO, "Client %d version mismatch: expected %d, got %d", client->fd, USBMUXD_PROTOCOL_VERSION, hdr->version);
521#endif
522 client_close(client);
523 return;
524 }
525 if(hdr->length > client->ib_capacity) {
526 usbmuxd_log(LL_INFO, "Client %d message is too long (%d bytes)", client->fd, hdr->length);
527 client_close(client);
528 return;
529 }
530 if(hdr->length < sizeof(struct usbmuxd_header)) {
531 usbmuxd_log(LL_ERROR, "Client %d message is too short (%d bytes)", client->fd, hdr->length);
532 client_close(client);
533 return;
534 }
535 if(client->ib_size < hdr->length) {
536 if(did_read)
537 return; //maybe we would block, so defer to next loop
538 res = recv(client->fd, client->ib_buf + client->ib_size, hdr->length - client->ib_size, 0);
539 if(res < 0) {
540 usbmuxd_log(LL_ERROR, "Receive from client fd %d failed: %s", client->fd, strerror(errno));
541 client_close(client);
542 return;
543 } else if(res == 0) {
544 usbmuxd_log(LL_INFO, "Client %d connection closed", client->fd);
545 client_close(client);
546 return;
547 }
548 client->ib_size += res;
549 if(client->ib_size < hdr->length)
550 return;
551 }
552 client_command(client, hdr);
553 client->ib_size = 0;
554}
555
556void client_process(int fd, short events)
557{
558 struct mux_client *client = NULL;
559 FOREACH(struct mux_client *lc, &client_list) {
560 if(lc->fd == fd) {
561 client = lc;
562 break;
563 }
564 } ENDFOREACH
565
566 if(!client) {
567 usbmuxd_log(LL_INFO, "client_process: fd %d not found in client list", fd);
568 return;
569 }
570
571 if(client->state == CLIENT_CONNECTED) {
572 usbmuxd_log(LL_SPEW, "client_process in CONNECTED state");
573 device_client_process(client->connect_device, client, events);
574 } else {
575 if(events & POLLIN) {
576 process_recv(client);
577 } else if(events & POLLOUT) { //not both in case client died as part of process_recv
578 process_send(client);
579 }
580 }
581
582}
583
584void client_device_add(struct device_info *dev)
585{
586 usbmuxd_log(LL_DEBUG, "client_device_add: id %d, location 0x%x, serial %s", dev->id, dev->location, dev->serial);
587 FOREACH(struct mux_client *client, &client_list) {
588 if(client->state == CLIENT_LISTEN)
589 notify_device_add(client, dev);
590 } ENDFOREACH
591}
592void client_device_remove(int device_id)
593{
594 uint32_t id = device_id;
595 usbmuxd_log(LL_DEBUG, "client_device_remove: id %d", device_id);
596 FOREACH(struct mux_client *client, &client_list) {
597 if(client->state == CLIENT_LISTEN)
598 notify_device_remove(client, id);
599 } ENDFOREACH
600}
601
602
603void client_init(void)
604{
605 usbmuxd_log(LL_DEBUG, "client_init");
606 collection_init(&client_list);
607}
608
609void client_shutdown(void)
610{
611 usbmuxd_log(LL_DEBUG, "client_shutdown");
612 FOREACH(struct mux_client *client, &client_list) {
613 client_close(client);
614 } ENDFOREACH
615 collection_free(&client_list);
616}
diff --git a/daemon/client.h b/daemon/client.h
deleted file mode 100644
index 60d8348..0000000
--- a/daemon/client.h
+++ /dev/null
@@ -1,47 +0,0 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 2 or version 3.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20*/
21
22#ifndef __CLIENT_H__
23#define __CLIENT_H__
24
25#include <stdint.h>
26#include "usbmuxd-proto.h"
27
28struct device_info;
29struct mux_client;
30
31int client_read(struct mux_client *client, void *buffer, uint32_t len);
32int client_write(struct mux_client *client, void *buffer, uint32_t len);
33int client_set_events(struct mux_client *client, short events);
34void client_close(struct mux_client *client);
35int client_notify_connect(struct mux_client *client, enum usbmuxd_result result);
36
37void client_device_add(struct device_info *dev);
38void client_device_remove(int device_id);
39
40int client_accept(int fd);
41void client_get_fds(struct fdlist *list);
42void client_process(int fd, short events);
43
44void client_init(void);
45void client_shutdown(void);
46
47#endif
diff --git a/daemon/device.c b/daemon/device.c
deleted file mode 100644
index 0a143b2..0000000
--- a/daemon/device.c
+++ /dev/null
@@ -1,781 +0,0 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 2 or version 3.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21#define _BSD_SOURCE
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include <sys/time.h>
28#include <netinet/in.h>
29#include <netinet/tcp.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdint.h>
33#include <inttypes.h>
34#include "device.h"
35#include "client.h"
36#include "usb.h"
37#include "log.h"
38
39int next_device_id;
40
41#define DEV_MRU 65536
42
43#define CONN_INBUF_SIZE 262144
44#define CONN_OUTBUF_SIZE 65536
45
46#define ACK_TIMEOUT 30
47
48enum mux_protocol {
49 MUX_PROTO_VERSION = 0,
50 MUX_PROTO_TCP = IPPROTO_TCP,
51};
52
53enum mux_dev_state {
54 MUXDEV_INIT, // sent version packet
55 MUXDEV_ACTIVE, // received version packet, active
56 MUXDEV_DEAD // dead
57};
58
59enum mux_conn_state {
60 CONN_CONNECTING, // SYN
61 CONN_CONNECTED, // SYN/SYNACK/ACK -> active
62 CONN_REFUSED, // RST received during SYN
63 CONN_DYING, // RST received
64 CONN_DEAD // being freed; used to prevent infinite recursion between client<->device freeing
65};
66
67struct mux_header
68{
69 uint32_t protocol;
70 uint32_t length;
71};
72
73struct version_header
74{
75 uint32_t major;
76 uint32_t minor;
77 uint32_t padding;
78};
79
80struct mux_device;
81
82#define CONN_ACK_PENDING 1
83
84struct mux_connection
85{
86 struct mux_device *dev;
87 struct mux_client *client;
88 enum mux_conn_state state;
89 uint16_t sport, dport;
90 uint32_t tx_seq, tx_ack, tx_acked, tx_win;
91 uint32_t rx_seq, rx_recvd, rx_ack, rx_win;
92 uint32_t max_payload;
93 uint32_t sendable;
94 int flags;
95 unsigned char *ib_buf;
96 uint32_t ib_size;
97 uint32_t ib_capacity;
98 unsigned char *ob_buf;
99 uint32_t ob_capacity;
100 short events;
101 uint64_t last_ack_time;
102};
103
104struct mux_device
105{
106 struct usb_device *usbdev;
107 int id;
108 enum mux_dev_state state;
109 struct collection connections;
110 uint16_t next_sport;
111 unsigned char *pktbuf;
112 uint32_t pktlen;
113};
114
115static struct collection device_list;
116
117uint64_t mstime64(void)
118{
119 struct timeval tv;
120 gettimeofday(&tv, NULL);
121 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
122}
123
124static int get_next_device_id(void)
125{
126 while(1) {
127 int ok = 1;
128 FOREACH(struct mux_device *dev, &device_list) {
129 if(dev->id == next_device_id) {
130 next_device_id++;
131 ok = 0;
132 break;
133 }
134 } ENDFOREACH
135 if(ok)
136 return next_device_id++;
137 }
138}
139
140static int send_packet(struct mux_device *dev, enum mux_protocol proto, void *header, const void *data, int length)
141{
142 unsigned char *buffer;
143 int hdrlen;
144 int res;
145
146 switch(proto) {
147 case MUX_PROTO_VERSION:
148 hdrlen = sizeof(struct version_header);
149 break;
150 case MUX_PROTO_TCP:
151 hdrlen = sizeof(struct tcphdr);
152 break;
153 default:
154 usbmuxd_log(LL_ERROR, "Invalid protocol %d for outgoing packet (dev %d hdr %p data %p len %d)", proto, dev->id, header, data, length);
155 return -1;
156 }
157 usbmuxd_log(LL_SPEW, "send_packet(%d, 0x%x, %p, %p, %d)", dev->id, proto, header, data, length);
158
159 int total = sizeof(struct mux_header) + hdrlen + length;
160
161 if(total > USB_MTU) {
162 usbmuxd_log(LL_ERROR, "Tried to send packet larger than USB MTU (hdr %d data %d total %d) to device %d", hdrlen, length, total, dev->id);
163 return -1;
164 }
165
166 buffer = malloc(total);
167 struct mux_header *mhdr = (struct mux_header *)buffer;
168 mhdr->protocol = htonl(proto);
169 mhdr->length = htonl(total);
170 memcpy(buffer + sizeof(struct mux_header), header, hdrlen);
171 if(data && length)
172 memcpy(buffer + sizeof(struct mux_header) + hdrlen, data, length);
173
174 if((res = usb_send(dev->usbdev, buffer, total)) < 0) {
175 usbmuxd_log(LL_ERROR, "usb_send failed while sending packet (len %d) to device %d: %d", total, dev->id, res);
176 free(buffer);
177 return res;
178 }
179 return total;
180}
181
182static uint16_t find_sport(struct mux_device *dev)
183{
184 if(collection_count(&dev->connections) >= 65535)
185 return 0; //insanity
186
187 while(1) {
188 int ok = 1;
189 FOREACH(struct mux_connection *conn, &dev->connections) {
190 if(dev->next_sport == conn->sport) {
191 dev->next_sport++;
192 ok = 0;
193 break;
194 }
195 } ENDFOREACH
196 if(ok)
197 return dev->next_sport++;
198 }
199}
200
201static int send_anon_rst(struct mux_device *dev, uint16_t sport, uint16_t dport, uint32_t ack)
202{
203 struct tcphdr th;
204 memset(&th, 0, sizeof(th));
205 th.th_sport = htons(sport);
206 th.th_dport = htons(dport);
207 th.th_ack = htonl(ack);
208 th.th_flags = TH_RST;
209 th.th_off = sizeof(th) / 4;
210
211 usbmuxd_log(LL_DEBUG, "[OUT] dev=%d sport=%d dport=%d flags=0x%x", dev->id, sport, dport, th.th_flags);
212
213 int res = send_packet(dev, MUX_PROTO_TCP, &th, NULL, 0);
214 return res;
215}
216
217static int send_tcp(struct mux_connection *conn, uint8_t flags, const unsigned char *data, int length)
218{
219 struct tcphdr th;
220 memset(&th, 0, sizeof(th));
221 th.th_sport = htons(conn->sport);
222 th.th_dport = htons(conn->dport);
223 th.th_seq = htonl(conn->tx_seq);
224 th.th_ack = htonl(conn->tx_ack);
225 th.th_flags = flags;
226 th.th_off = sizeof(th) / 4;
227 th.th_win = htons(conn->tx_win >> 8);
228
229 usbmuxd_log(LL_DEBUG, "[OUT] dev=%d sport=%d dport=%d seq=%d ack=%d flags=0x%x window=%d[%d] len=%d",
230 conn->dev->id, conn->sport, conn->dport, conn->tx_seq, conn->tx_ack, flags, conn->tx_win, conn->tx_win >> 8, length);
231
232 int res = send_packet(conn->dev, MUX_PROTO_TCP, &th, data, length);
233 if(res >= 0) {
234 conn->tx_acked = conn->tx_ack;
235 conn->last_ack_time = mstime64();
236 conn->flags &= ~CONN_ACK_PENDING;
237 }
238 return res;
239}
240
241static void connection_teardown(struct mux_connection *conn)
242{
243 int res;
244 if(conn->state == CONN_DEAD)
245 return;
246 usbmuxd_log(LL_DEBUG, "connection_teardown dev %d sport %d dport %d", conn->dev->id, conn->sport, conn->dport);
247 if(conn->dev->state != MUXDEV_DEAD && conn->state != CONN_DYING && conn->state != CONN_REFUSED) {
248 res = send_tcp(conn, TH_RST, NULL, 0);
249 if(res < 0)
250 usbmuxd_log(LL_ERROR, "Error sending TCP RST to device %d (%d->%d)", conn->dev->id, conn->sport, conn->dport);
251 }
252 if(conn->client) {
253 if(conn->state == CONN_REFUSED || conn->state == CONN_CONNECTING) {
254 client_notify_connect(conn->client, RESULT_CONNREFUSED);
255 } else {
256 conn->state = CONN_DEAD;
257 client_close(conn->client);
258 }
259 }
260 if(conn->ib_buf)
261 free(conn->ib_buf);
262 if(conn->ob_buf)
263 free(conn->ob_buf);
264 collection_remove(&conn->dev->connections, conn);
265 free(conn);
266}
267
268int device_start_connect(int device_id, uint16_t dport, struct mux_client *client)
269{
270 struct mux_device *dev = NULL;
271 FOREACH(struct mux_device *cdev, &device_list) {
272 if(cdev->id == device_id) {
273 dev = cdev;
274 break;
275 }
276 } ENDFOREACH
277 if(!dev) {
278 usbmuxd_log(LL_WARNING, "Attempted to connect to nonexistent device %d", device_id);
279 return -RESULT_BADDEV;
280 }
281
282 uint16_t sport = find_sport(dev);
283 if(!sport) {
284 usbmuxd_log(LL_WARNING, "Unable to allocate port for device %d", device_id);
285 return -RESULT_BADDEV;
286 }
287
288 struct mux_connection *conn;
289 conn = malloc(sizeof(struct mux_connection));
290 memset(conn, 0, sizeof(struct mux_connection));
291
292 conn->dev = dev;
293 conn->client = client;
294 conn->state = CONN_CONNECTING;
295 conn->sport = sport;
296 conn->dport = dport;
297 conn->tx_seq = 0;
298 conn->tx_ack = 0;
299 conn->tx_acked = 0;
300 conn->tx_win = 131072;
301 conn->rx_recvd = 0;
302 conn->flags = 0;
303 conn->max_payload = USB_MTU - sizeof(struct mux_header) - sizeof(struct tcphdr);
304
305 conn->ob_buf = malloc(CONN_OUTBUF_SIZE);
306 conn->ob_capacity = CONN_OUTBUF_SIZE;
307 conn->ib_buf = malloc(CONN_INBUF_SIZE);
308 conn->ib_capacity = CONN_INBUF_SIZE;
309 conn->ib_size = 0;
310
311 int res;
312
313 res = send_tcp(conn, TH_SYN, NULL, 0);
314 if(res < 0) {
315 usbmuxd_log(LL_ERROR, "Error sending TCP SYN to device %d (%d->%d)", dev->id, sport, dport);
316 free(conn);
317 return -RESULT_CONNREFUSED; //bleh
318 }
319 collection_add(&dev->connections, conn);
320 return 0;
321}
322
323static void update_connection(struct mux_connection *conn)
324{
325 uint32_t sent = conn->tx_seq - conn->rx_ack;
326
327 if(conn->rx_win > sent)
328 conn->sendable = conn->rx_win - sent;
329 else
330 conn->sendable = 0;
331
332 if(conn->sendable > conn->ob_capacity)
333 conn->sendable = conn->ob_capacity;
334 if(conn->sendable > conn->max_payload)
335 conn->sendable = conn->max_payload;
336
337 if(conn->sendable > 0)
338 conn->events |= POLLIN;
339 else
340 conn->events &= ~POLLIN;
341
342 if(conn->ib_size)
343 conn->events |= POLLOUT;
344 else
345 conn->events &= ~POLLOUT;
346
347 if(conn->tx_acked != conn->tx_ack)
348 conn->flags |= CONN_ACK_PENDING;
349 else
350 conn->flags &= ~CONN_ACK_PENDING;
351
352 usbmuxd_log(LL_SPEW, "update_connection: sendable %d, events %d, flags %d", conn->sendable, conn->events, conn->flags);
353 client_set_events(conn->client, conn->events);
354}
355
356void device_client_process(int device_id, struct mux_client *client, short events)
357{
358 struct mux_connection *conn = NULL;
359 FOREACH(struct mux_device *dev, &device_list) {
360 if(dev->id == device_id) {
361 FOREACH(struct mux_connection *lconn, &dev->connections) {
362 if(lconn->client == client) {
363 conn = lconn;
364 break;
365 }
366 } ENDFOREACH
367 break;
368 }
369 } ENDFOREACH
370
371 if(!conn) {
372 usbmuxd_log(LL_WARNING, "Could not find connection for device %d client %p", device_id, client);
373 return;
374 }
375 usbmuxd_log(LL_SPEW, "device_client_process (%d)", events);
376
377 int res;
378 int size;
379 if(events & POLLOUT) {
380 size = client_write(conn->client, conn->ib_buf, conn->ib_size);
381 if(size <= 0) {
382 usbmuxd_log(LL_DEBUG, "error writing to client (%d)", size);
383 connection_teardown(conn);
384 return;
385 }
386 conn->tx_ack += size;
387 if(size == conn->ib_size) {
388 conn->ib_size = 0;
389 } else {
390 conn->ib_size -= size;
391 memmove(conn->ib_buf, conn->ib_buf + size, conn->ib_size);
392 }
393 }
394 if(events & POLLIN) {
395 size = client_read(conn->client, conn->ob_buf, conn->sendable);
396 if(size <= 0) {
397 usbmuxd_log(LL_DEBUG, "error reading from client (%d)", size);
398 connection_teardown(conn);
399 return;
400 }
401 res = send_tcp(conn, TH_ACK, conn->ob_buf, size);
402 if(res < 0) {
403 connection_teardown(conn);
404 return;
405 }
406 conn->tx_seq += size;
407 }
408
409 update_connection(conn);
410}
411
412static void connection_device_input(struct mux_connection *conn, unsigned char *payload, uint32_t payload_length)
413{
414 if((conn->ib_size + payload_length) > conn->ib_capacity) {
415 usbmuxd_log(LL_ERROR, "Input buffer overflow on device %d connection %d->%d (space=%d, payload=%d)", conn->dev->id, conn->sport, conn->dport, conn->ib_capacity-conn->ib_size, payload_length);
416 connection_teardown(conn);
417 return;
418 }
419 memcpy(conn->ib_buf + conn->ib_size, payload, payload_length);
420 conn->ib_size += payload_length;
421 conn->rx_recvd += payload_length;
422 update_connection(conn);
423}
424
425void device_abort_connect(int device_id, struct mux_client *client)
426{
427 FOREACH(struct mux_device *dev, &device_list) {
428 if(dev->id == device_id) {
429 FOREACH(struct mux_connection *conn, &dev->connections) {
430 if(conn->client == client) {
431 connection_teardown(conn);
432 return;
433 }
434 } ENDFOREACH
435 usbmuxd_log(LL_WARNING, "Attempted to abort for nonexistent connection for device %d", device_id);
436 return;
437 }
438 } ENDFOREACH
439 usbmuxd_log(LL_WARNING, "Attempted to abort connection for nonexistent device %d", device_id);
440}
441
442static void device_version_input(struct mux_device *dev, struct version_header *vh)
443{
444 if(dev->state != MUXDEV_INIT) {
445 usbmuxd_log(LL_WARNING, "Version packet from already initialized device %d", dev->id);
446 return;
447 }
448 vh->major = ntohl(vh->major);
449 vh->minor = ntohl(vh->minor);
450 if(vh->major != 1 || vh->minor != 0) {
451 usbmuxd_log(LL_ERROR, "Device %d has unknown version %d.%d\n", dev->id, vh->major, vh->minor);
452 collection_remove(&device_list, dev);
453 free(dev);
454 return;
455 }
456 usbmuxd_log(LL_NOTICE, "Connected to v%d.%d device %d on location 0x%x with serial number %s", vh->major, vh->minor, dev->id, usb_get_location(dev->usbdev), usb_get_serial(dev->usbdev));
457 dev->state = MUXDEV_ACTIVE;
458 collection_init(&dev->connections);
459 struct device_info info;
460 info.id = dev->id;
461 info.location = usb_get_location(dev->usbdev);
462 info.serial = usb_get_serial(dev->usbdev);
463 info.pid = usb_get_pid(dev->usbdev);
464 client_device_add(&info);
465}
466
467static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, uint32_t payload_length)
468{
469 uint16_t sport = ntohs(th->th_dport);
470 uint16_t dport = ntohs(th->th_sport);
471 struct mux_connection *conn = NULL;
472
473 usbmuxd_log(LL_DEBUG, "[IN] dev=%d sport=%d dport=%d seq=%d ack=%d flags=0x%x window=%d[%d] len=%d",
474 dev->id, dport, sport, ntohl(th->th_seq), ntohl(th->th_ack), th->th_flags, ntohs(th->th_win) << 8, ntohs(th->th_win), payload_length);
475
476 if(dev->state != MUXDEV_ACTIVE) {
477 usbmuxd_log(LL_ERROR, "Received TCP packet from device %d but the device isn't active yet, discarding\n", dev->id);
478 return;
479 }
480
481 FOREACH(struct mux_connection *lconn, &dev->connections) {
482 if(lconn->sport == sport && lconn->dport == dport) {
483 conn = lconn;
484 break;
485 }
486 } ENDFOREACH
487
488 if(!conn) {
489 usbmuxd_log(LL_INFO, "No connection for device %d incoming packet %d->%d", dev->id, dport, sport);
490 if(!(th->th_flags & TH_RST)) {
491 if(send_anon_rst(dev, sport, dport, ntohl(th->th_seq)) < 0)
492 usbmuxd_log(LL_ERROR, "Error sending TCP RST to device %d (%d->%d)", conn->dev->id, sport, dport);
493 }
494 return;
495 }
496
497 conn->rx_seq = ntohl(th->th_seq);
498 conn->rx_ack = ntohl(th->th_ack);
499 conn->rx_win = ntohs(th->th_win) << 8;
500
501 if(th->th_flags & TH_RST) {
502 char *buf = malloc(payload_length+1);
503 memcpy(buf, payload, payload_length);
504 if(payload_length && (buf[payload_length-1] == '\n'))
505 buf[payload_length-1] = 0;
506 buf[payload_length] = 0;
507 usbmuxd_log(LL_DEBUG, "RST reason: %s", buf);
508 free(buf);
509 }
510
511 if(conn->state == CONN_CONNECTING) {
512 if(th->th_flags != (TH_SYN|TH_ACK)) {
513 if(th->th_flags & TH_RST)
514 conn->state = CONN_REFUSED;
515 usbmuxd_log(LL_INFO, "Connection refused by device %d (%d->%d)", dev->id, sport, dport);
516 connection_teardown(conn); //this also sends the notification to the client
517 } else {
518 conn->tx_seq++;
519 conn->tx_ack++;
520 conn->rx_recvd = conn->rx_seq;
521 if(send_tcp(conn, TH_ACK, NULL, 0) < 0) {
522 usbmuxd_log(LL_ERROR, "Error sending TCP ACK to device %d (%d->%d)", dev->id, sport, dport);
523 connection_teardown(conn);
524 return;
525 }
526 conn->state = CONN_CONNECTED;
527 if(client_notify_connect(conn->client, RESULT_OK) < 0) {
528 conn->client = NULL;
529 connection_teardown(conn);
530 }
531 update_connection(conn);
532 }
533 } else if(conn->state == CONN_CONNECTED) {
534 if(th->th_flags != TH_ACK) {
535 usbmuxd_log(LL_INFO, "Connection reset by device %d (%d->%d)", dev->id, sport, dport);
536 if(th->th_flags & TH_RST)
537 conn->state = CONN_DYING;
538 connection_teardown(conn);
539 } else {
540 connection_device_input(conn, payload, payload_length);
541 }
542 }
543}
544
545void device_data_input(struct usb_device *usbdev, unsigned char *buffer, uint32_t length)
546{
547 struct mux_device *dev = NULL;
548 FOREACH(struct mux_device *tdev, &device_list) {
549 if(tdev->usbdev == usbdev) {
550 dev = tdev;
551 break;
552 }
553 } ENDFOREACH
554 if(!dev) {
555 usbmuxd_log(LL_WARNING, "Cannot find device entry for RX input from USB device %p on location 0x%x", usbdev, usb_get_location(usbdev));
556 return;
557 }
558
559 if(!length)
560 return;
561
562 // sanity check (should never happen with current USB implementation)
563 if((length > USB_MRU) || (length > DEV_MRU)) {
564 usbmuxd_log(LL_ERROR, "Too much data received from USB (%d), file a bug", length);
565 return;
566 }
567
568 usbmuxd_log(LL_SPEW, "Mux data input for device %p: %p len %d", dev, buffer, length);
569
570 // handle broken up transfers
571 if(dev->pktlen) {
572 if((length + dev->pktlen) > DEV_MRU) {
573 usbmuxd_log(LL_ERROR, "Incoming split packet is too large (%d so far), dropping!", length + dev->pktlen);
574 dev->pktlen = 0;
575 return;
576 }
577 memcpy(dev->pktbuf + dev->pktlen, buffer, length);
578 struct mux_header *mhdr = (struct mux_header *)dev->pktbuf;
579 if((length < USB_MRU) || (ntohl(mhdr->length) == length)) {
580 buffer = dev->pktbuf;
581 length += dev->pktlen;
582 dev->pktlen = 0;
583 usbmuxd_log(LL_SPEW, "Gathered mux data from buffer (total size: %d)", length);
584 } else {
585 dev->pktlen += length;
586 usbmuxd_log(LL_SPEW, "Appended mux data to buffer (total size: %d)", dev->pktlen);
587 return;
588 }
589 } else {
590 struct mux_header *mhdr = (struct mux_header *)buffer;
591 if((length == USB_MRU) && (length < ntohl(mhdr->length))) {
592 memcpy(dev->pktbuf, buffer, length);
593 dev->pktlen = length;
594 usbmuxd_log(LL_SPEW, "Copied mux data to buffer (size: %d)", dev->pktlen);
595 return;
596 }
597 }
598
599 struct mux_header *mhdr = (struct mux_header *)buffer;
600
601 if(ntohl(mhdr->length) != length) {
602 usbmuxd_log(LL_ERROR, "Incoming packet size mismatch (dev %d, expected %d, got %d)", dev->id, ntohl(mhdr->length), length);
603 return;
604 }
605
606 struct tcphdr *th;
607 unsigned char *payload;
608 uint32_t payload_length;
609
610 switch(ntohl(mhdr->protocol)) {
611 case MUX_PROTO_VERSION:
612 if(length < (sizeof(struct mux_header) + sizeof(struct version_header))) {
613 usbmuxd_log(LL_ERROR, "Incoming version packet is too small (%d)", length);
614 return;
615 }
616 device_version_input(dev, (struct version_header *)(mhdr+1));
617 break;
618 case MUX_PROTO_TCP:
619 if(length < (sizeof(struct mux_header) + sizeof(struct tcphdr))) {
620 usbmuxd_log(LL_ERROR, "Incoming TCP packet is too small (%d)", length);
621 return;
622 }
623 th = (struct tcphdr *)(mhdr+1);
624 payload = (unsigned char *)(th+1);
625 payload_length = length - sizeof(struct tcphdr) - sizeof(struct mux_header);
626 device_tcp_input(dev, (struct tcphdr *)(mhdr+1), payload, payload_length);
627 break;
628 default:
629 usbmuxd_log(LL_ERROR, "Incoming packet for device %d has unknown protocol 0x%x)", dev->id, ntohl(mhdr->protocol));
630 break;
631 }
632
633}
634
635int device_add(struct usb_device *usbdev)
636{
637 int res;
638 int id = get_next_device_id();
639 struct mux_device *dev;
640 usbmuxd_log(LL_NOTICE, "Connecting to new device on location 0x%x as ID %d", usb_get_location(usbdev), id);
641 dev = malloc(sizeof(struct mux_device));
642 dev->id = id;
643 dev->usbdev = usbdev;
644 dev->state = MUXDEV_INIT;
645 dev->next_sport = 1;
646 dev->pktbuf = malloc(DEV_MRU);
647 dev->pktlen = 0;
648 struct version_header vh;
649 vh.major = htonl(1);
650 vh.minor = htonl(0);
651 vh.padding = 0;
652 if((res = send_packet(dev, MUX_PROTO_VERSION, &vh, NULL, 0)) < 0) {
653 usbmuxd_log(LL_ERROR, "Error sending version request packet to device %d", id);
654 free(dev);
655 return res;
656 }
657 collection_add(&device_list, dev);
658 return 0;
659}
660
661void device_remove(struct usb_device *usbdev)
662{
663 FOREACH(struct mux_device *dev, &device_list) {
664 if(dev->usbdev == usbdev) {
665 usbmuxd_log(LL_NOTICE, "Removed device %d on location 0x%x", dev->id, usb_get_location(usbdev));
666 if(dev->state == MUXDEV_ACTIVE) {
667 dev->state = MUXDEV_DEAD;
668 FOREACH(struct mux_connection *conn, &dev->connections) {
669 connection_teardown(conn);
670 } ENDFOREACH
671 client_device_remove(dev->id);
672 collection_free(&dev->connections);
673 }
674 collection_remove(&device_list, dev);
675 free(dev->pktbuf);
676 free(dev);
677 return;
678 }
679 } ENDFOREACH
680 usbmuxd_log(LL_WARNING, "Cannot find device entry while removing USB device %p on location 0x%x", usbdev, usb_get_location(usbdev));
681}
682
683int device_get_count(void)
684{
685 int count = 0;
686 FOREACH(struct mux_device *dev, &device_list) {
687 if(dev->state == MUXDEV_ACTIVE)
688 count++;
689 } ENDFOREACH
690 return count;
691}
692
693int device_get_list(struct device_info *p)
694{
695 int count = 0;
696 FOREACH(struct mux_device *dev, &device_list) {
697 if(dev->state == MUXDEV_ACTIVE) {
698 p->id = dev->id;
699 p->serial = usb_get_serial(dev->usbdev);
700 p->location = usb_get_location(dev->usbdev);
701 p->pid = usb_get_pid(dev->usbdev);
702 count++;
703 p++;
704 }
705 } ENDFOREACH
706 return count;
707}
708
709int device_get_timeout(void)
710{
711 uint64_t oldest = (uint64_t)-1;
712 FOREACH(struct mux_device *dev, &device_list) {
713 if(dev->state == MUXDEV_ACTIVE) {
714 FOREACH(struct mux_connection *conn, &dev->connections) {
715 if((conn->state == CONN_CONNECTED) && (conn->flags & CONN_ACK_PENDING) && conn->last_ack_time < oldest)
716 oldest = conn->last_ack_time;
717 } ENDFOREACH
718 }
719 } ENDFOREACH
720 uint64_t ct = mstime64();
721 if(oldest == -1)
722 return 100000; //meh
723 if((ct - oldest) > ACK_TIMEOUT)
724 return 0;
725 return ACK_TIMEOUT - (ct - oldest);
726}
727
728void device_check_timeouts(void)
729{
730 uint64_t ct = mstime64();
731 FOREACH(struct mux_device *dev, &device_list) {
732 if(dev->state == MUXDEV_ACTIVE) {
733 FOREACH(struct mux_connection *conn, &dev->connections) {
734 if((conn->state == CONN_CONNECTED) &&
735 (conn->flags & CONN_ACK_PENDING) &&
736 (ct - conn->last_ack_time) > ACK_TIMEOUT) {
737 usbmuxd_log(LL_DEBUG, "Sending ACK due to expired timeout (%" PRIu64 " -> %" PRIu64 ")", conn->last_ack_time, ct);
738 if(send_tcp(conn, TH_ACK, NULL, 0) < 0) {
739 usbmuxd_log(LL_ERROR, "Error sending TCP ACK to device %d (%d->%d)", dev->id, conn->sport, conn->dport);
740 connection_teardown(conn);
741 }
742 }
743 } ENDFOREACH
744 }
745 } ENDFOREACH
746}
747
748void device_init(void)
749{
750 usbmuxd_log(LL_DEBUG, "device_init");
751 collection_init(&device_list);
752 next_device_id = 1;
753}
754
755void device_kill_connections(void)
756{
757 usbmuxd_log(LL_DEBUG, "device_kill_connections");
758 FOREACH(struct mux_device *dev, &device_list) {
759 if(dev->state != MUXDEV_INIT) {
760 FOREACH(struct mux_connection *conn, &dev->connections) {
761 connection_teardown(conn);
762 } ENDFOREACH
763 }
764 } ENDFOREACH
765 // give USB a while to send the final connection RSTs and the like
766 usb_process_timeout(100);
767}
768
769void device_shutdown(void)
770{
771 usbmuxd_log(LL_DEBUG, "device_shutdown");
772 FOREACH(struct mux_device *dev, &device_list) {
773 FOREACH(struct mux_connection *conn, &dev->connections) {
774 connection_teardown(conn);
775 } ENDFOREACH
776 collection_free(&dev->connections);
777 collection_remove(&device_list, dev);
778 free(dev);
779 } ENDFOREACH
780 collection_free(&device_list);
781}
diff --git a/daemon/device.h b/daemon/device.h
deleted file mode 100644
index ea77069..0000000
--- a/daemon/device.h
+++ /dev/null
@@ -1,52 +0,0 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 2 or version 3.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21#ifndef __DEVICE_H__
22#define __DEVICE_H__
23
24#include "usb.h"
25#include "client.h"
26
27struct device_info {
28 int id;
29 const char *serial;
30 uint32_t location;
31 uint16_t pid;
32};
33
34void device_data_input(struct usb_device *dev, unsigned char *buf, uint32_t length);
35
36int device_add(struct usb_device *dev);
37void device_remove(struct usb_device *dev);
38
39int device_start_connect(int device_id, uint16_t port, struct mux_client *client);
40void device_client_process(int device_id, struct mux_client *client, short events);
41void device_abort_connect(int device_id, struct mux_client *client);
42
43int device_get_count(void);
44int device_get_list(struct device_info *p);
45
46int device_get_timeout(void);
47void device_check_timeouts(void);
48
49void device_init(void);
50void device_kill_connections(void);
51void device_shutdown(void);
52#endif
diff --git a/daemon/log.c b/daemon/log.c
deleted file mode 100644
index 1973257..0000000
--- a/daemon/log.c
+++ /dev/null
@@ -1,95 +0,0 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 2 or version 3.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20*/
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <stdarg.h>
30#include <time.h>
31#include <sys/time.h>
32#include <syslog.h>
33
34#include "log.h"
35
36int log_level = LL_WARNING;
37
38int log_syslog = 0;
39
40void log_enable_syslog()
41{
42 if (!log_syslog) {
43 openlog("usbmuxd", LOG_PID, 0);
44 log_syslog = 1;
45 }
46}
47
48void log_disable_syslog()
49{
50 if (log_syslog) {
51 closelog();
52 }
53}
54
55static int level_to_syslog_level(int level)
56{
57 int result = level + LOG_CRIT;
58 if (result > LOG_DEBUG) {
59 result = LOG_DEBUG;
60 }
61 return result;
62}
63
64void usbmuxd_log(enum loglevel level, const char *fmt, ...)
65{
66 va_list ap;
67 char *fs;
68 struct timeval ts;
69 struct tm *tp;
70
71 if(level > log_level)
72 return;
73
74 gettimeofday(&ts, NULL);
75 tp = localtime(&ts.tv_sec);
76
77 fs = malloc(20 + strlen(fmt));
78
79 if(log_syslog) {
80 sprintf(fs, "[%d] %s\n", level, fmt);
81 } else {
82 strftime(fs, 10, "[%H:%M:%S", tp);
83 sprintf(fs+9, ".%03d][%d] %s\n", (int)(ts.tv_usec / 1000), level, fmt);
84 }
85
86 va_start(ap, fmt);
87 if (log_syslog) {
88 vsyslog(level_to_syslog_level(level), fs, ap);
89 } else {
90 vfprintf(stderr, fs, ap);
91 }
92 va_end(ap);
93
94 free(fs);
95}
diff --git a/daemon/log.h b/daemon/log.h
deleted file mode 100644
index eeefa41..0000000
--- a/daemon/log.h
+++ /dev/null
@@ -1,44 +0,0 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 2 or version 3.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20*/
21
22#ifndef __LOG_H__
23#define __LOG_H__
24
25enum loglevel {
26 LL_FATAL = 0,
27 LL_ERROR,
28 LL_WARNING,
29 LL_NOTICE,
30 LL_INFO,
31 LL_DEBUG,
32 LL_SPEW,
33 LL_FLOOD,
34};
35
36extern int log_level;
37
38void log_enable_syslog();
39void log_disable_syslog();
40
41void usbmuxd_log(enum loglevel level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
42
43
44#endif
diff --git a/daemon/main.c b/daemon/main.c
deleted file mode 100644
index 140bee1..0000000
--- a/daemon/main.c
+++ /dev/null
@@ -1,618 +0,0 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
6Copyright (C) 2009 Paul Sladen <libiphone@paul.sladen.org>
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 2 or version 3.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
21*/
22
23#define _BSD_SOURCE
24#define _GNU_SOURCE
25
26#ifdef HAVE_CONFIG_H
27#include <config.h>
28#endif
29
30#include <stdio.h>
31#include <errno.h>
32#include <string.h>
33#include <stdlib.h>
34#include <signal.h>
35#include <unistd.h>
36#include <sys/socket.h>
37#include <sys/un.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <fcntl.h>
41#include <getopt.h>
42#include <pwd.h>
43#include <grp.h>
44
45#include "log.h"
46#include "usb.h"
47#include "device.h"
48#include "client.h"
49
50static const char *socket_path = "/var/run/usbmuxd";
51static const char *lockfile = "/var/run/usbmuxd.pid";
52
53int should_exit;
54int should_discover;
55
56static int verbose = 0;
57static int foreground = 0;
58static int drop_privileges = 0;
59static const char *drop_user = NULL;
60static int opt_udev = 0;
61static int opt_exit = 0;
62static int exit_signal = 0;
63static int daemon_pipe;
64
65static int report_to_parent = 0;
66
67int create_socket(void) {
68 struct sockaddr_un bind_addr;
69 int listenfd;
70
71 if(unlink(socket_path) == -1 && errno != ENOENT) {
72 usbmuxd_log(LL_FATAL, "unlink(%s) failed: %s", socket_path, strerror(errno));
73 return -1;
74 }
75
76 listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
77 if (listenfd == -1) {
78 usbmuxd_log(LL_FATAL, "socket() failed: %s", strerror(errno));
79 return -1;
80 }
81
82 bzero(&bind_addr, sizeof(bind_addr));
83 bind_addr.sun_family = AF_UNIX;
84 strcpy(bind_addr.sun_path, socket_path);
85 if (bind(listenfd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) != 0) {
86 usbmuxd_log(LL_FATAL, "bind() failed: %s", strerror(errno));
87 return -1;
88 }
89
90 // Start listening
91 if (listen(listenfd, 5) != 0) {
92 usbmuxd_log(LL_FATAL, "listen() failed: %s", strerror(errno));
93 return -1;
94 }
95
96 chmod(socket_path, 0666);
97
98 return listenfd;
99}
100
101void handle_signal(int sig)
102{
103 if (sig != SIGUSR1 && sig != SIGUSR2) {
104 usbmuxd_log(LL_NOTICE,"Caught signal %d, exiting", sig);
105 should_exit = 1;
106 } else {
107 if(opt_udev) {
108 if (sig == SIGUSR1) {
109 usbmuxd_log(LL_INFO, "Caught SIGUSR1, checking if we can terminate (no more devices attached)...");
110 if (device_get_count() > 0) {
111 // we can't quit, there are still devices attached.
112 usbmuxd_log(LL_NOTICE, "Refusing to terminate, there are still devices attached. Kill me with signal 15 (TERM) to force quit.");
113 } else {
114 // it's safe to quit
115 should_exit = 1;
116 }
117 } else if (sig == SIGUSR2) {
118 usbmuxd_log(LL_INFO, "Caught SIGUSR2, scheduling device discovery");
119 should_discover = 1;
120 }
121 } else {
122 usbmuxd_log(LL_INFO, "Caught SIGUSR1/2 but we weren't started in --udev mode, ignoring");
123 }
124 }
125}
126
127void set_signal_handlers(void)
128{
129 struct sigaction sa;
130 sigset_t set;
131
132 // Mask all signals we handle. They will be unmasked by ppoll().
133 sigemptyset(&set);
134 sigaddset(&set, SIGINT);
135 sigaddset(&set, SIGQUIT);
136 sigaddset(&set, SIGTERM);
137 sigaddset(&set, SIGUSR1);
138 sigaddset(&set, SIGUSR2);
139 sigprocmask(SIG_SETMASK, &set, NULL);
140
141 memset(&sa, 0, sizeof(struct sigaction));
142 sa.sa_handler = handle_signal;
143 sigaction(SIGINT, &sa, NULL);
144 sigaction(SIGQUIT, &sa, NULL);
145 sigaction(SIGTERM, &sa, NULL);
146 sigaction(SIGUSR1, &sa, NULL);
147 sigaction(SIGUSR2, &sa, NULL);
148}
149
150#if defined(__FreeBSD__) || defined(__APPLE__)
151static int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t *sigmask)
152{
153 int ready;
154 sigset_t origmask;
155 int to = timeout->tv_sec*1000 + timeout->tv_nsec/1000000;
156
157 sigprocmask(SIG_SETMASK, sigmask, &origmask);
158 ready = poll(fds, nfds, to);
159 sigprocmask(SIG_SETMASK, &origmask, NULL);
160
161 return ready;
162}
163#endif
164
165int main_loop(int listenfd)
166{
167 int to, cnt, i, dto;
168 struct fdlist pollfds;
169 struct timespec tspec;
170
171 sigset_t empty_sigset;
172 sigemptyset(&empty_sigset); // unmask all signals
173
174 fdlist_create(&pollfds);
175 while(!should_exit) {
176 usbmuxd_log(LL_FLOOD, "main_loop iteration");
177 to = usb_get_timeout();
178 usbmuxd_log(LL_FLOOD, "USB timeout is %d ms", to);
179 dto = device_get_timeout();
180 usbmuxd_log(LL_FLOOD, "Device timeout is %d ms", to);
181 if(dto < to)
182 to = dto;
183
184 fdlist_reset(&pollfds);
185 fdlist_add(&pollfds, FD_LISTEN, listenfd, POLLIN);
186 usb_get_fds(&pollfds);
187 client_get_fds(&pollfds);
188 usbmuxd_log(LL_FLOOD, "fd count is %d", pollfds.count);
189
190 tspec.tv_sec = to / 1000;
191 tspec.tv_nsec = (to % 1000) * 1000000;
192 cnt = ppoll(pollfds.fds, pollfds.count, &tspec, &empty_sigset);
193 usbmuxd_log(LL_FLOOD, "poll() returned %d", cnt);
194 if(cnt == -1) {
195 if(errno == EINTR) {
196 if(should_exit) {
197 usbmuxd_log(LL_INFO, "Event processing interrupted");
198 break;
199 }
200 if(should_discover) {
201 should_discover = 0;
202 usbmuxd_log(LL_INFO, "Device discovery triggered by udev");
203 usb_discover();
204 }
205 }
206 } else if(cnt == 0) {
207 if(usb_process() < 0) {
208 usbmuxd_log(LL_FATAL, "usb_process() failed");
209 fdlist_free(&pollfds);
210 return -1;
211 }
212 device_check_timeouts();
213 } else {
214 int done_usb = 0;
215 for(i=0; i<pollfds.count; i++) {
216 if(pollfds.fds[i].revents) {
217 if(!done_usb && pollfds.owners[i] == FD_USB) {
218 if(usb_process() < 0) {
219 usbmuxd_log(LL_FATAL, "usb_process() failed");
220 fdlist_free(&pollfds);
221 return -1;
222 }
223 done_usb = 1;
224 }
225 if(pollfds.owners[i] == FD_LISTEN) {
226 if(client_accept(listenfd) < 0) {
227 usbmuxd_log(LL_FATAL, "client_accept() failed");
228 fdlist_free(&pollfds);
229 return -1;
230 }
231 }
232 if(pollfds.owners[i] == FD_CLIENT) {
233 client_process(pollfds.fds[i].fd, pollfds.fds[i].revents);
234 }
235 }
236 }
237 }
238 }
239 fdlist_free(&pollfds);
240 return 0;
241}
242
243/**
244 * make this program run detached from the current console
245 */
246static int daemonize(void)
247{
248 pid_t pid;
249 pid_t sid;
250 int pfd[2];
251 int res;
252
253 // already a daemon
254 if (getppid() == 1)
255 return 0;
256
257 if((res = pipe(pfd)) < 0) {
258 usbmuxd_log(LL_FATAL, "pipe() failed.");
259 return res;
260 }
261
262 pid = fork();
263 if (pid < 0) {
264 usbmuxd_log(LL_FATAL, "fork() failed.");
265 return pid;
266 }
267
268 if (pid > 0) {
269 // exit parent process
270 int status;
271 close(pfd[1]);
272
273 if((res = read(pfd[0],&status,sizeof(int))) != sizeof(int)) {
274 fprintf(stderr, "usbmuxd: ERROR: Failed to get init status from child, check syslog for messages.\n");
275 exit(1);
276 }
277 if(status != 0)
278 fprintf(stderr, "usbmuxd: ERROR: Child process exited with error %d, check syslog for messages.\n", status);
279 exit(status);
280 }
281 // At this point we are executing as the child process
282 // but we need to do one more fork
283
284 daemon_pipe = pfd[1];
285 close(pfd[0]);
286 report_to_parent = 1;
287
288 // Change the file mode mask
289 umask(0);
290
291 // Create a new SID for the child process
292 sid = setsid();
293 if (sid < 0) {
294 usbmuxd_log(LL_FATAL, "setsid() failed.");
295 return -1;
296 }
297
298 pid = fork();
299 if (pid < 0) {
300 usbmuxd_log(LL_FATAL, "fork() failed (second).");
301 return pid;
302 }
303
304 if (pid > 0) {
305 // exit parent process
306 close(daemon_pipe);
307 exit(0);
308 }
309
310 // Change the current working directory.
311 if ((chdir("/")) < 0) {
312 usbmuxd_log(LL_FATAL, "chdir() failed");
313 return -2;
314 }
315 // Redirect standard files to /dev/null
316 if (!freopen("/dev/null", "r", stdin)) {
317 usbmuxd_log(LL_FATAL, "Redirection of stdin failed.");
318 return -3;
319 }
320 if (!freopen("/dev/null", "w", stdout)) {
321 usbmuxd_log(LL_FATAL, "Redirection of stdout failed.");
322 return -3;
323 }
324
325 return 0;
326}
327
328static int notify_parent(int status)
329{
330 int res;
331
332 report_to_parent = 0;
333 if ((res = write(daemon_pipe, &status, sizeof(int))) != sizeof(int)) {
334 usbmuxd_log(LL_FATAL, "Could not notify parent!");
335 if(res >= 0)
336 return -2;
337 else
338 return res;
339 }
340 close(daemon_pipe);
341 if (!freopen("/dev/null", "w", stderr)) {
342 usbmuxd_log(LL_FATAL, "Redirection of stderr failed.");
343 return -1;
344 }
345 return 0;
346}
347
348static void usage()
349{
350 printf("usage: usbmuxd [options]\n");
351 printf("\t-h|--help Print this message.\n");
352 printf("\t-v|--verbose Be verbose (use twice or more to increase).\n");
353 printf("\t-f|--foreground Do not daemonize (implies one -v).\n");
354 printf("\t-U|--user USER Change to this user after startup (needs usb privileges).\n");
355 printf("\t-u|--udev Run in udev operation mode.\n");
356 printf("\t-x|--exit Tell a running instance to exit if there are no devices\n");
357 printf("\t connected (must be in udev mode).\n");
358 printf("\t-X|--force-exit Tell a running instance to exit, even if there are still\n");
359 printf("\t devices connected (always works).\n");
360 printf("\n");
361}
362
363static void parse_opts(int argc, char **argv)
364{
365 static struct option longopts[] = {
366 {"help", 0, NULL, 'h'},
367 {"foreground", 0, NULL, 'f'},
368 {"verbose", 0, NULL, 'v'},
369 {"user", 2, NULL, 'U'},
370 {"udev", 0, NULL, 'u'},
371 {"exit", 0, NULL, 'x'},
372 {"force-exit", 0, NULL, 'X'},
373 {NULL, 0, NULL, 0}
374 };
375 int c;
376
377 while (1) {
378 c = getopt_long(argc, argv, "hfvuU:xX", longopts, (int *) 0);
379 if (c == -1) {
380 break;
381 }
382
383 switch (c) {
384 case 'h':
385 usage();
386 exit(0);
387 case 'f':
388 foreground = 1;
389 break;
390 case 'v':
391 ++verbose;
392 break;
393 case 'U':
394 drop_privileges = 1;
395 drop_user = optarg;
396 break;
397 case 'u':
398 opt_udev = 1;
399 break;
400 case 'x':
401 opt_exit = 1;
402 exit_signal = SIGUSR1;
403 break;
404 case 'X':
405 opt_exit = 1;
406 exit_signal = SIGTERM;
407 break;
408 default:
409 usage();
410 exit(2);
411 }
412 }
413}
414
415int main(int argc, char *argv[])
416{
417 int listenfd;
418 int res = 0;
419 int lfd;
420 struct flock lock;
421 char pids[10];
422
423 parse_opts(argc, argv);
424
425 argc -= optind;
426 argv += optind;
427
428 if (!foreground) {
429 verbose += LL_WARNING;
430 log_enable_syslog();
431 } else {
432 verbose += LL_NOTICE;
433 }
434
435 /* set log level to specified verbosity */
436 log_level = verbose;
437
438 usbmuxd_log(LL_NOTICE, "usbmuxd v%s starting up", USBMUXD_VERSION);
439 should_exit = 0;
440 should_discover = 0;
441
442 set_signal_handlers();
443 signal(SIGPIPE, SIG_IGN);
444
445 res = lfd = open(lockfile, O_WRONLY|O_CREAT, 0644);
446 if(res == -1) {
447 usbmuxd_log(LL_FATAL, "Could not open lockfile");
448 goto terminate;
449 }
450 lock.l_type = F_WRLCK;
451 lock.l_whence = SEEK_SET;
452 lock.l_start = 0;
453 lock.l_len = 0;
454 fcntl(lfd, F_GETLK, &lock);
455 close(lfd);
456 if (lock.l_type != F_UNLCK) {
457 if (opt_exit) {
458 if (lock.l_pid && !kill(lock.l_pid, 0)) {
459 usbmuxd_log(LL_NOTICE, "Sending signal %d to instance with pid %d", exit_signal, lock.l_pid);
460 res = 0;
461 if (kill(lock.l_pid, exit_signal) < 0) {
462 usbmuxd_log(LL_FATAL, "Could not deliver signal %d to pid %d", exit_signal, lock.l_pid);
463 res = -1;
464 }
465 goto terminate;
466 } else {
467 usbmuxd_log(LL_ERROR, "Could not determine pid of the other running instance!");
468 res = -1;
469 goto terminate;
470 }
471 } else {
472 if (!opt_udev) {
473 usbmuxd_log(LL_ERROR, "Another instance is already running (pid %d). exiting.", lock.l_pid);
474 res = -1;
475 } else {
476 usbmuxd_log(LL_NOTICE, "Another instance is already running (pid %d). Telling it to check for devices.", lock.l_pid);
477 if (lock.l_pid && !kill(lock.l_pid, 0)) {
478 usbmuxd_log(LL_NOTICE, "Sending signal SIGUSR2 to instance with pid %d", lock.l_pid);
479 res = 0;
480 if (kill(lock.l_pid, SIGUSR2) < 0) {
481 usbmuxd_log(LL_FATAL, "Could not deliver SIGUSR2 to pid %d", lock.l_pid);
482 res = -1;
483 }
484 } else {
485 usbmuxd_log(LL_ERROR, "Could not determine pid of the other running instance!");
486 res = -1;
487 }
488 }
489 goto terminate;
490 }
491 }
492 unlink(lockfile);
493
494 if (opt_exit) {
495 usbmuxd_log(LL_NOTICE, "No running instance found, none killed. exiting.");
496 goto terminate;
497 }
498
499 if (!foreground) {
500 if ((res = daemonize()) < 0) {
501 fprintf(stderr, "usbmuxd: FATAL: Could not daemonize!\n");
502 usbmuxd_log(LL_FATAL, "Could not daemonize!");
503 goto terminate;
504 }
505 }
506
507 // now open the lockfile and place the lock
508 res = lfd = open(lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
509 if(res < 0) {
510 usbmuxd_log(LL_FATAL, "Could not open lockfile");
511 goto terminate;
512 }
513 lock.l_type = F_WRLCK;
514 lock.l_whence = SEEK_SET;
515 lock.l_start = 0;
516 lock.l_len = 0;
517 if ((res = fcntl(lfd, F_SETLK, &lock)) < 0) {
518 usbmuxd_log(LL_FATAL, "Lockfile locking failed!");
519 goto terminate;
520 }
521 sprintf(pids, "%d", getpid());
522 if ((res = write(lfd, pids, strlen(pids))) != strlen(pids)) {
523 usbmuxd_log(LL_FATAL, "Could not write pidfile!");
524 if(res >= 0)
525 res = -2;
526 goto terminate;
527 }
528
529 usbmuxd_log(LL_INFO, "Creating socket");
530 res = listenfd = create_socket();
531 if(listenfd < 0)
532 goto terminate;
533
534 // drop elevated privileges
535 if (drop_privileges && (getuid() == 0 || geteuid() == 0)) {
536 struct passwd *pw;
537 if (!drop_user) {
538 usbmuxd_log(LL_FATAL, "No user to drop privileges to?");
539 res = -1;
540 goto terminate;
541 }
542 pw = getpwnam(drop_user);
543 if (!pw) {
544 usbmuxd_log(LL_FATAL, "Dropping privileges failed, check if user '%s' exists!", drop_user);
545 res = -1;
546 goto terminate;
547 }
548 if (pw->pw_uid == 0) {
549 usbmuxd_log(LL_INFO, "Not dropping privileges to root");
550 } else {
551 if ((res = initgroups(drop_user, pw->pw_gid)) < 0) {
552 usbmuxd_log(LL_FATAL, "Failed to drop privileges (cannot set supplementary groups)");
553 goto terminate;
554 }
555 if ((res = setgid(pw->pw_gid)) < 0) {
556 usbmuxd_log(LL_FATAL, "Failed to drop privileges (cannot set group ID to %d)", pw->pw_gid);
557 goto terminate;
558 }
559 if ((res = setuid(pw->pw_uid)) < 0) {
560 usbmuxd_log(LL_FATAL, "Failed to drop privileges (cannot set user ID to %d)", pw->pw_uid);
561 goto terminate;
562 }
563
564 // security check
565 if (setuid(0) != -1) {
566 usbmuxd_log(LL_FATAL, "Failed to drop privileges properly!");
567 res = -1;
568 goto terminate;
569 }
570 if (getuid() != pw->pw_uid || getgid() != pw->pw_gid) {
571 usbmuxd_log(LL_FATAL, "Failed to drop privileges properly!");
572 res = -1;
573 goto terminate;
574 }
575 usbmuxd_log(LL_NOTICE, "Successfully dropped privileges to '%s'", drop_user);
576 }
577 }
578
579 client_init();
580 device_init();
581 usbmuxd_log(LL_INFO, "Initializing USB");
582 if((res = usb_init()) < 0)
583 goto terminate;
584
585 usbmuxd_log(LL_INFO, "%d device%s detected", res, (res==1)?"":"s");
586
587 usbmuxd_log(LL_NOTICE, "Initialization complete");
588
589 if (report_to_parent)
590 if((res = notify_parent(0)) < 0)
591 goto terminate;
592
593 if(opt_udev)
594 usb_autodiscover(0); // discovery triggered by udev
595
596 res = main_loop(listenfd);
597 if(res < 0)
598 usbmuxd_log(LL_FATAL, "main_loop failed");
599
600 usbmuxd_log(LL_NOTICE, "usbmuxd shutting down");
601 device_kill_connections();
602 usb_shutdown();
603 device_shutdown();
604 client_shutdown();
605 usbmuxd_log(LL_NOTICE, "Shutdown complete");
606
607terminate:
608 log_disable_syslog();
609
610 if (res < 0)
611 res = -res;
612 else
613 res = 0;
614 if (report_to_parent)
615 notify_parent(res);
616
617 return res;
618}
diff --git a/daemon/usb-linux.c b/daemon/usb-linux.c
deleted file mode 100644
index 0860b46..0000000
--- a/daemon/usb-linux.c
+++ /dev/null
@@ -1,589 +0,0 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
6Copyright (C) 2009 Martin Szulecki <opensuse@sukimashita.com>
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 2 or version 3.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
21*/
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <stdint.h>
30#include <string.h>
31
32#include <libusb.h>
33
34#include "usb.h"
35#include "log.h"
36#include "device.h"
37
38// interval for device connection/disconnection polling, in milliseconds
39// we need this because there is currently no asynchronous device discovery mechanism in libusb
40#define DEVICE_POLL_TIME 1000
41
42struct usb_device {
43 libusb_device_handle *dev;
44 uint8_t bus, address;
45 uint16_t vid, pid;
46 char serial[256];
47 int alive;
48 uint8_t interface, ep_in, ep_out;
49 struct libusb_transfer *rx_xfer;
50 struct collection tx_xfers;
51 int wMaxPacketSize;
52};
53
54static struct collection device_list;
55
56static struct timeval next_dev_poll_time;
57
58static int devlist_failures;
59static int device_polling;
60
61static void usb_disconnect(struct usb_device *dev)
62{
63 if(!dev->dev) {
64 return;
65 }
66
67 // kill the rx xfer and tx xfers and try to make sure the callbacks get called before we free the device
68 if(dev->rx_xfer) {
69 usbmuxd_log(LL_DEBUG, "usb_disconnect: cancelling RX xfer");
70 libusb_cancel_transfer(dev->rx_xfer);
71 }
72 FOREACH(struct libusb_transfer *xfer, &dev->tx_xfers) {
73 usbmuxd_log(LL_DEBUG, "usb_disconnect: cancelling TX xfer %p", xfer);
74 libusb_cancel_transfer(xfer);
75 } ENDFOREACH
76
77 while(dev->rx_xfer || collection_count(&dev->tx_xfers)) {
78 struct timeval tv;
79 int res;
80
81 tv.tv_sec = 0;
82 tv.tv_usec = 1000;
83 if((res = libusb_handle_events_timeout(NULL, &tv)) < 0) {
84 usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout for usb_disconnect failed: %d", res);
85 break;
86 }
87 }
88 collection_free(&dev->tx_xfers);
89 libusb_release_interface(dev->dev, dev->interface);
90 libusb_close(dev->dev);
91 dev->dev = NULL;
92 collection_remove(&device_list, dev);
93 free(dev);
94}
95
96static void tx_callback(struct libusb_transfer *xfer)
97{
98 struct usb_device *dev = xfer->user_data;
99 usbmuxd_log(LL_SPEW, "TX callback dev %d-%d len %d -> %d status %d", dev->bus, dev->address, xfer->length, xfer->actual_length, xfer->status);
100 if(xfer->status != LIBUSB_TRANSFER_COMPLETED) {
101 switch(xfer->status) {
102 case LIBUSB_TRANSFER_COMPLETED: //shut up compiler
103 case LIBUSB_TRANSFER_ERROR:
104 // funny, this happens when we disconnect the device while waiting for a transfer, sometimes
105 usbmuxd_log(LL_INFO, "Device %d-%d TX aborted due to error or disconnect", dev->bus, dev->address);
106 break;
107 case LIBUSB_TRANSFER_TIMED_OUT:
108 usbmuxd_log(LL_ERROR, "TX transfer timed out for device %d-%d", dev->bus, dev->address);
109 break;
110 case LIBUSB_TRANSFER_CANCELLED:
111 usbmuxd_log(LL_DEBUG, "Device %d-%d TX transfer cancelled", dev->bus, dev->address);
112 break;
113 case LIBUSB_TRANSFER_STALL:
114 usbmuxd_log(LL_ERROR, "TX transfer stalled for device %d-%d", dev->bus, dev->address);
115 break;
116 case LIBUSB_TRANSFER_NO_DEVICE:
117 // other times, this happens, and also even when we abort the transfer after device removal
118 usbmuxd_log(LL_INFO, "Device %d-%d TX aborted due to disconnect", dev->bus, dev->address);
119 break;
120 case LIBUSB_TRANSFER_OVERFLOW:
121 usbmuxd_log(LL_ERROR, "TX transfer overflow for device %d-%d", dev->bus, dev->address);
122 break;
123 // and nothing happens (this never gets called) if the device is freed after a disconnect! (bad)
124 }
125 // we can't usb_disconnect here due to a deadlock, so instead mark it as dead and reap it after processing events
126 // we'll do device_remove there too
127 dev->alive = 0;
128 }
129 if(xfer->buffer)
130 free(xfer->buffer);
131 collection_remove(&dev->tx_xfers, xfer);
132 libusb_free_transfer(xfer);
133}
134
135int usb_send(struct usb_device *dev, const unsigned char *buf, int length)
136{
137 int res;
138 struct libusb_transfer *xfer = libusb_alloc_transfer(0);
139 libusb_fill_bulk_transfer(xfer, dev->dev, dev->ep_out, (void*)buf, length, tx_callback, dev, 0);
140 if((res = libusb_submit_transfer(xfer)) < 0) {
141 usbmuxd_log(LL_ERROR, "Failed to submit TX transfer %p len %d to device %d-%d: %d", buf, length, dev->bus, dev->address, res);
142 libusb_free_transfer(xfer);
143 return res;
144 }
145 collection_add(&dev->tx_xfers, xfer);
146 if (length % dev->wMaxPacketSize == 0) {
147 usbmuxd_log(LL_DEBUG, "Send ZLP");
148 // Send Zero Length Packet
149 xfer = libusb_alloc_transfer(0);
150 void *buffer = malloc(1);
151 libusb_fill_bulk_transfer(xfer, dev->dev, dev->ep_out, buffer, 0, tx_callback, dev, 0);
152 if((res = libusb_submit_transfer(xfer)) < 0) {
153 usbmuxd_log(LL_ERROR, "Failed to submit TX ZLP transfer to device %d-%d: %d", dev->bus, dev->address, res);
154 libusb_free_transfer(xfer);
155 return res;
156 }
157 collection_add(&dev->tx_xfers, xfer);
158 }
159 return 0;
160}
161
162static void rx_callback(struct libusb_transfer *xfer)
163{
164 struct usb_device *dev = xfer->user_data;
165 usbmuxd_log(LL_SPEW, "RX callback dev %d-%d len %d status %d", dev->bus, dev->address, xfer->actual_length, xfer->status);
166 if(xfer->status == LIBUSB_TRANSFER_COMPLETED) {
167 device_data_input(dev, xfer->buffer, xfer->actual_length);
168 libusb_submit_transfer(xfer);
169 } else {
170 switch(xfer->status) {
171 case LIBUSB_TRANSFER_COMPLETED: //shut up compiler
172 case LIBUSB_TRANSFER_ERROR:
173 // funny, this happens when we disconnect the device while waiting for a transfer, sometimes
174 usbmuxd_log(LL_INFO, "Device %d-%d RX aborted due to error or disconnect", dev->bus, dev->address);
175 break;
176 case LIBUSB_TRANSFER_TIMED_OUT:
177 usbmuxd_log(LL_ERROR, "RX transfer timed out for device %d-%d", dev->bus, dev->address);
178 break;
179 case LIBUSB_TRANSFER_CANCELLED:
180 usbmuxd_log(LL_DEBUG, "Device %d-%d RX transfer cancelled", dev->bus, dev->address);
181 break;
182 case LIBUSB_TRANSFER_STALL:
183 usbmuxd_log(LL_ERROR, "RX transfer stalled for device %d-%d", dev->bus, dev->address);
184 break;
185 case LIBUSB_TRANSFER_NO_DEVICE:
186 // other times, this happens, and also even when we abort the transfer after device removal
187 usbmuxd_log(LL_INFO, "Device %d-%d RX aborted due to disconnect", dev->bus, dev->address);
188 break;
189 case LIBUSB_TRANSFER_OVERFLOW:
190 usbmuxd_log(LL_ERROR, "RX transfer overflow for device %d-%d", dev->bus, dev->address);
191 break;
192 // and nothing happens (this never gets called) if the device is freed after a disconnect! (bad)
193 }
194 free(xfer->buffer);
195 dev->rx_xfer = NULL;
196 libusb_free_transfer(xfer);
197 // we can't usb_disconnect here due to a deadlock, so instead mark it as dead and reap it after processing events
198 // we'll do device_remove there too
199 dev->alive = 0;
200 }
201}
202
203static int start_rx(struct usb_device *dev)
204{
205 int res;
206 void *buf;
207 dev->rx_xfer = libusb_alloc_transfer(0);
208 buf = malloc(USB_MRU);
209 libusb_fill_bulk_transfer(dev->rx_xfer, dev->dev, dev->ep_in, buf, USB_MRU, rx_callback, dev, 0);
210 if((res = libusb_submit_transfer(dev->rx_xfer)) != 0) {
211 usbmuxd_log(LL_ERROR, "Failed to submit RX transfer to device %d-%d: %d", dev->bus, dev->address, res);
212 libusb_free_transfer(dev->rx_xfer);
213 dev->rx_xfer = NULL;
214 return res;
215 }
216 return 0;
217}
218
219int usb_discover(void)
220{
221 int cnt, i, j, res;
222 int valid_count = 0;
223 libusb_device **devs;
224
225 cnt = libusb_get_device_list(NULL, &devs);
226 if(cnt < 0) {
227 usbmuxd_log(LL_WARNING, "Could not get device list: %d", cnt);
228 devlist_failures++;
229 // sometimes libusb fails getting the device list if you've just removed something
230 if(devlist_failures > 5) {
231 usbmuxd_log(LL_FATAL, "Too many errors getting device list\n");
232 return cnt;
233 } else {
234 gettimeofday(&next_dev_poll_time, NULL);
235 next_dev_poll_time.tv_usec += DEVICE_POLL_TIME * 1000;
236 next_dev_poll_time.tv_sec += next_dev_poll_time.tv_usec / 1000000;
237 next_dev_poll_time.tv_usec = next_dev_poll_time.tv_usec % 1000000;
238 return 0;
239 }
240 }
241 devlist_failures = 0;
242
243 usbmuxd_log(LL_SPEW, "usb_discover: scanning %d devices", cnt);
244
245 FOREACH(struct usb_device *usbdev, &device_list) {
246 usbdev->alive = 0;
247 } ENDFOREACH
248
249 for(i=0; i<cnt; i++) {
250 // the following are non-blocking operations on the device list
251 libusb_device *dev = devs[i];
252 uint8_t bus = libusb_get_bus_number(dev);
253 uint8_t address = libusb_get_device_address(dev);
254 struct libusb_device_descriptor devdesc;
255 int found = 0;
256 FOREACH(struct usb_device *usbdev, &device_list) {
257 if(usbdev->bus == bus && usbdev->address == address) {
258 valid_count++;
259 usbdev->alive = 1;
260 found = 1;
261 break;
262 }
263 } ENDFOREACH
264 if(found)
265 continue; //device already found
266 if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) {
267 usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %d", bus, address, res);
268 continue;
269 }
270 if(devdesc.idVendor != VID_APPLE)
271 continue;
272 if((devdesc.idProduct < PID_RANGE_LOW) ||
273 (devdesc.idProduct > PID_RANGE_MAX))
274 continue;
275 libusb_device_handle *handle;
276 usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address);
277 // potentially blocking operations follow; they will only run when new devices are detected, which is acceptable
278 if((res = libusb_open(dev, &handle)) != 0) {
279 usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %d", bus, address, res);
280 continue;
281 }
282 int current_config = 0;
283 if((res = libusb_get_configuration(handle, &current_config)) != 0) {
284 usbmuxd_log(LL_WARNING, "Could not get configuration for device %d-%d: %d", bus, address, res);
285 libusb_close(handle);
286 continue;
287 }
288 if (current_config != devdesc.bNumConfigurations) {
289 struct libusb_config_descriptor *config;
290 if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) {
291 usbmuxd_log(LL_NOTICE, "Could not get old configuration descriptor for device %d-%d: %d", bus, address, res);
292 } else {
293 for(j=0; j<config->bNumInterfaces; j++) {
294 const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0];
295 if((res = libusb_kernel_driver_active(handle, intf->bInterfaceNumber)) < 0) {
296 usbmuxd_log(LL_NOTICE, "Could not check kernel ownership of interface %d for device %d-%d: %d", intf->bInterfaceNumber, bus, address, res);
297 continue;
298 }
299 if(res == 1) {
300 usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf->bInterfaceNumber);
301 if((res = libusb_detach_kernel_driver(handle, intf->bInterfaceNumber)) < 0) {
302 usbmuxd_log(LL_WARNING, "Could not detach kernel driver (%d), configuration change will probably fail!", res);
303 continue;
304 }
305 }
306 }
307 libusb_free_config_descriptor(config);
308 }
309 if((res = libusb_set_configuration(handle, devdesc.bNumConfigurations)) != 0) {
310 usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %d", devdesc.bNumConfigurations, bus, address, res);
311 libusb_close(handle);
312 continue;
313 }
314 }
315
316 struct libusb_config_descriptor *config;
317 if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) {
318 usbmuxd_log(LL_WARNING, "Could not get configuration descriptor for device %d-%d: %d", bus, address, res);
319 libusb_close(handle);
320 continue;
321 }
322
323 struct usb_device *usbdev;
324 usbdev = malloc(sizeof(struct usb_device));
325 memset(usbdev, 0, sizeof(*usbdev));
326
327 for(j=0; j<config->bNumInterfaces; j++) {
328 const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0];
329 if(intf->bInterfaceClass != INTERFACE_CLASS ||
330 intf->bInterfaceSubClass != INTERFACE_SUBCLASS ||
331 intf->bInterfaceProtocol != INTERFACE_PROTOCOL)
332 continue;
333 if(intf->bNumEndpoints != 2) {
334 usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address);
335 continue;
336 }
337 if((intf->endpoint[0].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_OUT ||
338 (intf->endpoint[1].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_IN) {
339 usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address);
340 continue;
341 }
342 usbdev->interface = intf->bInterfaceNumber;
343 usbdev->ep_out = intf->endpoint[0].bEndpointAddress;
344 usbdev->ep_in = intf->endpoint[1].bEndpointAddress;
345 usbmuxd_log(LL_INFO, "Found interface %d with endpoints %02x/%02x for device %d-%d", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address);
346 break;
347 }
348 libusb_free_config_descriptor(config);
349
350 if(j == config->bNumInterfaces) {
351 usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %d-%d", bus, address);
352 libusb_close(handle);
353 free(usbdev);
354 continue;
355 }
356
357 if((res = libusb_claim_interface(handle, usbdev->interface)) != 0) {
358 usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %d", usbdev->interface, bus, address, res);
359 libusb_close(handle);
360 free(usbdev);
361 continue;
362 }
363
364 if((res = libusb_get_string_descriptor_ascii(handle, devdesc.iSerialNumber, (uint8_t *)usbdev->serial, 256)) <= 0) {
365 usbmuxd_log(LL_WARNING, "Could not get serial number for device %d-%d: %d", bus, address, res);
366 libusb_release_interface(handle, usbdev->interface);
367 libusb_close(handle);
368 free(usbdev);
369 continue;
370 }
371 usbdev->serial[res] = 0;
372 usbdev->bus = bus;
373 usbdev->address = address;
374 usbdev->vid = devdesc.idVendor;
375 usbdev->pid = devdesc.idProduct;
376 usbdev->dev = handle;
377 usbdev->alive = 1;
378 usbdev->wMaxPacketSize = libusb_get_max_packet_size(dev, usbdev->ep_out);
379 if (usbdev->wMaxPacketSize <= 0) {
380 usbmuxd_log(LL_ERROR, "Could not determine wMaxPacketSize for device %d-%d, setting to 64", usbdev->bus, usbdev->address);
381 usbdev->wMaxPacketSize = 64;
382 } else {
383 usbmuxd_log(LL_INFO, "Using wMaxPacketSize=%d for device %d-%d", usbdev->wMaxPacketSize, usbdev->bus, usbdev->address);
384 }
385
386 collection_init(&usbdev->tx_xfers);
387
388 collection_add(&device_list, usbdev);
389
390 if(device_add(usbdev) < 0) {
391 usb_disconnect(usbdev);
392 continue;
393 }
394 if(start_rx(usbdev) < 0) {
395 device_remove(usbdev);
396 usb_disconnect(usbdev);
397 continue;
398 }
399 valid_count++;
400 }
401 FOREACH(struct usb_device *usbdev, &device_list) {
402 if(!usbdev->alive) {
403 device_remove(usbdev);
404 usb_disconnect(usbdev);
405 }
406 } ENDFOREACH
407
408 libusb_free_device_list(devs, 1);
409
410 gettimeofday(&next_dev_poll_time, NULL);
411 next_dev_poll_time.tv_usec += DEVICE_POLL_TIME * 1000;
412 next_dev_poll_time.tv_sec += next_dev_poll_time.tv_usec / 1000000;
413 next_dev_poll_time.tv_usec = next_dev_poll_time.tv_usec % 1000000;
414
415 return valid_count;
416}
417
418const char *usb_get_serial(struct usb_device *dev)
419{
420 if(!dev->dev) {
421 return NULL;
422 }
423 return dev->serial;
424}
425
426uint32_t usb_get_location(struct usb_device *dev)
427{
428 if(!dev->dev) {
429 return 0;
430 }
431 return (dev->bus << 16) | dev->address;
432}
433
434uint16_t usb_get_pid(struct usb_device *dev)
435{
436 if(!dev->dev) {
437 return 0;
438 }
439 return dev->pid;
440}
441
442void usb_get_fds(struct fdlist *list)
443{
444 const struct libusb_pollfd **usbfds;
445 const struct libusb_pollfd **p;
446 usbfds = libusb_get_pollfds(NULL);
447 if(!usbfds) {
448 usbmuxd_log(LL_ERROR, "libusb_get_pollfds failed");
449 return;
450 }
451 p = usbfds;
452 while(*p) {
453 fdlist_add(list, FD_USB, (*p)->fd, (*p)->events);
454 p++;
455 }
456 free(usbfds);
457}
458
459void usb_autodiscover(int enable)
460{
461 usbmuxd_log(LL_DEBUG, "usb polling enable: %d", enable);
462 device_polling = enable;
463}
464
465static int dev_poll_remain_ms(void)
466{
467 int msecs;
468 struct timeval tv;
469 if(!device_polling)
470 return 100000; // devices will never be polled if this is > 0
471 gettimeofday(&tv, NULL);
472 msecs = (next_dev_poll_time.tv_sec - tv.tv_sec) * 1000;
473 msecs += (next_dev_poll_time.tv_usec - tv.tv_usec) / 1000;
474 if(msecs < 0)
475 return 0;
476 return msecs;
477}
478
479int usb_get_timeout(void)
480{
481 struct timeval tv;
482 int msec;
483 int res;
484 int pollrem;
485 pollrem = dev_poll_remain_ms();
486 res = libusb_get_next_timeout(NULL, &tv);
487 if(res == 0)
488 return pollrem;
489 if(res < 0) {
490 usbmuxd_log(LL_ERROR, "libusb_get_next_timeout failed: %d", res);
491 return pollrem;
492 }
493 msec = tv.tv_sec * 1000;
494 msec += tv.tv_usec / 1000;
495 if(msec > pollrem)
496 return pollrem;
497 return msec;
498}
499
500int usb_process(void)
501{
502 int res;
503 struct timeval tv;
504 tv.tv_sec = tv.tv_usec = 0;
505 res = libusb_handle_events_timeout(NULL, &tv);
506 if(res < 0) {
507 usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %d", res);
508 return res;
509 }
510 // reap devices marked dead due to an RX error
511 FOREACH(struct usb_device *usbdev, &device_list) {
512 if(!usbdev->alive) {
513 device_remove(usbdev);
514 usb_disconnect(usbdev);
515 }
516 } ENDFOREACH
517
518 if(dev_poll_remain_ms() <= 0) {
519 res = usb_discover();
520 if(res < 0) {
521 usbmuxd_log(LL_ERROR, "usb_discover failed: %d", res);
522 return res;
523 }
524 }
525 return 0;
526}
527
528int usb_process_timeout(int msec)
529{
530 int res;
531 struct timeval tleft, tcur, tfin;
532 gettimeofday(&tcur, NULL);
533 tfin.tv_sec = tcur.tv_sec + (msec / 1000);
534 tfin.tv_usec = tcur.tv_usec + (msec % 1000) * 1000;
535 tfin.tv_sec += tfin.tv_usec / 1000000;
536 tfin.tv_usec %= 1000000;
537 while((tfin.tv_sec > tcur.tv_sec) || ((tfin.tv_sec == tcur.tv_sec) && (tfin.tv_usec > tcur.tv_usec))) {
538 tleft.tv_sec = tfin.tv_sec - tcur.tv_sec;
539 tleft.tv_usec = tfin.tv_usec - tcur.tv_usec;
540 if(tleft.tv_usec < 0) {
541 tleft.tv_usec += 1000000;
542 tleft.tv_sec -= 1;
543 }
544 res = libusb_handle_events_timeout(NULL, &tleft);
545 if(res < 0) {
546 usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %d", res);
547 return res;
548 }
549 // reap devices marked dead due to an RX error
550 FOREACH(struct usb_device *usbdev, &device_list) {
551 if(!usbdev->alive) {
552 device_remove(usbdev);
553 usb_disconnect(usbdev);
554 }
555 } ENDFOREACH
556 gettimeofday(&tcur, NULL);
557 }
558 return 0;
559}
560
561int usb_init(void)
562{
563 int res;
564 usbmuxd_log(LL_DEBUG, "usb_init for linux / libusb 1.0");
565
566 devlist_failures = 0;
567 device_polling = 1;
568 res = libusb_init(NULL);
569 //libusb_set_debug(NULL, 3);
570 if(res != 0) {
571 usbmuxd_log(LL_FATAL, "libusb_init failed: %d", res);
572 return -1;
573 }
574
575 collection_init(&device_list);
576
577 return usb_discover();
578}
579
580void usb_shutdown(void)
581{
582 usbmuxd_log(LL_DEBUG, "usb_shutdown");
583 FOREACH(struct usb_device *usbdev, &device_list) {
584 device_remove(usbdev);
585 usb_disconnect(usbdev);
586 } ENDFOREACH
587 collection_free(&device_list);
588 libusb_exit(NULL);
589}
diff --git a/daemon/usb.h b/daemon/usb.h
deleted file mode 100644
index 9884d7f..0000000
--- a/daemon/usb.h
+++ /dev/null
@@ -1,66 +0,0 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
6Copyright (C) 2009 Martin Szulecki <opensuse@sukimashita.com>
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 2 or version 3.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
21*/
22
23#ifndef __USB_H__
24#define __USB_H__
25
26#include <stdint.h>
27#include "utils.h"
28
29#define INTERFACE_CLASS 255
30#define INTERFACE_SUBCLASS 254
31#define INTERFACE_PROTOCOL 2
32
33// libusb fragments packets larger than this (usbfs limitation)
34// on input, this creates race conditions and other issues
35#define USB_MRU 16384
36
37// max transmission packet size
38// libusb fragments these too, but doesn't send ZLPs so we're safe
39// but we need to send a ZLP ourselves at the end (see usb-linux.c)
40// we're using 3 * 16384 to optimize for the fragmentation
41// this results in three URBs per full transfer, 32 USB packets each
42// if there are ZLP issues this should make them show up easily too
43#define USB_MTU (3 * 16384)
44
45#define USB_PACKET_SIZE 512
46
47#define VID_APPLE 0x5ac
48#define PID_RANGE_LOW 0x1290
49#define PID_RANGE_MAX 0x129f
50
51struct usb_device;
52
53int usb_init(void);
54void usb_shutdown(void);
55const char *usb_get_serial(struct usb_device *dev);
56uint32_t usb_get_location(struct usb_device *dev);
57uint16_t usb_get_pid(struct usb_device *dev);
58void usb_get_fds(struct fdlist *list);
59int usb_get_timeout(void);
60int usb_send(struct usb_device *dev, const unsigned char *buf, int length);
61int usb_discover(void);
62void usb_autodiscover(int enable);
63int usb_process(void);
64int usb_process_timeout(int msec);
65
66#endif