/**
 * 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;
}
示例#2
0
/** 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);
    }
}
示例#4
0
/**
 * 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;
}
示例#9
0
/**
 * 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");
}
示例#11
0
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);
}
示例#12
0
/**
 * 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;
}