summaryrefslogtreecommitdiffstats
path: root/src/notification_proxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/notification_proxy.c')
-rw-r--r--src/notification_proxy.c253
1 files changed, 107 insertions, 146 deletions
diff --git a/src/notification_proxy.c b/src/notification_proxy.c
index 80a82c4..60b2e03 100644
--- a/src/notification_proxy.c
+++ b/src/notification_proxy.c
@@ -8,17 +8,20 @@
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
@@ -26,7 +29,11 @@
#include "notification_proxy.h"
#include "property_list_service.h"
-#include "debug.h"
+#include "common/debug.h"
+
+#ifdef WIN32
+#define sleep(x) Sleep(x*1000)
+#endif
struct np_thread {
np_client_t client;
@@ -41,19 +48,19 @@ struct np_thread {
*/
static void np_lock(np_client_t client)
{
- debug_info("NP: Locked");
- g_mutex_lock(client->mutex);
+ debug_info("Locked");
+ mutex_lock(&client->mutex);
}
/**
* Unlocks a notification_proxy client, used for thread safety.
- *
+ *
* @param client notification_proxy client to unlock
*/
static void np_unlock(np_client_t client)
{
- debug_info("NP: Unlocked");
- g_mutex_unlock(client->mutex);
+ debug_info("Unlocked");
+ mutex_unlock(&client->mutex);
}
/**
@@ -82,78 +89,85 @@ static np_error_t np_error(property_list_service_error_t err)
return NP_E_UNKNOWN_ERROR;
}
-/**
- * Connects to the notification_proxy on the specified device.
- *
- * @param device The device to connect to.
- * @param port Destination port (usually given by lockdownd_start_service).
- * @param client Pointer that will be set to a newly allocated np_client_t
- * upon successful return.
- *
- * @return NP_E_SUCCESS on success, NP_E_INVALID_ARG when device is NULL,
- * or NP_E_CONN_FAILED when the connection to the device could not be
- * established.
- */
-np_error_t np_client_new(idevice_t device, uint16_t port, np_client_t *client)
+np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t service, np_client_t *client)
{
- /* makes sure thread environment is available */
- if (!g_thread_supported())
- g_thread_init(NULL);
-
- if (!device)
- return NP_E_INVALID_ARG;
-
property_list_service_client_t plistclient = NULL;
- if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
- return NP_E_CONN_FAILED;
+ np_error_t err = np_error(property_list_service_client_new(device, service, &plistclient));
+ if (err != NP_E_SUCCESS) {
+ return err;
}
np_client_t client_loc = (np_client_t) malloc(sizeof(struct np_client_private));
client_loc->parent = plistclient;
- client_loc->mutex = g_mutex_new();
-
- client_loc->notifier = NULL;
+ mutex_init(&client_loc->mutex);
+ client_loc->notifier = THREAD_T_NULL;
*client = client_loc;
return NP_E_SUCCESS;
}
-/**
- * Disconnects a notification_proxy client from the device and frees up the
- * notification_proxy client data.
- *
- * @param client The notification_proxy client to disconnect and free.
- *
- * @return NP_E_SUCCESS on success, or NP_E_INVALID_ARG when client is NULL.
- */
+np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label)
+{
+ np_error_t err = NP_E_UNKNOWN_ERROR;
+ service_client_factory_start_service(device, NP_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(np_client_new), &err);
+ return err;
+}
+
np_error_t np_client_free(np_client_t client)
{
+ plist_t dict;
+ property_list_service_client_t parent;
+
if (!client)
return NP_E_INVALID_ARG;
- property_list_service_client_free(client->parent);
+ dict = plist_new_dict();
+ plist_dict_set_item(dict,"Command", plist_new_string("Shutdown"));
+ property_list_service_send_xml_plist(client->parent, dict);
+ plist_free(dict);
+
+ parent = client->parent;
+ /* notifies the client->notifier thread that it should terminate */
client->parent = NULL;
+
if (client->notifier) {
debug_info("joining np callback");
- g_thread_join(client->notifier);
- }
- if (client->mutex) {
- g_mutex_free(client->mutex);
+ thread_join(client->notifier);
+ thread_free(client->notifier);
+ client->notifier = THREAD_T_NULL;
+ } else {
+ dict = NULL;
+ property_list_service_receive_plist(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_info("Did not get ProxyDeath but:");
+ debug_plist(dict);
+ }
+ if (cmd_value) {
+ free(cmd_value);
+ }
+#endif
+ plist_free(dict);
+ }
}
+
+ property_list_service_client_free(parent);
+
+ mutex_destroy(&client->mutex);
free(client);
return NP_E_SUCCESS;
}
-/**
- * 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) {
@@ -162,66 +176,24 @@ np_error_t np_post_notification(np_client_t client, const char *notification)
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));
+ 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_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!");
}
-
- // 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);
- }
- g_free(cmd_value);
-#endif
- plist_free(dict);
- }
-
np_unlock(client);
return res;
}
-/**
- * Tells the device to send a notification on the specified event.
- *
- * @param client The client to send to
- * @param notification The notifications that should be observed.
- *
- * @return NP_E_SUCCESS on success, NP_E_INVALID_ARG when client or
- * notification are NULL, or an error returned by np_plist_send.
- */
-np_error_t np_observe_notification( np_client_t client, const char *notification )
+static np_error_t internal_np_observe_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("ObserveNotification"));
- plist_dict_insert_item(dict,"Name", plist_new_string(notification));
+ plist_dict_set_item(dict,"Command", plist_new_string("ObserveNotification"));
+ 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));
if (res != NP_E_SUCCESS) {
@@ -229,21 +201,20 @@ np_error_t np_observe_notification( np_client_t client, const char *notification
}
plist_free(dict);
+ return res;
+}
+
+np_error_t np_observe_notification( np_client_t client, const char *notification )
+{
+ if (!client || !notification) {
+ return NP_E_INVALID_ARG;
+ }
+ np_lock(client);
+ np_error_t res = internal_np_observe_notification(client, notification);
np_unlock(client);
return res;
}
-/**
- * Tells the device to send a notification on specified events.
- *
- * @param client The client to send to
- * @param notification_spec Specification of the notifications that should be
- * observed. This is expected to be an array of const char* that MUST have a
- * terminating NULL entry.
- *
- * @return NP_E_SUCCESS on success, NP_E_INVALID_ARG when client is null,
- * or an error returned by np_observe_notification.
- */
np_error_t np_observe_notifications(np_client_t client, const char **notification_spec)
{
int i = 0;
@@ -258,13 +229,15 @@ np_error_t np_observe_notifications(np_client_t client, const char **notificatio
return NP_E_INVALID_ARG;
}
+ np_lock(client);
while (notifications[i]) {
- res = np_observe_notification(client, notifications[i]);
+ res = internal_np_observe_notification(client, notifications[i]);
if (res != NP_E_SUCCESS) {
break;
}
i++;
}
+ np_unlock(client);
return res;
}
@@ -277,7 +250,7 @@ np_error_t np_observe_notifications(np_client_t client, const char **notificatio
* 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.
+ * or a negative value if an error occurred.
*
* @note You probably want to check out np_set_notify_callback
* @see np_set_notify_callback
@@ -292,11 +265,15 @@ static int np_get_notification(np_client_t client, char **notification)
np_lock(client);
- property_list_service_receive_plist_with_timeout(client->parent, &dict, 500);
- if (!dict) {
+ 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 {
+ } else if (perr != PROPERTY_LIST_SERVICE_E_SUCCESS) {
+ debug_info("NotificationProxy: error %d occurred!", perr);
+ res = perr;
+ }
+ if (dict) {
char *cmd_value = NULL;
plist_t cmd_value_node = plist_dict_get_item(dict, "Command");
@@ -315,11 +292,11 @@ static int np_get_notification(np_client_t client, char **notification)
res = -2;
if (name_value_node && name_value) {
*notification = name_value;
- debug_info("got notification %s\n", __func__, name_value);
+ debug_info("got notification %s", __func__, name_value);
res = 0;
}
} else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) {
- debug_info("ERROR: NotificationProxy died!");
+ debug_info("NotificationProxy died!");
res = -1;
} else if (cmd_value) {
debug_info("unknown NotificationProxy command '%s' received!", cmd_value);
@@ -342,7 +319,7 @@ static int np_get_notification(np_client_t client, char **notification)
/**
* Internally used thread function.
*/
-gpointer np_notifier( gpointer arg )
+void* np_notifier( void* arg )
{
char *notification = NULL;
struct np_thread *npt = (struct np_thread*)arg;
@@ -351,7 +328,10 @@ gpointer np_notifier( gpointer arg )
debug_info("starting callback.");
while (npt->client->parent) {
- np_get_notification(npt->client, &notification);
+ if (np_get_notification(npt->client, &notification) < 0) {
+ npt->cbfunc("", npt->user_data);
+ break;
+ }
if (notification) {
npt->cbfunc(notification, npt->user_data);
free(notification);
@@ -366,25 +346,6 @@ gpointer np_notifier( gpointer arg )
return NULL;
}
-/**
- * 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)
@@ -394,11 +355,12 @@ np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb,
np_lock(client);
if (client->notifier) {
- debug_info("callback already set, removing\n");
+ debug_info("callback already set, removing");
property_list_service_client_t parent = client->parent;
client->parent = NULL;
- g_thread_join(client->notifier);
- client->notifier = NULL;
+ thread_join(client->notifier);
+ thread_free(client->notifier);
+ client->notifier = THREAD_T_NULL;
client->parent = parent;
}
@@ -409,8 +371,7 @@ np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb,
npt->cbfunc = notify_cb;
npt->user_data = user_data;
- client->notifier = g_thread_create(np_notifier, npt, TRUE, NULL);
- if (client->notifier) {
+ if (thread_new(&client->notifier, np_notifier, npt) == 0) {
res = NP_E_SUCCESS;
}
}