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.c301
1 files changed, 123 insertions, 178 deletions
diff --git a/src/property_list_service.c b/src/property_list_service.c
index 8af958e..2fca4e7 100644
--- a/src/property_list_service.c
+++ b/src/property_list_service.c
@@ -1,4 +1,4 @@
1/* 1/*
2 * property_list_service.c 2 * property_list_service.c
3 * PropertyList service implementation. 3 * PropertyList service implementation.
4 * 4 *
@@ -8,97 +8,86 @@
8 * modify it under the terms of the GNU Lesser General Public 8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version. 10 * version 2.1 of the License, or (at your option) any later version.
11 * 11 *
12 * This library is distributed in the hope that it will be useful, 12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details. 15 * Lesser General Public License for more details.
16 * 16 *
17 * You should have received a copy of the GNU Lesser General Public 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 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 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 20 */
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
21#include <stdlib.h> 24#include <stdlib.h>
22#include <string.h> 25#include <string.h>
23#include <glib.h>
24 26
25#include "property_list_service.h" 27#include "property_list_service.h"
26#include "idevice.h" 28#include "common/debug.h"
27#include "debug.h" 29#include "endianness.h"
28 30
29/** 31/**
30 * Convert an idevice_error_t value to an property_list_service_error_t value. 32 * Convert a service_error_t value to a property_list_service_error_t value.
31 * Used internally to get correct error codes. 33 * Used internally to get correct error codes.
32 * 34 *
33 * @param err An idevice_error_t error code 35 * @param err A service_error_t error code
34 * 36 *
35 * @return A matching property_list_service_error_t error code, 37 * @return A matching property_list_service_error_t error code,
36 * PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise. 38 * PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise.
37 */ 39 */
38static property_list_service_error_t idevice_to_property_list_service_error(idevice_error_t err) 40static property_list_service_error_t service_to_property_list_service_error(service_error_t err)
39{ 41{
40 switch (err) { 42 switch (err) {
41 case IDEVICE_E_SUCCESS: 43 case SERVICE_E_SUCCESS:
42 return PROPERTY_LIST_SERVICE_E_SUCCESS; 44 return PROPERTY_LIST_SERVICE_E_SUCCESS;
43 case IDEVICE_E_INVALID_ARG: 45 case SERVICE_E_INVALID_ARG:
44 return PROPERTY_LIST_SERVICE_E_INVALID_ARG; 46 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
45 case IDEVICE_E_SSL_ERROR: 47 case SERVICE_E_MUX_ERROR:
48 return PROPERTY_LIST_SERVICE_E_MUX_ERROR;
49 case SERVICE_E_SSL_ERROR:
46 return PROPERTY_LIST_SERVICE_E_SSL_ERROR; 50 return PROPERTY_LIST_SERVICE_E_SSL_ERROR;
51 case SERVICE_E_NOT_ENOUGH_DATA:
52 return PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA;
53 case SERVICE_E_TIMEOUT:
54 return PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT;
47 default: 55 default:
48 break; 56 break;
49 } 57 }
50 return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; 58 return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
51} 59}
52 60
53/** 61property_list_service_error_t property_list_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, property_list_service_client_t *client)
54 * Creates a new property list service for the specified port.
55 *
56 * @param device The device to connect to.
57 * @param port The port on the device to connect to, usually opened by a call to
58 * lockdownd_start_service.
59 * @param client Pointer that will be set to a newly allocated
60 * property_list_service_client_t upon successful return.
61 *
62 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
63 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when one of the arguments is invalid,
64 * or PROPERTY_LIST_SERVICE_E_MUX_ERROR when connecting to the device failed.
65 */
66property_list_service_error_t property_list_service_client_new(idevice_t device, uint16_t port, property_list_service_client_t *client)
67{ 62{
68 if (!device || port == 0 || !client || *client) 63 if (!device || !service || service->port == 0 || !client || *client)
69 return PROPERTY_LIST_SERVICE_E_INVALID_ARG; 64 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
70 65
71 /* Attempt connection */ 66 service_client_t parent = NULL;
72 idevice_connection_t connection = NULL; 67 service_error_t rerr = service_client_new(device, service, &parent);
73 if (idevice_connect(device, port, &connection) != IDEVICE_E_SUCCESS) { 68 if (rerr != SERVICE_E_SUCCESS) {
74 return PROPERTY_LIST_SERVICE_E_MUX_ERROR; 69 return service_to_property_list_service_error(rerr);
75 } 70 }
76 71
77 /* create client object */ 72 /* create client object */
78 property_list_service_client_t client_loc = (property_list_service_client_t)malloc(sizeof(struct property_list_service_client_private)); 73 property_list_service_client_t client_loc = (property_list_service_client_t)malloc(sizeof(struct property_list_service_client_private));
79 client_loc->connection = connection; 74 client_loc->parent = parent;
80 75
76 /* all done, return success */
81 *client = client_loc; 77 *client = client_loc;
82
83 return PROPERTY_LIST_SERVICE_E_SUCCESS; 78 return PROPERTY_LIST_SERVICE_E_SUCCESS;
84} 79}
85 80
86/**
87 * Frees a PropertyList service.
88 *
89 * @param client The property list service to free.
90 *
91 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
92 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client is invalid, or a
93 * PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when another error occured.
94 */
95property_list_service_error_t property_list_service_client_free(property_list_service_client_t client) 81property_list_service_error_t property_list_service_client_free(property_list_service_client_t client)
96{ 82{
97 if (!client) 83 if (!client)
98 return PROPERTY_LIST_SERVICE_E_INVALID_ARG; 84 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
99 85
100 property_list_service_error_t err = idevice_to_property_list_service_error(idevice_disconnect(client->connection)); 86 property_list_service_error_t err = service_to_property_list_service_error(service_client_free(client->parent));
87
101 free(client); 88 free(client);
89 client = NULL;
90
102 return err; 91 return err;
103} 92}
104 93
@@ -113,7 +102,8 @@ property_list_service_error_t property_list_service_client_free(property_list_se
113 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, 102 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
114 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when one or more parameters are 103 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when one or more parameters are
115 * invalid, PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid 104 * invalid, PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid
116 * plist, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified 105 * plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a communication error
106 * occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified
117 * error occurs. 107 * error occurs.
118 */ 108 */
119static property_list_service_error_t internal_plist_send(property_list_service_client_t client, plist_t plist, int binary) 109static property_list_service_error_t internal_plist_send(property_list_service_client_t client, plist_t plist, int binary)
@@ -122,9 +112,9 @@ static property_list_service_error_t internal_plist_send(property_list_service_c
122 char *content = NULL; 112 char *content = NULL;
123 uint32_t length = 0; 113 uint32_t length = 0;
124 uint32_t nlen = 0; 114 uint32_t nlen = 0;
125 int bytes = 0; 115 uint32_t bytes = 0;
126 116
127 if (!client || (client && !client->connection) || !plist) { 117 if (!client || (client && !client->parent) || !plist) {
128 return PROPERTY_LIST_SERVICE_E_INVALID_ARG; 118 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
129 } 119 }
130 120
@@ -138,15 +128,15 @@ static property_list_service_error_t internal_plist_send(property_list_service_c
138 return PROPERTY_LIST_SERVICE_E_PLIST_ERROR; 128 return PROPERTY_LIST_SERVICE_E_PLIST_ERROR;
139 } 129 }
140 130
141 nlen = GUINT32_TO_BE(length); 131 nlen = htobe32(length);
142 debug_info("sending %d bytes", length); 132 debug_info("sending %d bytes", length);
143 idevice_connection_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); 133 service_send(client->parent, (const char*)&nlen, sizeof(nlen), &bytes);
144 if (bytes == sizeof(nlen)) { 134 if (bytes == sizeof(nlen)) {
145 idevice_connection_send(client->connection, content, length, (uint32_t*)&bytes); 135 service_send(client->parent, content, length, &bytes);
146 if (bytes > 0) { 136 if (bytes > 0) {
147 debug_info("sent %d bytes", bytes); 137 debug_info("sent %d bytes", bytes);
148 debug_plist(plist); 138 debug_plist(plist);
149 if ((uint32_t)bytes == length) { 139 if (bytes == length) {
150 res = PROPERTY_LIST_SERVICE_E_SUCCESS; 140 res = PROPERTY_LIST_SERVICE_E_SUCCESS;
151 } else { 141 } else {
152 debug_info("ERROR: Could not send all data (%d of %d)!", bytes, length); 142 debug_info("ERROR: Could not send all data (%d of %d)!", bytes, length);
@@ -155,40 +145,18 @@ static property_list_service_error_t internal_plist_send(property_list_service_c
155 } 145 }
156 if (bytes <= 0) { 146 if (bytes <= 0) {
157 debug_info("ERROR: sending to device failed."); 147 debug_info("ERROR: sending to device failed.");
148 res = PROPERTY_LIST_SERVICE_E_MUX_ERROR;
158 } 149 }
159 150
160 free(content); 151 free(content);
161
162 return res; 152 return res;
163} 153}
164 154
165/**
166 * Sends an XML plist.
167 *
168 * @param client The property list service client to use for sending.
169 * @param plist plist to send
170 *
171 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
172 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or plist is NULL,
173 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid plist,
174 * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified error occurs.
175 */
176property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist) 155property_list_service_error_t property_list_service_send_xml_plist(property_list_service_client_t client, plist_t plist)
177{ 156{
178 return internal_plist_send(client, plist, 0); 157 return internal_plist_send(client, plist, 0);
179} 158}
180 159
181/**
182 * Sends a binary plist.
183 *
184 * @param client The property list service client to use for sending.
185 * @param plist plist to send
186 *
187 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
188 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or plist is NULL,
189 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid plist,
190 * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified error occurs.
191 */
192property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist) 160property_list_service_error_t property_list_service_send_binary_plist(property_list_service_client_t client, plist_t plist)
193{ 161{
194 return internal_plist_send(client, plist, 1); 162 return internal_plist_send(client, plist, 1);
@@ -205,6 +173,8 @@ property_list_service_error_t property_list_service_send_binary_plist(property_l
205 * 173 *
206 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, 174 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
207 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL, 175 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL,
176 * PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA when not enough data
177 * received, PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT when the connection times out,
208 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be 178 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be
209 * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a 179 * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a
210 * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR 180 * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR
@@ -216,135 +186,110 @@ static property_list_service_error_t internal_plist_receive_timeout(property_lis
216 uint32_t pktlen = 0; 186 uint32_t pktlen = 0;
217 uint32_t bytes = 0; 187 uint32_t bytes = 0;
218 188
219 if (!client || (client && !client->connection) || !plist) { 189 if (!client || (client && !client->parent) || !plist) {
220 return PROPERTY_LIST_SERVICE_E_INVALID_ARG; 190 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
221 } 191 }
222 192
223 idevice_connection_receive_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); 193 *plist = NULL;
224 debug_info("initial read=%i", bytes); 194 service_error_t serr = service_receive_with_timeout(client->parent, (char*)&pktlen, sizeof(pktlen), &bytes, timeout);
225 if (bytes < 4) { 195 if (serr != SERVICE_E_SUCCESS) {
226 debug_info("initial read failed!"); 196 debug_info("initial read failed!");
227 return PROPERTY_LIST_SERVICE_E_MUX_ERROR; 197 return service_to_property_list_service_error(serr);
228 } else { 198 }
229 pktlen = GUINT32_FROM_BE(pktlen); 199
230 if (pktlen < (1 << 24)) { /* prevent huge buffers */ 200 if (bytes == 0) {
231 uint32_t curlen = 0; 201 /* success but 0 bytes length, assume timeout */
232 char *content = NULL; 202 return PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT;
233 debug_info("%d bytes following", pktlen); 203 }
234 content = (char*)malloc(pktlen); 204
235 205 debug_info("initial read=%i", bytes);
236 while (curlen < pktlen) { 206
237 idevice_connection_receive(client->connection, content+curlen, pktlen-curlen, &bytes); 207 uint32_t curlen = 0;
238 if (bytes <= 0) { 208 char *content = NULL;
239 res = PROPERTY_LIST_SERVICE_E_MUX_ERROR; 209
240 break; 210 pktlen = be32toh(pktlen);
241 } 211 debug_info("%d bytes following", pktlen);
242 debug_info("received %d bytes", bytes); 212 content = (char*)malloc(pktlen);
243 curlen += bytes; 213 if (!content) {
244 } 214 debug_info("out of memory when allocating %d bytes", pktlen);
245 if (!memcmp(content, "bplist00", 8)) { 215 return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
246 plist_from_bin(content, pktlen, plist); 216 }
247 } else { 217
248 /* iOS 4.3 hack: plist data might contain invalid null characters, thus we convert those to spaces */ 218 while (curlen < pktlen) {
249 for (bytes = 0; bytes < pktlen-1; bytes++) { 219 serr = service_receive(client->parent, content+curlen, pktlen-curlen, &bytes);
250 if (content[bytes] == 0x0) 220 if (serr != SERVICE_E_SUCCESS) {
251 content[bytes] = 0x20; 221 res = service_to_property_list_service_error(serr);
252 } 222 break;
253 plist_from_xml(content, pktlen, plist);
254 }
255 if (*plist) {
256 debug_plist(*plist);
257 res = PROPERTY_LIST_SERVICE_E_SUCCESS;
258 } else {
259 res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR;
260 }
261 free(content);
262 content = NULL;
263 } else {
264 res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
265 } 223 }
224 debug_info("received %d bytes", bytes);
225 curlen += bytes;
266 } 226 }
227
228 if (curlen < pktlen) {
229 debug_info("received incomplete packet (%d of %d bytes)", curlen, pktlen);
230 if (curlen > 0) {
231 debug_info("incomplete packet following:");
232 debug_buffer(content, curlen);
233 }
234 free(content);
235 return res;
236 }
237
238 if ((pktlen > 8) && !memcmp(content, "bplist00", 8)) {
239 plist_from_bin(content, pktlen, plist);
240 } else if ((pktlen > 5) && !memcmp(content, "<?xml", 5)) {
241 /* iOS 4.3+ hack: plist data might contain invalid characters, thus we convert those to spaces */
242 for (bytes = 0; bytes < pktlen-1; bytes++) {
243 if ((content[bytes] >= 0) && (content[bytes] < 0x20) && (content[bytes] != 0x09) && (content[bytes] != 0x0a) && (content[bytes] != 0x0d))
244 content[bytes] = 0x20;
245 }
246 plist_from_xml(content, pktlen, plist);
247 } else {
248 debug_info("WARNING: received unexpected non-plist content");
249 debug_buffer(content, pktlen);
250 }
251
252 if (*plist) {
253 debug_plist(*plist);
254 res = PROPERTY_LIST_SERVICE_E_SUCCESS;
255 } else {
256 res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR;
257 }
258
259 free(content);
260 content = NULL;
261
267 return res; 262 return res;
268} 263}
269 264
270/**
271 * Receives a plist using the given property list service client with specified
272 * timeout.
273 * Binary or XML plists are automatically handled.
274 *
275 * @param client The property list service client to use for receiving
276 * @param plist pointer to a plist_t that will point to the received plist
277 * upon successful return
278 * @param timeout Maximum time in milliseconds to wait for data.
279 *
280 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
281 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when connection or *plist is NULL,
282 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be
283 * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a
284 * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when
285 * an unspecified error occurs.
286 */
287property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout) 265property_list_service_error_t property_list_service_receive_plist_with_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout)
288{ 266{
289 return internal_plist_receive_timeout(client, plist, timeout); 267 return internal_plist_receive_timeout(client, plist, timeout);
290} 268}
291 269
292/**
293 * Receives a plist using the given property list service client.
294 * Binary or XML plists are automatically handled.
295 *
296 * This function is like property_list_service_receive_plist_with_timeout
297 * using a timeout of 10 seconds.
298 * @see property_list_service_receive_plist_with_timeout
299 *
300 * @param client The property list service client to use for receiving
301 * @param plist pointer to a plist_t that will point to the received plist
302 * upon successful return
303 *
304 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
305 * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL,
306 * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be
307 * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a
308 * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when
309 * an unspecified error occurs.
310 */
311property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist) 270property_list_service_error_t property_list_service_receive_plist(property_list_service_client_t client, plist_t *plist)
312{ 271{
313 return internal_plist_receive_timeout(client, plist, 10000); 272 return internal_plist_receive_timeout(client, plist, 30000);
314} 273}
315 274
316/**
317 * Enable SSL for the given property list service client.
318 *
319 * @param client The connected property list service client for which SSL
320 * should be enabled.
321 *
322 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
323 * PROPERTY_LIST_SERVICE_E_INVALID_ARG if client or client->connection is
324 * NULL, PROPERTY_LIST_SERVICE_E_SSL_ERROR when SSL could not be enabled,
325 * or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise.
326 */
327property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client) 275property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client)
328{ 276{
329 if (!client || !client->connection) 277 if (!client || !client->parent)
330 return PROPERTY_LIST_SERVICE_E_INVALID_ARG; 278 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
331 return idevice_to_property_list_service_error(idevice_connection_enable_ssl(client->connection)); 279 return service_to_property_list_service_error(service_enable_ssl(client->parent));
332} 280}
333 281
334/**
335 * Disable SSL for the given property list service client.
336 *
337 * @param client The connected property list service client for which SSL
338 * should be disabled.
339 *
340 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
341 * PROPERTY_LIST_SERVICE_E_INVALID_ARG if client or client->connection is
342 * NULL, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise.
343 */
344property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client) 282property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client)
345{ 283{
346 if (!client || !client->connection) 284 if (!client || !client->parent)
347 return PROPERTY_LIST_SERVICE_E_INVALID_ARG; 285 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
348 return idevice_to_property_list_service_error(idevice_connection_disable_ssl(client->connection)); 286 return service_to_property_list_service_error(service_disable_ssl(client->parent));
349} 287}
350 288
289property_list_service_error_t property_list_service_get_service_client(property_list_service_client_t client, service_client_t *service_client)
290{
291 if (!client || !client->parent || !service_client)
292 return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
293 *service_client = client->parent;
294 return PROPERTY_LIST_SERVICE_E_SUCCESS;
295}