1 /*
2 * Copyright (C) 2007 Zeeshan Ali.
3 * Copyright (C) 2007 OpenedHand Ltd.
4 *
5 * Author: Zeeshan Ali <zeenix@gstreamer.net>
6 * Author: Jorn Baayen <jorn@openedhand.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23 #include <libgupnp/gupnp-root-device.h>
24 #include <libgupnp/gupnp-service.h>
25 #include <stdio.h>
26 #include <locale.h>
27 #include <string.h>
28 #include <gmodule.h>
29 #include <glib/gstdio.h>
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include "gui.h"
36 #include "upnp.h"
37 #include "main.h"
38
39 #define DESCRIPTION_DOC "xml/network-light-desc.xml"
40 #define DIMMING_SERVICE "urn:schemas-upnp-org:service:Dimming:1"
41 #define SWITCH_SERVICE "urn:schemas-upnp-org:service:SwitchPower:1"
42 #define NETWORK_LIGHT "urn:schemas-upnp-org:device:DimmableLight:1"
43
44 typedef struct
45 {
46 GUPnPRootDevice *dev;
47 GUPnPServiceInfo *switch_power;
48 GUPnPServiceInfo *dimming;
49 } NetworkLight;
50
51 static GUPnPContextManager *context_manager;
52 static GHashTable *nl_hash;
53
54 /* Other network light services on the network */
55 static GList *switch_proxies;
56 static GList *dimming_proxies;
57
58 static GUPnPXMLDoc *doc;
59 static char *desc_location;
60 static char *uuid;
61
62 void
63 on_get_status (GUPnPService *service,
64 GUPnPServiceAction *action,
65 gpointer user_data);
66
67 void
68 on_get_target (GUPnPService *service,
69 GUPnPServiceAction *action,
70 gpointer user_data);
71
72 void
73 on_set_target (GUPnPService *service,
74 GUPnPServiceAction *action,
75 gpointer user_data);
76
77 void
78 on_query_status (GUPnPService *service,
79 const char *variable_name,
80 GValue *value,
81 gpointer user_data);
82
83 void
84 on_query_target (GUPnPService *service,
85 const char *variable_name,
86 GValue *value,
87 gpointer user_data);
88
89 void
90 on_get_load_level_status (GUPnPService *service,
91 GUPnPServiceAction *action,
92 gpointer user_data);
93
94 void
95 on_get_load_level_target (GUPnPService *service,
96 GUPnPServiceAction *action,
97 gpointer user_data);
98
99 void
100 on_set_load_level_target (GUPnPService *service,
101 GUPnPServiceAction *action,
102 gpointer user_data);
103
104 void
105 on_query_load_level_status (GUPnPService *service,
106 const char *variable_name,
107 GValue *value,
108 gpointer user_data);
109
110 void
111 on_query_load_level_target (GUPnPService *service,
112 const char *variable_name,
113 GValue *value,
114 gpointer user_data);
115
116 static NetworkLight *
network_light_new(GUPnPRootDevice * dev,GUPnPServiceInfo * switch_power,GUPnPServiceInfo * dimming)117 network_light_new (GUPnPRootDevice *dev,
118 GUPnPServiceInfo *switch_power,
119 GUPnPServiceInfo *dimming)
120 {
121 NetworkLight *network_light;
122
123 network_light = g_slice_new (NetworkLight);
124
125 network_light->dev = dev;
126 network_light->switch_power = switch_power;
127 network_light->dimming = dimming;
128
129 return network_light;
130 }
131
132 static void
network_light_free(NetworkLight * network_light)133 network_light_free (NetworkLight *network_light)
134 {
135 g_object_unref (network_light->dev);
136 g_object_unref (network_light->switch_power);
137 g_object_unref (network_light->dimming);
138
139 g_slice_free (NetworkLight, network_light);
140 }
141
142 void
notify_status_change(gboolean status)143 notify_status_change (gboolean status)
144 {
145 GList *network_lights;
146 GList *nl_node;
147
148 network_lights = g_hash_table_get_values (nl_hash);
149
150 for (nl_node = network_lights;
151 nl_node != NULL;
152 nl_node = nl_node->next) {
153 NetworkLight *nl = (NetworkLight *) nl_node->data;
154
155 gupnp_service_notify (GUPNP_SERVICE (nl->switch_power),
156 "Status",
157 G_TYPE_BOOLEAN,
158 status,
159 NULL);
160 }
161
162 g_list_free (network_lights);
163 }
164
165 void
notify_load_level_change(gint load_level)166 notify_load_level_change (gint load_level)
167 {
168 GList *network_lights;
169 GList *nl_node;
170
171 network_lights = g_hash_table_get_values (nl_hash);
172
173 for (nl_node = network_lights;
174 nl_node != NULL;
175 nl_node = nl_node->next) {
176 NetworkLight *nl = (NetworkLight *) nl_node->data;
177
178 gupnp_service_notify (GUPNP_SERVICE (nl->dimming),
179 "LoadLevelStatus",
180 G_TYPE_UINT,
181 load_level,
182 NULL);
183 }
184
185 g_list_free (network_lights);
186 }
187
188 G_MODULE_EXPORT
189 void
on_get_status(GUPnPService * service,GUPnPServiceAction * action,gpointer user_data)190 on_get_status (GUPnPService *service,
191 GUPnPServiceAction *action,
192 gpointer user_data)
193 {
194 gupnp_service_action_set (action,
195 "ResultStatus",
196 G_TYPE_BOOLEAN,
197 get_status (),
198 NULL);
199
200 gupnp_service_action_return (action);
201 }
202
203 G_MODULE_EXPORT
204 void
on_get_target(GUPnPService * service,GUPnPServiceAction * action,gpointer user_data)205 on_get_target (GUPnPService *service,
206 GUPnPServiceAction *action,
207 gpointer user_data)
208 {
209 gupnp_service_action_set (action,
210 "RetTargetValue",
211 G_TYPE_BOOLEAN,
212 get_status (),
213 NULL);
214
215 gupnp_service_action_return (action);
216 }
217
218 G_MODULE_EXPORT
219 void
on_set_target(GUPnPService * service,GUPnPServiceAction * action,gpointer user_data)220 on_set_target (GUPnPService *service,
221 GUPnPServiceAction *action,
222 gpointer user_data)
223 {
224 gboolean status;
225
226 gupnp_service_action_get (action,
227 "newTargetValue",
228 G_TYPE_BOOLEAN,
229 &status,
230 NULL);
231 gupnp_service_action_return (action);
232
233 set_status (status);
234 }
235
236 G_MODULE_EXPORT
237 void
on_query_status(GUPnPService * service,const char * variable_name,GValue * value,gpointer user_data)238 on_query_status (GUPnPService *service,
239 const char *variable_name,
240 GValue *value,
241 gpointer user_data)
242 {
243 g_value_init (value, G_TYPE_BOOLEAN);
244 g_value_set_boolean (value, get_status ());
245 }
246
247 G_MODULE_EXPORT
248 void
on_query_target(GUPnPService * service,const char * variable_name,GValue * value,gpointer user_data)249 on_query_target (GUPnPService *service,
250 const char *variable_name,
251 GValue *value,
252 gpointer user_data)
253 {
254 g_value_init (value, G_TYPE_BOOLEAN);
255 g_value_set_boolean (value, get_status ());
256 }
257
258 G_MODULE_EXPORT
259 void
on_get_load_level_status(GUPnPService * service,GUPnPServiceAction * action,gpointer user_data)260 on_get_load_level_status (GUPnPService *service,
261 GUPnPServiceAction *action,
262 gpointer user_data)
263 {
264 gupnp_service_action_set (action,
265 "retLoadlevelStatus",
266 G_TYPE_UINT,
267 get_load_level (),
268 NULL);
269
270 gupnp_service_action_return (action);
271 }
272
273 G_MODULE_EXPORT
274 void
on_get_load_level_target(GUPnPService * service,GUPnPServiceAction * action,gpointer user_data)275 on_get_load_level_target (GUPnPService *service,
276 GUPnPServiceAction *action,
277 gpointer user_data)
278 {
279 gupnp_service_action_set (action,
280 "retLoadlevelTarget",
281 G_TYPE_UINT,
282 get_load_level (),
283 NULL);
284
285 gupnp_service_action_return (action);
286 }
287
288 G_MODULE_EXPORT
289 void
on_set_load_level_target(GUPnPService * service,GUPnPServiceAction * action,gpointer user_data)290 on_set_load_level_target (GUPnPService *service,
291 GUPnPServiceAction *action,
292 gpointer user_data)
293 {
294 guint load_level;
295
296 gupnp_service_action_get (action,
297 "newLoadlevelTarget",
298 G_TYPE_UINT,
299 &load_level,
300 NULL);
301 gupnp_service_action_return (action);
302
303 if (load_level > 100)
304 load_level = 100;
305
306 set_load_level (load_level);
307 }
308
309 G_MODULE_EXPORT
310 void
on_query_load_level_status(GUPnPService * service,const char * variable_name,GValue * value,gpointer user_data)311 on_query_load_level_status (GUPnPService *service,
312 const char *variable_name,
313 GValue *value,
314 gpointer user_data)
315 {
316 g_value_init (value, G_TYPE_UINT);
317 g_value_set_uint (value, get_load_level ());
318 }
319
320 G_MODULE_EXPORT
321 void
on_query_load_level_target(GUPnPService * service,const char * variable_name,GValue * value,gpointer user_data)322 on_query_load_level_target (GUPnPService *service,
323 const char *variable_name,
324 GValue *value,
325 gpointer user_data)
326 {
327 g_value_init (value, G_TYPE_UINT);
328 g_value_set_uint (value, get_load_level ());
329 }
330
331 static void
on_notify_failed(GUPnPService * service,const GList * callback_urls,const GError * reason,gpointer user_data)332 on_notify_failed (GUPnPService *service,
333 const GList *callback_urls,
334 const GError *reason,
335 gpointer user_data)
336 {
337 GList *url_node;
338 GString *warning;
339
340 warning = g_string_new (NULL);
341 g_string_printf (warning,
342 "NOTIFY failed for the following client URLs:\n");
343 for (url_node = (GList *) callback_urls;
344 url_node;
345 url_node = url_node->next) {
346 g_string_append_printf (warning,
347 "%s\n",
348 (char *) url_node->data);
349 }
350 g_string_append_printf (warning, "Reason: %s", reason->message);
351
352 g_warning ("%s", warning->str);
353 g_string_free (warning, TRUE);
354 }
355
356 /* Copied from gupnp/libgupnp/xml-utils.c */
357 static xmlNode *
xml_util_get_element(xmlNode * node,...)358 xml_util_get_element (xmlNode *node,
359 ...)
360 {
361 va_list var_args;
362
363 va_start (var_args, node);
364
365 while (TRUE) {
366 const char *arg;
367
368 arg = va_arg (var_args, const char *);
369 if (!arg)
370 break;
371
372 for (node = node->children; node; node = node->next) {
373 if (node->name == NULL)
374 continue;
375
376 if (!strcmp (arg, (char *) node->name))
377 break;
378 }
379
380 if (!node)
381 break;
382 }
383
384 va_end (var_args);
385
386 return node;
387 }
388
init_friendly_name(gchar * name)389 static void init_friendly_name (gchar *name)
390 {
391 xmlNode *fdn_node;
392
393 fdn_node = xml_util_get_element ((xmlNode *)
394 gupnp_xml_doc_get_doc (doc),
395 "root",
396 "device",
397 "friendlyName",
398 NULL);
399 if (fdn_node == NULL) {
400 g_warning ("Failed to find friendly name element"
401 "in device description, "
402 "using default value");
403
404 return;
405 }
406
407 xmlNodeSetContent (fdn_node, (unsigned char *) name);
408 }
409
init_uuid(void)410 static void init_uuid (void)
411 {
412 xmlNode *uuid_node;
413 char *udn;
414
415 uuid = gupnp_get_uuid ();
416 const xmlDoc *xml_doc = gupnp_xml_doc_get_doc (doc);
417
418 uuid_node = xml_util_get_element ((xmlNode *) xml_doc,
419 "root",
420 "device",
421 "UDN",
422 NULL);
423 if (uuid_node == NULL) {
424 g_critical ("Failed to find UDN element"
425 "in device description");
426
427 return;
428 }
429
430 udn = g_strdup_printf ("uuid:%s", uuid);
431
432 xmlNodeSetContent (uuid_node, (unsigned char *) udn);
433
434 g_free (udn);
435 }
436
437 static void
on_service_proxy_action_ret(GObject * object,GAsyncResult * result,gpointer user_data)438 on_service_proxy_action_ret (GObject *object,
439 GAsyncResult *result,
440 gpointer user_data)
441 {
442 GError *error = NULL;
443
444 gupnp_service_proxy_call_action_finish (GUPNP_SERVICE_PROXY (object),
445 result,
446 &error);
447
448 if (error != NULL) {
449 GUPnPServiceInfo *info = GUPNP_SERVICE_INFO (object);
450
451 g_warning ("Failed to call action \"%s\" on \"%s\": %s",
452 (char *) user_data,
453 gupnp_service_info_get_location (info),
454 error->message);
455
456 g_error_free (error);
457 }
458
459 g_free (user_data);
460 }
461
462 void
set_all_status(gboolean status)463 set_all_status (gboolean status)
464 {
465 GList *proxy_node;
466
467 for (proxy_node = switch_proxies;
468 proxy_node;
469 proxy_node = g_list_next (proxy_node)) {
470 GUPnPServiceProxy *proxy;
471 char *action_name;
472 GUPnPServiceProxyAction *action;
473
474 proxy = GUPNP_SERVICE_PROXY (proxy_node->data);
475 action_name = g_strdup ("SetTarget");
476
477 action = gupnp_service_proxy_action_new (action_name,
478 "newTargetValue",
479 G_TYPE_BOOLEAN,
480 status,
481 NULL);
482
483 gupnp_service_proxy_call_action_async (
484 proxy,
485 action,
486 NULL,
487 on_service_proxy_action_ret,
488 action_name);
489 gupnp_service_proxy_action_unref (action);
490 }
491 }
492
493 void
set_all_load_level(gint load_level)494 set_all_load_level (gint load_level)
495 {
496 GList *proxy_node;
497
498 for (proxy_node = dimming_proxies;
499 proxy_node;
500 proxy_node = g_list_next (proxy_node)) {
501 GUPnPServiceProxy *proxy;
502 char *action_name;
503 GUPnPServiceProxyAction *action;
504
505 proxy = GUPNP_SERVICE_PROXY (proxy_node->data);
506 action_name = g_strdup ("SetLoadLevelTarget");
507
508 action = gupnp_service_proxy_action_new (action_name,
509 "newLoadlevelTarget",
510 G_TYPE_UINT,
511 load_level,
512 NULL);
513
514 gupnp_service_proxy_call_action_async (
515 proxy,
516 action,
517 NULL,
518 on_service_proxy_action_ret,
519 action_name);
520
521 gupnp_service_proxy_action_unref (action);
522 }
523 }
524
525 static void
on_network_light_available(GUPnPControlPoint * cp,GUPnPDeviceProxy * light_proxy,gpointer user_data)526 on_network_light_available (GUPnPControlPoint *cp,
527 GUPnPDeviceProxy *light_proxy,
528 gpointer user_data)
529 {
530 GUPnPServiceProxy *switch_proxy;
531 GUPnPServiceProxy *dimming_proxy;
532 GUPnPServiceInfo *info;
533
534 info = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (light_proxy),
535 SWITCH_SERVICE);
536 switch_proxy = GUPNP_SERVICE_PROXY (info);
537
538 if (switch_proxy) {
539 switch_proxies = g_list_append (switch_proxies, switch_proxy);
540 }
541
542 info = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (light_proxy),
543 DIMMING_SERVICE);
544 dimming_proxy = GUPNP_SERVICE_PROXY (info);
545
546 if (dimming_proxy) {
547 dimming_proxies = g_list_append (dimming_proxies,
548 dimming_proxy);
549 }
550 }
551
compare_service(GUPnPServiceInfo * info1,GUPnPServiceInfo * info2)552 static gint compare_service (GUPnPServiceInfo *info1,
553 GUPnPServiceInfo *info2)
554 {
555 const char *udn1;
556 const char *udn2;
557
558 udn1 = gupnp_service_info_get_udn (info1);
559 udn2 = gupnp_service_info_get_udn (info2);
560
561 return strcmp (udn1, udn2);
562 }
563
remove_service_from_list(GUPnPServiceInfo * info,GList ** list)564 static void remove_service_from_list (GUPnPServiceInfo *info,
565 GList **list)
566 {
567 GList *proxy_node;
568
569 proxy_node = g_list_find_custom (*list,
570 info,
571 (GCompareFunc) compare_service);
572 if (proxy_node) {
573 g_object_unref (proxy_node->data);
574 *list = g_list_remove (*list, proxy_node->data);
575 }
576 }
577
578 static void
on_network_light_unavailable(GUPnPControlPoint * control_point,GUPnPDeviceProxy * light_proxy,gpointer user_data)579 on_network_light_unavailable (GUPnPControlPoint *control_point,
580 GUPnPDeviceProxy *light_proxy,
581 gpointer user_data)
582 {
583 GUPnPServiceInfo *info;
584
585 info = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (light_proxy),
586 SWITCH_SERVICE);
587 if (info) {
588 remove_service_from_list (info, &switch_proxies);
589 }
590
591 g_clear_object (&info);
592
593 info = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (light_proxy),
594 DIMMING_SERVICE);
595 if (info) {
596 remove_service_from_list (info, &dimming_proxies);
597 }
598
599 g_clear_object (&info);
600 }
601
602 static gboolean
init_server(GUPnPContext * context)603 init_server (GUPnPContext *context)
604 {
605 NetworkLight *network_light;
606 GUPnPRootDevice *dev;
607 GUPnPServiceInfo *switch_power;
608 GUPnPServiceInfo *dimming;
609 GError *error = NULL;
610
611 /* Create root device */
612 dev = gupnp_root_device_new_full (context,
613 gupnp_resource_factory_get_default (),
614 doc,
615 desc_location,
616 DATA_DIR,
617 &error);
618 if (error != NULL) {
619 g_warning ("Failed to create root device: %s",
620 error->message);
621 g_error_free (error);
622
623 return FALSE;
624 }
625
626 switch_power = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (dev),
627 SWITCH_SERVICE);
628
629 if (switch_power) {
630 gupnp_service_signals_autoconnect
631 (GUPNP_SERVICE (switch_power),
632 NULL,
633 &error);
634
635 g_signal_connect (switch_power,
636 "notify-failed",
637 G_CALLBACK (on_notify_failed),
638 NULL);
639 }
640
641 dimming = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (dev),
642 DIMMING_SERVICE);
643
644 if (dimming) {
645 gupnp_service_signals_autoconnect (GUPNP_SERVICE (dimming),
646 NULL,
647 &error);
648
649 g_signal_connect (dimming,
650 "notify-failed",
651 G_CALLBACK (on_notify_failed),
652 NULL);
653 }
654
655 network_light = network_light_new (dev, switch_power, dimming);
656 g_hash_table_insert (nl_hash, g_object_ref (context), network_light);
657
658 /* Run */
659 gupnp_root_device_set_available (dev, TRUE);
660
661 g_print ("Attaching to IP/Host %s on port %d\n",
662 gssdp_client_get_host_ip (GSSDP_CLIENT (context)),
663 gupnp_context_get_port (context));
664
665 return TRUE;
666 }
667
668 static gboolean
prepare_desc(gchar * name)669 prepare_desc (gchar *name)
670 {
671 GError *error = NULL;
672
673 doc = gupnp_xml_doc_new_from_path (DATA_DIR "/" DESCRIPTION_DOC,
674 &error);
675 if (doc == NULL) {
676 g_critical ("Unable to load the XML description file: %s",
677 error->message);
678
679 g_error_free (error);
680
681 return FALSE;
682 }
683
684 if (name && (strlen(name) > 0)) {
685 /* set the friendlyName in the xmlDoc */
686 init_friendly_name (name);
687 }
688
689 /* create and set the UUID in the xmlDoc */
690 init_uuid ();
691
692 /* saving the xml file to the temporal location with the uuid name */
693 desc_location = g_strdup_printf ("%s/gupnp-network-light-%s.xml",
694 g_get_tmp_dir (),
695 uuid);
696 g_assert (desc_location != NULL);
697
698 if (xmlSaveFile (desc_location, (xmlDoc *) gupnp_xml_doc_get_doc (doc)) < 0) {
699 g_print ("Error saving description file to %s.\n",
700 desc_location);
701
702 g_free (desc_location);
703 g_object_unref (doc);
704
705 return FALSE;
706 }
707
708 return TRUE;
709 }
710
711 static gboolean
init_client(GUPnPContext * context)712 init_client (GUPnPContext *context)
713 {
714 GUPnPControlPoint *cp;
715
716 cp = gupnp_control_point_new (context, NETWORK_LIGHT);
717
718 g_signal_connect (cp,
719 "device-proxy-available",
720 G_CALLBACK (on_network_light_available),
721 NULL);
722 g_signal_connect (cp,
723 "device-proxy-unavailable",
724 G_CALLBACK (on_network_light_unavailable),
725 NULL);
726
727 gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);
728
729 /* Let context manager take care of the control point life cycle */
730 gupnp_context_manager_manage_control_point (context_manager, cp);
731
732 /* We don't need to keep our own references to the control points */
733 g_object_unref (cp);
734
735 return TRUE;
736 }
737
738 static void
on_context_available(GUPnPContextManager * manager,GUPnPContext * context,gpointer user_data)739 on_context_available (GUPnPContextManager *manager,
740 GUPnPContext *context,
741 gpointer user_data)
742 {
743 /* Initialize client-side stuff */
744 init_client (context);
745
746 /* Then the server-side stuff */
747 init_server (context);
748 }
749
750 static void
on_context_unavailable(GUPnPContextManager * manager,GUPnPContext * context,gpointer user_data)751 on_context_unavailable (GUPnPContextManager *manager,
752 GUPnPContext *context,
753 gpointer user_data)
754 {
755 g_print ("Detaching from IP/Host %s and port %d\n",
756 gssdp_client_get_host_ip (GSSDP_CLIENT (context)),
757 gupnp_context_get_port (context));
758
759 g_hash_table_remove (nl_hash, context);
760 }
761
762 static gboolean
context_equal(GUPnPContext * context1,GUPnPContext * context2)763 context_equal (GUPnPContext *context1, GUPnPContext *context2)
764 {
765 return g_ascii_strcasecmp (gssdp_client_get_host_ip (GSSDP_CLIENT (context1)),
766 gssdp_client_get_host_ip (GSSDP_CLIENT (context2))) == 0;
767 }
768
769 gboolean
init_upnp(gchar ** interfaces,guint port,gchar * name,gboolean ipv4,gboolean ipv6)770 init_upnp (gchar **interfaces, guint port, gchar *name, gboolean ipv4, gboolean ipv6)
771 {
772 GUPnPWhiteList *white_list;
773
774 switch_proxies = NULL;
775 dimming_proxies = NULL;
776
777 nl_hash = g_hash_table_new_full (g_direct_hash,
778 (GEqualFunc) context_equal,
779 g_object_unref,
780 (GDestroyNotify) network_light_free);
781
782 if (!prepare_desc (name)) {
783 return FALSE;
784 }
785
786 // Default: Both
787 GSocketFamily family = G_SOCKET_FAMILY_INVALID;
788 if (!ipv4 && ipv6) {
789 g_debug ("Option a");
790 family = G_SOCKET_FAMILY_IPV6;
791 } else if (ipv4 && !ipv6) {
792 g_debug ("Option b");
793 family = G_SOCKET_FAMILY_IPV4;
794 } else {
795 g_debug ("Option c");
796 // Neither? Just do nothing and enable both
797 }
798
799 context_manager = gupnp_context_manager_create_full (GSSDP_UDA_VERSION_1_0,
800 family,
801 port);
802 g_assert (context_manager != NULL);
803
804 if (interfaces != NULL) {
805 white_list = gupnp_context_manager_get_white_list
806 (context_manager);
807 gupnp_white_list_add_entryv (white_list, interfaces);
808 gupnp_white_list_set_enabled (white_list, TRUE);
809 }
810
811 g_signal_connect (context_manager,
812 "context-available",
813 G_CALLBACK (on_context_available),
814 NULL);
815 g_signal_connect (context_manager,
816 "context-unavailable",
817 G_CALLBACK (on_context_unavailable),
818 NULL);
819
820 return TRUE;
821 }
822
823 void
deinit_upnp(void)824 deinit_upnp (void)
825 {
826 g_object_unref (context_manager);
827
828 g_hash_table_unref (nl_hash);
829
830 g_list_foreach (switch_proxies, (GFunc) g_object_unref, NULL);
831 g_list_foreach (dimming_proxies, (GFunc) g_object_unref, NULL);
832
833 /* Unref the descriptiont doc */
834 g_object_unref (doc);
835
836 if (g_remove (desc_location) != 0)
837 g_warning ("error removing %s\n", desc_location);
838 g_free (desc_location);
839 g_free (uuid);
840 uuid = NULL;
841 }
842
843