summaryrefslogtreecommitdiffstats
path: root/src/diagnostics_relay.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/diagnostics_relay.c')
-rw-r--r--src/diagnostics_relay.c467
1 files changed, 467 insertions, 0 deletions
diff --git a/src/diagnostics_relay.c b/src/diagnostics_relay.c
new file mode 100644
index 0000000..6ee3150
--- /dev/null
+++ b/src/diagnostics_relay.c
@@ -0,0 +1,467 @@
1/*
2 * diagnostics_relay.c
3 * com.apple.mobile.diagnostics_relay service implementation.
4 *
5 * Copyright (c) 2012 Martin Szulecki, 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
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25#include <string.h>
26#include <stdlib.h>
27#include "diagnostics_relay.h"
28#include "property_list_service.h"
29#include "common/debug.h"
30
31#define RESULT_SUCCESS 0
32#define RESULT_FAILURE 1
33#define RESULT_UNKNOWN_REQUEST 2
34
35/**
36 * Internally used function for checking the result from a service response
37 * plist to a previously sent request.
38 *
39 * @param dict The plist to evaluate.
40 *
41 * @return RESULT_SUCCESS when the result is 'Success',
42 * RESULT_FAILURE when the result is 'Failure',
43 * or a negative value if an error occurred during evaluation.
44 */
45static int diagnostics_relay_check_result(plist_t dict)
46{
47 int ret = -1;
48
49 plist_t result_node = plist_dict_get_item(dict, "Status");
50 if (!result_node)
51 return ret;
52
53 plist_type result_type = plist_get_node_type(result_node);
54 if (result_type == PLIST_STRING) {
55 char *result_value = NULL;
56
57 plist_get_string_val(result_node, &result_value);
58
59 if (result_value) {
60 if (!strcmp(result_value, "Success")) {
61 ret = RESULT_SUCCESS;
62 } else if (!strcmp(result_value, "Failure")) {
63 ret = RESULT_FAILURE;
64 } else if (!strcmp(result_value, "UnknownRequest")) {
65 ret = RESULT_UNKNOWN_REQUEST;
66 } else {
67 debug_info("ERROR: unknown result value '%s'", result_value);
68 }
69 }
70 if (result_value)
71 free(result_value);
72 }
73 return ret;
74}
75
76diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, diagnostics_relay_client_t *client)
77{
78 if (!device || !service || service->port == 0 || !client || *client) {
79 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
80 }
81
82 property_list_service_client_t plistclient = NULL;
83 if (property_list_service_client_new(device, service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
84 return DIAGNOSTICS_RELAY_E_MUX_ERROR;
85 }
86
87 /* create client object */
88 diagnostics_relay_client_t client_loc = (diagnostics_relay_client_t) malloc(sizeof(struct diagnostics_relay_client_private));
89 client_loc->parent = plistclient;
90
91 /* all done, return success */
92 *client = client_loc;
93 return DIAGNOSTICS_RELAY_E_SUCCESS;
94}
95
96diagnostics_relay_error_t diagnostics_relay_client_start_service(idevice_t device, diagnostics_relay_client_t * client, const char* label)
97{
98 diagnostics_relay_error_t err = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
99 service_client_factory_start_service(device, DIAGNOSTICS_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(diagnostics_relay_client_new), &err);
100 return err;
101}
102
103diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client)
104{
105 if (!client)
106 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
107
108 if (property_list_service_client_free(client->parent) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
109 return DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
110 }
111 free(client);
112 return DIAGNOSTICS_RELAY_E_SUCCESS;
113}
114
115/**
116 * Receives a plist from the service.
117 *
118 * @param client The diagnostics_relay client
119 * @param plist The plist to store the received data
120 *
121 * @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
122 * DIAGNOSTICS_RELAY_E_INVALID_ARG when client or plist is NULL
123 */
124static diagnostics_relay_error_t diagnostics_relay_receive(diagnostics_relay_client_t client, plist_t *plist)
125{
126 if (!client || !plist || (plist && *plist))
127 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
128
129 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_SUCCESS;
130 property_list_service_error_t err;
131
132 err = property_list_service_receive_plist(client->parent, plist);
133 if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
134 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
135 }
136
137 if (!*plist)
138 ret = DIAGNOSTICS_RELAY_E_PLIST_ERROR;
139
140 return ret;
141}
142
143/**
144 * Sends a plist to the service.
145 *
146 * @note This function is low-level and should only be used if you need to send
147 * a new type of message.
148 *
149 * @param client The diagnostics_relay client
150 * @param plist The plist to send
151 *
152 * @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
153 * DIAGNOSTICS_RELAY_E_INVALID_ARG when client or plist is NULL
154 */
155static diagnostics_relay_error_t diagnostics_relay_send(diagnostics_relay_client_t client, plist_t plist)
156{
157 if (!client || !plist)
158 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
159
160 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_SUCCESS;
161 property_list_service_error_t err;
162
163 err = property_list_service_send_xml_plist(client->parent, plist);
164 if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
165 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
166 }
167 return ret;
168}
169
170diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client)
171{
172 if (!client)
173 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
174
175 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
176
177 plist_t dict = plist_new_dict();
178 plist_dict_set_item(dict, "Request", plist_new_string("Goodbye"));
179
180 ret = diagnostics_relay_send(client, dict);
181 plist_free(dict);
182 dict = NULL;
183
184 ret = diagnostics_relay_receive(client, &dict);
185 if (!dict) {
186 debug_info("did not get goodbye response back");
187 return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
188 }
189
190 int check = diagnostics_relay_check_result(dict);
191 if (check == RESULT_SUCCESS) {
192 ret = DIAGNOSTICS_RELAY_E_SUCCESS;
193 } else if (check == RESULT_UNKNOWN_REQUEST) {
194 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
195 } else {
196 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
197 }
198
199 plist_free(dict);
200 dict = NULL;
201 return ret;
202}
203
204diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client)
205{
206 if (!client)
207 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
208
209 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
210
211 plist_t dict = plist_new_dict();
212
213 plist_dict_set_item(dict,"Request", plist_new_string("Sleep"));
214 ret = diagnostics_relay_send(client, dict);
215 plist_free(dict);
216 dict = NULL;
217
218 ret = diagnostics_relay_receive(client, &dict);
219 if (!dict) {
220 return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
221 }
222
223 int check = diagnostics_relay_check_result(dict);
224 if (check == RESULT_SUCCESS) {
225 ret = DIAGNOSTICS_RELAY_E_SUCCESS;
226 } else if (check == RESULT_UNKNOWN_REQUEST) {
227 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
228 } else {
229 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
230 }
231
232 plist_free(dict);
233 return ret;
234}
235
236static diagnostics_relay_error_t internal_diagnostics_relay_action(diagnostics_relay_client_t client, const char* name, diagnostics_relay_action_t flags)
237{
238 if (!client)
239 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
240
241 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
242
243 plist_t dict = plist_new_dict();
244 plist_dict_set_item(dict,"Request", plist_new_string(name));
245
246 if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) {
247 plist_dict_set_item(dict, "WaitForDisconnect", plist_new_bool(1));
248 }
249
250 if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS) {
251 plist_dict_set_item(dict, "DisplayPass", plist_new_bool(1));
252 }
253
254 if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL) {
255 plist_dict_set_item(dict, "DisplayFail", plist_new_bool(1));
256 }
257
258 ret = diagnostics_relay_send(client, dict);
259 plist_free(dict);
260 dict = NULL;
261
262 ret = diagnostics_relay_receive(client, &dict);
263 if (!dict) {
264 return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
265 }
266
267 int check = diagnostics_relay_check_result(dict);
268 if (check == RESULT_SUCCESS) {
269 ret = DIAGNOSTICS_RELAY_E_SUCCESS;
270 } else if (check == RESULT_UNKNOWN_REQUEST) {
271 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
272 } else {
273 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
274 }
275
276 plist_free(dict);
277 return ret;
278}
279
280diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
281{
282 return internal_diagnostics_relay_action(client, "Restart", flags);
283}
284
285diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
286{
287 return internal_diagnostics_relay_action(client, "Shutdown", flags);
288}
289
290diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics)
291{
292 if (!client || diagnostics == NULL)
293 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
294
295 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
296
297 plist_t dict = plist_new_dict();
298 plist_dict_set_item(dict,"Request", plist_new_string(type));
299 ret = diagnostics_relay_send(client, dict);
300 plist_free(dict);
301 dict = NULL;
302 if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
303 return ret;
304 }
305
306 ret = diagnostics_relay_receive(client, &dict);
307 if (!dict) {
308 return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
309 }
310
311 int check = diagnostics_relay_check_result(dict);
312 if (check == RESULT_SUCCESS) {
313 ret = DIAGNOSTICS_RELAY_E_SUCCESS;
314 } else if (check == RESULT_UNKNOWN_REQUEST) {
315 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
316 } else {
317 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
318 }
319
320 if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
321 plist_free(dict);
322 return ret;
323 }
324
325 plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
326 if (value_node) {
327 *diagnostics = plist_copy(value_node);
328 }
329
330 plist_free(dict);
331 return ret;
332}
333
334diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result)
335{
336 if (!client || plist_get_node_type(keys) != PLIST_ARRAY || result == NULL)
337 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
338
339 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
340
341 plist_t dict = plist_new_dict();
342 plist_dict_set_item(dict,"MobileGestaltKeys", plist_copy(keys));
343 plist_dict_set_item(dict,"Request", plist_new_string("MobileGestalt"));
344 ret = diagnostics_relay_send(client, dict);
345 plist_free(dict);
346 dict = NULL;
347 if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
348 return ret;
349 }
350
351 ret = diagnostics_relay_receive(client, &dict);
352 if (!dict) {
353 return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
354 }
355
356 int check = diagnostics_relay_check_result(dict);
357 if (check == RESULT_SUCCESS) {
358 ret = DIAGNOSTICS_RELAY_E_SUCCESS;
359 } else if (check == RESULT_UNKNOWN_REQUEST) {
360 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
361 } else {
362 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
363 }
364
365 if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
366 plist_free(dict);
367 return ret;
368 }
369
370 plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
371 if (value_node) {
372 *result = plist_copy(value_node);
373 }
374
375 plist_free(dict);
376 return ret;
377}
378
379diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* entry_name, const char* entry_class, plist_t* result)
380{
381 if (!client || (entry_name == NULL && entry_class == NULL) || result == NULL)
382 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
383
384 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
385
386 plist_t dict = plist_new_dict();
387 if (entry_name)
388 plist_dict_set_item(dict,"EntryName", plist_new_string(entry_name));
389 if (entry_class)
390 plist_dict_set_item(dict,"EntryClass", plist_new_string(entry_class));
391 plist_dict_set_item(dict,"Request", plist_new_string("IORegistry"));
392 ret = diagnostics_relay_send(client, dict);
393 plist_free(dict);
394 dict = NULL;
395 if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
396 return ret;
397 }
398
399 ret = diagnostics_relay_receive(client, &dict);
400 if (!dict) {
401 return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
402 }
403
404 int check = diagnostics_relay_check_result(dict);
405 if (check == RESULT_SUCCESS) {
406 ret = DIAGNOSTICS_RELAY_E_SUCCESS;
407 } else if (check == RESULT_UNKNOWN_REQUEST) {
408 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
409 } else {
410 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
411 }
412
413 if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
414 plist_free(dict);
415 return ret;
416 }
417
418 plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
419 if (value_node) {
420 *result = plist_copy(value_node);
421 }
422
423 plist_free(dict);
424 return ret;
425}
426
427diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result)
428{
429 if (!client || plane == NULL || result == NULL)
430 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
431
432 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
433
434 plist_t dict = plist_new_dict();
435 plist_dict_set_item(dict,"CurrentPlane", plist_new_string(plane));
436 plist_dict_set_item(dict,"Request", plist_new_string("IORegistry"));
437 ret = diagnostics_relay_send(client, dict);
438 plist_free(dict);
439 dict = NULL;
440
441 ret = diagnostics_relay_receive(client, &dict);
442 if (!dict) {
443 return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
444 }
445
446 int check = diagnostics_relay_check_result(dict);
447 if (check == RESULT_SUCCESS) {
448 ret = DIAGNOSTICS_RELAY_E_SUCCESS;
449 } else if (check == RESULT_UNKNOWN_REQUEST) {
450 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
451 } else {
452 ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
453 }
454
455 if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
456 plist_free(dict);
457 return ret;
458 }
459
460 plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
461 if (value_node) {
462 *result = plist_copy(value_node);
463 }
464
465 plist_free(dict);
466 return ret;
467}