diff options
| author | 2009-05-10 08:27:53 -0700 | |
|---|---|---|
| committer | 2009-05-10 08:28:04 -0700 | |
| commit | 1351b686d450112ae55d26d81d9d59c5f542f12e (patch) | |
| tree | 442c7e48eb83f96a22f7c6d889e8fe26151d6cba /src | |
| parent | e91caeb1c9929f9dc8af747bb3a2e52ec06b03af (diff) | |
| download | libimobiledevice-1351b686d450112ae55d26d81d9d59c5f542f12e.tar.gz libimobiledevice-1351b686d450112ae55d26d81d9d59c5f542f12e.tar.bz2 | |
NotificationProxy support added.0.9.0
[#27 state:resolved]
Signed-off-by: Matt Colyer <matt@colyer.name>
Diffstat (limited to 'src')
| -rw-r--r-- | src/NotificationProxy.c | 404 | ||||
| -rw-r--r-- | src/NotificationProxy.h | 16 | ||||
| -rw-r--r-- | src/iphone.c | 5 | ||||
| -rw-r--r-- | src/iphone.h | 2 | ||||
| -rw-r--r-- | src/lockdown.c | 13 | ||||
| -rw-r--r-- | src/usbmux.c | 31 |
6 files changed, 359 insertions, 112 deletions
diff --git a/src/NotificationProxy.c b/src/NotificationProxy.c index bf837bf..d8bcc34 100644 --- a/src/NotificationProxy.c +++ b/src/NotificationProxy.c | |||
| @@ -21,10 +21,16 @@ | |||
| 21 | 21 | ||
| 22 | #include <string.h> | 22 | #include <string.h> |
| 23 | #include <stdio.h> | 23 | #include <stdio.h> |
| 24 | #include <arpa/inet.h> | ||
| 24 | #include <plist/plist.h> | 25 | #include <plist/plist.h> |
| 25 | #include "NotificationProxy.h" | 26 | #include "NotificationProxy.h" |
| 26 | #include "utils.h" | 27 | #include "utils.h" |
| 27 | 28 | ||
| 29 | struct np_thread { | ||
| 30 | iphone_np_client_t client; | ||
| 31 | iphone_np_notify_cb_t cbfunc; | ||
| 32 | }; | ||
| 33 | |||
| 28 | /** Locks an NP client, done for thread safety stuff. | 34 | /** Locks an NP client, done for thread safety stuff. |
| 29 | * | 35 | * |
| 30 | * @param client The NP | 36 | * @param client The NP |
| @@ -45,6 +51,54 @@ static void np_unlock(iphone_np_client_t client) | |||
| 45 | g_mutex_unlock(client->mutex); | 51 | g_mutex_unlock(client->mutex); |
| 46 | } | 52 | } |
| 47 | 53 | ||
| 54 | /** | ||
| 55 | * Sends an xml plist to the device using the connection specified in client. | ||
| 56 | * This function is only used internally. | ||
| 57 | * | ||
| 58 | * @param client NP to send data to | ||
| 59 | * @param dict plist to send | ||
| 60 | * | ||
| 61 | * @return IPHONE_E_SUCCESS or an error code. | ||
| 62 | */ | ||
| 63 | static iphone_error_t np_plist_send(iphone_np_client_t client, plist_t dict) | ||
| 64 | { | ||
| 65 | char *XML_content = NULL; | ||
| 66 | uint32_t length = 0; | ||
| 67 | uint32_t nlen = 0; | ||
| 68 | int bytes = 0; | ||
| 69 | iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; | ||
| 70 | |||
| 71 | if (!client || !dict) { | ||
| 72 | return IPHONE_E_INVALID_ARG; | ||
| 73 | } | ||
| 74 | |||
| 75 | plist_to_xml(dict, &XML_content, &length); | ||
| 76 | |||
| 77 | if (!XML_content || length == 0) { | ||
| 78 | return IPHONE_E_PLIST_ERROR; | ||
| 79 | } | ||
| 80 | |||
| 81 | nlen = htonl(length); | ||
| 82 | iphone_mux_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); | ||
| 83 | if (bytes == sizeof(nlen)) { | ||
| 84 | iphone_mux_send(client->connection, XML_content, length, (uint32_t*)&bytes); | ||
| 85 | if (bytes > 0) { | ||
| 86 | if ((uint32_t)bytes == length) { | ||
| 87 | res = IPHONE_E_SUCCESS; | ||
| 88 | } else { | ||
| 89 | log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | if (bytes <= 0) { | ||
| 94 | log_debug_msg("%s: ERROR: sending to device failed.\n", __func__); | ||
| 95 | } | ||
| 96 | |||
| 97 | free(XML_content); | ||
| 98 | |||
| 99 | return res; | ||
| 100 | } | ||
| 101 | |||
| 48 | /** Makes a connection to the NP service on the phone. | 102 | /** Makes a connection to the NP service on the phone. |
| 49 | * | 103 | * |
| 50 | * @param phone The iPhone to connect on. | 104 | * @param phone The iPhone to connect on. |
| @@ -53,7 +107,7 @@ static void np_unlock(iphone_np_client_t client) | |||
| 53 | * | 107 | * |
| 54 | * @return A handle to the newly-connected client or NULL upon error. | 108 | * @return A handle to the newly-connected client or NULL upon error. |
| 55 | */ | 109 | */ |
| 56 | iphone_error_t iphone_np_new_client(iphone_device_t device, int src_port, int dst_port, iphone_np_client_t * client) | 110 | iphone_error_t iphone_np_new_client ( iphone_device_t device, int src_port, int dst_port, iphone_np_client_t *client ) |
| 57 | { | 111 | { |
| 58 | int ret = IPHONE_E_SUCCESS; | 112 | int ret = IPHONE_E_SUCCESS; |
| 59 | 113 | ||
| @@ -75,6 +129,8 @@ iphone_error_t iphone_np_new_client(iphone_device_t device, int src_port, int ds | |||
| 75 | 129 | ||
| 76 | client_loc->mutex = g_mutex_new(); | 130 | client_loc->mutex = g_mutex_new(); |
| 77 | 131 | ||
| 132 | client_loc->notifier = NULL; | ||
| 133 | |||
| 78 | *client = client_loc; | 134 | *client = client_loc; |
| 79 | return IPHONE_E_SUCCESS; | 135 | return IPHONE_E_SUCCESS; |
| 80 | } | 136 | } |
| @@ -83,91 +139,97 @@ iphone_error_t iphone_np_new_client(iphone_device_t device, int src_port, int ds | |||
| 83 | * | 139 | * |
| 84 | * @param client The client to disconnect. | 140 | * @param client The client to disconnect. |
| 85 | */ | 141 | */ |
| 86 | iphone_error_t iphone_np_free_client(iphone_np_client_t client) | 142 | iphone_error_t iphone_np_free_client ( iphone_np_client_t client ) |
| 87 | { | 143 | { |
| 88 | if (!client || !client->connection) | 144 | if (!client) |
| 89 | return IPHONE_E_INVALID_ARG; | 145 | return IPHONE_E_INVALID_ARG; |
| 90 | 146 | ||
| 91 | iphone_mux_free_client(client->connection); | 147 | if (client->connection) { |
| 148 | iphone_mux_free_client(client->connection); | ||
| 149 | client->connection = NULL; | ||
| 150 | if (client->notifier) { | ||
| 151 | log_debug_msg("joining np callback\n"); | ||
| 152 | g_thread_join(client->notifier); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | if (client->mutex) { | ||
| 156 | g_mutex_free(client->mutex); | ||
| 157 | } | ||
| 92 | free(client); | 158 | free(client); |
| 159 | |||
| 93 | return IPHONE_E_SUCCESS; | 160 | return IPHONE_E_SUCCESS; |
| 94 | } | 161 | } |
| 95 | 162 | ||
| 96 | /** Sends a notification to the NP client. | 163 | /** Sends a notification to the device's Notification Proxy. |
| 97 | * | 164 | * |
| 98 | * notification messages seen so far: | 165 | * notification messages seen so far: |
| 99 | * com.apple.itunes-mobdev.syncWillStart | 166 | * com.apple.itunes-mobdev.syncWillStart |
| 100 | * com.apple.itunes-mobdev.syncDidStart | 167 | * com.apple.itunes-mobdev.syncDidStart |
| 101 | * | 168 | * |
| 102 | * @param client The client to send to | 169 | * @param client The client to send to |
| 103 | * @param notification The notification Message | 170 | * @param notification The notification message to send |
| 104 | */ | 171 | */ |
| 105 | iphone_error_t iphone_np_post_notification(iphone_np_client_t client, const char *notification) | 172 | iphone_error_t iphone_np_post_notification( iphone_np_client_t client, const char *notification ) |
| 106 | { | 173 | { |
| 107 | char *XML_content = NULL; | ||
| 108 | uint32_t length = 0; | ||
| 109 | int bytes = 0; | ||
| 110 | iphone_error_t ret; | ||
| 111 | unsigned char sndbuf[4096]; | ||
| 112 | int sndlen = 0; | ||
| 113 | int nlen = 0; | ||
| 114 | plist_t dict = NULL; | ||
| 115 | |||
| 116 | if (!client || !notification) { | 174 | if (!client || !notification) { |
| 117 | return IPHONE_E_INVALID_ARG; | 175 | return IPHONE_E_INVALID_ARG; |
| 118 | } | 176 | } |
| 119 | np_lock(client); | 177 | np_lock(client); |
| 120 | 178 | ||
| 121 | dict = plist_new_dict(); | 179 | plist_t dict = plist_new_dict(); |
| 122 | plist_add_sub_key_el(dict, "Command"); | 180 | plist_add_sub_key_el(dict, "Command"); |
| 123 | plist_add_sub_string_el(dict, "PostNotification"); | 181 | plist_add_sub_string_el(dict, "PostNotification"); |
| 124 | plist_add_sub_key_el(dict, "Name"); | 182 | plist_add_sub_key_el(dict, "Name"); |
| 125 | plist_add_sub_string_el(dict, notification); | 183 | plist_add_sub_string_el(dict, notification); |
| 126 | plist_to_xml(dict, &XML_content, &length); | ||
| 127 | |||
| 128 | nlen = htonl(length); | ||
| 129 | |||
| 130 | memcpy(sndbuf + sndlen, &nlen, 4); | ||
| 131 | sndlen += 4; | ||
| 132 | memcpy(sndbuf + sndlen, XML_content, length); | ||
| 133 | sndlen += length; | ||
| 134 | 184 | ||
| 185 | iphone_error_t res = np_plist_send(client, dict); | ||
| 135 | plist_free(dict); | 186 | plist_free(dict); |
| 136 | dict = NULL; | ||
| 137 | free(XML_content); | ||
| 138 | XML_content = NULL; | ||
| 139 | 187 | ||
| 140 | dict = plist_new_dict(); | 188 | dict = plist_new_dict(); |
| 141 | plist_add_sub_key_el(dict, "Command"); | 189 | plist_add_sub_key_el(dict, "Command"); |
| 142 | plist_add_sub_string_el(dict, "Shutdown"); | 190 | plist_add_sub_string_el(dict, "Shutdown"); |
| 143 | plist_to_xml(dict, &XML_content, &length); | ||
| 144 | 191 | ||
| 145 | nlen = htonl(length); | 192 | res = np_plist_send(client, dict); |
| 193 | plist_free(dict); | ||
| 146 | 194 | ||
| 147 | memcpy(sndbuf + sndlen, &nlen, 4); | 195 | if (res != IPHONE_E_SUCCESS) { |
| 148 | sndlen += 4; | 196 | log_debug_msg("%s: Error sending XML plist to device!\n", __func__); |
| 197 | } | ||
| 149 | 198 | ||
| 150 | memcpy(sndbuf + sndlen, XML_content, length); | 199 | np_unlock(client); |
| 151 | sndlen += length; | 200 | return res; |
| 201 | } | ||
| 152 | 202 | ||
| 153 | plist_free(dict); | 203 | /** Notifies the iphone to send a notification on the specified event. |
| 154 | dict = NULL; | 204 | * |
| 155 | free(XML_content); | 205 | * @param client The client to send to |
| 156 | XML_content = NULL; | 206 | * @param notification The notifications that should be observed. |
| 207 | */ | ||
| 208 | iphone_error_t iphone_np_observe_notification( iphone_np_client_t client, const char *notification ) | ||
| 209 | { | ||
| 210 | if (!client || !notification) { | ||
| 211 | return IPHONE_E_INVALID_ARG; | ||
| 212 | } | ||
| 213 | np_lock(client); | ||
| 157 | 214 | ||
| 158 | log_debug_buffer(sndbuf, sndlen); | 215 | plist_t dict = plist_new_dict(); |
| 216 | plist_add_sub_key_el(dict, "Command"); | ||
| 217 | plist_add_sub_string_el(dict, "ObserveNotification"); | ||
| 218 | plist_add_sub_key_el(dict, "Name"); | ||
| 219 | plist_add_sub_string_el(dict, notification); | ||
| 159 | 220 | ||
| 160 | iphone_mux_send(client->connection, sndbuf, sndlen, &bytes); | 221 | iphone_error_t res = np_plist_send(client, dict); |
| 161 | if (bytes <= 0) { | 222 | if (res != IPHONE_E_SUCCESS) { |
| 162 | np_unlock(client); | 223 | log_debug_msg("%s: Error sending XML plist to device!\n", __func__); |
| 163 | return bytes; | ||
| 164 | } | 224 | } |
| 225 | plist_free(dict); | ||
| 165 | 226 | ||
| 166 | np_unlock(client); | 227 | np_unlock(client); |
| 167 | return bytes; | 228 | return res; |
| 168 | } | 229 | } |
| 169 | 230 | ||
| 170 | /** Notifies the iphone to send a notification on certain events. | 231 | |
| 232 | /** Notifies the iphone to send a notification on specified events. | ||
| 171 | * | 233 | * |
| 172 | * observation messages seen so far: | 234 | * observation messages seen so far: |
| 173 | * com.apple.itunes-client.syncCancelRequest | 235 | * com.apple.itunes-client.syncCancelRequest |
| @@ -181,85 +243,217 @@ iphone_error_t iphone_np_post_notification(iphone_np_client_t client, const char | |||
| 181 | * com.apple.mobile.application_uninstalled | 243 | * com.apple.mobile.application_uninstalled |
| 182 | * | 244 | * |
| 183 | * @param client The client to send to | 245 | * @param client The client to send to |
| 246 | * @param notification_spec Specification of the notifications that should be | ||
| 247 | * observed. This is expected to be an array of const char* that MUST have a | ||
| 248 | * terminating NULL entry. However this parameter can be NULL; in this case, | ||
| 249 | * the default set of notifications will be used. | ||
| 184 | */ | 250 | */ |
| 185 | iphone_error_t iphone_np_observe_notification(iphone_np_client_t client) | 251 | iphone_error_t iphone_np_observe_notifications( iphone_np_client_t client, const char **notification_spec ) |
| 186 | { | 252 | { |
| 187 | plist_t dict = NULL; | ||
| 188 | char *XML_content = NULL; | ||
| 189 | uint32_t length = 0; | ||
| 190 | int bytes = 0; | ||
| 191 | iphone_error_t ret; | ||
| 192 | unsigned char sndbuf[4096]; | ||
| 193 | int sndlen = 0; | ||
| 194 | int nlen = 0; | ||
| 195 | int i = 0; | 253 | int i = 0; |
| 196 | const char *notifications[10] = { | 254 | iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; |
| 197 | "com.apple.itunes-client.syncCancelRequest", | 255 | const char **notifications = notification_spec; |
| 198 | "com.apple.itunes-client.syncSuspendRequest", | ||
| 199 | "com.apple.itunes-client.syncResumeRequest", | ||
| 200 | "com.apple.mobile.lockdown.phone_number_changed", | ||
| 201 | "com.apple.mobile.lockdown.device_name_changed", | ||
| 202 | "com.apple.springboard.attemptactivation", | ||
| 203 | "com.apple.mobile.data_sync.domain_changed", | ||
| 204 | "com.apple.mobile.application_installed", | ||
| 205 | "com.apple.mobile.application_uninstalled", | ||
| 206 | NULL | ||
| 207 | }; | ||
| 208 | |||
| 209 | sndlen = 0; | ||
| 210 | 256 | ||
| 211 | if (!client) { | 257 | if (!client) { |
| 212 | return IPHONE_E_INVALID_ARG; | 258 | return IPHONE_E_INVALID_ARG; |
| 213 | } | 259 | } |
| 214 | np_lock(client); | 260 | |
| 261 | if (!notifications) { | ||
| 262 | notifications = np_default_notifications; | ||
| 263 | } | ||
| 215 | 264 | ||
| 216 | while (notifications[i]) { | 265 | while (notifications[i]) { |
| 266 | res = iphone_np_observe_notification(client, notifications[i]); | ||
| 267 | if (res != IPHONE_E_SUCCESS) { | ||
| 268 | break; | ||
| 269 | } | ||
| 270 | i++; | ||
| 271 | } | ||
| 272 | |||
| 273 | return res; | ||
| 274 | } | ||
| 217 | 275 | ||
| 218 | dict = plist_new_dict(); | 276 | /** |
| 219 | plist_add_sub_key_el(dict, "Command"); | 277 | * Checks if a notification has been sent. |
| 220 | plist_add_sub_string_el(dict, "ObserveNotification"); | 278 | * |
| 221 | plist_add_sub_key_el(dict, "Name"); | 279 | * @param client NP to get a notification from |
| 222 | plist_add_sub_string_el(dict, notifications[i++]); | 280 | * @param notification Pointer to a buffer that will be allocated and filled |
| 223 | plist_to_xml(dict, &XML_content, &length); | 281 | * with the notification that has been received. |
| 224 | 282 | * | |
| 225 | nlen = htonl(length); | 283 | * @return IPHONE_E_SUCCESS if a notification has been received, |
| 226 | memcpy(sndbuf + sndlen, &nlen, 4); | 284 | * IPHONE_E_TIMEOUT if nothing has been received, |
| 227 | sndlen += 4; | 285 | * or an error value if an error occured. |
| 228 | memcpy(sndbuf + sndlen, XML_content, length); | 286 | * |
| 229 | sndlen += length; | 287 | * @note You probably want to check out iphone_np_set_notify_callback |
| 230 | 288 | * @see iphone_np_set_notify_callback | |
| 231 | plist_free(dict); | 289 | */ |
| 232 | dict = NULL; | 290 | iphone_error_t iphone_np_get_notification( iphone_np_client_t client, char **notification ) |
| 233 | free(XML_content); | 291 | { |
| 234 | XML_content = NULL; | 292 | uint32_t bytes = 0; |
| 293 | iphone_error_t res; | ||
| 294 | uint32_t pktlen = 0; | ||
| 295 | char *XML_content = NULL; | ||
| 296 | plist_t dict = NULL; | ||
| 297 | |||
| 298 | if (!client || !client->connection || *notification) { | ||
| 299 | return IPHONE_E_INVALID_ARG; | ||
| 235 | } | 300 | } |
| 236 | 301 | ||
| 237 | dict = plist_new_dict(); | 302 | np_lock(client); |
| 238 | plist_add_sub_key_el(dict, "Command"); | ||
| 239 | plist_add_sub_string_el(dict, "Shutdown"); | ||
| 240 | plist_to_xml(dict, &XML_content, &length); | ||
| 241 | 303 | ||
| 242 | nlen = htonl(length); | 304 | iphone_mux_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, 500); |
| 305 | log_debug_msg("NotificationProxy: initial read=%i\n", bytes); | ||
| 306 | if (bytes < 4) { | ||
| 307 | log_debug_msg("NotificationProxy: no notification received!\n"); | ||
| 308 | res = IPHONE_E_TIMEOUT; | ||
| 309 | } else { | ||
| 310 | if ((char)pktlen == 0) { | ||
| 311 | pktlen = ntohl(pktlen); | ||
| 312 | log_debug_msg("NotificationProxy: %d bytes following\n", pktlen); | ||
| 313 | XML_content = (char*)malloc(pktlen); | ||
| 314 | log_debug_msg("pointer %p\n", XML_content); | ||
| 315 | |||
| 316 | iphone_mux_recv_timeout(client->connection, XML_content, pktlen, &bytes, 1000); | ||
| 317 | if (bytes <= 0) { | ||
| 318 | res = IPHONE_E_UNKNOWN_ERROR; | ||
| 319 | } else { | ||
| 320 | log_debug_msg("NotificationProxy: received data:\n"); | ||
| 321 | log_debug_buffer(XML_content, pktlen); | ||
| 322 | |||
| 323 | plist_from_xml(XML_content, bytes, &dict); | ||
| 324 | if (!dict) { | ||
| 325 | np_unlock(client); | ||
| 326 | return IPHONE_E_PLIST_ERROR; | ||
| 327 | } | ||
| 328 | |||
| 329 | plist_t cmd_key_node = plist_find_node_by_key(dict, "Command"); | ||
| 330 | plist_t cmd_value_node = plist_get_next_sibling(cmd_key_node); | ||
| 331 | char *cmd_value = NULL; | ||
| 332 | |||
| 333 | if (plist_get_node_type(cmd_value_node) == PLIST_STRING) { | ||
| 334 | plist_get_string_val(cmd_value_node, &cmd_value); | ||
| 335 | } | ||
| 336 | |||
| 337 | if (cmd_value && !strcmp(cmd_value, "RelayNotification")) { | ||
| 338 | plist_t name_key_node = plist_get_next_sibling(cmd_value_node); | ||
| 339 | plist_t name_value_node = plist_get_next_sibling(name_key_node); | ||
| 340 | |||
| 341 | char *name_key = NULL; | ||
| 342 | char *name_value = NULL; | ||
| 343 | |||
| 344 | if (plist_get_node_type(name_key_node) == PLIST_KEY) { | ||
| 345 | plist_get_key_val(name_key_node, &name_key); | ||
| 346 | } | ||
| 347 | if (plist_get_node_type(name_value_node) == PLIST_STRING) { | ||
| 348 | plist_get_string_val(name_value_node, &name_value); | ||
| 349 | } | ||
| 350 | |||
| 351 | res = IPHONE_E_PLIST_ERROR; | ||
| 352 | if (name_key && name_value && !strcmp(name_key, "Name")) { | ||
| 353 | *notification = name_value; | ||
| 354 | log_debug_msg("%s: got notification %s\n", __func__, name_value); | ||
| 355 | res = IPHONE_E_SUCCESS; | ||
| 356 | } | ||
| 357 | free(name_key); | ||
| 358 | } else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) { | ||
| 359 | log_debug_msg("%s: ERROR: NotificationProxy died!\n", __func__); | ||
| 360 | res = IPHONE_E_UNKNOWN_ERROR; | ||
| 361 | } else if (cmd_value) { | ||
| 362 | log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__); | ||
| 363 | res = IPHONE_E_UNKNOWN_ERROR; | ||
| 364 | } else { | ||
| 365 | res = IPHONE_E_PLIST_ERROR; | ||
| 366 | } | ||
| 367 | if (cmd_value) { | ||
| 368 | free(cmd_value); | ||
| 369 | } | ||
| 370 | plist_free(dict); | ||
| 371 | dict = NULL; | ||
| 372 | free(XML_content); | ||
| 373 | XML_content = NULL; | ||
| 374 | } | ||
| 375 | } else { | ||
| 376 | res = IPHONE_E_UNKNOWN_ERROR; | ||
| 377 | } | ||
| 378 | } | ||
| 243 | 379 | ||
| 244 | memcpy(sndbuf + sndlen, &nlen, 4); | 380 | np_unlock(client); |
| 245 | sndlen += 4; | ||
| 246 | 381 | ||
| 247 | memcpy(sndbuf + sndlen, XML_content, length); | 382 | return res; |
| 248 | sndlen += length; | 383 | } |
| 249 | 384 | ||
| 250 | plist_free(dict); | 385 | /** |
| 251 | dict = NULL; | 386 | * Internally used thread function. |
| 252 | free(XML_content); | 387 | */ |
| 253 | XML_content = NULL; | 388 | gpointer iphone_np_notifier( gpointer arg ) |
| 389 | { | ||
| 390 | char *notification = NULL; | ||
| 391 | struct np_thread *npt = (struct np_thread*)arg; | ||
| 392 | |||
| 393 | if (!npt) return NULL; | ||
| 394 | |||
| 395 | log_debug_msg("%s: starting callback.\n", __func__); | ||
| 396 | while (npt->client->connection) { | ||
| 397 | iphone_np_get_notification(npt->client, ¬ification); | ||
| 398 | if (notification) { | ||
| 399 | npt->cbfunc(notification); | ||
| 400 | free(notification); | ||
| 401 | notification = NULL; | ||
| 402 | } | ||
| 403 | sleep(1); | ||
| 404 | } | ||
| 405 | if (npt) { | ||
| 406 | free(npt); | ||
| 407 | } | ||
| 254 | 408 | ||
| 255 | log_debug_buffer(sndbuf, sndlen); | 409 | return NULL; |
| 410 | } | ||
| 256 | 411 | ||
| 257 | iphone_mux_send(client->connection, sndbuf, sndlen, &bytes); | 412 | /** |
| 258 | if (bytes <= 0) { | 413 | * This function allows an application to define a callback function that will |
| 259 | np_unlock(client); | 414 | * be called when a notification has been received. |
| 260 | return bytes; | 415 | * It will start a thread that polls for notifications and calls the callback |
| 416 | * function if a notification has been received. | ||
| 417 | * | ||
| 418 | * @param client the NP client | ||
| 419 | * @param notify_cb pointer to a callback function or NULL to de-register a | ||
| 420 | * previously set callback function | ||
| 421 | * | ||
| 422 | * @return IPHONE_E_SUCCESS when the callback was successfully registered, | ||
| 423 | * or an error value when an error occured. | ||
| 424 | */ | ||
| 425 | iphone_error_t iphone_np_set_notify_callback( iphone_np_client_t client, iphone_np_notify_cb_t notify_cb ) | ||
| 426 | { | ||
| 427 | if (!client) { | ||
| 428 | return IPHONE_E_INVALID_ARG; | ||
| 429 | } | ||
| 430 | iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; | ||
| 431 | |||
| 432 | np_lock(client); | ||
| 433 | if (client->notifier) { | ||
| 434 | log_debug_msg("%s: callback already set, removing\n"); | ||
| 435 | iphone_umux_client_t conn = client->connection; | ||
| 436 | client->connection = NULL; | ||
| 437 | g_thread_join(client->notifier); | ||
| 438 | client->notifier = NULL; | ||
| 439 | client->connection = conn; | ||
| 261 | } | 440 | } |
| 262 | 441 | ||
| 442 | if (notify_cb) { | ||
| 443 | struct np_thread *npt = (struct np_thread*)malloc(sizeof(struct np_thread)); | ||
| 444 | if (npt) { | ||
| 445 | npt->client = client; | ||
| 446 | npt->cbfunc = notify_cb; | ||
| 447 | |||
| 448 | client->notifier = g_thread_create(iphone_np_notifier, npt, TRUE, NULL); | ||
| 449 | if (client->notifier) { | ||
| 450 | res = IPHONE_E_SUCCESS; | ||
| 451 | } | ||
| 452 | } | ||
| 453 | } else { | ||
| 454 | log_debug_msg("%s: no callback set\n", __func__); | ||
| 455 | } | ||
| 263 | np_unlock(client); | 456 | np_unlock(client); |
| 264 | return bytes; | 457 | |
| 458 | return res; | ||
| 265 | } | 459 | } |
diff --git a/src/NotificationProxy.h b/src/NotificationProxy.h index 7b4b48d..3552b79 100644 --- a/src/NotificationProxy.h +++ b/src/NotificationProxy.h | |||
| @@ -27,4 +27,20 @@ | |||
| 27 | struct iphone_np_client_int { | 27 | struct iphone_np_client_int { |
| 28 | iphone_umux_client_t connection; | 28 | iphone_umux_client_t connection; |
| 29 | GMutex *mutex; | 29 | GMutex *mutex; |
| 30 | GThread *notifier; | ||
| 30 | }; | 31 | }; |
| 32 | |||
| 33 | static const char *np_default_notifications[10] = { | ||
| 34 | NP_SYNC_SUSPEND_REQUEST, | ||
| 35 | NP_SYNC_RESUME_REQUEST, | ||
| 36 | NP_PHONE_NUMBER_CHANGED, | ||
| 37 | NP_SYNC_CANCEL_REQUEST, | ||
| 38 | NP_DEVICE_NAME_CHANGED, | ||
| 39 | NP_ATTEMPTACTIVATION, | ||
| 40 | NP_DS_DOMAIN_CHANGED, | ||
| 41 | NP_APP_INSTALLED, | ||
| 42 | NP_APP_UNINSTALLED, | ||
| 43 | NULL | ||
| 44 | }; | ||
| 45 | |||
| 46 | gpointer iphone_np_notifier( gpointer arg ); | ||
diff --git a/src/iphone.c b/src/iphone.c index 3c3034e..9dd3c07 100644 --- a/src/iphone.c +++ b/src/iphone.c | |||
| @@ -288,10 +288,11 @@ int send_to_phone(iphone_device_t phone, char *data, int datalen) | |||
| 288 | * @param phone The iPhone to receive data from | 288 | * @param phone The iPhone to receive data from |
| 289 | * @param data Where to put data read | 289 | * @param data Where to put data read |
| 290 | * @param datalen How much data to read in | 290 | * @param datalen How much data to read in |
| 291 | * @param timeout How many milliseconds to wait for data | ||
| 291 | * | 292 | * |
| 292 | * @return How many bytes were read in, or -1 on error. | 293 | * @return How many bytes were read in, or -1 on error. |
| 293 | */ | 294 | */ |
| 294 | int recv_from_phone(iphone_device_t phone, char *data, int datalen) | 295 | int recv_from_phone(iphone_device_t phone, char *data, int datalen, int timeout) |
| 295 | { | 296 | { |
| 296 | if (!phone) | 297 | if (!phone) |
| 297 | return -1; | 298 | return -1; |
| @@ -301,7 +302,7 @@ int recv_from_phone(iphone_device_t phone, char *data, int datalen) | |||
| 301 | return -1; | 302 | return -1; |
| 302 | log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen); | 303 | log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen); |
| 303 | 304 | ||
| 304 | bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, 3500); | 305 | bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, timeout); |
| 305 | if (bytes < 0) { | 306 | if (bytes < 0) { |
| 306 | log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), | 307 | log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), |
| 307 | strerror(-bytes)); | 308 | strerror(-bytes)); |
diff --git a/src/iphone.h b/src/iphone.h index 222a1be..15515e3 100644 --- a/src/iphone.h +++ b/src/iphone.h | |||
| @@ -41,5 +41,5 @@ struct iphone_device_int { | |||
| 41 | 41 | ||
| 42 | // Function definitions | 42 | // Function definitions |
| 43 | int send_to_phone(iphone_device_t phone, char *data, int datalen); | 43 | int send_to_phone(iphone_device_t phone, char *data, int datalen); |
| 44 | int recv_from_phone(iphone_device_t phone, char *data, int datalen); | 44 | int recv_from_phone(iphone_device_t phone, char *data, int datalen, int timeout); |
| 45 | #endif | 45 | #endif |
diff --git a/src/lockdown.c b/src/lockdown.c index c017cdf..5ade79a 100644 --- a/src/lockdown.c +++ b/src/lockdown.c | |||
| @@ -472,6 +472,19 @@ iphone_error_t lockdownd_get_device_public_key(iphone_lckd_client_t control, gnu | |||
| 472 | return lockdownd_generic_get_value(control, "Key", "DevicePublicKey", public_key); | 472 | return lockdownd_generic_get_value(control, "Key", "DevicePublicKey", public_key); |
| 473 | } | 473 | } |
| 474 | 474 | ||
| 475 | /** Askes for the device's name. | ||
| 476 | * | ||
| 477 | * @return IPHONE_E_SUCCESS on succes or an error value < 0 on failure. | ||
| 478 | */ | ||
| 479 | iphone_error_t lockdownd_get_device_name(iphone_lckd_client_t control, char **device_name) | ||
| 480 | { | ||
| 481 | gnutls_datum_t temp = { NULL, 0 }; | ||
| 482 | iphone_error_t res = lockdownd_generic_get_value(control, "Key", "DeviceName", &temp); | ||
| 483 | log_debug_msg("%s: %s\n", __func__, temp.data); | ||
| 484 | *device_name = (char*)temp.data; | ||
| 485 | return res; | ||
| 486 | } | ||
| 487 | |||
| 475 | /** Completes the entire lockdownd handshake. | 488 | /** Completes the entire lockdownd handshake. |
| 476 | * | 489 | * |
| 477 | * @param phone The iPhone | 490 | * @param phone The iPhone |
diff --git a/src/usbmux.c b/src/usbmux.c index 22ce588..7d74b4b 100644 --- a/src/usbmux.c +++ b/src/usbmux.c | |||
| @@ -143,7 +143,7 @@ iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port, | |||
| 143 | if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) { | 143 | if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) { |
| 144 | usbmux_tcp_header *response; | 144 | usbmux_tcp_header *response; |
| 145 | response = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header)); | 145 | response = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header)); |
| 146 | bytes = recv_from_phone(device, (char *) response, sizeof(*response)); | 146 | bytes = recv_from_phone(device, (char *) response, sizeof(*response), 3500); |
| 147 | if (response->tcp_flags != 0x12) { | 147 | if (response->tcp_flags != 0x12) { |
| 148 | free(response); | 148 | free(response); |
| 149 | return IPHONE_E_UNKNOWN_ERROR; | 149 | return IPHONE_E_UNKNOWN_ERROR; |
| @@ -268,10 +268,13 @@ iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, ui | |||
| 268 | * @param connection The connection to receive data on. | 268 | * @param connection The connection to receive data on. |
| 269 | * @param data Where to put the data we receive. | 269 | * @param data Where to put the data we receive. |
| 270 | * @param datalen How much data to read. | 270 | * @param datalen How much data to read. |
| 271 | * @param recv_bytes Pointer to a uint32_t that will be set | ||
| 272 | * to the number of bytes received. | ||
| 273 | * @param timeout How many milliseconds to wait for data. | ||
| 271 | * | 274 | * |
| 272 | * @return How many bytes were read, or -1 if something bad happens. | 275 | * @return IPHONE_E_SUCCESS on success, or and error value. |
| 273 | */ | 276 | */ |
| 274 | iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes) | 277 | iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout) |
| 275 | { | 278 | { |
| 276 | 279 | ||
| 277 | if (!client || !data || datalen == 0 || !recv_bytes) | 280 | if (!client || !data || datalen == 0 || !recv_bytes) |
| @@ -323,7 +326,7 @@ iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t | |||
| 323 | buffer = (char *) malloc(sizeof(char) * 131072); // make sure we get enough ;) | 326 | buffer = (char *) malloc(sizeof(char) * 131072); // make sure we get enough ;) |
| 324 | 327 | ||
| 325 | // See #3. | 328 | // See #3. |
| 326 | bytes = recv_from_phone(client->phone, buffer, 131072); | 329 | bytes = recv_from_phone(client->phone, buffer, 131072, timeout); |
| 327 | if (bytes < 28) { | 330 | if (bytes < 28) { |
| 328 | free(buffer); | 331 | free(buffer); |
| 329 | log_debug_msg("mux_recv: Did not even get the header.\n"); | 332 | log_debug_msg("mux_recv: Did not even get the header.\n"); |
| @@ -385,3 +388,23 @@ iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t | |||
| 385 | log_debug_msg("mux_recv: Heisenbug: bytes and datalen not matching up\n"); | 388 | log_debug_msg("mux_recv: Heisenbug: bytes and datalen not matching up\n"); |
| 386 | return IPHONE_E_UNKNOWN_ERROR; | 389 | return IPHONE_E_UNKNOWN_ERROR; |
| 387 | } | 390 | } |
| 391 | |||
| 392 | /** | ||
| 393 | * This function is just like 'iphone_mux_recv_timeout' but you do not need | ||
| 394 | * to specify a timeout. It simply calls iphone_mux_recv_timeout with a | ||
| 395 | * timeout value of 3500 milliseconds. | ||
| 396 | * | ||
| 397 | * @param connection The connection to receive data on. | ||
| 398 | * @param data Where to put the data we receive. | ||
| 399 | * @param datalen How much data to read. | ||
| 400 | * @param recv_bytes Pointer to a uint32_t that will be set | ||
| 401 | * to the number of bytes received. | ||
| 402 | * | ||
| 403 | * @return The return value of iphone_mux_recv_timeout. | ||
| 404 | * | ||
| 405 | * @see iphone_mux_recv_timeout | ||
| 406 | */ | ||
| 407 | iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes) | ||
| 408 | { | ||
| 409 | return iphone_mux_recv_timeout(client, data, datalen, recv_bytes, 3500); | ||
| 410 | } | ||
