summaryrefslogtreecommitdiffstats
path: root/src/property_list_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/property_list_service.c')
-rw-r--r--src/property_list_service.c346
1 files changed, 346 insertions, 0 deletions
diff --git a/src/property_list_service.c b/src/property_list_service.c
new file mode 100644
index 0000000..852ed9c
--- /dev/null
+++ b/src/property_list_service.c
@@ -0,0 +1,346 @@
1/*
2 * property_list_service.c
3 * PropertyList 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 <stdlib.h>
22#include <string.h>
23#include <errno.h>
24#include <arpa/inet.h>
25
26#include "property_list_service.h"
27#include "iphone.h"
28#include "debug.h"
29
30/**
31 * Convert an iphone_error_t value to an property_list_service_error_t value.
32 * Used internally to get correct error codes.
33 *
34 * @param err An iphone_error_t error code
35 *
36 * @return A matching property_list_service_error_t error code,
37 * PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise.
38 */
39static property_list_service_error_t iphone_to_property_list_service_error(iphone_error_t err)
40{
41 switch (err) {
42 case IPHONE_E_SUCCESS:
43 return PROPERTY_LIST_SERVICE_E_SUCCESS;
44 case IPHONE_E_INVALID_ARG:
45 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
46 case IPHONE_E_SSL_ERROR:
47 return PROPERTY_LIST_SERVICE_E_SSL_ERROR;
48 default:
49 break;
50 }
51 return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
52}
53
54/**
55 * Creates a new property list service for the specified port.
56 *
57 * @param device The device to connect to.
58 * @param port The port on the device to connect to, usually opened by a call to
59 * lockdownd_start_service.
60 * @param client Pointer that will be set to a newly allocated
61 * property_list_service_client_t upon successful return.
62 *
63 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
64 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when one of the arguments is invalid,
65 * or PROPERTY_LIST_SERVICE_E_MUX_ERROR when connecting to the device failed.
66 */
67property_list_service_error_t property_list_service_client_new(iphone_device_t device, uint16_t port, property_list_service_client_t *client)
68{
69 if (!device || port == 0 || !client || *client)
70 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
71
72 /* Attempt connection */
73 iphone_connection_t connection = NULL;
74 if (iphone_device_connect(device, port, &connection) != IPHONE_E_SUCCESS) {
75 return PROPERTY_LIST_SERVICE_E_MUX_ERROR;
76 }
77
78 /* create client object */
79 property_list_service_client_t client_loc = (property_list_service_client_t)malloc(sizeof(struct property_list_service_client_int));
80 client_loc->connection = connection;
81
82 *client = client_loc;
83
84 return PROPERTY_LIST_SERVICE_E_SUCCESS;
85}
86
87/**
88 * Frees a PropertyList service.
89 *
90 * @param client The property list service to free.
91 *
92 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
93 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client is invalid, or a
94 * PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when another error occured.
95 */
96property_list_service_error_t property_list_service_client_free(property_list_service_client_t client)
97{
98 if (!client)
99 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
100
101 property_list_service_error_t err = iphone_to_property_list_service_error(iphone_device_disconnect(client->connection));
102 free(client);
103 return err;
104}
105
106/**
107 * Sends a plist using the given property list service client.
108 * Internally used generic plist send function.
109 *
110 * @param client The property list service client to use for sending.
111 * @param plist plist to send
112 * @param binary 1 = send binary plist, 0 = send xml plist
113 *
114 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
115 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when one or more parameters are
116 * invalid, PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid
117 * plist, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified
118 * error occurs.
119 */
120static property_list_service_error_t internal_plist_send(property_list_service_client_t client, plist_t plist, int binary)
121{
122 property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
123 char *content = NULL;
124 uint32_t length = 0;
125 uint32_t nlen = 0;
126 int bytes = 0;
127
128 if (!client || (client && !client->connection) || !plist) {
129 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
130 }
131
132 if (binary) {
133 plist_to_bin(plist, &content, &length);
134 } else {
135 plist_to_xml(plist, &content, &length);
136 }
137
138 if (!content || length == 0) {
139 return PROPERTY_LIST_SERVICE_E_PLIST_ERROR;
140 }
141
142 nlen = htonl(length);
143 debug_info("sending %d bytes", length);
144 iphone_device_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes);
145 if (bytes == sizeof(nlen)) {
146 iphone_device_send(client->connection, content, length, (uint32_t*)&bytes);
147 if (bytes > 0) {
148 debug_info("sent %d bytes", bytes);
149 debug_plist(plist);
150 if ((uint32_t)bytes == length) {
151 res = PROPERTY_LIST_SERVICE_E_SUCCESS;
152 } else {
153 debug_info("ERROR: Could not send all data (%d of %d)!", bytes, length);
154 }
155 }
156 }
157 if (bytes <= 0) {
158 debug_info("ERROR: sending to device failed.");
159 }
160
161 free(content);
162
163 return res;
164}
165
166/**
167 * Sends an XML plist.
168 *
169 * @param client The property list service client to use for sending.
170 * @param plist plist to send
171 *
172 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
173 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or plist is NULL,
174 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid plist,
175 * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified error occurs.
176 */
177property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist)
178{
179 return internal_plist_send(client, plist, 0);
180}
181
182/**
183 * Sends a binary plist.
184 *
185 * @param client The property list service client to use for sending.
186 * @param plist plist to send
187 *
188 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
189 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or plist is NULL,
190 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid plist,
191 * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified error occurs.
192 */
193property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist)
194{
195 return internal_plist_send(client, plist, 1);
196}
197
198/**
199 * Receives a plist using the given property list service client.
200 * Internally used generic plist receive function.
201 *
202 * @param client The property list service client to use for receiving
203 * @param plist pointer to a plist_t that will point to the received plist
204 * upon successful return
205 * @param timeout Maximum time in milliseconds to wait for data.
206 *
207 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
208 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL,
209 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be
210 * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a
211 * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR
212 * when an unspecified error occurs.
213 */
214static property_list_service_error_t internal_plist_recv_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout)
215{
216 property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
217 uint32_t pktlen = 0;
218 uint32_t bytes = 0;
219
220 if (!client || (client && !client->connection) || !plist) {
221 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
222 }
223
224 iphone_device_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout);
225 debug_info("initial read=%i", bytes);
226 if (bytes < 4) {
227 debug_info("initial read failed!");
228 return PROPERTY_LIST_SERVICE_E_MUX_ERROR;
229 } else {
230 if ((char)pktlen == 0) { /* prevent huge buffers */
231 uint32_t curlen = 0;
232 char *content = NULL;
233 pktlen = ntohl(pktlen);
234 debug_info("%d bytes following", pktlen);
235 content = (char*)malloc(pktlen);
236
237 while (curlen < pktlen) {
238 iphone_device_recv(client->connection, content+curlen, pktlen-curlen, &bytes);
239 if (bytes <= 0) {
240 res = PROPERTY_LIST_SERVICE_E_MUX_ERROR;
241 break;
242 }
243 debug_info("received %d bytes", bytes);
244 curlen += bytes;
245 }
246 if (!memcmp(content, "bplist00", 8)) {
247 plist_from_bin(content, pktlen, plist);
248 } else {
249 plist_from_xml(content, pktlen, plist);
250 }
251 if (*plist) {
252 debug_plist(*plist);
253 res = PROPERTY_LIST_SERVICE_E_SUCCESS;
254 } else {
255 res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR;
256 }
257 free(content);
258 content = NULL;
259 } else {
260 res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
261 }
262 }
263 return res;
264}
265
266/**
267 * Receives a plist using the given property list service client with specified
268 * timeout.
269 * Binary or XML plists are automatically handled.
270 *
271 * @param client The property list service client to use for receiving
272 * @param plist pointer to a plist_t that will point to the received plist
273 * upon successful return
274 * @param timeout Maximum time in milliseconds to wait for data.
275 *
276 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
277 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when connection or *plist is NULL,
278 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be
279 * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a
280 * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when
281 * an unspecified error occurs.
282 */
283property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout)
284{
285 return internal_plist_recv_timeout(client, plist, timeout);
286}
287
288/**
289 * Receives a plist using the given property list service client.
290 * Binary or XML plists are automatically handled.
291 *
292 * This function is like property_list_service_receive_plist_with_timeout
293 * using a timeout of 10 seconds.
294 * @see property_list_service_receive_plist_with_timeout
295 *
296 * @param client The property list service client to use for receiving
297 * @param plist pointer to a plist_t that will point to the received plist
298 * upon successful return
299 *
300 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
301 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL,
302 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be
303 * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a
304 * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when
305 * an unspecified error occurs.
306 */
307property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist)
308{
309 return internal_plist_recv_timeout(client, plist, 10000);
310}
311
312/**
313 * Enable SSL for the given property list service client.
314 *
315 * @param client The connected property list service client for which SSL
316 * should be enabled.
317 *
318 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
319 * PROPERTY_LIST_SERVICE_E_INVALID_ARG if client or client->connection is
320 * NULL, PROPERTY_LIST_SERVICE_E_SSL_ERROR when SSL could not be enabled,
321 * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise.
322 */
323property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client)
324{
325 if (!client || !client->connection)
326 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
327 return iphone_to_property_list_service_error(iphone_connection_enable_ssl(client->connection));
328}
329
330/**
331 * Disable SSL for the given property list service client.
332 *
333 * @param client The connected property list service client for which SSL
334 * should be disabled.
335 *
336 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
337 * PROPERTY_LIST_SERVICE_E_INVALID_ARG if client or client->connection is
338 * NULL, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise.
339 */
340property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client)
341{
342 if (!client || !client->connection)
343 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
344 return iphone_to_property_list_service_error(iphone_connection_disable_ssl(client->connection));
345}
346