~ubuntu-branches/ubuntu/utopic/gssdp/utopic-proposed

« back to all changes in this revision

Viewing changes to libgssdp/gssdp-resource-group.c

  • Committer: Bazaar Package Importer
  • Author(s): Ross Burton
  • Date: 2009-02-20 12:00:22 UTC
  • mto: (1.1.5 upstream) (2.2.1 sid)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20090220120022-lfgejr3cz3gvd02c
Tags: upstream-0.6.4
ImportĀ upstreamĀ versionĀ 0.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
55
55
 
56
56
        gulong       message_received_id;
57
57
 
58
 
        guint        timeout_id;
 
58
        GSource     *timeout_src;
59
59
 
60
60
        guint        last_resource_id;
 
61
        
 
62
        guint        message_delay;
 
63
        GQueue      *message_queue;
 
64
        guint        message_src_id;
61
65
};
62
66
 
63
67
enum {
64
68
        PROP_0,
65
69
        PROP_CLIENT,
66
70
        PROP_MAX_AGE,
67
 
        PROP_AVAILABLE
 
71
        PROP_AVAILABLE,
 
72
        PROP_MESSAGE_DELAY
68
73
};
69
74
 
70
75
typedef struct {
77
82
        GList               *responses;
78
83
 
79
84
        guint                id;
 
85
 
 
86
        gboolean             initial_alive_sent;
80
87
} Resource;
81
88
 
82
89
typedef struct {
85
92
        char     *target;
86
93
        Resource *resource;
87
94
 
88
 
        guint     timeout_id;
 
95
        GSource  *timeout_src;
89
96
} DiscoveryResponse;
90
97
 
 
98
#define DEFAULT_MESSAGE_DELAY 20 
 
99
 
91
100
/* Function prototypes */
92
101
static void
93
102
gssdp_resource_group_set_client (GSSDPResourceGroup *resource_group,
111
120
discovery_response_timeout      (gpointer            user_data);
112
121
static void
113
122
discovery_response_free         (DiscoveryResponse  *response);
 
123
static gboolean
 
124
process_queue                   (gpointer            data);
114
125
 
115
126
static void
116
127
gssdp_resource_group_init (GSSDPResourceGroup *resource_group)
121
132
                                         GSSDPResourceGroupPrivate);
122
133
 
123
134
        resource_group->priv->max_age = SSDP_DEFAULT_MAX_AGE;
 
135
        resource_group->priv->message_delay = DEFAULT_MESSAGE_DELAY;
 
136
 
 
137
        resource_group->priv->message_queue = g_queue_new ();
124
138
}
125
139
 
126
140
static void
149
163
                        (value,
150
164
                         gssdp_resource_group_get_available (resource_group));
151
165
                break;
 
166
        case PROP_MESSAGE_DELAY:
 
167
                g_value_set_uint
 
168
                        (value,
 
169
                         gssdp_resource_group_get_message_delay 
 
170
                                (resource_group));
 
171
                break;
152
172
        default:
153
173
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
154
174
                break;
178
198
                gssdp_resource_group_set_available
179
199
                        (resource_group, g_value_get_boolean (value));
180
200
                break;
 
201
        case PROP_MESSAGE_DELAY:
 
202
                gssdp_resource_group_set_message_delay
 
203
                        (resource_group, g_value_get_uint (value));
 
204
                break;
181
205
        default:
182
206
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
183
207
                break;
188
212
gssdp_resource_group_dispose (GObject *object)
189
213
{
190
214
        GSSDPResourceGroup *resource_group;
 
215
        GSSDPResourceGroupPrivate *priv;
191
216
 
192
217
        resource_group = GSSDP_RESOURCE_GROUP (object);
193
 
 
194
 
        while (resource_group->priv->resources) {
195
 
                resource_free (resource_group->priv->resources->data);
196
 
                resource_group->priv->resources =
197
 
                        g_list_delete_link (resource_group->priv->resources,
198
 
                                            resource_group->priv->resources);
199
 
        }
200
 
 
201
 
        if (resource_group->priv->timeout_id > 0) {
202
 
                g_source_remove (resource_group->priv->timeout_id);
203
 
                resource_group->priv->timeout_id = 0;
204
 
        }
205
 
 
206
 
        if (resource_group->priv->client) {
 
218
        priv = resource_group->priv;
 
219
 
 
220
        while (priv->resources) {
 
221
                resource_free (priv->resources->data);
 
222
                priv->resources =
 
223
                        g_list_delete_link (priv->resources,
 
224
                                            priv->resources);
 
225
        }
 
226
 
 
227
        if (priv->message_queue) {
 
228
                /* send messages without usual delay */
 
229
                while (!g_queue_is_empty (priv->message_queue)) {
 
230
                        if (priv->available)
 
231
                                process_queue (resource_group);
 
232
                        else
 
233
                                g_free (g_queue_pop_head
 
234
                                        (priv->message_queue));
 
235
                }
 
236
 
 
237
                g_queue_free (priv->message_queue);
 
238
                priv->message_queue = NULL;
 
239
        }
 
240
 
 
241
        if (priv->message_src_id > 0) {
 
242
                g_source_remove (priv->message_src_id);
 
243
                priv->message_src_id = 0;
 
244
        }
 
245
 
 
246
        if (priv->timeout_src) {
 
247
                g_source_destroy (priv->timeout_src);
 
248
                priv->timeout_src = NULL;
 
249
        }
 
250
 
 
251
        if (priv->client) {
207
252
                if (g_signal_handler_is_connected
208
 
                        (resource_group->priv->client,
209
 
                         resource_group->priv->message_received_id)) {
 
253
                        (priv->client,
 
254
                         priv->message_received_id)) {
210
255
                        g_signal_handler_disconnect
211
 
                                (resource_group->priv->client,
212
 
                                 resource_group->priv->message_received_id);
 
256
                                (priv->client,
 
257
                                 priv->message_received_id);
213
258
                }
214
259
                                                   
215
 
                g_object_unref (resource_group->priv->client);
216
 
                resource_group->priv->client = NULL;
 
260
                g_object_unref (priv->client);
 
261
                priv->client = NULL;
217
262
        }
218
263
}
219
264
 
283
328
                          G_PARAM_READWRITE |
284
329
                          G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
285
330
                          G_PARAM_STATIC_BLURB));
 
331
 
 
332
        /**
 
333
         * GSSDPResourceGroup:message-delay
 
334
         *
 
335
         * The minimum number of milliseconds between SSDP messages.
 
336
         * The default is 20 based on DLNA specification.
 
337
         **/
 
338
        g_object_class_install_property
 
339
                (object_class,
 
340
                 PROP_MESSAGE_DELAY,
 
341
                 g_param_spec_uint
 
342
                         ("message-delay",
 
343
                          "Message delay",
 
344
                          "The minimum number of milliseconds between SSDP "
 
345
                          "messages.",
 
346
                          0,
 
347
                          G_MAXUINT,
 
348
                          DEFAULT_MESSAGE_DELAY,
 
349
                          G_PARAM_READWRITE |
 
350
                          G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
 
351
                          G_PARAM_STATIC_BLURB));
286
352
}
287
353
 
288
354
/**
338
404
/**
339
405
 * gssdp_resource_group_set_max_age
340
406
 * @resource_group: A #GSSDPResourceGroup
341
 
 * @mx: The number of seconds advertisements are valid
 
407
 * @max_age: The number of seconds advertisements are valid
342
408
 *
343
409
 * Sets the number of seconds advertisements are valid to @max_age.
344
410
 **/
371
437
}
372
438
 
373
439
/**
 
440
 * gssdp_resource_group_set_message_delay
 
441
 * @resource_group: A #GSSDPResourceGroup
 
442
 * @message_delay: The message delay in ms.
 
443
 *
 
444
 * Sets the minimum time between each SSDP message.
 
445
 **/
 
446
void
 
447
gssdp_resource_group_set_message_delay (GSSDPResourceGroup *resource_group,
 
448
                                        guint               message_delay)
 
449
{
 
450
        g_return_if_fail (GSSDP_IS_RESOURCE_GROUP (resource_group));
 
451
 
 
452
        if (resource_group->priv->message_delay == message_delay)
 
453
                return;
 
454
 
 
455
        resource_group->priv->message_delay = message_delay;
 
456
        
 
457
        g_object_notify (G_OBJECT (resource_group), "message-delay");
 
458
}
 
459
 
 
460
/**
 
461
 * gssdp_resource_group_get_message_delay
 
462
 * @resource_group: A #GSSDPResourceGroup
 
463
 *
 
464
 * Return value: the minimum time between each SSDP message in ms.
 
465
 **/
 
466
guint
 
467
gssdp_resource_group_get_message_delay (GSSDPResourceGroup *resource_group)
 
468
{
 
469
        g_return_val_if_fail (GSSDP_IS_RESOURCE_GROUP (resource_group), 0);
 
470
 
 
471
        return resource_group->priv->message_delay;
 
472
}
 
473
 
 
474
/**
374
475
 * gssdp_resource_group_set_available
375
476
 * @resource_group: A #GSSDPResourceGroup
376
477
 * @available: TRUE if @resource_group should be available (advertised)
393
494
        resource_group->priv->available = available;
394
495
 
395
496
        if (available) {
 
497
                GMainContext *context;
396
498
                int timeout;
397
499
 
398
500
                /* We want to re-announce before actually timing out */
401
503
                        timeout = timeout / 2 - 1;
402
504
 
403
505
                /* Add re-announcement timer */
404
 
                resource_group->priv->timeout_id =
405
 
                        g_timeout_add_seconds (timeout,
406
 
                                               resource_group_timeout,
407
 
                                               resource_group);
 
506
                resource_group->priv->timeout_src =
 
507
                        g_timeout_source_new_seconds (timeout);
 
508
                g_source_set_callback (resource_group->priv->timeout_src,
 
509
                                       resource_group_timeout,
 
510
                                       resource_group, NULL);
 
511
 
 
512
                context = gssdp_client_get_main_context
 
513
                        (resource_group->priv->client);
 
514
                g_source_attach (resource_group->priv->timeout_src, context);
 
515
 
 
516
                g_source_unref (resource_group->priv->timeout_src);
408
517
 
409
518
                /* Announce all resources */
410
519
                for (l = resource_group->priv->resources; l; l = l->next)
415
524
                        resource_byebye (l->data);
416
525
 
417
526
                /* Remove re-announcement timer */
418
 
                g_source_remove (resource_group->priv->timeout_id);
419
 
                resource_group->priv->timeout_id = 0;
 
527
                g_source_destroy (resource_group->priv->timeout_src);
 
528
                resource_group->priv->timeout_src = NULL;
420
529
        }
421
530
        
422
531
        g_object_notify (G_OBJECT (resource_group), "available");
469
578
        resource->target = g_strdup (target);
470
579
        resource->usn    = g_strdup (usn);
471
580
 
 
581
        resource->initial_alive_sent = FALSE;
 
582
 
472
583
        for (l = locations; l; l = l->next) {
473
584
                resource->locations = g_list_append (resource->locations,
474
585
                                                    g_strdup (l->data));
565
676
}
566
677
 
567
678
/**
568
 
 * Called every max-age seconds to re-announce all resources
 
679
 * Called to re-announce all resources periodically
569
680
 **/
570
681
static gboolean
571
682
resource_group_timeout (gpointer user_data)
637
748
                        /* Match. */
638
749
                        guint timeout;
639
750
                        DiscoveryResponse *response;
 
751
                        GMainContext *context;
640
752
 
641
753
                        /* Get a random timeout from the interval [0, mx] */
642
754
                        timeout = g_random_int_range (0, mx * 1000);
646
758
                        
647
759
                        response->dest_ip   = g_strdup (from_ip);
648
760
                        response->dest_port = from_port;
649
 
                        response->target    = g_strdup (target);
650
761
                        response->resource  = resource;
651
762
 
 
763
                        if (want_all)
 
764
                                response->target = g_strdup (resource->target);
 
765
                        else
 
766
                                response->target = g_strdup (target);
 
767
 
652
768
                        /* Add timeout */
653
 
                        response->timeout_id =
654
 
                                g_timeout_add (timeout,
655
 
                                               discovery_response_timeout,
656
 
                                               response);
 
769
                        response->timeout_src = g_timeout_source_new (timeout);
 
770
                        g_source_set_callback (response->timeout_src,
 
771
                                               discovery_response_timeout,
 
772
                                               response, NULL);
 
773
 
 
774
                        context = gssdp_client_get_main_context (client);
 
775
                        g_source_attach (response->timeout_src, context);
 
776
 
 
777
                        g_source_unref (response->timeout_src);
657
778
                        
658
779
                        /* Add to resource */
659
780
                        resource->responses =
744
865
        response->resource->responses =
745
866
                g_list_remove (response->resource->responses, response);
746
867
 
747
 
        g_source_remove (response->timeout_id);
 
868
        g_source_destroy (response->timeout_src);
748
869
        
749
870
        g_free (response->dest_ip);
750
871
        g_free (response->target);
753
874
}
754
875
 
755
876
/**
 
877
 * Send the next queued message, if any
 
878
 **/
 
879
static gboolean
 
880
process_queue (gpointer data)
 
881
{
 
882
        GSSDPResourceGroup *resource_group;
 
883
 
 
884
        resource_group = GSSDP_RESOURCE_GROUP (data);
 
885
 
 
886
        if (g_queue_is_empty (resource_group->priv->message_queue)) {
 
887
                /* this is the timeout after last message in queue */
 
888
                resource_group->priv->message_src_id = 0;
 
889
 
 
890
                return FALSE;
 
891
        } else {
 
892
                GSSDPClient *client;
 
893
                char *message;
 
894
 
 
895
                client = resource_group->priv->client;
 
896
                message = g_queue_pop_head
 
897
                        (resource_group->priv->message_queue);
 
898
 
 
899
                _gssdp_client_send_message (client,
 
900
                                            NULL,
 
901
                                            0,
 
902
                                            message);
 
903
                g_free (message);
 
904
 
 
905
                return TRUE;
 
906
        }
 
907
}
 
908
 
 
909
/**
 
910
 * Add a message to sending queue
 
911
 * 
 
912
 * Do not free @message.
 
913
 **/
 
914
static void
 
915
queue_message (GSSDPResourceGroup *resource_group,
 
916
               char               *message)
 
917
{
 
918
        g_queue_push_tail (resource_group->priv->message_queue, 
 
919
                           message);
 
920
 
 
921
        if (resource_group->priv->message_src_id == 0) {
 
922
                /* nothing in the queue: process message immediately 
 
923
                   and add a timeout for (possible) next message */
 
924
 
 
925
                process_queue (resource_group);
 
926
                resource_group->priv->message_src_id = 
 
927
                        g_timeout_add (resource_group->priv->message_delay, 
 
928
                                       process_queue,
 
929
                                       resource_group);
 
930
        }
 
931
}
 
932
 
 
933
/**
756
934
 * Send ssdp:alive message for @resource
757
935
 **/
758
936
static void
762
940
        guint max_age;
763
941
        char *al, *message;
764
942
 
 
943
        if (!resource->initial_alive_sent) {
 
944
                /* Unannounce before first announce. This is done to
 
945
                   minimize the possibility of control points thinking
 
946
                   that this is just a reannouncement. */
 
947
                resource_byebye (resource);
 
948
 
 
949
                resource->initial_alive_sent = TRUE;
 
950
        }
 
951
 
765
952
        /* Send message */
766
953
        client = resource->resource_group->priv->client;
767
954
 
777
964
                                   resource->target,
778
965
                                   resource->usn);
779
966
 
780
 
        _gssdp_client_send_message (client,
781
 
                                    NULL,
782
 
                                    0,
783
 
                                    message);
 
967
        queue_message (resource->resource_group, message);
784
968
 
785
 
        g_free (message);
786
969
        g_free (al);
787
970
}
788
971
 
792
975
static void
793
976
resource_byebye (Resource *resource)
794
977
{
795
 
        GSSDPClient *client;
796
978
        char *message;
797
979
 
798
 
        /* Send message */
799
 
        client = resource->resource_group->priv->client;
800
 
 
 
980
        /* Queue message */
801
981
        message = g_strdup_printf (SSDP_BYEBYE_MESSAGE,
802
982
                                   resource->target,
803
983
                                   resource->usn);
804
984
        
805
 
        _gssdp_client_send_message (client,
806
 
                                    NULL,
807
 
                                    0,
808
 
                                    message);
809
 
 
810
 
        g_free (message);
 
985
        queue_message (resource->resource_group, message);
811
986
}
812
987
 
813
988
/**