summaryrefslogtreecommitdiffstats
path: root/src/iphone.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/iphone.c')
-rw-r--r--src/iphone.c371
1 files changed, 305 insertions, 66 deletions
diff --git a/src/iphone.c b/src/iphone.c
index e694373..80e796b 100644
--- a/src/iphone.c
+++ b/src/iphone.c
@@ -1,8 +1,9 @@
1/* 1/*
2 * iphone.c 2 * iphone.c
3 * Functions for creating and initializing iPhone structures. 3 * Device discovery and communication interface.
4 * 4 *
5 * Copyright (c) 2008 Zach C. All Rights Reserved. 5 * Copyright (c) 2008 Zach C. All Rights Reserved.
6 * Copyright (c) 2009 Nikias Bassen. All Rights Reserved.
6 * 7 *
7 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public 9 * modify it under the terms of the GNU Lesser General Public
@@ -19,104 +20,161 @@
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 21 */
21 22
22#include <stdio.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h> 24#include <string.h>
25#include <errno.h>
25 26
27#include <usbmuxd.h>
26#include "iphone.h" 28#include "iphone.h"
27#include "utils.h" 29#include "utils.h"
28 30
31static iphone_event_cb_t event_cb = NULL;
32
33static void usbmux_event_cb(const usbmuxd_event_t *event, void *user_data)
34{
35 iphone_event_t ev;
36
37 ev.event = event->event;
38 ev.uuid = event->device.uuid;
39 ev.conn_type = CONNECTION_USBMUXD;
40
41 if (event_cb) {
42 event_cb(&ev, user_data);
43 }
44}
45
29/** 46/**
30 * Retrieves a list of connected devices from usbmuxd and matches their 47 * Register a callback function that will be called when device add/remove
31 * UUID with the given UUID. If the given UUID is NULL then the first 48 * events occur.
32 * device reported by usbmuxd is used.
33 * 49 *
34 * @param device Upon calling this function, a pointer to a location of type 50 * @param callback Callback function to call.
35 * iphone_device_t, which must have the value NULL. On return, this location 51 * @param user_data Application-specific data passed as parameter
36 * will be filled with a handle to the device. 52 * to the registered callback function.
37 * @param uuid The UUID to match.
38 * 53 *
39 * @return IPHONE_E_SUCCESS if ok, otherwise an error code. 54 * @return IPHONE_E_SUCCESS on success or an error value when an error occured.
40 */ 55 */
41iphone_error_t iphone_get_device_by_uuid(iphone_device_t * device, const char *uuid) 56iphone_error_t iphone_event_subscribe(iphone_event_cb_t callback, void *user_data)
42{ 57{
43 iphone_device_t phone; 58 event_cb = callback;
44 uint32_t handle = 0; 59 int res = usbmuxd_subscribe(usbmux_event_cb, user_data);
45 char *serial_number = malloc(41); 60 if (res != 0) {
46 usbmuxd_scan_result *dev_list = NULL; 61 event_cb = NULL;
47 int i; 62 log_debug_msg("%s: Error %d when subscribing usbmux event callback!\n", __func__, res);
48 63 return IPHONE_E_UNKNOWN_ERROR;
49 if (usbmuxd_scan(&dev_list) < 0) {
50 log_debug_msg("%s: usbmuxd_scan returned an error, is usbmuxd running?\n", __func__);
51 }
52 if (dev_list && dev_list[0].handle > 0) {
53 if (!uuid) {
54 /* select first device found if no UUID specified */
55 handle = dev_list[0].handle;
56 strcpy(serial_number, dev_list[0].serial_number);
57 } else {
58 /* otherwise walk through the list */
59 for (i = 0; dev_list[i].handle > 0; i++) {
60 log_debug_msg("%s: device handle=%d, uuid=%s\n", __func__, dev_list[i].handle, dev_list[i].serial_number);
61 if (strcasecmp(uuid, dev_list[i].serial_number) == 0) {
62 handle = dev_list[i].handle;
63 strcpy(serial_number, dev_list[i].serial_number);
64 break;
65 }
66 }
67 }
68 free(dev_list);
69
70 if (handle > 0) {
71 phone = (iphone_device_t) malloc(sizeof(struct iphone_device_int));
72 phone->handle = handle;
73 phone->serial_number = serial_number;
74 *device = phone;
75 return IPHONE_E_SUCCESS;
76 }
77 } 64 }
65 return IPHONE_E_SUCCESS;
66}
78 67
79 return IPHONE_E_NO_DEVICE; 68/**
69 * Release the event callback function that has been registered with
70 * iphone_event_subscribe().
71 *
72 * @return IPHONE_E_SUCCESS on success or an error value when an error occured.
73 */
74iphone_error_t iphone_event_unsubscribe()
75{
76 event_cb = NULL;
77 int res = usbmuxd_unsubscribe();
78 if (res != 0) {
79 log_debug_msg("%s: Error %d when unsubscribing usbmux event callback!\n", __func__, res);
80 return IPHONE_E_UNKNOWN_ERROR;
81 }
82 return IPHONE_E_SUCCESS;
80} 83}
81 84
82/** 85/**
83 * This function has the purpose to retrieve a handle to the first 86 * Get a list of currently available devices.
84 * attached iPhone/iPod reported by usbmuxd.
85 * 87 *
86 * @param Upon calling this function, a pointer to a location of type 88 * @param devices List of uuids of devices that are currently available.
87 * iphone_device_t, which must have the value NULL. On return, this location 89 * This list is terminated by a NULL pointer.
88 * will be filled with a handle to the device. 90 * @param count Number of devices found.
89 * 91 *
90 * @return IPHONE_E_SUCCESS if ok, otherwise an error code. 92 * @return IPHONE_E_SUCCESS on success or an error value when an error occured.
91 */ 93 */
92iphone_error_t iphone_get_device(iphone_device_t * device) 94iphone_error_t iphone_get_device_list(char ***devices, int *count)
93{ 95{
94 return iphone_get_device_by_uuid(device, NULL); 96 usbmuxd_device_info_t *dev_list;
97
98 *devices = NULL;
99 *count = 0;
100
101 if (usbmuxd_get_device_list(&dev_list) < 0) {
102 log_debug_msg("%s: ERROR: usbmuxd is not running!\n", __func__);
103 return IPHONE_E_NO_DEVICE;
104 }
105
106 char **newlist = NULL;
107 int i, newcount = 0;
108
109 for (i = 0; dev_list[i].handle > 0; i++) {
110 newlist = realloc(*devices, sizeof(char*) * (newcount+1));
111 newlist[newcount++] = strdup(dev_list[i].uuid);
112 *devices = newlist;
113 }
114 usbmuxd_free_device_list(dev_list);
115
116 *count = newcount;
117 newlist = realloc(*devices, sizeof(char*) * (newcount+1));
118 newlist[newcount] = NULL;
119 *devices = newlist;
120
121 return IPHONE_E_SUCCESS;
95} 122}
96 123
97iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle) 124/**
125 * Free a list of device uuids.
126 *
127 * @param devices List of uuids to free.
128 *
129 * @return Always returnes IPHONE_E_SUCCESS.
130 */
131iphone_error_t iphone_free_device_list(char **devices)
98{ 132{
99 if (!device) 133 if (devices) {
100 return IPHONE_E_INVALID_ARG; 134 int i = 0;
101 135 while (devices[i++]) {
102 *handle = device->handle; 136 free(devices[i]);
137 }
138 free(devices);
139 }
103 return IPHONE_E_SUCCESS; 140 return IPHONE_E_SUCCESS;
104} 141}
105 142
106iphone_error_t iphone_device_get_uuid(iphone_device_t device, char **uuid) 143/**
144 * Creates an iphone_device_t structure for the device specified by uuid,
145 * if the device is available.
146 *
147 * @note The resulting iphone_device_t structure has to be freed with
148 * iphone_device_free() if it is no longer used.
149 *
150 * @param device Upon calling this function, a pointer to a location of type
151 * iphone_device_t. On successful return, this location will be populated.
152 * @param uuid The UUID to match.
153 *
154 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
155 */
156iphone_error_t iphone_device_new(iphone_device_t * device, const char *uuid)
107{ 157{
108 if (!device) 158 usbmuxd_device_info_t muxdev;
109 return IPHONE_E_INVALID_ARG; 159 int res = usbmuxd_get_device_by_uuid(uuid, &muxdev);
160 if (res > 0) {
161 iphone_device_t phone = (iphone_device_t) malloc(sizeof(struct iphone_device_int));
162 phone->uuid = strdup(muxdev.uuid);
163 phone->conn_type = CONNECTION_USBMUXD;
164 phone->conn_data = (void*)muxdev.handle;
165 *device = phone;
166 return IPHONE_E_SUCCESS;
167 }
168 /* other connection types could follow here */
110 169
111 *uuid = strdup(device->serial_number); 170 return IPHONE_E_NO_DEVICE;
112 return IPHONE_E_SUCCESS;
113} 171}
114 172
115/** Cleans up an iPhone structure, then frees the structure itself. 173/** Cleans up an iPhone structure, then frees the structure itself.
116 * This is a library-level function; deals directly with the iPhone to tear 174 * This is a library-level function; deals directly with the iPhone to tear
117 * down relations, but otherwise is mostly internal. 175 * down relations, but otherwise is mostly internal.
118 * 176 *
119 * @param phone A pointer to an iPhone structure. 177 * @param device A pointer to an iPhone structure.
120 */ 178 */
121iphone_error_t iphone_device_free(iphone_device_t device) 179iphone_error_t iphone_device_free(iphone_device_t device)
122{ 180{
@@ -126,8 +184,189 @@ iphone_error_t iphone_device_free(iphone_device_t device)
126 184
127 ret = IPHONE_E_SUCCESS; 185 ret = IPHONE_E_SUCCESS;
128 186
129 free(device->serial_number); 187 free(device->uuid);
188
189 if (device->conn_type == CONNECTION_USBMUXD) {
190 device->conn_data = 0;
191 }
192 if (device->conn_data) {
193 free(device->conn_data);
194 }
130 free(device); 195 free(device);
131 return ret; 196 return ret;
132} 197}
133 198
199/**
200 * Set up a connection to the given device.
201 *
202 * @param device The device to connect to.
203 * @param dst_port The destination port to connect to.
204 * @param connection Pointer to an iphone_connection_t that will be filled
205 * with the necessary data of the connection.
206 *
207 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
208 */
209iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t dst_port, iphone_connection_t *connection)
210{
211 if (!device) {
212 return IPHONE_E_INVALID_ARG;
213 }
214
215 if (device->conn_type == CONNECTION_USBMUXD) {
216 int sfd = usbmuxd_connect((uint32_t)(device->conn_data), dst_port);
217 if (sfd < 0) {
218 log_debug_msg("%s: ERROR: Connecting to usbmuxd failed: %d (%s)\n", __func__, sfd, strerror(-sfd));
219 return IPHONE_E_UNKNOWN_ERROR;
220 }
221 iphone_connection_t new_connection = (iphone_connection_t)malloc(sizeof(struct iphone_connection_int));
222 new_connection->type = CONNECTION_USBMUXD;
223 new_connection->data = (void*)sfd;
224 *connection = new_connection;
225 return IPHONE_E_SUCCESS;
226 } else {
227 log_debug_msg("%s: Unknown connection type %d\n", __func__, device->conn_type);
228 }
229
230 return IPHONE_E_UNKNOWN_ERROR;
231}
232
233/**
234 * Disconnect from the device and clean up the connection structure.
235 *
236 * @param connection The connection to close.
237 *
238 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
239 */
240iphone_error_t iphone_device_disconnect(iphone_connection_t connection)
241{
242 if (!connection) {
243 return IPHONE_E_INVALID_ARG;
244 }
245 iphone_error_t result = IPHONE_E_UNKNOWN_ERROR;
246 if (connection->type == CONNECTION_USBMUXD) {
247 usbmuxd_disconnect((int)(connection->data));
248 result = IPHONE_E_SUCCESS;
249 } else {
250 log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type);
251 }
252 free(connection);
253 return result;
254}
255
256/**
257 * Send data to a device via the given connection.
258 *
259 * @param connection The connection to send data over.
260 * @param data Buffer with data to send.
261 * @param len Size of the buffer to send.
262 * @param sent_bytes Pointer to an uint32_t that will be filled
263 * with the number of bytes actually sent.
264 *
265 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
266 */
267iphone_error_t iphone_device_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes)
268{
269 if (!connection || !data) {
270 return IPHONE_E_INVALID_ARG;
271 }
272
273 if (connection->type == CONNECTION_USBMUXD) {
274 int res = usbmuxd_send((int)(connection->data), data, len, sent_bytes);
275 if (res < 0) {
276 log_debug_msg("%s: ERROR: usbmuxd_send returned %d (%s)\n", __func__, res, strerror(-res));
277 return IPHONE_E_UNKNOWN_ERROR;
278 }
279 return IPHONE_E_SUCCESS;
280 } else {
281 log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type);
282 }
283 return IPHONE_E_UNKNOWN_ERROR;
284}
285
286/**
287 * Receive data from a device via the given connection.
288 * This function will return after the given timeout even if no data has been
289 * received.
290 *
291 * @param connection The connection to receive data from.
292 * @param data Buffer that will be filled with the received data.
293 * This buffer has to be large enough to hold len bytes.
294 * @param len Buffer size or number of bytes to receive.
295 * @param recv_bytes Number of bytes actually received.
296 * @param timeout Timeout in milliseconds after which this function should
297 * return even if no data has been received.
298 *
299 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
300 */
301iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
302{
303 if (!connection) {
304 return IPHONE_E_INVALID_ARG;
305 }
306
307 if (connection->type == CONNECTION_USBMUXD) {
308 int res = usbmuxd_recv_timeout((int)(connection->data), data, len, recv_bytes, timeout);
309 if (res < 0) {
310 log_debug_msg("%s: ERROR: usbmuxd_recv_timeout returned %d (%s)\n", __func__, res, strerror(-res));
311 return IPHONE_E_UNKNOWN_ERROR;
312 }
313 } else {
314 log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type);
315 }
316 return IPHONE_E_UNKNOWN_ERROR;
317}
318
319/**
320 * Receive data from a device via the given connection.
321 * This function is like iphone_device_recv_timeout, but with a predefined
322 * reasonable timeout.
323 *
324 * @param connection The connection to receive data from.
325 * @param data Buffer that will be filled with the received data.
326 * This buffer has to be large enough to hold len bytes.
327 * @param len Buffer size or number of bytes to receive.
328 * @param recv_bytes Number of bytes actually received.
329 *
330 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
331 */
332iphone_error_t iphone_device_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes)
333{
334 if (!connection) {
335 return -EINVAL;
336 }
337
338 if (connection->type == CONNECTION_USBMUXD) {
339 int res = usbmuxd_recv((int)(connection->data), data, len, recv_bytes);
340 if (res < 0) {
341 log_debug_msg("%s: ERROR: usbmuxd_recv returned %d (%s)\n", __func__, res, strerror(-res));
342 return IPHONE_E_UNKNOWN_ERROR;
343 }
344 } else {
345 log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type);
346 }
347 return IPHONE_E_UNKNOWN_ERROR;
348}
349
350iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle)
351{
352 if (!device)
353 return IPHONE_E_INVALID_ARG;
354
355 if (device->conn_type == CONNECTION_USBMUXD) {
356 *handle = (uint32_t)device->conn_data;
357 return IPHONE_E_SUCCESS;
358 } else {
359 log_debug_msg("%s: Unknown connection type %d\n", __func__, device->conn_type);
360 }
361 return IPHONE_E_UNKNOWN_ERROR;
362}
363
364iphone_error_t iphone_device_get_uuid(iphone_device_t device, char **uuid)
365{
366 if (!device)
367 return IPHONE_E_INVALID_ARG;
368
369 *uuid = strdup(device->uuid);
370 return IPHONE_E_SUCCESS;
371}
372