/* * dLeyna * * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * * Mark Ryan * Regis Merlino * */ #include #include #include #include #include #include #include #include #include "async.h" #include "client.h" #include "control-point-server.h" #include "device.h" #include "interface.h" #include "manager.h" #include "path.h" #include "server.h" #include "upnp.h" #ifdef UA_PREFIX #define DLS_PRG_NAME UA_PREFIX " dLeyna/" VERSION #else #define DLS_PRG_NAME "dLeyna/" VERSION #endif typedef struct dls_server_context_t_ dls_server_context_t; struct dls_server_context_t_ { dleyna_connector_id_t connection; dleyna_task_processor_t *processor; const dleyna_connector_t *connector; dleyna_settings_t *settings; guint dls_id[DLS_MANAGER_INTERFACE_INFO_MAX]; GHashTable *watchers; dls_upnp_t *upnp; dls_manager_t *manager; }; static dls_server_context_t g_context; static const gchar g_root_introspection[] = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; static const gchar g_server_introspection[] = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; static const gchar *g_manager_interfaces[DLS_MANAGER_INTERFACE_INFO_MAX] = { /* MUST be in the exact same order as g_root_introspection */ DLEYNA_SERVER_INTERFACE_MANAGER, DLS_INTERFACE_PROPERTIES }; const dleyna_connector_t *dls_server_get_connector(void) { return g_context.connector; } dleyna_task_processor_t *dls_server_get_task_processor(void) { return g_context.processor; } static void prv_process_sync_task(dls_task_t *task) { dls_client_t *client; const gchar *client_name; switch (task->type) { case DLS_TASK_GET_VERSION: task->result = g_variant_ref_sink(g_variant_new_string( VERSION)); dls_task_complete(task); break; case DLS_TASK_GET_SERVERS: task->result = dls_upnp_get_device_ids(g_context.upnp); dls_task_complete(task); break; case DLS_TASK_RESCAN: dls_upnp_rescan(g_context.upnp); dls_task_complete(task); break; case DLS_TASK_SET_PROTOCOL_INFO: client_name = dleyna_task_queue_get_source(task->atom.queue_id); client = g_hash_table_lookup(g_context.watchers, client_name); if (client) { g_free(client->protocol_info); if (task->ut.protocol_info.protocol_info[0]) { client->protocol_info = task->ut.protocol_info.protocol_info; task->ut.protocol_info.protocol_info = NULL; } else { client->protocol_info = NULL; } } dls_task_complete(task); break; case DLS_TASK_SET_PREFER_LOCAL_ADDRESSES: client_name = dleyna_task_queue_get_source(task->atom.queue_id); client = g_hash_table_lookup(g_context.watchers, client_name); if (client) { client->prefer_local_addresses = task->ut.prefer_local_addresses.prefer; } dls_task_complete(task); break; case DLS_TASK_GET_UPLOAD_STATUS: dls_upnp_get_upload_status(g_context.upnp, task); break; case DLS_TASK_GET_UPLOAD_IDS: dls_upnp_get_upload_ids(g_context.upnp, task); break; case DLS_TASK_CANCEL_UPLOAD: dls_upnp_cancel_upload(g_context.upnp, task); break; default: goto finished; break; } dleyna_task_queue_task_completed(task->atom.queue_id); finished: return; } static void prv_async_task_complete(dls_task_t *task, GError *error) { DLEYNA_LOG_DEBUG("Enter"); if (!error) { dls_task_complete(task); } else { dls_task_fail(task, error); g_error_free(error); } dleyna_task_queue_task_completed(task->atom.queue_id); DLEYNA_LOG_DEBUG("Exit"); } static void prv_process_async_task(dls_task_t *task) { dls_async_task_t *async_task = (dls_async_task_t *)task; dls_client_t *client; const gchar *client_name; DLEYNA_LOG_DEBUG("Enter"); async_task->cancellable = g_cancellable_new(); client_name = dleyna_task_queue_get_source(task->atom.queue_id); client = g_hash_table_lookup(g_context.watchers, client_name); switch (task->type) { case DLS_TASK_MANAGER_GET_PROP: dls_manager_get_prop(g_context.manager, g_context.settings, task, prv_async_task_complete); break; case DLS_TASK_MANAGER_GET_ALL_PROPS: dls_manager_get_all_props(g_context.manager, g_context.settings, task, prv_async_task_complete); break; case DLS_TASK_MANAGER_SET_PROP: dls_manager_set_prop(g_context.manager, g_context.settings, task, prv_async_task_complete); break; case DLS_TASK_GET_CHILDREN: dls_upnp_get_children(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_GET_PROP: dls_upnp_get_prop(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_GET_ALL_PROPS: dls_upnp_get_all_props(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_SEARCH: dls_upnp_search(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_BROWSE_OBJECTS: dls_upnp_browse_objects(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_GET_RESOURCE: dls_upnp_get_resource(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_UPLOAD_TO_ANY: dls_upnp_upload_to_any(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_UPLOAD: dls_upnp_upload(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_DELETE_OBJECT: dls_upnp_delete_object(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_CREATE_CONTAINER: dls_upnp_create_container(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_CREATE_CONTAINER_IN_ANY: dls_upnp_create_container_in_any(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_UPDATE_OBJECT: dls_upnp_update_object(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_GET_OBJECT_METADATA: dls_upnp_get_object_metadata(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_CREATE_REFERENCE: dls_upnp_create_reference(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_GET_ICON: dls_upnp_get_icon(g_context.upnp, client, task, prv_async_task_complete); break; case DLS_TASK_WAKE: dls_upnp_wake(g_context.upnp, client, task, prv_async_task_complete); break; default: break; } DLEYNA_LOG_DEBUG("Exit"); } static void prv_process_task(dleyna_task_atom_t *task, gpointer user_data) { dls_task_t *client_task = (dls_task_t *)task; if (client_task->synchronous) prv_process_sync_task(client_task); else prv_process_async_task(client_task); } static void prv_cancel_task(dleyna_task_atom_t *task, gpointer user_data) { dls_task_cancel((dls_task_t *)task); } static void prv_delete_task(dleyna_task_atom_t *task, gpointer user_data) { dls_task_delete((dls_task_t *)task); } static void prv_manager_root_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation); static void prv_manager_props_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation); static void prv_object_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation); static void prv_item_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation); static void prv_con_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation); static void prv_props_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation); static void prv_device_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation); static const dleyna_connector_dispatch_cb_t g_root_vtables[DLS_MANAGER_INTERFACE_INFO_MAX] = { /* MUST be in the exact same order as g_root_introspection */ prv_manager_root_method_call, prv_manager_props_method_call }; static const dleyna_connector_dispatch_cb_t g_server_vtables[DLS_INTERFACE_INFO_MAX] = { /* MUST be in the exact same order as g_server_introspection */ prv_props_method_call, prv_object_method_call, prv_con_method_call, prv_item_method_call, prv_device_method_call }; static void prv_remove_client(const gchar *name) { dleyna_task_processor_remove_queues_for_source(g_context.processor, name); (void) g_hash_table_remove(g_context.watchers, name); if (g_hash_table_size(g_context.watchers) == 0) if (!dleyna_settings_is_never_quit(g_context.settings)) dleyna_task_processor_set_quitting(g_context.processor); } static void prv_lost_client(const gchar *name) { DLEYNA_LOG_DEBUG("Lost Client %s", name); prv_remove_client(name); } static void prv_add_task(dls_task_t *task, const gchar *source, const gchar *sink) { dls_client_t *client; const dleyna_task_queue_key_t *queue_id; if (!g_hash_table_lookup(g_context.watchers, source)) { client = g_new0(dls_client_t, 1); client->prefer_local_addresses = TRUE; g_context.connector->watch_client(source); g_hash_table_insert(g_context.watchers, g_strdup(source), client); } queue_id = dleyna_task_processor_lookup_queue(g_context.processor, source, sink); if (!queue_id) queue_id = dleyna_task_processor_add_queue( g_context.processor, source, sink, DLEYNA_TASK_QUEUE_FLAG_AUTO_START, prv_process_task, prv_cancel_task, prv_delete_task); dleyna_task_queue_add_task(queue_id, &task->atom); } static void prv_manager_root_method_call( dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation) { dls_task_t *task; if (!strcmp(method, DLS_INTERFACE_RELEASE)) { prv_remove_client(sender); g_context.connector->return_response(invocation, NULL); goto finished; } else if (!strcmp(method, DLS_INTERFACE_RESCAN)) { task = dls_task_rescan_new(invocation); } else if (!strcmp(method, DLS_INTERFACE_GET_VERSION)) { task = dls_task_get_version_new(invocation); } else if (!strcmp(method, DLS_INTERFACE_GET_SERVERS)) { task = dls_task_get_servers_new(invocation); } else if (!strcmp(method, DLS_INTERFACE_SET_PROTOCOL_INFO)) { task = dls_task_set_protocol_info_new(invocation, parameters); } else if (!strcmp(method, DLS_INTERFACE_PREFER_LOCAL_ADDRESSES)) { task = dls_task_prefer_local_addresses_new(invocation, parameters); } else { goto finished; } prv_add_task(task, sender, DLS_SERVER_SINK); finished: return; } static void prv_manager_props_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation) { dls_task_t *task; GError *error = NULL; if (!strcmp(method, DLS_INTERFACE_GET_ALL)) task = dls_task_manager_get_props_new(invocation, object, parameters, &error); else if (!strcmp(method, DLS_INTERFACE_GET)) task = dls_task_manager_get_prop_new(invocation, object, parameters, &error); else if (!strcmp(method, DLS_INTERFACE_SET)) task = dls_task_manager_set_prop_new(invocation, object, parameters, &error); else goto finished; if (!task) { g_context.connector->return_error(invocation, error); g_error_free(error); goto finished; } prv_add_task(task, sender, task->target.path); finished: return; } gboolean dls_server_get_object_info(const gchar *object_path, gchar **root_path, gchar **object_id, dls_device_t **device, GError **error) { if (!dls_path_get_path_and_id(object_path, root_path, object_id, error)) { DLEYNA_LOG_WARNING("Bad object %s", object_path); goto on_error; } *device = dls_device_from_path(*root_path, dls_upnp_get_device_udn_map(g_context.upnp)); if (*device == NULL) { *device = dls_device_from_path(*root_path, dls_upnp_get_sleeping_device_udn_map( g_context.upnp)); } if (*device == NULL) { DLEYNA_LOG_WARNING("Cannot locate device for %s", *root_path); *error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_OBJECT_NOT_FOUND, "Cannot locate device corresponding to" " the specified path"); g_free(*root_path); g_free(*object_id); goto on_error; } return TRUE; on_error: return FALSE; } gboolean dls_server_is_device_sleeping(dls_device_t *dev) { if (dev->sleeping_context != NULL) return TRUE; else return dev->sleeping; } void dls_server_delete_sleeping_device(dls_device_t *dev) { if (dev->sleeping_context != NULL) dls_upnp_delete_sleeping_device(g_context.upnp, dev); } static const gchar *prv_get_device_id(const gchar *object, GError **error) { dls_device_t *device; gchar *root_path; gchar *id; if (!dls_server_get_object_info(object, &root_path, &id, &device, error)) goto on_error; g_free(id); g_free(root_path); return device->path; on_error: return NULL; } static void prv_object_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation) { dls_task_t *task; GError *error = NULL; if (!strcmp(method, DLS_INTERFACE_DELETE)) task = dls_task_delete_new(invocation, object, &error); else if (!strcmp(method, DLS_INTERFACE_UPDATE)) task = dls_task_update_new(invocation, object, parameters, &error); else if (!strcmp(method, DLS_INTERFACE_GET_METADATA)) task = dls_task_get_metadata_new(invocation, object, &error); else goto finished; if (!task) { g_context.connector->return_error(invocation, error); g_error_free(error); goto finished; } prv_add_task(task, sender, task->target.device->path); finished: return; } static void prv_item_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation) { dls_task_t *task; GError *error = NULL; if (!strcmp(method, DLS_INTERFACE_GET_COMPATIBLE_RESOURCE)) { task = dls_task_get_resource_new(invocation, object, parameters, &error); if (!task) { g_context.connector->return_error(invocation, error); g_error_free(error); goto finished; } prv_add_task(task, sender, task->target.device->path); } finished: return; } static void prv_con_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation) { dls_task_t *task; GError *error = NULL; if (!strcmp(method, DLS_INTERFACE_LIST_CHILDREN)) task = dls_task_get_children_new(invocation, object, parameters, TRUE, TRUE, &error); else if (!strcmp(method, DLS_INTERFACE_LIST_CHILDREN_EX)) task = dls_task_get_children_ex_new(invocation, object, parameters, TRUE, TRUE, &error); else if (!strcmp(method, DLS_INTERFACE_LIST_ITEMS)) task = dls_task_get_children_new(invocation, object, parameters, TRUE, FALSE, &error); else if (!strcmp(method, DLS_INTERFACE_LIST_ITEMS_EX)) task = dls_task_get_children_ex_new(invocation, object, parameters, TRUE, FALSE, &error); else if (!strcmp(method, DLS_INTERFACE_LIST_CONTAINERS)) task = dls_task_get_children_new(invocation, object, parameters, FALSE, TRUE, &error); else if (!strcmp(method, DLS_INTERFACE_LIST_CONTAINERS_EX)) task = dls_task_get_children_ex_new(invocation, object, parameters, FALSE, TRUE, &error); else if (!strcmp(method, DLS_INTERFACE_SEARCH_OBJECTS)) task = dls_task_search_new(invocation, object, parameters, &error); else if (!strcmp(method, DLS_INTERFACE_SEARCH_OBJECTS_EX)) task = dls_task_search_ex_new(invocation, object, parameters, &error); else if (!strcmp(method, DLS_INTERFACE_UPLOAD)) task = dls_task_upload_new(invocation, object, parameters, &error); else if (!strcmp(method, DLS_INTERFACE_CREATE_CONTAINER)) task = dls_task_create_container_new_generic(invocation, DLS_TASK_CREATE_CONTAINER, object, parameters, &error); else if (!strcmp(method, DLS_INTERFACE_GET_COMPATIBLE_RESOURCE)) task = dls_task_get_resource_new(invocation, object, parameters, &error); else if (!strcmp(method, DLS_INTERFACE_CREATE_REFERENCE)) task = dls_task_create_reference_new(invocation, DLS_TASK_CREATE_REFERENCE, object, parameters, &error); else goto finished; if (!task) { g_context.connector->return_error(invocation, error); g_error_free(error); goto finished; } prv_add_task(task, sender, task->target.device->path); finished: return; } static void prv_props_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation) { dls_task_t *task; GError *error = NULL; if (!strcmp(method, DLS_INTERFACE_GET_ALL)) task = dls_task_get_props_new(invocation, object, parameters, &error); else if (!strcmp(method, DLS_INTERFACE_GET)) task = dls_task_get_prop_new(invocation, object, parameters, &error); else goto finished; if (!task) { g_context.connector->return_error(invocation, error); g_error_free(error); goto finished; } prv_add_task(task, sender, task->target.device->path); finished: return; } static void prv_device_method_call(dleyna_connector_id_t conn, const gchar *sender, const gchar *object, const gchar *interface, const gchar *method, GVariant *parameters, dleyna_connector_msg_id_t invocation) { dls_task_t *task; GError *error = NULL; const gchar *device_id; const dleyna_task_queue_key_t *queue_id; if (!strcmp(method, DLS_INTERFACE_UPLOAD_TO_ANY)) { task = dls_task_upload_to_any_new(invocation, object, parameters, &error); } else if (!strcmp(method, DLS_INTERFACE_CREATE_CONTAINER_IN_ANY)) { task = dls_task_create_container_new_generic( invocation, DLS_TASK_CREATE_CONTAINER_IN_ANY, object, parameters, &error); } else if (!strcmp(method, DLS_INTERFACE_GET_UPLOAD_STATUS)) { task = dls_task_get_upload_status_new(invocation, object, parameters, &error); } else if (!strcmp(method, DLS_INTERFACE_GET_UPLOAD_IDS)) { task = dls_task_get_upload_ids_new(invocation, object, &error); } else if (!strcmp(method, DLS_INTERFACE_CANCEL_UPLOAD)) { task = dls_task_cancel_upload_new(invocation, object, parameters, &error); } else if (!strcmp(method, DLS_INTERFACE_GET_ICON)) { task = dls_task_get_icon_new(invocation, object, parameters, &error); } else if (!strcmp(method, DLS_INTERFACE_BROWSE_OBJECTS)) { task = dls_task_browse_objects_new(invocation, object, parameters, &error); } else if (!strcmp(method, DLS_INTERFACE_WAKE)) { task = dls_task_wake_new(invocation, object, &error); } else if (!strcmp(method, DLS_INTERFACE_CANCEL)) { task = NULL; device_id = prv_get_device_id(object, &error); if (!device_id) goto on_error; queue_id = dleyna_task_processor_lookup_queue( g_context.processor, sender, device_id); if (queue_id) dleyna_task_processor_cancel_queue(queue_id); g_context.connector->return_response(invocation, NULL); goto finished; } else { goto finished; } on_error: if (!task) { g_context.connector->return_error(invocation, error); g_error_free(error); goto finished; } prv_add_task(task, sender, task->target.device->path); finished: return; } static void prv_found_media_server(const gchar *path, void *user_data) { (void) g_context.connector->notify(g_context.connection, DLEYNA_SERVER_OBJECT, DLEYNA_SERVER_INTERFACE_MANAGER, DLS_INTERFACE_FOUND_SERVER, g_variant_new("(o)", path), NULL); } static void prv_lost_media_server(const gchar *path, void *user_data) { (void) g_context.connector->notify(g_context.connection, DLEYNA_SERVER_OBJECT, DLEYNA_SERVER_INTERFACE_MANAGER, DLS_INTERFACE_LOST_SERVER, g_variant_new("(o)", path), NULL); dleyna_task_processor_remove_queues_for_sink(g_context.processor, path); } static void prv_unregister_client(gpointer user_data) { dls_client_t *client = user_data; if (client) { g_free(client->protocol_info); g_free(client); } } dls_upnp_t *dls_server_get_upnp(void) { return g_context.upnp; } static void prv_white_list_init(void) { gboolean enabled; GVariant *entries; dleyna_white_list_t *wl; DLEYNA_LOG_DEBUG("Enter"); enabled = dleyna_settings_is_white_list_enabled(g_context.settings); entries = dleyna_settings_white_list_entries(g_context.settings); wl = dls_manager_get_white_list(g_context.manager); dleyna_white_list_enable(wl, enabled); dleyna_white_list_add_entries(wl, entries); DLEYNA_LOG_DEBUG("Exit"); } static gboolean prv_control_point_start_service( dleyna_connector_id_t connection) { gboolean retval = TRUE; uint i; g_context.connection = connection; for (i = 0; i < DLS_MANAGER_INTERFACE_INFO_MAX; i++) g_context.dls_id[i] = g_context.connector->publish_object( connection, DLEYNA_SERVER_OBJECT, TRUE, g_manager_interfaces[i], g_root_vtables + i); if (g_context.dls_id[DLS_MANAGER_INTERFACE_MANAGER]) { g_context.upnp = dls_upnp_new(connection, dleyna_settings_port(g_context.settings), g_server_vtables, prv_found_media_server, prv_lost_media_server, NULL); g_context.manager = dls_manager_new(connection, dls_upnp_get_context_manager( g_context.upnp)); prv_white_list_init(); } else { retval = FALSE; } return retval; } static void prv_control_point_stop_service(void) { uint i; if (g_context.manager) { dls_manager_delete(g_context.manager); g_context.manager = NULL; } if (g_context.upnp) { dls_upnp_unsubscribe(g_context.upnp); dls_upnp_delete(g_context.upnp); g_context.upnp = NULL; } if (g_context.connection) { for (i = 0; i < DLS_MANAGER_INTERFACE_INFO_MAX; i++) if (g_context.dls_id[i]) g_context.connector->unpublish_object( g_context.connection, g_context.dls_id[i]); } } static void prv_control_point_initialize(const dleyna_connector_t *connector, dleyna_task_processor_t *processor, dleyna_settings_t *settings) { memset(&g_context, 0, sizeof(g_context)); g_context.connector = connector; g_context.processor = processor; g_context.settings = settings; g_context.connector->set_client_lost_cb(prv_lost_client); g_context.watchers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, prv_unregister_client); g_set_prgname(DLS_PRG_NAME); } static void prv_control_point_free(void) { if (g_context.watchers) g_hash_table_unref(g_context.watchers); } static const gchar *prv_control_point_server_name(void) { return DLEYNA_SERVER_NAME; } static const gchar *prv_control_point_server_introspection(void) { return g_server_introspection; } static const gchar *prv_control_point_root_introspection(void) { return g_root_introspection; } static const gchar *prv_control_point_get_version(void) { return VERSION; } static const dleyna_control_point_t g_control_point = { prv_control_point_initialize, prv_control_point_free, prv_control_point_server_name, prv_control_point_server_introspection, prv_control_point_root_introspection, prv_control_point_start_service, prv_control_point_stop_service, prv_control_point_get_version }; const dleyna_control_point_t *dleyna_control_point_get_server(void) { return &g_control_point; }