summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Martin Szulecki2010-01-10 13:12:00 +0100
committerGravatar Martin Szulecki2010-01-10 13:12:00 +0100
commit2232caa09147bdbbf26b52f3bb17c264051d413d (patch)
treec1db37e1bc49c3e9d9f396e2614ede7cf92a3864
parentcec7e6b7591d018dd700c6fa6b5c85b29ec43b34 (diff)
parent69b4015bea6c32e523404e9784c225be8bfc0ef3 (diff)
downloadlibimobiledevice-2232caa09147bdbbf26b52f3bb17c264051d413d.tar.gz
libimobiledevice-2232caa09147bdbbf26b52f3bb17c264051d413d.tar.bz2
Merge branch 'master' of git://github.com/MattColyer/libiphone into martin
-rw-r--r--include/libiphone/libiphone.h1
-rw-r--r--src/InstallationProxy.c138
-rw-r--r--src/MobileSync.c69
-rw-r--r--src/NotificationProxy.c162
-rw-r--r--src/SBServices.c155
-rw-r--r--src/iphone.c281
-rw-r--r--src/iphone.h13
-rw-r--r--src/lockdown.c98
8 files changed, 453 insertions, 464 deletions
diff --git a/include/libiphone/libiphone.h b/include/libiphone/libiphone.h
index 923bc58..eb58d5c 100644
--- a/include/libiphone/libiphone.h
+++ b/include/libiphone/libiphone.h
@@ -39,6 +39,7 @@ extern "C" {
39#define IPHONE_E_NO_DEVICE -3 39#define IPHONE_E_NO_DEVICE -3
40#define IPHONE_E_NOT_ENOUGH_DATA -4 40#define IPHONE_E_NOT_ENOUGH_DATA -4
41#define IPHONE_E_BAD_HEADER -5 41#define IPHONE_E_BAD_HEADER -5
42#define IPHONE_E_PLIST_ERROR -6
42 43
43typedef int16_t iphone_error_t; 44typedef int16_t iphone_error_t;
44 45
diff --git a/src/InstallationProxy.c b/src/InstallationProxy.c
index 917886d..387f9ca 100644
--- a/src/InstallationProxy.c
+++ b/src/InstallationProxy.c
@@ -56,112 +56,28 @@ static void instproxy_unlock(instproxy_client_t client)
56} 56}
57 57
58/** 58/**
59 * Sends an xml plist to the device using the connection specified in client. 59 * Convert an iphone_error_t value to an instproxy_error_t value.
60 * This function is only used internally. 60 * Used internally to get correct error codes when using plist helper
61 * functions.
61 * 62 *
62 * @param client The installation_proxy to send data to 63 * @param err An iphone_error_t error code
63 * @param plist plist to send
64 * 64 *
65 * @return INSTPROXY_E_SUCCESS on success, INSTPROXY_E_INVALID_ARG when client 65 * @return A matching instproxy_error_t error code,
66 * or plist are NULL, INSTPROXY_E_PLIST_ERROR when dict is not a valid 66 * INSTPROXY_E_UNKNOWN_ERROR otherwise.
67 * plist, or INSTPROXY_E_UNKNOWN_ERROR when an unspecified error occurs.
68 */ 67 */
69static instproxy_error_t instproxy_plist_send(instproxy_client_t client, plist_t plist) 68static instproxy_error_t iphone_to_instproxy_error(iphone_error_t err)
70{ 69{
71 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; 70 switch (err) {
72 char *XML_content = NULL; 71 case IPHONE_E_SUCCESS:
73 uint32_t length = 0; 72 return INSTPROXY_E_SUCCESS;
74 uint32_t nlen = 0; 73 case IPHONE_E_INVALID_ARG:
75 int bytes = 0; 74 return INSTPROXY_E_INVALID_ARG;
76 75 case IPHONE_E_PLIST_ERROR:
77 if (!client || !plist) { 76 return INSTPROXY_E_PLIST_ERROR;
78 return INSTPROXY_E_INVALID_ARG; 77 default:
79 } 78 break;
80
81 plist_to_xml(plist, &XML_content, &length);
82
83 if (!XML_content || length == 0) {
84 return INSTPROXY_E_PLIST_ERROR;
85 }
86
87 nlen = htonl(length);
88 log_debug_msg("%s: sending %d bytes\n", __func__, length);
89 iphone_device_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes);
90 if (bytes == sizeof(nlen)) {
91 iphone_device_send(client->connection, XML_content, length, (uint32_t*)&bytes);
92 if (bytes > 0) {
93 log_debug_msg("%s: received %d bytes\n", __func__, bytes);
94 log_debug_buffer(XML_content, bytes);
95 if ((uint32_t)bytes == length) {
96 res = INSTPROXY_E_SUCCESS;
97 } else {
98 log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length);
99 }
100 }
101 }
102 if (bytes <= 0) {
103 log_dbg_msg(DBGMASK_INSTPROXY, "%s: ERROR: sending to device failed.\n", __func__);
104 }
105
106 free(XML_content);
107
108 return res;
109}
110
111/**
112 * Receives an xml plist from the device using the connection specified in
113 * client.
114 * This function is only used internally.
115 *
116 * @param client The installation_proxy to receive data from
117 * @param plist pointer to a plist_t that will point to the received plist
118 * upon successful return
119 *
120 * @return INSTPROXY_E_SUCCESS on success, INSTPROXY_E_INVALID_ARG when client
121 * or *plist are NULL, INSTPROXY_E_PLIST_ERROR when dict is not a valid
122 * plist, or INSTPROXY_E_UNKNOWN_ERROR when an unspecified error occurs.
123 */
124static instproxy_error_t instproxy_plist_recv(instproxy_client_t client, plist_t *plist)
125{
126 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
127 char *XML_content = NULL;
128 uint32_t pktlen = 0;
129 uint32_t bytes = 0;
130
131 if (!client || !plist) {
132 return INSTPROXY_E_INVALID_ARG;
133 }
134
135 iphone_device_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, 300000); /* 5 minute timeout should be enough */
136 log_debug_msg("%s: initial read=%i\n", __func__, bytes);
137 if (bytes < 4) {
138 log_dbg_msg(DBGMASK_INSTPROXY, "%s: initial read failed!\n");
139 } else {
140 if ((char)pktlen == 0) {
141 uint32_t curlen = 0;
142 pktlen = ntohl(pktlen);
143 log_debug_msg("%s: %d bytes following\n", __func__, pktlen);
144 XML_content = (char*)malloc(pktlen);
145
146 while (curlen < pktlen) {
147 iphone_device_recv(client->connection, XML_content+curlen, pktlen-curlen, &bytes);
148 if (bytes <= 0) {
149 res = INSTPROXY_E_UNKNOWN_ERROR;
150 break;
151 }
152 log_debug_msg("%s: received %d bytes\n", __func__, bytes);
153 curlen += bytes;
154 }
155 log_debug_buffer(XML_content, pktlen);
156 plist_from_xml(XML_content, pktlen, plist);
157 res = INSTPROXY_E_SUCCESS;
158 free(XML_content);
159 XML_content = NULL;
160 } else {
161 res = INSTPROXY_E_UNKNOWN_ERROR;
162 }
163 } 79 }
164 return res; 80 return INSTPROXY_E_UNKNOWN_ERROR;
165} 81}
166 82
167/** 83/**
@@ -268,7 +184,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_
268 plist_dict_insert_item(dict, "Command", plist_new_string("Browse")); 184 plist_dict_insert_item(dict, "Command", plist_new_string("Browse"));
269 185
270 instproxy_lock(client); 186 instproxy_lock(client);
271 res = instproxy_plist_send(client, dict); 187 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict));
272 plist_free(dict); 188 plist_free(dict);
273 if (res != INSTPROXY_E_SUCCESS) { 189 if (res != INSTPROXY_E_SUCCESS) {
274 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist\n", __func__); 190 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not send plist\n", __func__);
@@ -280,7 +196,7 @@ instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_
280 do { 196 do {
281 browsing = 0; 197 browsing = 0;
282 dict = NULL; 198 dict = NULL;
283 res = instproxy_plist_recv(client, &dict); 199 res = iphone_to_instproxy_error(iphone_device_receive_plist(client->connection, &dict));
284 if (res != INSTPROXY_E_SUCCESS) { 200 if (res != INSTPROXY_E_SUCCESS) {
285 break; 201 break;
286 } 202 }
@@ -345,7 +261,7 @@ static instproxy_error_t instproxy_perform_operation(instproxy_client_t client,
345 261
346 do { 262 do {
347 instproxy_lock(client); 263 instproxy_lock(client);
348 res = instproxy_plist_recv(client, &dict); 264 res = iphone_to_instproxy_error(iphone_device_receive_plist_with_timeout(client->connection, &dict, 30000));
349 instproxy_unlock(client); 265 instproxy_unlock(client);
350 if (res != INSTPROXY_E_SUCCESS) { 266 if (res != INSTPROXY_E_SUCCESS) {
351 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not receive plist, error %d\n", __func__, res); 267 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not receive plist, error %d\n", __func__, res);
@@ -517,7 +433,7 @@ static instproxy_error_t instproxy_install_or_upgrade(instproxy_client_t client,
517 plist_dict_insert_item(dict, "PackagePath", plist_new_string(pkg_path)); 433 plist_dict_insert_item(dict, "PackagePath", plist_new_string(pkg_path));
518 434
519 instproxy_lock(client); 435 instproxy_lock(client);
520 res = instproxy_plist_send(client, dict); 436 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict));
521 instproxy_unlock(client); 437 instproxy_unlock(client);
522 438
523 plist_free(dict); 439 plist_free(dict);
@@ -610,7 +526,7 @@ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *app
610 plist_dict_insert_item(dict, "Command", plist_new_string("Uninstall")); 526 plist_dict_insert_item(dict, "Command", plist_new_string("Uninstall"));
611 527
612 instproxy_lock(client); 528 instproxy_lock(client);
613 res = instproxy_plist_send(client, dict); 529 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict));
614 instproxy_unlock(client); 530 instproxy_unlock(client);
615 531
616 plist_free(dict); 532 plist_free(dict);
@@ -647,7 +563,7 @@ instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t *
647 563
648 instproxy_lock(client); 564 instproxy_lock(client);
649 565
650 res = instproxy_plist_send(client, dict); 566 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict));
651 plist_free(dict); 567 plist_free(dict);
652 568
653 if (res != INSTPROXY_E_SUCCESS) { 569 if (res != INSTPROXY_E_SUCCESS) {
@@ -655,7 +571,7 @@ instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t *
655 goto leave_unlock; 571 goto leave_unlock;
656 } 572 }
657 573
658 res = instproxy_plist_recv(client, result); 574 res = iphone_to_instproxy_error(iphone_device_receive_plist(client->connection, result));
659 if (res != INSTPROXY_E_SUCCESS) { 575 if (res != INSTPROXY_E_SUCCESS) {
660 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not receive plist, error %d\n", __func__, res); 576 log_dbg_msg(DBGMASK_INSTPROXY, "%s: could not receive plist, error %d\n", __func__, res);
661 goto leave_unlock; 577 goto leave_unlock;
@@ -718,7 +634,7 @@ instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid
718 plist_dict_insert_item(dict, "Command", plist_new_string("Archive")); 634 plist_dict_insert_item(dict, "Command", plist_new_string("Archive"));
719 635
720 instproxy_lock(client); 636 instproxy_lock(client);
721 res = instproxy_plist_send(client, dict); 637 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict));
722 instproxy_unlock(client); 638 instproxy_unlock(client);
723 639
724 plist_free(dict); 640 plist_free(dict);
@@ -764,7 +680,7 @@ instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid
764 plist_dict_insert_item(dict, "Command", plist_new_string("Restore")); 680 plist_dict_insert_item(dict, "Command", plist_new_string("Restore"));
765 681
766 instproxy_lock(client); 682 instproxy_lock(client);
767 res = instproxy_plist_send(client, dict); 683 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict));
768 instproxy_unlock(client); 684 instproxy_unlock(client);
769 685
770 plist_free(dict); 686 plist_free(dict);
@@ -810,7 +726,7 @@ instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char
810 plist_dict_insert_item(dict, "Command", plist_new_string("RemoveArchive")); 726 plist_dict_insert_item(dict, "Command", plist_new_string("RemoveArchive"));
811 727
812 instproxy_lock(client); 728 instproxy_lock(client);
813 res = instproxy_plist_send(client, dict); 729 res = iphone_to_instproxy_error(iphone_device_send_xml_plist(client->connection, dict));
814 instproxy_unlock(client); 730 instproxy_unlock(client);
815 731
816 plist_free(dict); 732 plist_free(dict);
diff --git a/src/MobileSync.c b/src/MobileSync.c
index 77d2710..76aefa0 100644
--- a/src/MobileSync.c
+++ b/src/MobileSync.c
@@ -31,6 +31,31 @@
31#define MSYNC_VERSION_INT1 100 31#define MSYNC_VERSION_INT1 100
32#define MSYNC_VERSION_INT2 100 32#define MSYNC_VERSION_INT2 100
33 33
34/**
35 * Convert an iphone_error_t value to an mobilesync_error_t value.
36 * Used internally to get correct error codes when using plist helper
37 * functions.
38 *
39 * @param err An iphone_error_t error code
40 *
41 * @return A matching mobilesync_error_t error code,
42 * MOBILESYNC_E_UNKNOWN_ERROR otherwise.
43 */
44static mobilesync_error_t iphone_to_mobilesync_error(iphone_error_t err)
45{
46 switch (err) {
47 case IPHONE_E_SUCCESS:
48 return MOBILESYNC_E_SUCCESS;
49 case IPHONE_E_INVALID_ARG:
50 return MOBILESYNC_E_INVALID_ARG;
51 case IPHONE_E_PLIST_ERROR:
52 return MOBILESYNC_E_PLIST_ERROR;
53 default:
54 break;
55 }
56 return MOBILESYNC_E_UNKNOWN_ERROR;
57}
58
34mobilesync_error_t mobilesync_client_new(iphone_device_t device, int dst_port, 59mobilesync_error_t mobilesync_client_new(iphone_device_t device, int dst_port,
35 mobilesync_client_t * client) 60 mobilesync_client_t * client)
36{ 61{
@@ -160,35 +185,19 @@ mobilesync_error_t mobilesync_recv(mobilesync_client_t client, plist_t * plist)
160{ 185{
161 if (!client || !plist || (plist && *plist)) 186 if (!client || !plist || (plist && *plist))
162 return MOBILESYNC_E_INVALID_ARG; 187 return MOBILESYNC_E_INVALID_ARG;
163 mobilesync_error_t ret = MOBILESYNC_E_UNKNOWN_ERROR;
164 char *receive = NULL;
165 uint32_t datalen = 0, bytes = 0, received_bytes = 0;
166
167 ret = iphone_device_recv(client->connection, (char *) &datalen, sizeof(datalen), &bytes);
168 datalen = ntohl(datalen);
169
170 receive = (char *) malloc(sizeof(char) * datalen);
171
172 /* fill buffer and request more packets if needed */
173 while ((received_bytes < datalen) && (ret == MOBILESYNC_E_SUCCESS)) {
174 ret = iphone_device_recv(client->connection, receive + received_bytes, datalen - received_bytes, &bytes);
175 received_bytes += bytes;
176 }
177 188
189 mobilesync_error_t ret = iphone_to_mobilesync_error(iphone_device_receive_plist(client->connection, plist));
178 if (ret != MOBILESYNC_E_SUCCESS) { 190 if (ret != MOBILESYNC_E_SUCCESS) {
179 free(receive);
180 return MOBILESYNC_E_MUX_ERROR; 191 return MOBILESYNC_E_MUX_ERROR;
181 } 192 }
182 193
183 plist_from_bin(receive, received_bytes, plist); 194#ifndef STRIP_DEBUG_CODE
184 free(receive);
185
186 char *XMLContent = NULL; 195 char *XMLContent = NULL;
187 uint32_t length = 0; 196 uint32_t length = 0;
188 plist_to_xml(*plist, &XMLContent, &length); 197 plist_to_xml(*plist, &XMLContent, &length);
189 log_dbg_msg(DBGMASK_MOBILESYNC, "%s: plist size: %i\nbuffer :\n%s\n", __func__, length, XMLContent); 198 log_dbg_msg(DBGMASK_MOBILESYNC, "%s: plist size: %i\nbuffer :\n%s\n", __func__, length, XMLContent);
190 free(XMLContent); 199 free(XMLContent);
191 200#endif
192 return ret; 201 return ret;
193} 202}
194 203
@@ -207,28 +216,12 @@ mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist)
207 if (!client || !plist) 216 if (!client || !plist)
208 return MOBILESYNC_E_INVALID_ARG; 217 return MOBILESYNC_E_INVALID_ARG;
209 218
219#ifndef STRIP_DEBUG_CODE
210 char *XMLContent = NULL; 220 char *XMLContent = NULL;
211 uint32_t length = 0; 221 uint32_t length = 0;
212 plist_to_xml(plist, &XMLContent, &length); 222 plist_to_xml(plist, &XMLContent, &length);
213 log_dbg_msg(DBGMASK_MOBILESYNC, "%s: plist size: %i\nbuffer :\n%s\n", __func__, length, XMLContent); 223 log_dbg_msg(DBGMASK_MOBILESYNC, "%s: plist size: %i\nbuffer :\n%s\n", __func__, length, XMLContent);
214 free(XMLContent); 224 free(XMLContent);
215 225#endif
216 char *content = NULL; 226 return (iphone_device_send_binary_plist(client->connection, plist) == IPHONE_E_SUCCESS ? MOBILESYNC_E_SUCCESS : MOBILESYNC_E_MUX_ERROR);
217 length = 0;
218
219 plist_to_bin(plist, &content, &length);
220
221 char *real_query;
222 int bytes;
223 mobilesync_error_t ret = MOBILESYNC_E_UNKNOWN_ERROR;
224
225 real_query = (char *) malloc(sizeof(char) * (length + 4));
226 length = htonl(length);
227 memcpy(real_query, &length, sizeof(length));
228 memcpy(real_query + 4, content, ntohl(length));
229
230 ret = iphone_device_send(client->connection, real_query, ntohl(length) + sizeof(length), (uint32_t*)&bytes);
231 free(real_query);
232 return (ret == 0 ? MOBILESYNC_E_SUCCESS: MOBILESYNC_E_MUX_ERROR);
233} 227}
234
diff --git a/src/NotificationProxy.c b/src/NotificationProxy.c
index cba12b9..b73b521 100644
--- a/src/NotificationProxy.c
+++ b/src/NotificationProxy.c
@@ -56,53 +56,28 @@ static void np_unlock(np_client_t client)
56} 56}
57 57
58/** 58/**
59 * Sends an xml plist to the device using the connection specified in client. 59 * Convert an iphone_error_t value to an np_error_t value.
60 * This function is only used internally. 60 * Used internally to get correct error codes when using plist helper
61 * functions.
61 * 62 *
62 * @param client NP to send data to 63 * @param err An iphone_error_t error code
63 * @param dict plist to send
64 * 64 *
65 * @return NP_E_SUCCESS on success, NP_E_INVALID_ARG when client or dict 65 * @return A matching np_error_t error code,
66 * are NULL, NP_E_PLIST_ERROR when dict is not a valid plist, 66 * NP_E_UNKNOWN_ERROR otherwise.
67 * or NP_E_UNKNOWN_ERROR when an unspecified error occurs.
68 */ 67 */
69static np_error_t np_plist_send(np_client_t client, plist_t dict) 68static np_error_t iphone_to_np_error(iphone_error_t err)
70{ 69{
71 char *XML_content = NULL; 70 switch (err) {
72 uint32_t length = 0; 71 case IPHONE_E_SUCCESS:
73 uint32_t nlen = 0; 72 return NP_E_SUCCESS;
74 int bytes = 0; 73 case IPHONE_E_INVALID_ARG:
75 np_error_t res = NP_E_UNKNOWN_ERROR; 74 return NP_E_INVALID_ARG;
76 75 case IPHONE_E_PLIST_ERROR:
77 if (!client || !dict) { 76 return NP_E_PLIST_ERROR;
78 return NP_E_INVALID_ARG; 77 default:
79 } 78 break;
80
81 plist_to_xml(dict, &XML_content, &length);
82
83 if (!XML_content || length == 0) {
84 return NP_E_PLIST_ERROR;
85 }
86
87 nlen = htonl(length);
88 iphone_device_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes);
89 if (bytes == sizeof(nlen)) {
90 iphone_device_send(client->connection, XML_content, length, (uint32_t*)&bytes);
91 if (bytes > 0) {
92 if ((uint32_t)bytes == length) {
93 res = NP_E_SUCCESS;
94 } else {
95 log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length);
96 }
97 }
98 }
99 if (bytes <= 0) {
100 log_debug_msg("%s: ERROR: sending to device failed.\n", __func__);
101 } 79 }
102 80 return NP_E_UNKNOWN_ERROR;
103 free(XML_content);
104
105 return res;
106} 81}
107 82
108/** Makes a connection to the NP service on the phone. 83/** Makes a connection to the NP service on the phone.
@@ -185,13 +160,13 @@ np_error_t np_post_notification(np_client_t client, const char *notification)
185 plist_dict_insert_item(dict,"Command", plist_new_string("PostNotification")); 160 plist_dict_insert_item(dict,"Command", plist_new_string("PostNotification"));
186 plist_dict_insert_item(dict,"Name", plist_new_string(notification)); 161 plist_dict_insert_item(dict,"Name", plist_new_string(notification));
187 162
188 np_error_t res = np_plist_send(client, dict); 163 np_error_t res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict));
189 plist_free(dict); 164 plist_free(dict);
190 165
191 dict = plist_new_dict(); 166 dict = plist_new_dict();
192 plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown")); 167 plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown"));
193 168
194 res = np_plist_send(client, dict); 169 res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict));
195 plist_free(dict); 170 plist_free(dict);
196 171
197 if (res != NP_E_SUCCESS) { 172 if (res != NP_E_SUCCESS) {
@@ -221,7 +196,7 @@ np_error_t np_observe_notification( np_client_t client, const char *notification
221 plist_dict_insert_item(dict,"Command", plist_new_string("ObserveNotification")); 196 plist_dict_insert_item(dict,"Command", plist_new_string("ObserveNotification"));
222 plist_dict_insert_item(dict,"Name", plist_new_string(notification)); 197 plist_dict_insert_item(dict,"Name", plist_new_string(notification));
223 198
224 np_error_t res = np_plist_send(client, dict); 199 np_error_t res = iphone_to_np_error(iphone_device_send_xml_plist(client->connection, dict));
225 if (res != NP_E_SUCCESS) { 200 if (res != NP_E_SUCCESS) {
226 log_debug_msg("%s: Error sending XML plist to device!\n", __func__); 201 log_debug_msg("%s: Error sending XML plist to device!\n", __func__);
227 } 202 }
@@ -281,10 +256,7 @@ np_error_t np_observe_notifications(np_client_t client, const char **notificatio
281 */ 256 */
282static int np_get_notification(np_client_t client, char **notification) 257static int np_get_notification(np_client_t client, char **notification)
283{ 258{
284 uint32_t bytes = 0;
285 int res = 0; 259 int res = 0;
286 uint32_t pktlen = 0;
287 char *XML_content = NULL;
288 plist_t dict = NULL; 260 plist_t dict = NULL;
289 261
290 if (!client || !client->connection || *notification) 262 if (!client || !client->connection || *notification)
@@ -292,72 +264,46 @@ static int np_get_notification(np_client_t client, char **notification)
292 264
293 np_lock(client); 265 np_lock(client);
294 266
295 iphone_device_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, 500); 267 iphone_device_receive_plist_with_timeout(client->connection, &dict, 500);
296 log_debug_msg("NotificationProxy: initial read=%i\n", bytes); 268 if (!dict) {
297 if (bytes < 4) {
298 log_debug_msg("NotificationProxy: no notification received!\n"); 269 log_debug_msg("NotificationProxy: no notification received!\n");
299 res = 0; 270 res = 0;
300 } else { 271 } else {
301 if ((char)pktlen == 0) { 272 char *cmd_value = NULL;
302 pktlen = ntohl(pktlen); 273 plist_t cmd_value_node = plist_dict_get_item(dict, "Command");
303 log_debug_msg("NotificationProxy: %d bytes following\n", pktlen); 274
304 XML_content = (char*)malloc(pktlen); 275 if (plist_get_node_type(cmd_value_node) == PLIST_STRING) {
305 log_debug_msg("pointer %p\n", XML_content); 276 plist_get_string_val(cmd_value_node, &cmd_value);
306 277 }
307 iphone_device_recv_timeout(client->connection, XML_content, pktlen, &bytes, 1000); 278
308 if (bytes <= 0) { 279 if (cmd_value && !strcmp(cmd_value, "RelayNotification")) {
309 res = -1; 280 char *name_value = NULL;
310 } else { 281 plist_t name_value_node = plist_dict_get_item(dict, "Name");
311 log_debug_msg("NotificationProxy: received data:\n"); 282
312 log_debug_buffer(XML_content, pktlen); 283 if (plist_get_node_type(name_value_node) == PLIST_STRING) {
313 284 plist_get_string_val(name_value_node, &name_value);
314 plist_from_xml(XML_content, bytes, &dict);
315 if (!dict) {
316 np_unlock(client);
317 return -2;
318 }
319
320 char *cmd_value = NULL;
321 plist_t cmd_value_node = plist_dict_get_item(dict, "Command");
322
323 if (plist_get_node_type(cmd_value_node) == PLIST_STRING) {
324 plist_get_string_val(cmd_value_node, &cmd_value);
325 }
326
327 if (cmd_value && !strcmp(cmd_value, "RelayNotification")) {
328 char *name_value = NULL;
329 plist_t name_value_node = plist_dict_get_item(dict, "Name");
330
331 if (plist_get_node_type(name_value_node) == PLIST_STRING) {
332 plist_get_string_val(name_value_node, &name_value);
333 }
334
335 res = -2;
336 if (name_value_node && name_value) {
337 *notification = name_value;
338 log_debug_msg("%s: got notification %s\n", __func__, name_value);
339 res = 0;
340 }
341 } else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) {
342 log_debug_msg("%s: ERROR: NotificationProxy died!\n", __func__);
343 res = -1;
344 } else if (cmd_value) {
345 log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__);
346 res = -1;
347 } else {
348 res = -2;
349 }
350 if (cmd_value) {
351 free(cmd_value);
352 }
353 plist_free(dict);
354 dict = NULL;
355 free(XML_content);
356 XML_content = NULL;
357 } 285 }
358 } else { 286
287 res = -2;
288 if (name_value_node && name_value) {
289 *notification = name_value;
290 log_debug_msg("%s: got notification %s\n", __func__, name_value);
291 res = 0;
292 }
293 } else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) {
294 log_debug_msg("%s: ERROR: NotificationProxy died!\n", __func__);
359 res = -1; 295 res = -1;
296 } else if (cmd_value) {
297 log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__);
298 res = -1;
299 } else {
300 res = -2;
301 }
302 if (cmd_value) {
303 free(cmd_value);
360 } 304 }
305 plist_free(dict);
306 dict = NULL;
361 } 307 }
362 308
363 np_unlock(client); 309 np_unlock(client);
diff --git a/src/SBServices.c b/src/SBServices.c
index 9849415..1296245 100644
--- a/src/SBServices.c
+++ b/src/SBServices.c
@@ -87,112 +87,39 @@ sbservices_error_t sbservices_client_free(sbservices_client_t client)
87 return SBSERVICES_E_SUCCESS; 87 return SBSERVICES_E_SUCCESS;
88} 88}
89 89
90/**
91 * Sends a binary plist to the device using the connection specified in client.
92 * This function is only used internally.
93 *
94 * @param client InstallationProxy to send data to
95 * @param dict plist to send
96 *
97 * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when
98 * client or dict are NULL, SBSERVICES_E_PLIST_ERROR when dict is not a
99 * valid plist, or SBSERVICES_E_UNKNOWN_ERROR when an unspecified error
100 * occurs.
101 */
102static sbservices_error_t sbservices_plist_send(sbservices_client_t client, plist_t dict)
103{
104 char *content = NULL;
105 uint32_t length = 0;
106 uint32_t nlen = 0;
107 int bytes = 0;
108 sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR;
109
110 if (!client || !dict) {
111 return SBSERVICES_E_INVALID_ARG;
112 }
113
114 plist_to_bin(dict, &content, &length);
115
116 if (!content || length == 0) {
117 return SBSERVICES_E_PLIST_ERROR;
118 }
119
120 nlen = htonl(length);
121 log_debug_msg("%s: sending %d bytes\n", __func__, length);
122 iphone_device_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes);
123 if (bytes == sizeof(nlen)) {
124 iphone_device_send(client->connection, content, length, (uint32_t*)&bytes);
125 if (bytes > 0) {
126 if ((uint32_t)bytes == length) {
127 res = SBSERVICES_E_SUCCESS;
128 } else {
129 log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length);
130 }
131 }
132 }
133 if (bytes <= 0) {
134 log_debug_msg("%s: ERROR: sending to device failed.\n", __func__);
135 }
136
137 free(content);
138
139 return res;
140}
141
142sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state) 90sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state)
143{ 91{
144 if (!client || !client->connection || !state) 92 if (!client || !client->connection || !state)
145 return SBSERVICES_E_INVALID_ARG; 93 return SBSERVICES_E_INVALID_ARG;
146 94
147 sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; 95 sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR;
148 uint32_t pktlen = 0;
149 uint32_t bytes = 0;
150 96
151 plist_t dict = plist_new_dict(); 97 plist_t dict = plist_new_dict();
152 plist_dict_insert_item(dict, "command", plist_new_string("getIconState")); 98 plist_dict_insert_item(dict, "command", plist_new_string("getIconState"));
153 99
154 sbs_lock(client); 100 sbs_lock(client);
155 101
156 res = sbservices_plist_send(client, dict); 102 if (iphone_device_send_binary_plist(client->connection, dict) != IPHONE_E_SUCCESS) {
157 plist_free(dict);
158 if (res != SBSERVICES_E_SUCCESS) {
159 log_debug_msg("%s: could not send plist\n", __func__); 103 log_debug_msg("%s: could not send plist\n", __func__);
160 goto leave_unlock; 104 goto leave_unlock;
161 } 105 }
106 plist_free(dict);
107 dict = NULL;
162 108
163 iphone_device_recv(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes); 109 if (iphone_device_receive_plist(client->connection, state) == IPHONE_E_SUCCESS) {
164 log_debug_msg("%s: initial read=%i\n", __func__, bytes); 110 res = SBSERVICES_E_SUCCESS;
165 if (bytes < 4) {
166 log_debug_msg("%s: initial read failed!\n");
167 res = 0;
168 } else { 111 } else {
169 if ((char)pktlen == 0) { 112 log_debug_msg("%s: could not get icon state!\n", __func__);
170 char *content = NULL; 113 if (*state) {
171 uint32_t curlen = 0; 114 plist_free(*state);
172 pktlen = ntohl(pktlen); 115 *state = NULL;
173 log_debug_msg("%s: %d bytes following\n", __func__, pktlen);
174 content = (char*)malloc(pktlen);
175 log_debug_msg("pointer %p\n", content);
176
177 while (curlen < pktlen) {
178 iphone_device_recv(client->connection, content+curlen, pktlen-curlen, &bytes);
179 if (bytes <= 0) {
180 res = SBSERVICES_E_UNKNOWN_ERROR;
181 break;
182 }
183 log_debug_msg("%s: received %d bytes\n", __func__, bytes);
184 curlen += bytes;
185 }
186 log_debug_buffer(content, pktlen);
187 plist_from_bin(content, pktlen, state);
188 res = SBSERVICES_E_SUCCESS;
189 free(content);
190 } else {
191 res = SBSERVICES_E_UNKNOWN_ERROR;
192 } 116 }
193 } 117 }
194 118
195leave_unlock: 119leave_unlock:
120 if (dict) {
121 plist_free(dict);
122 }
196 sbs_unlock(client); 123 sbs_unlock(client);
197 return res; 124 return res;
198} 125}
@@ -210,15 +137,16 @@ sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t
210 137
211 sbs_lock(client); 138 sbs_lock(client);
212 139
213 res = sbservices_plist_send(client, dict); 140 if (iphone_device_send_binary_plist(client->connection, dict) != IPHONE_E_SUCCESS) {
214 plist_free(dict);
215 if (res != SBSERVICES_E_SUCCESS) {
216 log_debug_msg("%s: could not send plist\n", __func__); 141 log_debug_msg("%s: could not send plist\n", __func__);
217 goto leave_unlock; 142 goto leave_unlock;
218 } 143 }
219 // NO RESPONSE 144 // NO RESPONSE
220 145
221leave_unlock: 146leave_unlock:
147 if (dict) {
148 plist_free(dict);
149 }
222 sbs_unlock(client); 150 sbs_unlock(client);
223 return res; 151 return res;
224} 152}
@@ -229,8 +157,6 @@ sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const
229 return SBSERVICES_E_INVALID_ARG; 157 return SBSERVICES_E_INVALID_ARG;
230 158
231 sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; 159 sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR;
232 uint32_t pktlen = 0;
233 uint32_t bytes = 0;
234 160
235 plist_t dict = plist_new_dict(); 161 plist_t dict = plist_new_dict();
236 plist_dict_insert_item(dict, "command", plist_new_string("getIconPNGData")); 162 plist_dict_insert_item(dict, "command", plist_new_string("getIconPNGData"));
@@ -238,52 +164,25 @@ sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const
238 164
239 sbs_lock(client); 165 sbs_lock(client);
240 166
241 res = sbservices_plist_send(client, dict); 167 if (iphone_device_send_binary_plist(client->connection, dict) != IPHONE_E_SUCCESS) {
242 plist_free(dict);
243 if (res != SBSERVICES_E_SUCCESS) {
244 log_debug_msg("%s: could not send plist\n", __func__); 168 log_debug_msg("%s: could not send plist\n", __func__);
245 goto leave_unlock; 169 goto leave_unlock;
246 } 170 }
171 plist_free(dict);
247 172
248 iphone_device_recv(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes); 173 dict = NULL;
249 log_debug_msg("%s: initial read=%i\n", __func__, bytes); 174 if (iphone_device_receive_plist(client->connection, &dict) == IPHONE_E_SUCCESS) {
250 if (bytes < 4) { 175 plist_t node = plist_dict_get_item(dict, "pngData");
251 log_debug_msg("%s: initial read failed!\n"); 176 if (node) {
252 res = 0; 177 plist_get_data_val(node, pngdata, pngsize);
253 } else {
254 if ((char)pktlen == 0) {
255 char *content = NULL;
256 uint32_t curlen = 0;
257 pktlen = ntohl(pktlen);
258 log_debug_msg("%s: %d bytes following\n", __func__, pktlen);
259 content = (char*)malloc(pktlen);
260 log_debug_msg("pointer %p\n", content);
261
262 while (curlen < pktlen) {
263 iphone_device_recv(client->connection, content+curlen, pktlen-curlen, &bytes);
264 if (bytes <= 0) {
265 res = SBSERVICES_E_UNKNOWN_ERROR;
266 break;
267 }
268 log_debug_msg("%s: received %d bytes\n", __func__, bytes);
269 curlen += bytes;
270 }
271 log_debug_buffer(content, pktlen);
272 plist_t pngdict = NULL;
273 plist_from_bin(content, pktlen, &pngdict);
274 plist_t node = plist_dict_get_item(pngdict, "pngData");
275 if (node) {
276 plist_get_data_val(node, pngdata, pngsize);
277 }
278 plist_free(pngdict);
279 res = SBSERVICES_E_SUCCESS;
280 free(content);
281 } else {
282 res = SBSERVICES_E_UNKNOWN_ERROR;
283 } 178 }
179 res = SBSERVICES_E_SUCCESS;
284 } 180 }
285 181
286leave_unlock: 182leave_unlock:
183 if (dict) {
184 plist_free(dict);
185 }
287 sbs_unlock(client); 186 sbs_unlock(client);
288 return res; 187 return res;
289 188
diff --git a/src/iphone.c b/src/iphone.c
index 586b3bc..3c13859 100644
--- a/src/iphone.c
+++ b/src/iphone.c
@@ -23,6 +23,7 @@
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h> 24#include <string.h>
25#include <errno.h> 25#include <errno.h>
26#include <arpa/inet.h>
26 27
27#include <usbmuxd.h> 28#include <usbmuxd.h>
28#include "iphone.h" 29#include "iphone.h"
@@ -350,6 +351,286 @@ iphone_error_t iphone_device_recv(iphone_connection_t connection, char *data, ui
350 return IPHONE_E_UNKNOWN_ERROR; 351 return IPHONE_E_UNKNOWN_ERROR;
351} 352}
352 353
354/**
355 * Sends a plist over the given connection.
356 * Internally used generic plist send function.
357 *
358 * @param connection The connection to use for sending.
359 * Can be NULL if ssl_session is non-NULL.
360 * @param plist plist to send
361 * @param binary 1 = send binary plist, 0 = send xml plist
362 * @param ssl_session If set to NULL, the communication will be unencrypted.
363 * For encrypted communication, pass a valid and properly initialized
364 * gnutls_session_t. connection is ignored when ssl_session is non-NULL.
365 *
366 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when one or more
367 * parameters are invalid, IPHONE_E_PLIST_ERROR when dict is not a valid
368 * plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs.
369 */
370static iphone_error_t internal_plist_send(iphone_connection_t connection, plist_t plist, int binary, gnutls_session_t ssl_session)
371{
372 iphone_error_t res = IPHONE_E_UNKNOWN_ERROR;
373 char *content = NULL;
374 uint32_t length = 0;
375 uint32_t nlen = 0;
376 int bytes = 0;
377
378 if ((!connection && !ssl_session) || !plist) {
379 return IPHONE_E_INVALID_ARG;
380 }
381
382 if (binary) {
383 plist_to_bin(plist, &content, &length);
384 } else {
385 plist_to_xml(plist, &content, &length);
386 }
387
388 if (!content || length == 0) {
389 return IPHONE_E_PLIST_ERROR;
390 }
391
392 nlen = htonl(length);
393 log_debug_msg("%s: sending %d bytes\n", __func__, length);
394 if (ssl_session) {
395 bytes = gnutls_record_send(ssl_session, (const char*)&nlen, sizeof(nlen));
396 } else {
397 iphone_device_send(connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes);
398 }
399 if (bytes == sizeof(nlen)) {
400 if (ssl_session) {
401 bytes = gnutls_record_send(ssl_session, content, length);
402 } else {
403 iphone_device_send(connection, content, length, (uint32_t*)&bytes);
404 }
405 if (bytes > 0) {
406 log_debug_msg("%s: received %d bytes\n", __func__, bytes);
407 log_debug_buffer(content, bytes);
408 if ((uint32_t)bytes == length) {
409 res = IPHONE_E_SUCCESS;
410 } else {
411 log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length);
412 }
413 }
414 }
415 if (bytes <= 0) {
416 log_debug_msg("%s: ERROR: sending to device failed.\n", __func__);
417 }
418
419 free(content);
420
421 return res;
422}
423
424/**
425 * Sends an XML plist over the given connection.
426 *
427 * @param connection The connection to send data over
428 * @param plist plist to send
429 *
430 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection
431 * or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist,
432 * or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs.
433 */
434iphone_error_t iphone_device_send_xml_plist(iphone_connection_t connection, plist_t plist)
435{
436 return internal_plist_send(connection, plist, 0, NULL);
437}
438
439/**
440 * Sends a binary plist over the given connection.
441 *
442 * @param connection The connection to send data over
443 * @param plist plist to send
444 *
445 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection
446 * or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist,
447 * or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs.
448 */
449iphone_error_t iphone_device_send_binary_plist(iphone_connection_t connection, plist_t plist)
450{
451 return internal_plist_send(connection, plist, 1, NULL);
452}
453
454/**
455 * Sends an encrypted XML plist.
456 *
457 * @param ssl_session Valid and properly initialized gnutls_session_t.
458 * @param plist plist to send
459 *
460 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session
461 * or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist,
462 * or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs.
463 */
464iphone_error_t iphone_device_send_encrypted_xml_plist(gnutls_session_t ssl_session, plist_t plist)
465{
466 return internal_plist_send(NULL, plist, 0, ssl_session);
467}
468
469/**
470 * Sends an encrypted binary plist.
471 *
472 * @param ssl_session Valid and properly initialized gnutls_session_t.
473 * @param plist plist to send
474 *
475 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session
476 * or plist is NULL, IPHONE_E_PLIST_ERROR when dict is not a valid plist,
477 * or IPHONE_E_UNKNOWN_ERROR when an unspecified error occurs.
478 */
479iphone_error_t iphone_device_send_encrypted_binary_plist(gnutls_session_t ssl_session, plist_t plist)
480{
481 return internal_plist_send(NULL, plist, 1, ssl_session);
482}
483
484/**
485 * Receives a plist over the given connection.
486 * Internally used generic plist send function.
487 *
488 * @param connection The connection to receive data on
489 * @param plist pointer to a plist_t that will point to the received plist
490 * upon successful return
491 * @param timeout Maximum time in milliseconds to wait for data.
492 * @param ssl_session If set to NULL, the communication will be unencrypted.
493 * For encrypted communication, pass a valid and properly initialized
494 * gnutls_session_t.
495 *
496 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection
497 * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be
498 * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified
499 * error occurs.
500 */
501static iphone_error_t internal_plist_recv_timeout(iphone_connection_t connection, plist_t *plist, unsigned int timeout, gnutls_session_t ssl_session)
502{
503 iphone_error_t res = IPHONE_E_UNKNOWN_ERROR;
504 uint32_t pktlen = 0;
505 uint32_t bytes = 0;
506
507 if ((!connection && !ssl_session) || !plist) {
508 return IPHONE_E_INVALID_ARG;
509 }
510
511 iphone_device_recv_timeout(connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout);
512 log_debug_msg("%s: initial read=%i\n", __func__, bytes);
513 if (bytes < 4) {
514 log_debug_msg("%s: initial read failed!\n", __func__);
515 return IPHONE_E_NOT_ENOUGH_DATA;
516 } else {
517 if ((char)pktlen == 0) { /* prevent huge buffers */
518 uint32_t curlen = 0;
519 char *content = NULL;
520 pktlen = ntohl(pktlen);
521 log_debug_msg("%s: %d bytes following\n", __func__, pktlen);
522 content = (char*)malloc(pktlen);
523
524 while (curlen < pktlen) {
525 iphone_device_recv(connection, content+curlen, pktlen-curlen, &bytes);
526 if (bytes <= 0) {
527 res = IPHONE_E_UNKNOWN_ERROR;
528 break;
529 }
530 log_debug_msg("%s: received %d bytes\n", __func__, bytes);
531 curlen += bytes;
532 }
533 log_debug_buffer(content, pktlen);
534 if (!memcmp(content, "bplist00", 8)) {
535 plist_from_bin(content, pktlen, plist);
536 } else {
537 plist_from_xml(content, pktlen, plist);
538 }
539 if (*plist) {
540 res = IPHONE_E_SUCCESS;
541 } else {
542 res = IPHONE_E_PLIST_ERROR;
543 }
544 free(content);
545 content = NULL;
546 } else {
547 res = IPHONE_E_UNKNOWN_ERROR;
548 }
549 }
550 return res;
551}
552
553/**
554 * Receives a plist over the given connection with specified timeout.
555 * Binary or XML plists are automatically handled.
556 *
557 * @param connection The connection to receive data on
558 * @param plist pointer to a plist_t that will point to the received plist
559 * upon successful return
560 * @param timeout Maximum time in milliseconds to wait for data.
561 *
562 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection
563 * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be
564 * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified
565 * error occurs.
566 */
567iphone_error_t iphone_device_receive_plist_with_timeout(iphone_connection_t connection, plist_t *plist, unsigned int timeout)
568{
569 return internal_plist_recv_timeout(connection, plist, timeout, NULL);
570}
571
572/**
573 * Receives a plist over the given connection.
574 * Binary or XML plists are automatically handled.
575 *
576 * This function is like iphone_device_receive_plist_with_timeout
577 * using a timeout of 10 seconds.
578 * @see iphone_device_receive_plist_with_timeout
579 *
580 * @param connection The connection to receive data on
581 * @param plist pointer to a plist_t that will point to the received plist
582 * upon successful return
583 *
584 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection
585 * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be
586 * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified
587 * error occurs.
588 */
589iphone_error_t iphone_device_receive_plist(iphone_connection_t connection, plist_t *plist)
590{
591 return internal_plist_recv_timeout(connection, plist, 10000, NULL);
592}
593
594/**
595 * Receives an encrypted plist with specified timeout.
596 * Binary or XML plists are automatically handled.
597 *
598 * @param ssl_session Valid and properly initialized gnutls_session_t.
599 * @param plist pointer to a plist_t that will point to the received plist
600 * upon successful return
601 * @param timeout Maximum time in milliseconds to wait for data.
602 *
603 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session
604 * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be
605 * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified
606 * error occurs.
607 */
608iphone_error_t iphone_device_receive_encrypted_plist_with_timeout(gnutls_session_t ssl_session, plist_t *plist, unsigned int timeout)
609{
610 return internal_plist_recv_timeout(NULL, plist, timeout, ssl_session);
611}
612
613/**
614 * Receives an encrypted plist.
615 * Binary or XML plists are automatically handled.
616 * This function is like iphone_device_receive_encrypted_plist_with_timeout
617 * with a timeout value of 10 seconds.
618 *
619 * @param ssl_session Valid and properly initialized gnutls_session_t.
620 * @param connection The connection to receive data on
621 * @param plist pointer to a plist_t that will point to the received plist
622 * upon successful return
623 *
624 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when ssl_session
625 * or *plist is NULL, IPHONE_E_PLIST_ERROR when the received data cannot be
626 * converted to a plist, or IPHONE_E_UNKNOWN_ERROR when an unspecified
627 * error occurs.
628 */
629iphone_error_t iphone_device_receive_encrypted_plist(gnutls_session_t ssl_session, plist_t *plist)
630{
631 return internal_plist_recv_timeout(NULL, plist, 10000, ssl_session);
632}
633
353iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle) 634iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle)
354{ 635{
355 if (!device) 636 if (!device)
diff --git a/src/iphone.h b/src/iphone.h
index 98b0ed8..7ffc811 100644
--- a/src/iphone.h
+++ b/src/iphone.h
@@ -21,6 +21,9 @@
21#ifndef IPHONE_H 21#ifndef IPHONE_H
22#define IPHONE_H 22#define IPHONE_H
23 23
24#include <plist/plist.h>
25#include <gnutls/gnutls.h>
26
24#include "libiphone/libiphone.h" 27#include "libiphone/libiphone.h"
25 28
26enum connection_type { 29enum connection_type {
@@ -38,4 +41,14 @@ struct iphone_device_int {
38 void *conn_data; 41 void *conn_data;
39}; 42};
40 43
44iphone_error_t iphone_device_send_xml_plist(iphone_connection_t connection, plist_t plist);
45iphone_error_t iphone_device_send_binary_plist(iphone_connection_t connection, plist_t plist);
46iphone_error_t iphone_device_send_encrypted_xml_plist(gnutls_session_t ssl_session, plist_t plist);
47iphone_error_t iphone_device_send_encrypted_binary_plist(gnutls_session_t ssl_session, plist_t plist);
48
49iphone_error_t iphone_device_receive_plist_with_timeout(iphone_connection_t connection, plist_t *plist, unsigned int timeout);
50iphone_error_t iphone_device_receive_plist(iphone_connection_t connection, plist_t *plist);
51iphone_error_t iphone_device_receive_encrypted_plist_with_timeout(gnutls_session_t ssl_session, plist_t *plist, unsigned int timeout);
52iphone_error_t iphone_device_receive_encrypted_plist(gnutls_session_t ssl_session, plist_t *plist);
53
41#endif 54#endif
diff --git a/src/lockdown.c b/src/lockdown.c
index 1b33830..24dd4a1 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -271,61 +271,21 @@ lockdownd_error_t lockdownd_recv(lockdownd_client_t client, plist_t *plist)
271{ 271{
272 if (!client || !plist || (plist && *plist)) 272 if (!client || !plist || (plist && *plist))
273 return LOCKDOWN_E_INVALID_ARG; 273 return LOCKDOWN_E_INVALID_ARG;
274 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 274 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
275 char *receive = NULL; 275 iphone_error_t err;
276 uint32_t datalen = 0, bytes = 0, received_bytes = 0;
277
278 if (!client->in_SSL)
279 ret = iphone_device_recv(client->connection, (char *) &datalen, sizeof(datalen), &bytes);
280 else {
281 ssize_t res = gnutls_record_recv(client->ssl_session, &datalen, sizeof(datalen));
282 if (res < 0) {
283 log_dbg_msg(DBGMASK_LOCKDOWND, "gnutls_record_recv: Error occured: %s\n", gnutls_strerror(res));
284 return LOCKDOWN_E_SSL_ERROR;
285 } else {
286 bytes = res;
287 ret = LOCKDOWN_E_SUCCESS;
288 }
289 }
290 datalen = ntohl(datalen);
291 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: datalen = %d\n", __func__, datalen);
292
293 receive = (char *) malloc(sizeof(char) * datalen);
294 276
295 /* fill buffer and request more packets if needed */
296 if (!client->in_SSL) { 277 if (!client->in_SSL) {
297 while ((received_bytes < datalen) && (ret == LOCKDOWN_E_SUCCESS)) { 278 err = iphone_device_receive_plist(client->connection, plist);
298 ret = iphone_device_recv(client->connection, receive + received_bytes, datalen - received_bytes, &bytes); 279 if (err != IPHONE_E_SUCCESS) {
299 received_bytes += bytes; 280 ret = LOCKDOWN_E_UNKNOWN_ERROR;
300 } 281 }
301 } else { 282 } else {
302 ssize_t res = 0; 283 err = iphone_device_receive_encrypted_plist(client->ssl_session, plist);
303 while ((received_bytes < datalen) && (ret == LOCKDOWN_E_SUCCESS)) { 284 if (err != IPHONE_E_SUCCESS) {
304 res = gnutls_record_recv(client->ssl_session, receive + received_bytes, datalen - received_bytes); 285 return LOCKDOWN_E_SSL_ERROR;
305 if (res < 0) {
306 log_dbg_msg(DBGMASK_LOCKDOWND, "gnutls_record_recv: Error occured: %s\n", gnutls_strerror(res));
307 ret = LOCKDOWN_E_SSL_ERROR;
308 } else {
309 received_bytes += res;
310 ret = LOCKDOWN_E_SUCCESS;
311 }
312 } 286 }
313 } 287 }
314 288
315 if (ret != LOCKDOWN_E_SUCCESS) {
316 free(receive);
317 return ret;
318 }
319
320 if ((ssize_t)received_bytes <= 0) {
321 free(receive);
322 return LOCKDOWN_E_NOT_ENOUGH_DATA;
323 }
324
325 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: received msg size: %i, buffer follows:\n%s", __func__, received_bytes, receive);
326 plist_from_xml(receive, received_bytes, plist);
327 free(receive);
328
329 if (!*plist) 289 if (!*plist)
330 ret = LOCKDOWN_E_PLIST_ERROR; 290 ret = LOCKDOWN_E_PLIST_ERROR;
331 291
@@ -346,41 +306,21 @@ lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist)
346{ 306{
347 if (!client || !plist) 307 if (!client || !plist)
348 return LOCKDOWN_E_INVALID_ARG; 308 return LOCKDOWN_E_INVALID_ARG;
349 char *real_query;
350 int bytes;
351 char *XMLContent = NULL;
352 uint32_t length = 0;
353 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
354 309
355 plist_to_xml(plist, &XMLContent, &length); 310 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
356 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending msg size %i, buffer follows:\n%s", __func__, length, XMLContent); 311 iphone_error_t err;
357 312
358 real_query = (char *) malloc(sizeof(char) * (length + 4)); 313 if (!client->in_SSL) {
359 length = htonl(length); 314 err = iphone_device_send_xml_plist(client->connection, plist);
360 memcpy(real_query, &length, sizeof(length)); 315 if (err != IPHONE_E_SUCCESS) {
361 memcpy(real_query + 4, XMLContent, ntohl(length)); 316 ret = LOCKDOWN_E_UNKNOWN_ERROR;
362 free(XMLContent);
363 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: made the query, sending it along\n", __func__);
364
365 if (!client->in_SSL)
366 ret = iphone_device_send(client->connection, real_query, ntohl(length) + sizeof(length), (uint32_t*)&bytes);
367 else {
368 ssize_t res = gnutls_record_send(client->ssl_session, real_query, ntohl(length) + sizeof(length));
369 if (res < 0) {
370 log_dbg_msg(DBGMASK_LOCKDOWND, "gnutls_record_send: Error occured: %s\n", gnutls_strerror(res));
371 ret = LOCKDOWN_E_SSL_ERROR;
372 } else {
373 bytes = res;
374 ret = LOCKDOWN_E_SUCCESS;
375 } 317 }
376 }
377 if (ret == LOCKDOWN_E_SUCCESS) {
378 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sent it!\n", __func__);
379 } else { 318 } else {
380 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending failed!\n", __func__); 319 err = iphone_device_send_encrypted_xml_plist(client->ssl_session, plist);
320 if (err != IPHONE_E_SUCCESS) {
321 ret = LOCKDOWN_E_SSL_ERROR;
322 }
381 } 323 }
382 free(real_query);
383
384 return ret; 324 return ret;
385} 325}
386 326