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