summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Martin Szulecki2013-08-19 04:02:26 +0200
committerGravatar Martin Szulecki2013-08-19 04:02:26 +0200
commit83c931bd0486265dda735e61fb62aac521a444d4 (patch)
treec15779f80a33b6650fc389ceda0ba029e374e6cb /src
parent3d1de1b31ec2bd5e9db93dea8522743b1627675e (diff)
downloadlibimobiledevice-83c931bd0486265dda735e61fb62aac521a444d4.tar.gz
libimobiledevice-83c931bd0486265dda735e61fb62aac521a444d4.tar.bz2
webinspector: Implement support for partial messages when sending or receiving
The protocol appears to split plist payload on 8096 bytes boundries into multiple WIRPartialMessage messages. Now partial messages are correctly decoded during receiving and split automatically when sending large messages by the implementation.
Diffstat (limited to 'src')
-rw-r--r--src/webinspector.c165
-rw-r--r--src/webinspector.h2
2 files changed, 125 insertions, 42 deletions
diff --git a/src/webinspector.c b/src/webinspector.c
index d7c86d0..c042df9 100644
--- a/src/webinspector.c
+++ b/src/webinspector.c
@@ -149,27 +149,56 @@ webinspector_error_t webinspector_client_free(webinspector_client_t client)
149webinspector_error_t webinspector_send(webinspector_client_t client, plist_t plist) 149webinspector_error_t webinspector_send(webinspector_client_t client, plist_t plist)
150{ 150{
151 webinspector_error_t res = WEBINSPECTOR_E_UNKNOWN_ERROR; 151 webinspector_error_t res = WEBINSPECTOR_E_UNKNOWN_ERROR;
152 char * buf = NULL;
153 uint32_t length = 0;
154 152
155 plist_to_bin(plist, &buf, &length); 153 uint32_t offset = 0;
156 if (!buf || length == 0) { 154 int is_final_message = 0;
155
156 char *packet = NULL;
157 uint32_t packet_length = 0;
158
159 debug_info("Sending webinspector message...");
160 debug_plist(plist);
161
162 /* convert plist to packet */
163 plist_to_bin(plist, &packet, &packet_length);
164 if (!packet || packet_length == 0) {
157 debug_info("Error converting plist to binary."); 165 debug_info("Error converting plist to binary.");
158 return res; 166 return res;
159 } 167 }
160 168
161 plist_t outplist = plist_new_dict(); 169 do {
162 plist_dict_insert_item(outplist, "WIRFinalMessageKey", plist_new_data(buf, length)); 170 /* determine if we need to send partial messages */
163 free(buf); 171 if (packet_length < WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE) {
172 is_final_message = 1;
173 } else {
174 /* send partial packet */
175 is_final_message = 0;
176 }
164 177
165 debug_plist(outplist); 178 plist_t outplist = plist_new_dict();
179 if (!is_final_message) {
180 /* split packet into partial chunks */
181 plist_dict_insert_item(outplist, "WIRPartialMessageKey", plist_new_data(packet + offset, WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE));
182 offset += WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE;
183 packet_length -= WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE;
184 } else {
185 /* send final chunk */
186 plist_dict_insert_item(outplist, "WIRFinalMessageKey", plist_new_data(packet + offset, packet_length));
187 offset += packet_length;
188 packet_length -= packet_length;
189 }
166 190
167 res = webinspector_error(property_list_service_send_binary_plist(client->parent, outplist)); 191 res = webinspector_error(property_list_service_send_binary_plist(client->parent, outplist));
168 plist_free(outplist); 192 plist_free(outplist);
169 if (res != WEBINSPECTOR_E_SUCCESS) { 193 outplist = NULL;
170 debug_info("Sending plist failed with error %d", res); 194 if (res != WEBINSPECTOR_E_SUCCESS) {
171 return res; 195 debug_info("Sending plist failed with error %d", res);
172 } 196 return res;
197 }
198 } while(packet_length > 0);
199
200 free(packet);
201 packet = NULL;
173 202
174 return res; 203 return res;
175} 204}
@@ -206,40 +235,92 @@ webinspector_error_t webinspector_receive(webinspector_client_t client, plist_t
206webinspector_error_t webinspector_receive_with_timeout(webinspector_client_t client, plist_t * plist, uint32_t timeout_ms) 235webinspector_error_t webinspector_receive_with_timeout(webinspector_client_t client, plist_t * plist, uint32_t timeout_ms)
207{ 236{
208 webinspector_error_t res = WEBINSPECTOR_E_UNKNOWN_ERROR; 237 webinspector_error_t res = WEBINSPECTOR_E_UNKNOWN_ERROR;
209 plist_t outplist = NULL; 238 plist_t message = NULL;
239 plist_t key = NULL;
210 240
211 res = webinspector_error(property_list_service_receive_plist_with_timeout(client->parent, &outplist, timeout_ms)); 241 int is_final_message = 1;
212 if (res != WEBINSPECTOR_E_SUCCESS || !outplist) {
213 debug_info("Could not receive plist, error %d", res);
214 plist_free(outplist);
215 return WEBINSPECTOR_E_MUX_ERROR;
216 }
217 242
218 plist_t inplistdata = plist_dict_get_item(outplist, "WIRFinalMessageKey"); 243 char* buffer = NULL;
219 if (!inplistdata) { 244 uint64_t length = 0;
220 debug_info("Could not find the internal message plist.");
221 plist_free(outplist);
222 return WEBINSPECTOR_E_PLIST_ERROR;
223 }
224 245
225 char * buf; 246 char* packet = NULL;
226 uint64_t length64; 247 char* newpacket = NULL;
227 plist_get_data_val(inplistdata, &buf, &length64); 248 uint64_t packet_length = 0;
228 plist_free(outplist); 249
229 if (!buf || length64 == 0 || length64 > 0xFFFFFFFF) { 250 debug_info("Receiving webinspector message...");
230 debug_info("Error getting the inner plist binary data.");
231 free(buf);
232 return WEBINSPECTOR_E_PLIST_ERROR;
233 }
234 251
235 plist_from_bin(buf, (uint32_t) length64, plist); 252 do {
236 free(buf); 253 /* receive message */
237 if (!*plist) { 254 res = webinspector_error(property_list_service_receive_plist_with_timeout(client->parent, &message, timeout_ms));
238 debug_info("Error restoring the inner plist."); 255 if (res != WEBINSPECTOR_E_SUCCESS || !message) {
239 return WEBINSPECTOR_E_PLIST_ERROR; 256 debug_info("Could not receive message, error %d", res);
257 plist_free(message);
258 return WEBINSPECTOR_E_MUX_ERROR;
259 }
260
261 /* get message key */
262 key = plist_dict_get_item(message, "WIRFinalMessageKey");
263 if (!key) {
264 key = plist_dict_get_item(message, "WIRPartialMessageKey");
265 if (!key) {
266 debug_info("ERROR: Unable to read message key.");
267 plist_free(message);
268 return WEBINSPECTOR_E_PLIST_ERROR;
269 }
270 is_final_message = 0;
271 } else {
272 is_final_message = 1;
273 }
274
275 /* read partial data */
276 plist_get_data_val(key, &buffer, &length);
277 if (!buffer || length == 0 || length > 0xFFFFFFFF) {
278 debug_info("ERROR: Unable to get the inner plist binary data.");
279 free(packet);
280 free(buffer);
281 return WEBINSPECTOR_E_PLIST_ERROR;
282 }
283
284 /* (re)allocate packet data */
285 if (!packet) {
286 packet = (char*)malloc(length * sizeof(char));
287 } else {
288 newpacket = (char*)realloc(packet, (packet_length + length) * sizeof(char));
289 packet = newpacket;
290 }
291
292 /* copy partial data into final packet data */
293 memcpy(packet + packet_length, buffer, length);
294
295 /* cleanup buffer */
296 free(buffer);
297 buffer = NULL;
298
299 if (message) {
300 plist_free(message);
301 message = NULL;
302 }
303
304 /* adjust packet length */
305 packet_length += length;
306 length = 0;
307 } while(!is_final_message);
308
309 /* read final message */
310 if (packet_length) {
311 plist_from_bin(packet, (uint32_t)packet_length, plist);
312 if (!*plist) {
313 debug_info("Error restoring the final plist.");
314 free(packet);
315 return WEBINSPECTOR_E_PLIST_ERROR;
316 }
317
318 debug_plist(*plist);
240 } 319 }
241 320
242 debug_plist(*plist); 321 if (packet) {
322 free(packet);
323 }
243 324
244 return res; 325 return res;
245} 326}
diff --git a/src/webinspector.h b/src/webinspector.h
index ab04a70..3c8e695 100644
--- a/src/webinspector.h
+++ b/src/webinspector.h
@@ -25,6 +25,8 @@
25#include "libimobiledevice/webinspector.h" 25#include "libimobiledevice/webinspector.h"
26#include "property_list_service.h" 26#include "property_list_service.h"
27 27
28#define WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE 8096
29
28struct webinspector_client_private { 30struct webinspector_client_private {
29 property_list_service_client_t parent; 31 property_list_service_client_t parent;
30}; 32};