/** * 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; }
/** * 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; }
static void np_write_stream(OutputStream * out, int byte) { ChannelNP * c = channel2np(out2channel(out)); assert(c->magic == CHANNEL_MAGIC); if (!c->chan.out.supports_zero_copy || c->chan.out.cur >= c->chan.out.end - 32 || byte < 0) { if (c->out_bin_block != NULL) np_bin_block_end(c); if (c->chan.out.cur == c->chan.out.end) np_flush_with_flags(c, MSG_MORE); if (byte < 0 || byte == ESC) { char esc = 0; *c->chan.out.cur++ = ESC; if (byte == ESC) esc = 0; else if (byte == MARKER_EOM) esc = 1; else if (byte == MARKER_EOS) esc = 2; else assert(0); if (c->chan.out.cur == c->chan.out.end) np_flush_with_flags(c, MSG_MORE); *c->chan.out.cur++ = esc; if (byte == MARKER_EOM) { c->out_eom_cnt++; if (c->out_flush_cnt < 2) { if (c->out_flush_cnt++ == 0) np_lock(&c->chan); post_event_with_delay(np_flush_event, c, 0); } } return; } } else if (c->out_bin_block == NULL) { np_bin_block_start(c); } *c->chan.out.cur++ = (char)byte; }
/** 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; }
/** * 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; }
/** * 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 post_write_request(OutputBuffer * bf) { ChannelNP * c = obuf2np(bf->queue); assert(c->socket != NOPOLL_INVALID_SOCKET); c->wr_req.client_data = c; c->wr_req.done = done_write_request; { NpIOReq * req = loc_alloc( sizeof(NpIOReq)); req->bufp = bf->buf + bf->buf_pos; req->bufsz = bf->buf_len - bf->buf_pos; req->np_sock = c->np_socket; c->wr_req.type = AsyncReqUser; c->wr_req.u.user.data = req; c->wr_req.u.user.func = np_wt_write_request; async_req_post(&c->wr_req); } np_lock(&c->chan); }
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; }
static Npfcall* np_process_request(Npreq *req, Npstats *stats) { Npfcall *rc = NULL; Npfcall *tc = req->tcall; int ecode, valid_op = 1; u64 rbytes = 0, wbytes = 0; np_uerror(0); switch (tc->type) { case P9_TSTATFS: rc = np_statfs(req, tc); break; case P9_TLOPEN: rc = np_lopen(req, tc); break; case P9_TLCREATE: rc = np_lcreate(req, tc); break; case P9_TSYMLINK: rc = np_symlink(req, tc); break; case P9_TMKNOD: rc = np_mknod(req, tc); break; case P9_TRENAME: rc = np_rename(req, tc); break; case P9_TREADLINK: rc = np_readlink(req, tc); break; case P9_TGETATTR: rc = np_getattr(req, tc); break; case P9_TSETATTR: rc = np_setattr(req, tc); break; case P9_TXATTRWALK: rc = np_xattrwalk(req, tc); break; case P9_TXATTRCREATE: rc = np_xattrcreate(req, tc); break; case P9_TREADDIR: rc = np_readdir(req, tc); break; case P9_TFSYNC: rc = np_fsync(req, tc); break; case P9_TLOCK: rc = np_lock(req, tc); break; case P9_TGETLOCK: rc = np_getlock(req, tc); break; case P9_TLINK: rc = np_link(req, tc); break; case P9_TMKDIR: rc = np_mkdir(req, tc); break; case P9_TVERSION: rc = np_version(req, tc); break; case P9_TAUTH: rc = np_auth(req, tc); break; case P9_TATTACH: rc = np_attach(req, tc); break; case P9_TFLUSH: rc = np_flush(req, tc); break; case P9_TWALK: rc = np_walk(req, tc); break; case P9_TREAD: rc = np_read(req, tc); rbytes = rc->u.rread.count; break; case P9_TWRITE: rc = np_write(req, tc); wbytes = rc->u.rwrite.count; break; case P9_TCLUNK: rc = np_clunk(req, tc); break; case P9_TREMOVE: rc = np_remove(req, tc); break; default: /* N.B. shouldn't get here - unhandled ops are * caught in np_deserialize (). */ np_uerror(ENOSYS); valid_op = 0; break; } if ((ecode = np_rerror())) { if (rc) free(rc); rc = np_create_rlerror(ecode); } if (valid_op) { xpthread_mutex_lock (&stats->lock); stats->rbytes += rbytes; stats->wbytes += wbytes; stats->nreqs[tc->type]++; xpthread_mutex_unlock (&stats->lock); } return rc; }