/** * Checks if a notification has been sent by the device. * * @param client NP to get a notification from * @param notification Pointer to a buffer that will be allocated and filled * with the notification that has been received. * * @return 0 if a notification has been received or nothing has been received, * or a negative value if an error occured. * * @note You probably want to check out np_set_notify_callback * @see np_set_notify_callback */ static int np_get_notification(np_client_t client, char **notification) { int res = 0; plist_t dict = NULL; if (!client || !client->parent || *notification) return -1; np_lock(client); property_list_service_error_t perr = property_list_service_receive_plist_with_timeout(client->parent, &dict, 500); if (perr == PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT) { debug_info("NotificationProxy: no notification received!"); res = 0; } else if (perr != PROPERTY_LIST_SERVICE_E_SUCCESS) { debug_info("NotificationProxy: error %d occured!", perr); res = perr; } if (dict) { char *cmd_value = NULL; plist_t cmd_value_node = plist_dict_get_item(dict, "Command"); if (plist_get_node_type(cmd_value_node) == PLIST_STRING) { plist_get_string_val(cmd_value_node, &cmd_value); } if (cmd_value && !strcmp(cmd_value, "RelayNotification")) { char *name_value = NULL; plist_t name_value_node = plist_dict_get_item(dict, "Name"); if (plist_get_node_type(name_value_node) == PLIST_STRING) { plist_get_string_val(name_value_node, &name_value); } res = -2; if (name_value_node && name_value) { *notification = name_value; debug_info("got notification %s", __func__, name_value); res = 0; } } else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) { debug_info("NotificationProxy died!"); res = -1; } else if (cmd_value) { debug_info("unknown NotificationProxy command '%s' received!", cmd_value); res = -1; } else { res = -2; } if (cmd_value) { free(cmd_value); } plist_free(dict); dict = NULL; } np_unlock(client); return res; }
/** Sends a notification to the device's Notification Proxy. * * notification messages seen so far: * com.apple.itunes-mobdev.syncWillStart * com.apple.itunes-mobdev.syncDidStart * * @param client The client to send to * @param notification The notification message to send */ np_error_t np_post_notification(np_client_t client, const char *notification) { if (!client || !notification) { return NP_E_INVALID_ARG; } np_lock(client); plist_t dict = plist_new_dict(); plist_dict_insert_item(dict,"Command", plist_new_string("PostNotification")); plist_dict_insert_item(dict,"Name", plist_new_string(notification)); np_error_t res = np_plist_send(client, dict); plist_free(dict); dict = plist_new_dict(); plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown")); res = np_plist_send(client, dict); plist_free(dict); if (res != NP_E_SUCCESS) { log_debug_msg("%s: Error sending XML plist to device!\n", __func__); } np_unlock(client); return res; }
static void np_channel_read_done(void * x) { AsyncReqInfo * req = (AsyncReqInfo *)x; ChannelNP * c = (ChannelNP *)req->client_data; ssize_t len = 0; assert(is_dispatch_thread()); assert(c->magic == CHANNEL_MAGIC); assert(c->read_pending != 0); assert(c->lock_cnt > 0); loc_free(req->u.user.data); c->read_pending = 0; /* some data is available retrieve it */ { len = c->rd_req.u.user.rval; if (req->error) { if (c->chan.state != ChannelStateDisconnected) { trace(LOG_ALWAYS, "Can't read from socket: %s", errno_to_str(req->error)); } len = 0; /* Treat error as EOF */ } } if (c->chan.state != ChannelStateDisconnected) { ibuf_read_done(&c->ibuf, len); } else if (len > 0) { np_post_read(&c->ibuf, c->ibuf.buf, c->ibuf.buf_size); } else { np_unlock(&c->chan); } }
/** * This function allows an application to define a callback function that will * be called when a notification has been received. * It will start a thread that polls for notifications and calls the callback * function if a notification has been received. * * @param client the NP client * @param notify_cb pointer to a callback function or NULL to de-register a * previously set callback function * * @return NP_E_SUCCESS when the callback was successfully registered, * or an error value when an error occured. */ np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb ) { if (!client) return NP_E_INVALID_ARG; np_error_t res = NP_E_UNKNOWN_ERROR; np_lock(client); if (client->notifier) { log_debug_msg("%s: callback already set, removing\n"); iphone_connection_t conn = client->connection; client->connection = NULL; g_thread_join(client->notifier); client->notifier = NULL; client->connection = conn; } if (notify_cb) { struct np_thread *npt = (struct np_thread*)malloc(sizeof(struct np_thread)); if (npt) { npt->client = client; npt->cbfunc = notify_cb; client->notifier = g_thread_create(np_notifier, npt, TRUE, NULL); if (client->notifier) { res = NP_E_SUCCESS; } } } else { log_debug_msg("%s: no callback set\n", __func__); } np_unlock(client); return res; }
/** * Sends a notification to the device's notification_proxy. * * @param client The client to send to * @param notification The notification message to send * * @return NP_E_SUCCESS on success, or an error returned by np_plist_send */ np_error_t np_post_notification(np_client_t client, const char *notification) { if (!client || !notification) { return NP_E_INVALID_ARG; } np_lock(client); plist_t dict = plist_new_dict(); plist_dict_insert_item(dict,"Command", plist_new_string("PostNotification")); plist_dict_insert_item(dict,"Name", plist_new_string(notification)); np_error_t res = np_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); dict = plist_new_dict(); plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown")); res = np_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); if (res != NP_E_SUCCESS) { debug_info("Error sending XML plist to device!"); } np_unlock(client); return res; }
/** * This function allows an application to define a callback function that will * be called when a notification has been received. * It will start a thread that polls for notifications and calls the callback * function if a notification has been received. * In case of an error condition when polling for notifications - e.g. device * disconnect - the thread will call the callback function with an empty * notification "" and terminate itself. * * @param client the NP client * @param notify_cb pointer to a callback function or NULL to de-register a * previously set callback function. * @param user_data Pointer that will be passed to the callback function as * user data. If notify_cb is NULL, this parameter is ignored. * * @note Only one callback function can be registered at the same time; * any previously set callback function will be removed automatically. * * @return NP_E_SUCCESS when the callback was successfully registered, * NP_E_INVALID_ARG when client is NULL, or NP_E_UNKNOWN_ERROR when * the callback thread could no be created. */ np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb, void *user_data ) { if (!client) return NP_E_INVALID_ARG; np_error_t res = NP_E_UNKNOWN_ERROR; np_lock(client); if (client->notifier) { debug_info("callback already set, removing"); property_list_service_client_t parent = client->parent; client->parent = NULL; thread_join(client->notifier); client->notifier = (thread_t)NULL; client->parent = parent; } if (notify_cb) { struct np_thread *npt = (struct np_thread*)malloc(sizeof(struct np_thread)); if (npt) { npt->client = client; npt->cbfunc = notify_cb; npt->user_data = user_data; if (thread_create(&client->notifier, np_notifier, npt) == 0) { res = NP_E_SUCCESS; } } } else { debug_info("no callback set"); } np_unlock(client); return res; }
static void np_flush_event(void * x) { ChannelNP * c = (ChannelNP *)x; assert(c->magic == CHANNEL_MAGIC); if (--c->out_flush_cnt == 0) { int congestion_level = c->chan.congestion_level; if (congestion_level > 0) usleep(congestion_level * 2500); np_flush_with_flags(c, 0); np_unlock(&c->chan); } else if (c->out_eom_cnt > 3) { np_flush_with_flags(c, 0); } }
/** * Sends a notification to the device's notification_proxy. * * @param client The client to send to * @param notification The notification message to send * * @return NP_E_SUCCESS on success, or an error returned by np_plist_send */ np_error_t np_post_notification(np_client_t client, const char *notification) { if (!client || !notification) { return NP_E_INVALID_ARG; } np_lock(client); plist_t dict = plist_new_dict(); plist_dict_set_item(dict,"Command", plist_new_string("PostNotification")); plist_dict_set_item(dict,"Name", plist_new_string(notification)); np_error_t res = np_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); dict = plist_new_dict(); plist_dict_set_item(dict,"Command", plist_new_string("Shutdown")); res = np_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); if (res != NP_E_SUCCESS) { debug_info("Error sending XML plist to device!"); } // try to read an answer, we just ignore errors here dict = NULL; property_list_service_receive_plist(client->parent, &dict); if (dict) { #ifndef STRIP_DEBUG_CODE char *cmd_value = NULL; plist_t cmd_value_node = plist_dict_get_item(dict, "Command"); if (plist_get_node_type(cmd_value_node) == PLIST_STRING) { plist_get_string_val(cmd_value_node, &cmd_value); } if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) { // this is the expected answer } else { debug_plist(dict); } if (cmd_value) { free(cmd_value); } #endif plist_free(dict); } np_unlock(client); return res; }
/** * This function allows an application to define a callback function that will * be called when a notification has been received. * It will start a thread that polls for notifications and calls the callback * function if a notification has been received. * * @param client the NP client * @param notify_cb pointer to a callback function or NULL to de-register a * previously set callback function. * @param user_data Pointer that will be passed to the callback function as * user data. If notify_cb is NULL, this parameter is ignored. * * @note Only one callback function can be registered at the same time; * any previously set callback function will be removed automatically. * * @return NP_E_SUCCESS when the callback was successfully registered, * NP_E_INVALID_ARG when client is NULL, or NP_E_UNKNOWN_ERROR when * the callback thread could no be created. */ np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb, void *user_data ) { if (!client) return NP_E_INVALID_ARG; np_error_t res = NP_E_UNKNOWN_ERROR; np_lock(client); if (client->notifier) { debug_info("callback already set, removing\n"); property_list_service_client_t parent = client->parent; client->parent = NULL; #ifdef WIN32 WaitForSingleObject(client->notifier, INFINITE); client->notifier = NULL; #else pthread_join(client->notifier, NULL); client->notifier = (pthread_t)NULL; #endif client->parent = parent; } if (notify_cb) { struct np_thread *npt = (struct np_thread*)malloc(sizeof(struct np_thread)); if (npt) { npt->client = client; npt->cbfunc = notify_cb; npt->user_data = user_data; #ifdef WIN32 client->notifier = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)np_notifier, npt, 0, NULL); if (client->notifier != INVALID_HANDLE_VALUE) { res = NP_E_SUCCESS; } else { client->notifier = NULL; } #else if (pthread_create(&client->notifier, NULL, np_notifier, npt) == 0) { res = NP_E_SUCCESS; } #endif } } else { debug_info("no callback set"); } np_unlock(client); return res; }
static void done_write_request(void * args) { ChannelNP * c = (ChannelNP *)((AsyncReqInfo *)args)->client_data; int size = 0; int error = 0; assert(args == &c->wr_req); assert(c->socket != NOPOLL_INVALID_SOCKET); loc_free(((AsyncReqInfo *)args)->u.user.data); if (c->wr_req.u.user.rval < 0) error = c->wr_req.error; size = c->wr_req.u.user.rval; output_queue_done(&c->out_queue, error, size); if (error) c->out_errno = error; if (output_queue_is_empty(&c->out_queue) && c->chan.state == ChannelStateDisconnected) nopoll_conn_shutdown(c->np_socket); np_unlock(&c->chan); trace(LOG_PROTOCOL, "done_write_request"); }
static void dump_context(htsbuf_queue_t *out, np_context_t *np) { np_lock(np); htsbuf_qprintf(out, "\n--- %s ------------------------\n", np->np_path); htsbuf_qprintf(out, " Loaded from %s\n", np->np_path); htsbuf_qprintf(out, "\n Heap\n"); heap_walker_aux_t heap = {out}; vmir_walk_heap(np->np_unit, heap_printer, &heap); htsbuf_qprintf(out, " Heap total inuse: %d bytes\n", heap.inuse); htsbuf_qprintf(out, "\n Open descriptors\n"); vmir_walk_fds(np->np_unit, fd_printer, out); const vmir_stats_t *s = vmir_get_stats(np->np_unit); htsbuf_qprintf(out, "\n"); htsbuf_qprintf(out, " Memory usage stats\n"); htsbuf_qprintf(out, " VM code size: %d\n", s->vm_code_size); htsbuf_qprintf(out, " JIT code size: %d\n", s->jit_code_size); htsbuf_qprintf(out, " Data size: %d\n", s->data_size); htsbuf_qprintf(out, " Peak heap size: %d\n", s->peak_heap_size); htsbuf_qprintf(out, " Peak stack usage: %d\n", s->peak_stack_size); htsbuf_qprintf(out, "\n"); htsbuf_qprintf(out, " Code transformation stats\n"); htsbuf_qprintf(out, " Moves killed: %d\n", s->moves_killed); htsbuf_qprintf(out, " Lea+Load combined: %d\n", s->lea_load_combined); htsbuf_qprintf(out, " Lea+Load comb-fail: %d\n", s->lea_load_combined_failed); htsbuf_qprintf(out, " Cmp+Branch combined: %d\n", s->cmp_branch_combine); htsbuf_qprintf(out, " Cmp+Select combined: %d\n", s->cmp_select_combine); htsbuf_qprintf(out, " Mul+Add combined: %d\n", s->mla_combine); htsbuf_qprintf(out, " Load+Cast combined: %d\n", s->load_cast_combine); htsbuf_qprintf(out, "\n"); np_unlock(np); }
/** * Checks if a notification has been sent. * * @param client NP to get a notification from * @param notification Pointer to a buffer that will be allocated and filled * with the notification that has been received. * * @return 0 if a notification has been received or nothing has been received, * or an error value if an error occured. * * @note You probably want to check out np_set_notify_callback * @see np_set_notify_callback */ static int np_get_notification(np_client_t client, char **notification) { uint32_t bytes = 0; int res = 0; uint32_t pktlen = 0; char *XML_content = NULL; plist_t dict = NULL; if (!client || !client->connection || *notification) return -1; np_lock(client); iphone_device_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, 500); log_debug_msg("NotificationProxy: initial read=%i\n", bytes); if (bytes < 4) { log_debug_msg("NotificationProxy: no notification received!\n"); res = 0; } else { if ((char)pktlen == 0) { pktlen = ntohl(pktlen); log_debug_msg("NotificationProxy: %d bytes following\n", pktlen); XML_content = (char*)malloc(pktlen); log_debug_msg("pointer %p\n", XML_content); iphone_device_recv_timeout(client->connection, XML_content, pktlen, &bytes, 1000); if (bytes <= 0) { res = -1; } else { log_debug_msg("NotificationProxy: received data:\n"); log_debug_buffer(XML_content, pktlen); plist_from_xml(XML_content, bytes, &dict); if (!dict) { np_unlock(client); return -2; } plist_t cmd_key_node = plist_find_node_by_key(dict, "Command"); plist_t cmd_value_node = plist_get_next_sibling(cmd_key_node); char *cmd_value = NULL; if (plist_get_node_type(cmd_value_node) == PLIST_STRING) { plist_get_string_val(cmd_value_node, &cmd_value); } if (cmd_value && !strcmp(cmd_value, "RelayNotification")) { plist_t name_key_node = plist_get_next_sibling(cmd_value_node); plist_t name_value_node = plist_get_next_sibling(name_key_node); char *name_key = NULL; char *name_value = NULL; if (plist_get_node_type(name_key_node) == PLIST_KEY) { plist_get_key_val(name_key_node, &name_key); } if (plist_get_node_type(name_value_node) == PLIST_STRING) { plist_get_string_val(name_value_node, &name_value); } res = -2; if (name_key && name_value && !strcmp(name_key, "Name")) { *notification = name_value; log_debug_msg("%s: got notification %s\n", __func__, name_value); res = 0; } free(name_key); } else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) { log_debug_msg("%s: ERROR: NotificationProxy died!\n", __func__); res = -1; } else if (cmd_value) { log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__); res = -1; } else { res = -2; } if (cmd_value) { free(cmd_value); } plist_free(dict); dict = NULL; free(XML_content); XML_content = NULL; } } else { res = -1; } } np_unlock(client); return res; }