summaryrefslogtreecommitdiffstats
path: root/src/preboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/preboard.c')
-rw-r--r--src/preboard.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/src/preboard.c b/src/preboard.c
new file mode 100644
index 0000000..c3eff02
--- /dev/null
+++ b/src/preboard.c
@@ -0,0 +1,256 @@
1/*
2 * preboard.c
3 * com.apple.preboardservice_v2 service implementation.
4 *
5 * Copyright (c) 2019 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
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25#include <string.h>
26#include <stdlib.h>
27#include <plist/plist.h>
28
29#include "preboard.h"
30#include "lockdown.h"
31#include "common/debug.h"
32
33/**
34 * Convert a property_list_service_error_t value to a preboard_error_t value.
35 * Used internally to get correct error codes.
36 *
37 * @param err An property_list_service_error_t error code
38 *
39 * @return A matching preboard_error_t error code,
40 * PREBOARD_E_UNKNOWN_ERROR otherwise.
41 */
42static preboard_error_t preboard_error(property_list_service_error_t err)
43{
44 switch (err) {
45 case PROPERTY_LIST_SERVICE_E_SUCCESS:
46 return PREBOARD_E_SUCCESS;
47 case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
48 return PREBOARD_E_INVALID_ARG;
49 case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
50 return PREBOARD_E_PLIST_ERROR;
51 case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
52 return PREBOARD_E_MUX_ERROR;
53 case PROPERTY_LIST_SERVICE_E_SSL_ERROR:
54 return PREBOARD_E_SSL_ERROR;
55 case PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA:
56 return PREBOARD_E_NOT_ENOUGH_DATA;
57 case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT:
58 return PREBOARD_E_TIMEOUT;
59 default:
60 break;
61 }
62 return PREBOARD_E_UNKNOWN_ERROR;
63}
64
65preboard_error_t preboard_client_new(idevice_t device, lockdownd_service_descriptor_t service, preboard_client_t * client)
66{
67 *client = NULL;
68
69 if (!device || !service || service->port == 0 || !client || *client) {
70 debug_info("Incorrect parameter passed to preboard_client_new.");
71 return PREBOARD_E_INVALID_ARG;
72 }
73
74 debug_info("Creating preboard_client, port = %d.", service->port);
75
76 property_list_service_client_t plclient = NULL;
77 preboard_error_t ret = preboard_error(property_list_service_client_new(device, service, &plclient));
78 if (ret != PREBOARD_E_SUCCESS) {
79 debug_info("Creating a property list client failed. Error: %i", ret);
80 return ret;
81 }
82
83 preboard_client_t client_loc = (preboard_client_t) malloc(sizeof(struct preboard_client_private));
84 client_loc->parent = plclient;
85 client_loc->receive_status_thread = THREAD_T_NULL;
86
87 *client = client_loc;
88
89 debug_info("preboard_client successfully created.");
90 return 0;
91}
92
93preboard_error_t preboard_client_start_service(idevice_t device, preboard_client_t * client, const char* label)
94{
95 preboard_error_t err = PREBOARD_E_UNKNOWN_ERROR;
96 service_client_factory_start_service(device, PREBOARD_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(preboard_client_new), &err);
97 return err;
98}
99
100preboard_error_t preboard_client_free(preboard_client_t client)
101{
102 if (!client)
103 return PREBOARD_E_INVALID_ARG;
104
105 property_list_service_client_t parent = client->parent;
106 client->parent = NULL;
107 if (client->receive_status_thread) {
108 debug_info("joining receive_status_thread");
109 thread_join(client->receive_status_thread);
110 thread_free(client->receive_status_thread);
111 client->receive_status_thread = THREAD_T_NULL;
112 }
113 preboard_error_t err = preboard_error(property_list_service_client_free(parent));
114 free(client);
115
116 return err;
117}
118
119preboard_error_t preboard_send(preboard_client_t client, plist_t plist)
120{
121 preboard_error_t res = PREBOARD_E_UNKNOWN_ERROR;
122 res = preboard_error(property_list_service_send_binary_plist(client->parent, plist));
123 if (res != PREBOARD_E_SUCCESS) {
124 debug_info("Sending plist failed with error %d", res);
125 return res;
126 }
127 return res;
128}
129
130preboard_error_t preboard_receive_with_timeout(preboard_client_t client, plist_t * plist, uint32_t timeout_ms)
131{
132 preboard_error_t res = PREBOARD_E_UNKNOWN_ERROR;
133 plist_t outplist = NULL;
134 res = preboard_error(property_list_service_receive_plist_with_timeout(client->parent, &outplist, timeout_ms));
135 if (res != PREBOARD_E_SUCCESS && res != PREBOARD_E_TIMEOUT) {
136 debug_info("Could not receive plist, error %d", res);
137 plist_free(outplist);
138 } else if (res == PREBOARD_E_SUCCESS) {
139 *plist = outplist;
140 }
141 return res;
142}
143
144preboard_error_t preboard_receive(preboard_client_t client, plist_t * plist)
145{
146 return preboard_receive_with_timeout(client, plist, 5000);
147}
148
149struct preboard_status_data {
150 preboard_client_t client;
151 preboard_status_cb_t cbfunc;
152 void *user_data;
153};
154
155static void* preboard_receive_status_loop_thread(void* arg)
156{
157 struct preboard_status_data *data = (struct preboard_status_data*)arg;
158
159 /* run until the service disconnects or an error occurs */
160 while (data->client && data->client->parent) {
161 plist_t pl = NULL;
162 preboard_error_t perr = preboard_receive_with_timeout(data->client, &pl, 1000);
163 if (perr == PREBOARD_E_TIMEOUT) {
164 continue;
165 }
166 if (perr == PREBOARD_E_SUCCESS) {
167 data->cbfunc(pl, data->user_data);
168 }
169 plist_free(pl);
170 if (perr != PREBOARD_E_SUCCESS) {
171 data->cbfunc(NULL, data->user_data);
172 break;
173 }
174 }
175
176 /* cleanup */
177 debug_info("done, cleaning up.");
178
179 if (data->client->receive_status_thread) {
180 thread_free(data->client->receive_status_thread);
181 data->client->receive_status_thread = THREAD_T_NULL;
182 }
183 free(data);
184
185 return NULL;
186}
187
188static preboard_error_t preboard_receive_status_loop_with_callback(preboard_client_t client, preboard_status_cb_t status_cb, void *user_data)
189{
190 if (!client || !client->parent) {
191 return PREBOARD_E_INVALID_ARG;
192 }
193
194 if (client->receive_status_thread) {
195 return PREBOARD_E_OP_IN_PROGRESS;
196 }
197
198 preboard_error_t res = PREBOARD_E_UNKNOWN_ERROR;
199 struct preboard_status_data *data = (struct preboard_status_data*)malloc(sizeof(struct preboard_status_data));
200 if (data) {
201 data->client = client;
202 data->cbfunc = status_cb;
203 data->user_data = user_data;
204 if (thread_new(&client->receive_status_thread, preboard_receive_status_loop_thread, data) == 0) {
205 res = PREBOARD_E_SUCCESS;
206 }
207 }
208
209 return res;
210}
211
212preboard_error_t preboard_create_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data)
213{
214 if (!client) {
215 return PREBOARD_E_INVALID_ARG;
216 }
217
218 plist_t dict = plist_new_dict();
219 plist_dict_set_item(dict, "Command", plist_new_string("CreateStashbag"));
220 if (manifest) {
221 plist_dict_set_item(dict, "Manifest", plist_copy(manifest));
222 }
223 preboard_error_t perr = preboard_send(client, dict);
224 plist_free(dict);
225 if (perr != PREBOARD_E_SUCCESS) {
226 return perr;
227 }
228 if (!status_cb) {
229 return PREBOARD_E_SUCCESS;
230 }
231
232 return preboard_receive_status_loop_with_callback(client, status_cb, user_data);
233}
234
235preboard_error_t preboard_commit_stashbag(preboard_client_t client, plist_t manifest, preboard_status_cb_t status_cb, void *user_data)
236{
237 if (!client) {
238 return PREBOARD_E_INVALID_ARG;
239 }
240
241 plist_t dict = plist_new_dict();
242 plist_dict_set_item(dict, "Command", plist_new_string("CommitStashbag"));
243 if (manifest) {
244 plist_dict_set_item(dict, "Manifest", plist_copy(manifest));
245 }
246 preboard_error_t perr = preboard_send(client, dict);
247 plist_free(dict);
248 if (perr != PREBOARD_E_SUCCESS) {
249 return perr;
250 }
251 if (!status_cb) {
252 return PREBOARD_E_SUCCESS;
253 }
254
255 return preboard_receive_status_loop_with_callback(client, status_cb, user_data);
256}