summaryrefslogtreecommitdiffstats
path: root/src/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/client.c')
-rw-r--r--src/client.c1058
1 files changed, 1058 insertions, 0 deletions
diff --git a/src/client.c b/src/client.c
new file mode 100644
index 0000000..dbbdd5f
--- /dev/null
+++ b/src/client.c
@@ -0,0 +1,1058 @@
1/*
2 * client.c
3 *
4 * Copyright (C) 2009 Hector Martin <hector@marcansoft.com>
5 * Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 or version 3.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#define _GNU_SOURCE 1
26
27#include <stdlib.h>
28#include <string.h>
29#include <stdio.h>
30#include <errno.h>
31#include <unistd.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <netinet/in.h>
35#include <netinet/tcp.h>
36#include <sys/un.h>
37#include <arpa/inet.h>
38#include <fcntl.h>
39
40#include <plist/plist.h>
41#include <libimobiledevice-glue/collection.h>
42#include <libimobiledevice-glue/thread.h>
43
44#include "log.h"
45#include "usb.h"
46#include "client.h"
47#include "device.h"
48#include "conf.h"
49
50#define CMD_BUF_SIZE 0x10000
51#define REPLY_BUF_SIZE 0x10000
52
53enum client_state {
54 CLIENT_COMMAND, // waiting for command
55 CLIENT_LISTEN, // listening for devices
56 CLIENT_CONNECTING1, // issued connection request
57 CLIENT_CONNECTING2, // connection established, but waiting for response message to get sent
58 CLIENT_CONNECTED, // connected
59 CLIENT_DEAD
60};
61
62struct mux_client {
63 int fd;
64 unsigned char *ob_buf;
65 uint32_t ob_size;
66 uint32_t ob_capacity;
67 unsigned char *ib_buf;
68 uint32_t ib_size;
69 uint32_t ib_capacity;
70 short events, devents;
71 uint32_t connect_tag;
72 int connect_device;
73 enum client_state state;
74 uint32_t proto_version;
75 uint32_t number;
76 plist_t info;
77};
78
79static struct collection client_list;
80mutex_t client_list_mutex;
81static uint32_t client_number = 0;
82
83#ifdef SO_PEERCRED
84static char* _get_process_name_by_pid(const int pid)
85{
86 char* name = (char*)calloc(1024, sizeof(char));
87 if(name) {
88 sprintf(name, "/proc/%d/cmdline", pid);
89 FILE* f = fopen(name, "r");
90 if(f) {
91 size_t size;
92 size = fread(name, sizeof(char), 1024, f);
93 if(size > 0) {
94 if('\n' == name[size-1])
95 name[size-1]='\0';
96 }
97 fclose(f);
98 }
99 }
100 return name;
101}
102#endif
103
104/**
105 * Receive raw data from the client socket.
106 *
107 * @param client Client to read from.
108 * @param buffer Buffer to store incoming data.
109 * @param len Max number of bytes to read.
110 * @return Same as recv() system call. Number of bytes read; when < 0 errno will be set.
111 */
112int client_read(struct mux_client *client, void *buffer, uint32_t len)
113{
114 usbmuxd_log(LL_SPEW, "client_read fd %d buf %p len %d", client->fd, buffer, len);
115 if(client->state != CLIENT_CONNECTED) {
116 usbmuxd_log(LL_ERROR, "Attempted to read from client %d not in CONNECTED state", client->fd);
117 return -1;
118 }
119 return recv(client->fd, buffer, len, 0);
120}
121
122/**
123 * Send raw data to the client socket.
124 *
125 * @param client Client to send to.
126 * @param buffer The data to send.
127 * @param len Number of bytes to write.
128 * @return Same as system call send(). Number of bytes written; when < 0 errno will be set.
129 */
130int client_write(struct mux_client *client, void *buffer, uint32_t len)
131{
132 int sret = -1;
133
134 usbmuxd_log(LL_SPEW, "client_write fd %d buf %p len %d", client->fd, buffer, len);
135 if(client->state != CLIENT_CONNECTED) {
136 usbmuxd_log(LL_ERROR, "Attempted to write to client %d not in CONNECTED state", client->fd);
137 return -1;
138 }
139
140 sret = send(client->fd, buffer, len, 0);
141 if (sret < 0) {
142 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
143 usbmuxd_log(LL_DEBUG, "client_write: fd %d not ready for writing", client->fd);
144 sret = 0;
145 } else {
146 usbmuxd_log(LL_ERROR, "ERROR: client_write: sending to fd %d failed: %s", client->fd, strerror(errno));
147 }
148 }
149 return sret;
150}
151
152/**
153 * Set event mask to use for ppoll()ing the client socket.
154 * Typically POLLOUT and/or POLLIN. Note that this overrides
155 * the current mask, that is, it is not ORing the argument
156 * into the current mask.
157 *
158 * @param client The client to set the event mask on.
159 * @param events The event mask to sert.
160 * @return 0 on success, -1 on error.
161 */
162int client_set_events(struct mux_client *client, short events)
163{
164 if((client->state != CLIENT_CONNECTED) && (client->state != CLIENT_CONNECTING2)) {
165 usbmuxd_log(LL_ERROR, "client_set_events to client %d not in CONNECTED state", client->fd);
166 return -1;
167 }
168 client->devents = events;
169 if(client->state == CLIENT_CONNECTED)
170 client->events = events;
171 return 0;
172}
173
174/**
175 * Wait for an inbound connection on the usbmuxd socket
176 * and create a new mux_client instance for it, and store
177 * the client in the client list.
178 *
179 * @param listenfd the socket fd to accept() on.
180 * @return The connection fd for the client, or < 0 for error
181 * in which case errno will be set.
182 */
183int client_accept(int listenfd)
184{
185 struct sockaddr_un addr;
186 int cfd;
187 socklen_t len = sizeof(struct sockaddr_un);
188 cfd = accept(listenfd, (struct sockaddr *)&addr, &len);
189 if (cfd < 0) {
190 usbmuxd_log(LL_ERROR, "accept() failed (%s)", strerror(errno));
191 return cfd;
192 }
193
194 int flags = fcntl(cfd, F_GETFL, 0);
195 if (flags < 0) {
196 usbmuxd_log(LL_ERROR, "ERROR: Could not get socket flags!");
197 } else {
198 if (fcntl(cfd, F_SETFL, flags | O_NONBLOCK) < 0) {
199 usbmuxd_log(LL_ERROR, "ERROR: Could not set socket to non-blocking mode");
200 }
201 }
202
203 int bufsize = 0x20000;
204 if (setsockopt(cfd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(int)) == -1) {
205 usbmuxd_log(LL_WARNING, "Could not set send buffer for client socket");
206 }
207 if (setsockopt(cfd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(int)) == -1) {
208 usbmuxd_log(LL_WARNING, "Could not set receive buffer for client socket");
209 }
210
211 int yes = 1;
212 setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int));
213
214 struct mux_client *client;
215 client = malloc(sizeof(struct mux_client));
216 memset(client, 0, sizeof(struct mux_client));
217
218 client->fd = cfd;
219 client->ob_buf = malloc(REPLY_BUF_SIZE);
220 client->ob_size = 0;
221 client->ob_capacity = REPLY_BUF_SIZE;
222 client->ib_buf = malloc(CMD_BUF_SIZE);
223 client->ib_size = 0;
224 client->ib_capacity = CMD_BUF_SIZE;
225 client->state = CLIENT_COMMAND;
226 client->events = POLLIN;
227 client->info = NULL;
228
229 mutex_lock(&client_list_mutex);
230 client->number = client_number++;
231 collection_add(&client_list, client);
232 mutex_unlock(&client_list_mutex);
233
234#ifdef SO_PEERCRED
235 if (log_level >= LL_INFO) {
236 struct ucred cr;
237 len = sizeof(struct ucred);
238 getsockopt(client->fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
239
240 if (getpid() == cr.pid) {
241 usbmuxd_log(LL_INFO, "Client %d accepted: %s[%d]", client->fd, PACKAGE_NAME, cr.pid);
242 } else {
243 char* process_name = _get_process_name_by_pid(cr.pid);
244 usbmuxd_log(LL_INFO, "Client %d accepted: %s[%d]", client->fd, process_name, cr.pid);
245 free(process_name);
246 }
247 }
248#else
249 usbmuxd_log(LL_INFO, "Client %d accepted", client->fd);
250#endif
251 return client->fd;
252}
253
254void client_close(struct mux_client *client)
255{
256 int found = 0;
257 mutex_lock(&client_list_mutex);
258 FOREACH(struct mux_client *lc, &client_list) {
259 if (client == lc) {
260 found = 1;
261 break;
262 }
263 } ENDFOREACH
264 if (!found) {
265 // in case we get called again but client was already freed
266 usbmuxd_log(LL_DEBUG, "%s: ignoring for non-existing client %p", __func__, client);
267 mutex_unlock(&client_list_mutex);
268 return;
269 }
270#ifdef SO_PEERCRED
271 if (log_level >= LL_INFO) {
272 struct ucred cr;
273 socklen_t len = sizeof(struct ucred);
274 getsockopt(client->fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
275
276 if (getpid() == cr.pid) {
277 usbmuxd_log(LL_INFO, "Client %d is going to be disconnected: %s[%d]", client->fd, PACKAGE_NAME, cr.pid);
278 } else {
279 char* process_name = _get_process_name_by_pid(cr.pid);
280 usbmuxd_log(LL_INFO, "Client %d is going to be disconnected: %s[%d]", client->fd, process_name, cr.pid);
281 free(process_name);
282 }
283 }
284#else
285 usbmuxd_log(LL_INFO, "Client %d is going to be disconnected", client->fd);
286#endif
287 if(client->state == CLIENT_CONNECTING1 || client->state == CLIENT_CONNECTING2) {
288 usbmuxd_log(LL_INFO, "Client died mid-connect, aborting device %d connection", client->connect_device);
289 client->state = CLIENT_DEAD;
290 device_abort_connect(client->connect_device, client);
291 }
292 close(client->fd);
293 free(client->ob_buf);
294 free(client->ib_buf);
295 plist_free(client->info);
296
297 collection_remove(&client_list, client);
298 mutex_unlock(&client_list_mutex);
299 free(client);
300}
301
302void client_get_fds(struct fdlist *list)
303{
304 mutex_lock(&client_list_mutex);
305 FOREACH(struct mux_client *client, &client_list) {
306 fdlist_add(list, FD_CLIENT, client->fd, client->events);
307 } ENDFOREACH
308 mutex_unlock(&client_list_mutex);
309}
310
311static int output_buffer_add_message(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtype msg, void *payload, int payload_length)
312{
313 struct usbmuxd_header hdr;
314 hdr.version = client->proto_version;
315 hdr.length = sizeof(hdr) + payload_length;
316 hdr.message = msg;
317 hdr.tag = tag;
318 usbmuxd_log(LL_DEBUG, "Client %d output buffer got tag %d msg %d payload_length %d", client->fd, tag, msg, payload_length);
319
320 uint32_t available = client->ob_capacity - client->ob_size;
321 /* the output buffer _should_ be large enough, but just in case */
322 if(available < hdr.length) {
323 unsigned char* new_buf;
324 uint32_t new_size = ((client->ob_capacity + hdr.length + 4096) / 4096) * 4096;
325 usbmuxd_log(LL_DEBUG, "%s: Enlarging client %d output buffer %d -> %d", __func__, client->fd, client->ob_capacity, new_size);
326 new_buf = realloc(client->ob_buf, new_size);
327 if (!new_buf) {
328 usbmuxd_log(LL_FATAL, "%s: Failed to realloc.", __func__);
329 return -1;
330 }
331 client->ob_buf = new_buf;
332 client->ob_capacity = new_size;
333 }
334 memcpy(client->ob_buf + client->ob_size, &hdr, sizeof(hdr));
335 if(payload && payload_length)
336 memcpy(client->ob_buf + client->ob_size + sizeof(hdr), payload, payload_length);
337 client->ob_size += hdr.length;
338 client->events |= POLLOUT;
339 return hdr.length;
340}
341
342static int send_plist(struct mux_client *client, uint32_t tag, plist_t plist)
343{
344 int res = -1;
345 char *xml = NULL;
346 uint32_t xmlsize = 0;
347 plist_to_xml(plist, &xml, &xmlsize);
348 if (xml) {
349 res = output_buffer_add_message(client, tag, MESSAGE_PLIST, xml, xmlsize);
350 free(xml);
351 } else {
352 usbmuxd_log(LL_ERROR, "%s: Could not convert plist to xml", __func__);
353 }
354 return res;
355}
356
357static int send_result(struct mux_client *client, uint32_t tag, uint32_t result)
358{
359 int res = -1;
360 if (client->proto_version == 1) {
361 /* XML plist packet */
362 plist_t dict = plist_new_dict();
363 plist_dict_set_item(dict, "MessageType", plist_new_string("Result"));
364 plist_dict_set_item(dict, "Number", plist_new_uint(result));
365 res = send_plist(client, tag, dict);
366 plist_free(dict);
367 } else {
368 /* binary packet */
369 res = output_buffer_add_message(client, tag, MESSAGE_RESULT, &result, sizeof(uint32_t));
370 }
371 return res;
372}
373
374int client_notify_connect(struct mux_client *client, enum usbmuxd_result result)
375{
376 usbmuxd_log(LL_SPEW, "client_notify_connect fd %d result %d", client->fd, result);
377 if(client->state == CLIENT_DEAD)
378 return -1;
379 if(client->state != CLIENT_CONNECTING1) {
380 usbmuxd_log(LL_ERROR, "client_notify_connect when client %d is not in CONNECTING1 state", client->fd);
381 return -1;
382 }
383 if(send_result(client, client->connect_tag, result) < 0)
384 return -1;
385 if(result == RESULT_OK) {
386 client->state = CLIENT_CONNECTING2;
387 client->events = POLLOUT; // wait for the result packet to go through
388 // no longer need this
389 free(client->ib_buf);
390 client->ib_buf = NULL;
391 } else {
392 client->state = CLIENT_COMMAND;
393 }
394 return 0;
395}
396
397static plist_t create_device_attached_plist(struct device_info *dev)
398{
399 plist_t dict = plist_new_dict();
400 plist_dict_set_item(dict, "MessageType", plist_new_string("Attached"));
401 plist_dict_set_item(dict, "DeviceID", plist_new_uint(dev->id));
402 plist_t props = plist_new_dict();
403 plist_dict_set_item(props, "ConnectionSpeed", plist_new_uint(dev->speed));
404 plist_dict_set_item(props, "ConnectionType", plist_new_string("USB"));
405 plist_dict_set_item(props, "DeviceID", plist_new_uint(dev->id));
406 plist_dict_set_item(props, "LocationID", plist_new_uint(dev->location));
407 plist_dict_set_item(props, "ProductID", plist_new_uint(dev->pid));
408 plist_dict_set_item(props, "SerialNumber", plist_new_string(dev->serial));
409 plist_dict_set_item(dict, "Properties", props);
410 return dict;
411}
412
413static int send_device_list(struct mux_client *client, uint32_t tag)
414{
415 int res = -1;
416 plist_t dict = plist_new_dict();
417 plist_t devices = plist_new_array();
418
419 struct device_info *devs = NULL;
420 struct device_info *dev;
421 int i;
422
423 int count = device_get_list(0, &devs);
424 dev = devs;
425 for (i = 0; devs && i < count; i++) {
426 plist_t device = create_device_attached_plist(dev++);
427 if (device) {
428 plist_array_append_item(devices, device);
429 }
430 }
431 if (devs)
432 free(devs);
433
434 plist_dict_set_item(dict, "DeviceList", devices);
435 res = send_plist(client, tag, dict);
436 plist_free(dict);
437 return res;
438}
439
440static int send_listener_list(struct mux_client *client, uint32_t tag)
441{
442 int res = -1;
443
444 plist_t dict = plist_new_dict();
445 plist_t listeners = plist_new_array();
446
447 mutex_lock(&client_list_mutex);
448 FOREACH(struct mux_client *lc, &client_list) {
449 if (lc->state == CLIENT_LISTEN) {
450 plist_t n = NULL;
451 plist_t l = plist_new_dict();
452 plist_dict_set_item(l, "Blacklisted", plist_new_bool(0));
453 n = NULL;
454 if (lc->info) {
455 n = plist_dict_get_item(lc->info, "BundleID");
456 }
457 if (n) {
458 plist_dict_set_item(l, "BundleID", plist_copy(n));
459 }
460 plist_dict_set_item(l, "ConnType", plist_new_uint(0));
461
462 n = NULL;
463 char *progname = NULL;
464 if (lc->info) {
465 n = plist_dict_get_item(lc->info, "ProgName");
466 }
467 if (n) {
468 plist_get_string_val(n, &progname);
469 }
470 if (!progname) {
471 progname = strdup("unknown");
472 }
473 char *idstring = malloc(strlen(progname) + 12);
474 sprintf(idstring, "%u-%s", client->number, progname);
475
476 plist_dict_set_item(l, "ID String", plist_new_string(idstring));
477 free(idstring);
478 plist_dict_set_item(l, "ProgName", plist_new_string(progname));
479 free(progname);
480
481 n = NULL;
482 uint64_t version = 0;
483 if (lc->info) {
484 n = plist_dict_get_item(lc->info, "kLibUSBMuxVersion");
485 }
486 if (n) {
487 plist_get_uint_val(n, &version);
488 }
489 plist_dict_set_item(l, "kLibUSBMuxVersion", plist_new_uint(version));
490
491 plist_array_append_item(listeners, l);
492 }
493 } ENDFOREACH
494 mutex_unlock(&client_list_mutex);
495
496 plist_dict_set_item(dict, "ListenerList", listeners);
497 res = send_plist(client, tag, dict);
498 plist_free(dict);
499
500 return res;
501}
502
503static int send_system_buid(struct mux_client *client, uint32_t tag)
504{
505 int res = -1;
506 char* buid = NULL;
507
508 config_get_system_buid(&buid);
509
510 plist_t dict = plist_new_dict();
511 plist_dict_set_item(dict, "BUID", plist_new_string(buid));
512 free(buid);
513 res = send_plist(client, tag, dict);
514 plist_free(dict);
515 return res;
516}
517
518static int send_pair_record(struct mux_client *client, uint32_t tag, const char* record_id)
519{
520 int res = -1;
521 char* record_data = NULL;
522 uint64_t record_size = 0;
523
524 if (!record_id) {
525 return send_result(client, tag, EINVAL);
526 }
527
528 config_get_device_record(record_id, &record_data, &record_size);
529
530 if (record_data) {
531 plist_t dict = plist_new_dict();
532 plist_dict_set_item(dict, "PairRecordData", plist_new_data(record_data, record_size));
533 free(record_data);
534 res = send_plist(client, tag, dict);
535 plist_free(dict);
536 } else {
537 res = send_result(client, tag, ENOENT);
538 }
539 return res;
540}
541
542static int send_device_add(struct mux_client *client, struct device_info *dev)
543{
544 int res = -1;
545 if (client->proto_version == 1) {
546 /* XML plist packet */
547 plist_t dict = create_device_attached_plist(dev);
548 res = send_plist(client, 0, dict);
549 plist_free(dict);
550 } else {
551 /* binary packet */
552 struct usbmuxd_device_record dmsg;
553 memset(&dmsg, 0, sizeof(dmsg));
554 dmsg.device_id = dev->id;
555 strncpy(dmsg.serial_number, dev->serial, 256);
556 dmsg.serial_number[255] = 0;
557 dmsg.location = dev->location;
558 dmsg.product_id = dev->pid;
559 res = output_buffer_add_message(client, 0, MESSAGE_DEVICE_ADD, &dmsg, sizeof(dmsg));
560 }
561 return res;
562}
563
564static int send_device_remove(struct mux_client *client, uint32_t device_id)
565{
566 int res = -1;
567 if (client->proto_version == 1) {
568 /* XML plist packet */
569 plist_t dict = plist_new_dict();
570 plist_dict_set_item(dict, "MessageType", plist_new_string("Detached"));
571 plist_dict_set_item(dict, "DeviceID", plist_new_uint(device_id));
572 res = send_plist(client, 0, dict);
573 plist_free(dict);
574 } else {
575 /* binary packet */
576 res = output_buffer_add_message(client, 0, MESSAGE_DEVICE_REMOVE, &device_id, sizeof(uint32_t));
577 }
578 return res;
579}
580
581static int send_device_paired(struct mux_client *client, uint32_t device_id)
582{
583 int res = -1;
584 if (client->proto_version == 1) {
585 /* XML plist packet */
586 plist_t dict = plist_new_dict();
587 plist_dict_set_item(dict, "MessageType", plist_new_string("Paired"));
588 plist_dict_set_item(dict, "DeviceID", plist_new_uint(device_id));
589 res = send_plist(client, 0, dict);
590 plist_free(dict);
591 }
592 else {
593 /* binary packet */
594 res = output_buffer_add_message(client, 0, MESSAGE_DEVICE_PAIRED, &device_id, sizeof(uint32_t));
595 }
596 return res;
597}
598
599static int start_listen(struct mux_client *client)
600{
601 struct device_info *devs = NULL;
602 struct device_info *dev;
603 int count, i;
604
605 client->state = CLIENT_LISTEN;
606
607 count = device_get_list(0, &devs);
608 dev = devs;
609 for(i=0; devs && i < count; i++) {
610 if(send_device_add(client, dev++) < 0) {
611 free(devs);
612 return -1;
613 }
614 }
615 if (devs)
616 free(devs);
617
618 return count;
619}
620
621static char* plist_dict_get_string_val(plist_t dict, const char* key)
622{
623 if (!dict || plist_get_node_type(dict) != PLIST_DICT)
624 return NULL;
625 plist_t item = plist_dict_get_item(dict, key);
626 if (!item || plist_get_node_type(item) != PLIST_STRING)
627 return NULL;
628 char *str = NULL;
629 plist_get_string_val(item, &str);
630 return str;
631}
632
633static void update_client_info(struct mux_client *client, plist_t dict)
634{
635 plist_t node = NULL;
636 plist_t info = plist_new_dict();
637
638 node = plist_dict_get_item(dict, "BundleID");
639 if (node && (plist_get_node_type(node) == PLIST_STRING)) {
640 plist_dict_set_item(info, "BundleID", plist_copy(node));
641 }
642
643 node = plist_dict_get_item(dict, "ClientVersionString");
644 if (node && (plist_get_node_type(node) == PLIST_STRING)) {
645 plist_dict_set_item(info, "ClientVersionString", plist_copy(node));
646 }
647
648 node = plist_dict_get_item(dict, "ProgName");
649 if (node && (plist_get_node_type(node) == PLIST_STRING)) {
650 plist_dict_set_item(info, "ProgName", plist_copy(node));
651 }
652
653 node = plist_dict_get_item(dict, "kLibUSBMuxVersion");
654 if (node && (plist_get_node_type(node) == PLIST_UINT)) {
655 plist_dict_set_item(info, "kLibUSBMuxVersion", plist_copy(node));
656 }
657 plist_free(client->info);
658 client->info = info;
659}
660
661static int handle_command(struct mux_client *client, struct usbmuxd_header *hdr)
662{
663 int res;
664 usbmuxd_log(LL_DEBUG, "Client %d command len %d ver %d msg %d tag %d", client->fd, hdr->length, hdr->version, hdr->message, hdr->tag);
665
666 if(client->state != CLIENT_COMMAND) {
667 usbmuxd_log(LL_ERROR, "Client %d command received in the wrong state, got %d but want %d", client->fd, client->state, CLIENT_COMMAND);
668 if(send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
669 return -1;
670 client_close(client);
671 return -1;
672 }
673
674 if((hdr->version != 0) && (hdr->version != 1)) {
675 usbmuxd_log(LL_INFO, "Client %d version mismatch: expected 0 or 1, got %d", client->fd, hdr->version);
676 send_result(client, hdr->tag, RESULT_BADVERSION);
677 return 0;
678 }
679
680 struct usbmuxd_connect_request *ch;
681 char *payload;
682 uint32_t payload_size;
683
684 switch(hdr->message) {
685 case MESSAGE_PLIST:
686 client->proto_version = 1;
687 payload = (char*)(hdr) + sizeof(struct usbmuxd_header);
688 payload_size = hdr->length - sizeof(struct usbmuxd_header);
689 plist_t dict = NULL;
690 plist_from_xml(payload, payload_size, &dict);
691 if (!dict) {
692 usbmuxd_log(LL_ERROR, "Could not parse plist from payload!");
693 return -1;
694 } else {
695 char *message = NULL;
696 plist_t node = plist_dict_get_item(dict, "MessageType");
697 if (!node || plist_get_node_type(node) != PLIST_STRING) {
698 usbmuxd_log(LL_ERROR, "Could not read valid MessageType node from plist!");
699 plist_free(dict);
700 return -1;
701 }
702 plist_get_string_val(node, &message);
703 if (!message) {
704 usbmuxd_log(LL_ERROR, "Could not extract MessageType from plist!");
705 plist_free(dict);
706 return -1;
707 }
708 update_client_info(client, dict);
709 if (!strcmp(message, "Listen")) {
710 free(message);
711 plist_free(dict);
712 if (send_result(client, hdr->tag, 0) < 0)
713 return -1;
714 usbmuxd_log(LL_DEBUG, "Client %d now LISTENING", client->fd);
715 return start_listen(client);
716 } else if (!strcmp(message, "Connect")) {
717 uint64_t val;
718 uint16_t portnum = 0;
719 uint32_t device_id = 0;
720 free(message);
721 // get device id
722 node = plist_dict_get_item(dict, "DeviceID");
723 if (!node) {
724 usbmuxd_log(LL_ERROR, "Received connect request without device_id!");
725 plist_free(dict);
726 if (send_result(client, hdr->tag, RESULT_BADDEV) < 0)
727 return -1;
728 return 0;
729 }
730 val = 0;
731 plist_get_uint_val(node, &val);
732 device_id = (uint32_t)val;
733
734 // get port number
735 node = plist_dict_get_item(dict, "PortNumber");
736 if (!node) {
737 usbmuxd_log(LL_ERROR, "Received connect request without port number!");
738 plist_free(dict);
739 if (send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
740 return -1;
741 return 0;
742 }
743 val = 0;
744 plist_get_uint_val(node, &val);
745 portnum = (uint16_t)val;
746 plist_free(dict);
747
748 usbmuxd_log(LL_DEBUG, "Client %d requesting connection to device %d port %d", client->fd, device_id, ntohs(portnum));
749 res = device_start_connect(device_id, ntohs(portnum), client);
750 if(res < 0) {
751 if (send_result(client, hdr->tag, -res) < 0)
752 return -1;
753 } else {
754 client->connect_tag = hdr->tag;
755 client->connect_device = device_id;
756 client->state = CLIENT_CONNECTING1;
757 }
758 return 0;
759 } else if (!strcmp(message, "ListDevices")) {
760 free(message);
761 plist_free(dict);
762 if (send_device_list(client, hdr->tag) < 0)
763 return -1;
764 return 0;
765 } else if (!strcmp(message, "ListListeners")) {
766 free(message);
767 plist_free(dict);
768 if (send_listener_list(client, hdr->tag) < 0)
769 return -1;
770 return 0;
771 } else if (!strcmp(message, "ReadBUID")) {
772 free(message);
773 plist_free(dict);
774 if (send_system_buid(client, hdr->tag) < 0)
775 return -1;
776 return 0;
777 } else if (!strcmp(message, "ReadPairRecord")) {
778 free(message);
779 char* record_id = plist_dict_get_string_val(dict, "PairRecordID");
780 plist_free(dict);
781
782 res = send_pair_record(client, hdr->tag, record_id);
783 if (record_id)
784 free(record_id);
785 if (res < 0)
786 return -1;
787 return 0;
788 } else if (!strcmp(message, "SavePairRecord")) {
789 uint32_t rval = RESULT_OK;
790 free(message);
791 char* record_id = plist_dict_get_string_val(dict, "PairRecordID");
792 char* record_data = NULL;
793 uint64_t record_size = 0;
794 plist_t rdata = plist_dict_get_item(dict, "PairRecordData");
795 if (rdata && plist_get_node_type(rdata) == PLIST_DATA) {
796 plist_get_data_val(rdata, &record_data, &record_size);
797 }
798
799 if (record_id && record_data) {
800 res = config_set_device_record(record_id, record_data, record_size);
801 if (res < 0) {
802 rval = -res;
803 } else {
804 plist_t p_dev_id = plist_dict_get_item(dict, "DeviceID");
805 uint32_t dev_id = 0;
806 if (p_dev_id && plist_get_node_type(p_dev_id) == PLIST_UINT) {
807 uint64_t u_dev_id = 0;
808 plist_get_uint_val(p_dev_id, &u_dev_id);
809 dev_id = (uint32_t)u_dev_id;
810 }
811 if (dev_id > 0) {
812 struct device_info *devs = NULL;
813 struct device_info *dev;
814 int i;
815 int count = device_get_list(1, &devs);
816 int found = 0;
817 dev = devs;
818 for (i = 0; devs && i < count; i++, dev++) {
819 if ((uint32_t)dev->id == dev_id && (strcmp(dev->serial, record_id) == 0)) {
820 found++;
821 break;
822 }
823 }
824 if (!found) {
825 usbmuxd_log(LL_ERROR, "ERROR: SavePairRecord: DeviceID %d (%s) is not connected\n", dev_id, record_id);
826 } else {
827 client_device_paired(dev_id);
828 }
829 free(devs);
830 }
831 }
832 free(record_id);
833 } else {
834 rval = EINVAL;
835 }
836 free(record_data);
837 plist_free(dict);
838 if (send_result(client, hdr->tag, rval) < 0)
839 return -1;
840 return 0;
841 } else if (!strcmp(message, "DeletePairRecord")) {
842 uint32_t rval = RESULT_OK;
843 free(message);
844 char* record_id = plist_dict_get_string_val(dict, "PairRecordID");
845 plist_free(dict);
846 if (record_id) {
847 res = config_remove_device_record(record_id);
848 if (res < 0) {
849 rval = -res;
850 }
851 free(record_id);
852 } else {
853 rval = EINVAL;
854 }
855 if (send_result(client, hdr->tag, rval) < 0)
856 return -1;
857 return 0;
858 } else {
859 usbmuxd_log(LL_ERROR, "Unexpected command '%s' received!", message);
860 free(message);
861 plist_free(dict);
862 if (send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
863 return -1;
864 return 0;
865 }
866 }
867 // should not be reached?!
868 return -1;
869 case MESSAGE_LISTEN:
870 if(send_result(client, hdr->tag, 0) < 0)
871 return -1;
872 usbmuxd_log(LL_DEBUG, "Client %d now LISTENING", client->fd);
873 return start_listen(client);
874 case MESSAGE_CONNECT:
875 ch = (void*)hdr;
876 usbmuxd_log(LL_DEBUG, "Client %d connection request to device %d port %d", client->fd, ch->device_id, ntohs(ch->port));
877 res = device_start_connect(ch->device_id, ntohs(ch->port), client);
878 if(res < 0) {
879 if(send_result(client, hdr->tag, -res) < 0)
880 return -1;
881 } else {
882 client->connect_tag = hdr->tag;
883 client->connect_device = ch->device_id;
884 client->state = CLIENT_CONNECTING1;
885 }
886 return 0;
887 default:
888 usbmuxd_log(LL_ERROR, "Client %d invalid command %d", client->fd, hdr->message);
889 if(send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
890 return -1;
891 return 0;
892 }
893 return -1;
894}
895
896static void output_buffer_process(struct mux_client *client)
897{
898 int res;
899 if(!client->ob_size) {
900 usbmuxd_log(LL_WARNING, "Client %d OUT process but nothing to send?", client->fd);
901 client->events &= ~POLLOUT;
902 return;
903 }
904 res = send(client->fd, client->ob_buf, client->ob_size, 0);
905 if(res <= 0) {
906 usbmuxd_log(LL_ERROR, "Sending to client fd %d failed: %d %s", client->fd, res, strerror(errno));
907 client_close(client);
908 return;
909 }
910 if((uint32_t)res == client->ob_size) {
911 client->ob_size = 0;
912 client->events &= ~POLLOUT;
913 if(client->state == CLIENT_CONNECTING2) {
914 usbmuxd_log(LL_DEBUG, "Client %d switching to CONNECTED state", client->fd);
915 client->state = CLIENT_CONNECTED;
916 client->events = client->devents;
917 // no longer need this
918 free(client->ob_buf);
919 client->ob_buf = NULL;
920 }
921 } else {
922 client->ob_size -= res;
923 memmove(client->ob_buf, client->ob_buf + res, client->ob_size);
924 }
925}
926static void input_buffer_process(struct mux_client *client)
927{
928 int res;
929 int did_read = 0;
930 if(client->ib_size < sizeof(struct usbmuxd_header)) {
931 res = recv(client->fd, client->ib_buf + client->ib_size, sizeof(struct usbmuxd_header) - client->ib_size, 0);
932 if(res <= 0) {
933 if(res < 0)
934 usbmuxd_log(LL_ERROR, "Receive from client fd %d failed: %s", client->fd, strerror(errno));
935 else
936 usbmuxd_log(LL_INFO, "Client %d connection closed", client->fd);
937 client_close(client);
938 return;
939 }
940 client->ib_size += res;
941 if(client->ib_size < sizeof(struct usbmuxd_header))
942 return;
943 did_read = 1;
944 }
945 struct usbmuxd_header *hdr = (void*)client->ib_buf;
946 if(hdr->length > client->ib_capacity) {
947 usbmuxd_log(LL_INFO, "Client %d message is too long (%d bytes)", client->fd, hdr->length);
948 client_close(client);
949 return;
950 }
951 if(hdr->length < sizeof(struct usbmuxd_header)) {
952 usbmuxd_log(LL_ERROR, "Client %d message is too short (%d bytes)", client->fd, hdr->length);
953 client_close(client);
954 return;
955 }
956 if(client->ib_size < hdr->length) {
957 if(did_read)
958 return; //maybe we would block, so defer to next loop
959 res = recv(client->fd, client->ib_buf + client->ib_size, hdr->length - client->ib_size, 0);
960 if(res < 0) {
961 usbmuxd_log(LL_ERROR, "Receive from client fd %d failed: %s", client->fd, strerror(errno));
962 client_close(client);
963 return;
964 } else if(res == 0) {
965 usbmuxd_log(LL_INFO, "Client %d connection closed", client->fd);
966 client_close(client);
967 return;
968 }
969 client->ib_size += res;
970 if(client->ib_size < hdr->length)
971 return;
972 }
973 handle_command(client, hdr);
974 client->ib_size = 0;
975}
976
977void client_process(int fd, short events)
978{
979 struct mux_client *client = NULL;
980 mutex_lock(&client_list_mutex);
981 FOREACH(struct mux_client *lc, &client_list) {
982 if(lc->fd == fd) {
983 client = lc;
984 break;
985 }
986 } ENDFOREACH
987 mutex_unlock(&client_list_mutex);
988
989 if(!client) {
990 usbmuxd_log(LL_INFO, "client_process: fd %d not found in client list", fd);
991 return;
992 }
993
994 if(client->state == CLIENT_CONNECTED) {
995 usbmuxd_log(LL_SPEW, "client_process in CONNECTED state");
996 device_client_process(client->connect_device, client, events);
997 } else {
998 if(events & POLLIN) {
999 input_buffer_process(client);
1000 } else if(events & POLLOUT) { //not both in case client died as part of process_recv
1001 output_buffer_process(client);
1002 }
1003 }
1004
1005}
1006
1007void client_device_add(struct device_info *dev)
1008{
1009 mutex_lock(&client_list_mutex);
1010 usbmuxd_log(LL_DEBUG, "client_device_add: id %d, location 0x%x, serial %s", dev->id, dev->location, dev->serial);
1011 device_set_visible(dev->id);
1012 FOREACH(struct mux_client *client, &client_list) {
1013 if(client->state == CLIENT_LISTEN)
1014 send_device_add(client, dev);
1015 } ENDFOREACH
1016 mutex_unlock(&client_list_mutex);
1017}
1018
1019void client_device_remove(int device_id)
1020{
1021 mutex_lock(&client_list_mutex);
1022 uint32_t id = device_id;
1023 usbmuxd_log(LL_DEBUG, "client_device_remove: id %d", device_id);
1024 FOREACH(struct mux_client *client, &client_list) {
1025 if(client->state == CLIENT_LISTEN)
1026 send_device_remove(client, id);
1027 } ENDFOREACH
1028 mutex_unlock(&client_list_mutex);
1029}
1030
1031void client_device_paired(int device_id)
1032{
1033 mutex_lock(&client_list_mutex);
1034 uint32_t id = device_id;
1035 usbmuxd_log(LL_DEBUG, "client_device_paired: id %d", device_id);
1036 FOREACH(struct mux_client *client, &client_list) {
1037 if (client->state == CLIENT_LISTEN)
1038 send_device_paired(client, id);
1039 } ENDFOREACH
1040 mutex_unlock(&client_list_mutex);
1041}
1042
1043void client_init(void)
1044{
1045 usbmuxd_log(LL_DEBUG, "client_init");
1046 collection_init(&client_list);
1047 mutex_init(&client_list_mutex);
1048}
1049
1050void client_shutdown(void)
1051{
1052 usbmuxd_log(LL_DEBUG, "client_shutdown");
1053 FOREACH(struct mux_client *client, &client_list) {
1054 client_close(client);
1055 } ENDFOREACH
1056 mutex_destroy(&client_list_mutex);
1057 collection_free(&client_list);
1058}