summaryrefslogtreecommitdiffstats
path: root/src/device_link_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/device_link_service.c')
-rw-r--r--src/device_link_service.c299
1 files changed, 299 insertions, 0 deletions
diff --git a/src/device_link_service.c b/src/device_link_service.c
new file mode 100644
index 0000000..e1155a5
--- /dev/null
+++ b/src/device_link_service.c
@@ -0,0 +1,299 @@
1 /*
2 * device_link_service.c
3 * DeviceLink service implementation.
4 *
5 * Copyright (c) 2010 Nikias Bassen, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21#include <string.h>
22#include <stdlib.h>
23#include "device_link_service.h"
24#include "property_list_service.h"
25#include "debug.h"
26
27/**
28 * Internally used function to extract the message string from a DLMessage*
29 * plist.
30 *
31 * @param dl_msg The DeviceLink property list to parse.
32 *
33 * @return An allocated char* with the DLMessage from the given plist,
34 * or NULL when the plist does not contain any DLMessage. It is up to
35 * the caller to free the allocated memory.
36 */
37static char *device_link_service_get_message(plist_t dl_msg)
38{
39 uint32_t cnt = 0;
40 plist_t cmd = 0;
41 char *cmd_str = NULL;
42
43 /* sanity check */
44 if ((plist_get_node_type(dl_msg) != PLIST_ARRAY) || ((cnt = plist_array_get_size(dl_msg)) < 1)) {
45 return NULL;
46 }
47
48 /* get dl command */
49 cmd = plist_array_get_item(dl_msg, 0);
50 if (!cmd || (plist_get_node_type(cmd) != PLIST_STRING)) {
51 return NULL;
52 }
53
54 plist_get_string_val(cmd, &cmd_str);
55 if (!cmd_str) {
56 return NULL;
57 }
58
59 if ((strlen(cmd_str) < (strlen("DLMessage")+1))
60 || (strncmp(cmd_str, "DLMessage", strlen("DLMessage")))) {
61 free(cmd_str);
62 return NULL;
63 }
64
65 /* we got a DLMessage* command */
66 return cmd_str;
67}
68
69/**
70 * Creates a new device link service client.
71 *
72 * @param device The device to connect to.
73 * @param port Port on device to connect to.
74 * @param client Reference that will point to a newly allocated
75 * device_link_service_client_t upon successful return.
76 *
77 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
78 * DEVICE_LINK_SERVICE_E_INVALID_ARG when one of the parameters is invalid,
79 * or DEVICE_LINK_SERVICE_E_MUX_ERROR when the connection failed.
80 */
81device_link_service_error_t device_link_service_client_new(iphone_device_t device, uint16_t port, device_link_service_client_t *client)
82{
83 if (!device || port == 0 || !client || *client) {
84 return DEVICE_LINK_SERVICE_E_INVALID_ARG;
85 }
86
87 property_list_service_client_t plistclient = NULL;
88 if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
89 return DEVICE_LINK_SERVICE_E_MUX_ERROR;
90 }
91
92 /* create client object */
93 device_link_service_client_t client_loc = (device_link_service_client_t) malloc(sizeof(struct device_link_service_client_int));
94 client_loc->parent = plistclient;
95
96 /* all done, return success */
97 *client = client_loc;
98 return DEVICE_LINK_SERVICE_E_SUCCESS;
99}
100
101/**
102 * Frees a device link service client.
103 *
104 * @param client The device_link_service_client_t to free.
105 *
106 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
107 * DEVICE_LINK_SERVICE_E_INVALID_ARG when one of client or client->parent
108 * is invalid, or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR when the was an error
109 * freeing the parent property_list_service client.
110 */
111device_link_service_error_t device_link_service_client_free(device_link_service_client_t client)
112{
113 if (!client)
114 return DEVICE_LINK_SERVICE_E_INVALID_ARG;
115
116 if (property_list_service_client_free(client->parent) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
117 return DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
118 }
119 return DEVICE_LINK_SERVICE_E_SUCCESS;
120}
121
122/**
123 * Performs the DLMessageVersionExchange with the connected device.
124 * This should be the first operation to be executed by an implemented
125 * device link service client.
126 *
127 * @param client The device_link_service client to use.
128 * @param version_major The major version number to check.
129 * @param version_minor The minor version number to check.
130 *
131 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
132 * DEVICE_LINK_SERVICE_E_INVALID_ARG when client is NULL,
133 * DEVICE_LINK_SERVICE_E_MUX_ERROR when a communication error occurs,
134 * DEVICE_LINK_SERVICE_E_PLIST_ERROR when the received plist has not the
135 * expected contents, DEVICE_LINK_SERVICE_E_BAD_VERSION when the version
136 * given by the device is larger than the given version,
137 * or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR otherwise.
138 */
139device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor)
140{
141 if (!client)
142 return DEVICE_LINK_SERVICE_E_INVALID_ARG;
143
144 device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
145
146 /* perform version exchange */
147 plist_t array = NULL;
148 char *msg = NULL;
149
150 /* receive DLMessageVersionExchange from device */
151 if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
152 debug_info("Did not receive initial message from device!");
153 err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
154 goto leave;
155 }
156 msg = device_link_service_get_message(array);
157 if (!msg || strcmp(msg, "DLMessageVersionExchange")) {
158 debug_info("Did not receive DLMessageVersionExchange from device!");
159 err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
160 goto leave;
161 }
162 free(msg);
163 msg = NULL;
164
165 /* get major and minor version number */
166 if (plist_array_get_size(array) < 3) {
167 debug_info("DLMessageVersionExchange has unexpected format!");
168 err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
169 goto leave;
170 }
171 plist_t maj = plist_array_get_item(array, 1);
172 plist_t min = plist_array_get_item(array, 2);
173 uint64_t vmajor = 0;
174 uint64_t vminor = 0;
175 if (maj) {
176 plist_get_uint_val(maj, &vmajor);
177 }
178 if (min) {
179 plist_get_uint_val(min, &vminor);
180 }
181 if (vmajor > version_major) {
182 debug_info("Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor);
183 err = DEVICE_LINK_SERVICE_E_BAD_VERSION;
184 goto leave;
185 } else if ((vmajor == version_major) && (vminor > version_minor)) {
186 debug_info("WARNING: Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor);
187 err = DEVICE_LINK_SERVICE_E_BAD_VERSION;
188 goto leave;
189 }
190 plist_free(array);
191
192 /* version is ok, send reply */
193 array = plist_new_array();
194 plist_array_append_item(array, plist_new_string("DLMessageVersionExchange"));
195 plist_array_append_item(array, plist_new_string("DLVersionsOk"));
196 if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
197 debug_info("Error when sending DLVersionsOk");
198 err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
199 goto leave;
200 }
201 plist_free(array);
202
203 /* receive DeviceReady message */
204 array = NULL;
205 if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
206 debug_info("Error when receiving DLMessageDeviceReady!");
207 err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
208 goto leave;
209 }
210 msg = device_link_service_get_message(array);
211 if (!msg || strcmp(msg, "DLMessageDeviceReady")) {
212 debug_info("Did not get DLMessageDeviceReady!");
213 err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
214 goto leave;
215 }
216 err = DEVICE_LINK_SERVICE_E_SUCCESS;
217
218leave:
219 if (msg) {
220 free(msg);
221 }
222 if (array) {
223 plist_free(array);
224 }
225 return err;
226}
227
228/**
229 * Performs a disconnect with the connected device link service client.
230 *
231 * @param client The device link service client to disconnect.
232 *
233 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
234 * DEVICE_LINK_SERVICE_E_INVALID_ARG if client is NULL,
235 * or DEVICE_LINK_SERVICE_E_MUX_ERROR when there's an error when sending
236 * the the disconnect message.
237 */
238device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client)
239{
240 if (!client)
241 return DEVICE_LINK_SERVICE_E_INVALID_ARG;
242
243 plist_t array = plist_new_array();
244 plist_array_append_item(array, plist_new_string("DLMessageDisconnect"));
245 plist_array_append_item(array, plist_new_string("All done, thanks for the memories"));
246
247 device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS;
248 if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
249 err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
250 }
251 plist_free(array);
252 return err;
253}
254
255/**
256 * Generic device link service send function.
257 *
258 * @param client The device link service client to use for sending
259 * @param plist The property list to send
260 *
261 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
262 * DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL,
263 * or DEVICE_LINK_SERVICE_E_MUX_ERROR when the given property list could
264 * not be sent.
265 */
266device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist)
267{
268 if (!client || !plist) {
269 return DEVICE_LINK_SERVICE_E_INVALID_ARG;
270 }
271 if (property_list_service_send_binary_plist(client->parent, plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
272 return DEVICE_LINK_SERVICE_E_MUX_ERROR;
273 }
274 return DEVICE_LINK_SERVICE_E_SUCCESS;
275}
276
277/* Generic device link service receive function.
278 *
279 * @param client The device link service client to use for sending
280 * @param plist Pointer that will point to the property list received upon
281 * successful return.
282 *
283 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
284 * DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL,
285 * or DEVICE_LINK_SERVICE_E_MUX_ERROR when no property list could be
286 * received.
287 */
288device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist)
289{
290 if (!client || !plist || (plist && *plist)) {
291 return DEVICE_LINK_SERVICE_E_INVALID_ARG;
292 }
293
294 if (property_list_service_receive_plist(client->parent, plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
295 return DEVICE_LINK_SERVICE_E_MUX_ERROR;
296 }
297 return DEVICE_LINK_SERVICE_E_SUCCESS;
298}
299