static void gssdp_resource_group_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { GSSDPResourceGroup *resource_group; resource_group = GSSDP_RESOURCE_GROUP (object); switch (property_id) { case PROP_CLIENT: gssdp_resource_group_set_client (resource_group, g_value_get_object (value)); break; case PROP_MAX_AGE: gssdp_resource_group_set_max_age (resource_group, g_value_get_long (value)); break; case PROP_AVAILABLE: gssdp_resource_group_set_available (resource_group, g_value_get_boolean (value)); break; case PROP_MESSAGE_DELAY: gssdp_resource_group_set_message_delay (resource_group, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
/* * Send the next queued message, if any */ static gboolean process_queue (gpointer data) { GSSDPResourceGroup *resource_group; resource_group = GSSDP_RESOURCE_GROUP (data); if (g_queue_is_empty (resource_group->priv->message_queue)) { /* this is the timeout after last message in queue */ resource_group->priv->message_src = NULL; return FALSE; } else { GSSDPClient *client; char *message; client = resource_group->priv->client; message = g_queue_pop_head (resource_group->priv->message_queue); _gssdp_client_send_message (client, NULL, 0, message, _GSSDP_DISCOVERY_RESPONSE); g_free (message); return TRUE; } }
static void gssdp_resource_group_dispose (GObject *object) { GSSDPResourceGroup *resource_group; GSSDPResourceGroupPrivate *priv; resource_group = GSSDP_RESOURCE_GROUP (object); priv = resource_group->priv; while (priv->resources) { resource_free (priv->resources->data); priv->resources = g_list_delete_link (priv->resources, priv->resources); } if (priv->message_queue) { /* send messages without usual delay */ while (!g_queue_is_empty (priv->message_queue)) { if (priv->available) process_queue (resource_group); else g_free (g_queue_pop_head (priv->message_queue)); } g_queue_free (priv->message_queue); priv->message_queue = NULL; } if (priv->message_src) { g_source_destroy (priv->message_src); priv->message_src = NULL; } if (priv->timeout_src) { g_source_destroy (priv->timeout_src); priv->timeout_src = NULL; } if (priv->client) { if (g_signal_handler_is_connected (priv->client, priv->message_received_id)) { g_signal_handler_disconnect (priv->client, priv->message_received_id); } g_object_unref (priv->client); priv->client = NULL; } G_OBJECT_CLASS (gssdp_resource_group_parent_class)->dispose (object); }
/* * Called to re-announce all resources periodically */ static gboolean resource_group_timeout (gpointer user_data) { GSSDPResourceGroup *resource_group; resource_group = GSSDP_RESOURCE_GROUP (user_data); send_announcement_set (resource_group->priv->resources, (GFunc) resource_alive); return TRUE; }
/* * Called to re-announce all resources periodically */ static gboolean resource_group_timeout (gpointer user_data) { GSSDPResourceGroup *resource_group; GSSDPResourceGroupPrivate *priv; resource_group = GSSDP_RESOURCE_GROUP (user_data); priv = gssdp_resource_group_get_instance_private (resource_group); send_announcement_set (priv->resources, (GFunc) resource_alive, NULL); return TRUE; }
static void gssdp_resource_group_dispose (GObject *object) { GSSDPResourceGroup *resource_group; GSSDPResourceGroupPrivate *priv; resource_group = GSSDP_RESOURCE_GROUP (object); priv = gssdp_resource_group_get_instance_private (resource_group); g_list_free_full (priv->resources, (GFreeFunc) resource_free); priv->resources = NULL; if (priv->message_queue) { /* send messages without usual delay */ while (!g_queue_is_empty (priv->message_queue)) { if (priv->available) process_queue (resource_group); else g_free (g_queue_pop_head (priv->message_queue)); } g_clear_pointer (&priv->message_queue, g_queue_free); } /* No need to unref sources, already done on creation */ g_clear_pointer (&priv->message_src, g_source_destroy); g_clear_pointer (&priv->timeout_src, g_source_destroy); if (priv->client) { if (g_signal_handler_is_connected (priv->client, priv->message_received_id)) { g_signal_handler_disconnect (priv->client, priv->message_received_id); } g_clear_object (&priv->client); } G_OBJECT_CLASS (gssdp_resource_group_parent_class)->dispose (object); }
/* * Received a message */ static void message_received_cb (GSSDPClient *client, const char *from_ip, gushort from_port, _GSSDPMessageType type, SoupMessageHeaders *headers, gpointer user_data) { GSSDPResourceGroup *resource_group; const char *target, *mx_str, *version_str, *man; gboolean want_all; int mx, version; GList *l; resource_group = GSSDP_RESOURCE_GROUP (user_data); /* Only process if we are available */ if (!resource_group->priv->available) return; /* We only handle discovery requests */ if (type != _GSSDP_DISCOVERY_REQUEST) return; /* Extract target */ target = soup_message_headers_get_one (headers, "ST"); if (!target) { g_warning ("Discovery request did not have an ST header"); return; } /* Is this the "ssdp:all" target? */ want_all = (strcmp (target, GSSDP_ALL_RESOURCES) == 0); /* Extract MX */ mx_str = soup_message_headers_get_one (headers, "MX"); if (!mx_str || atoi (mx_str) <= 0) { g_warning ("Discovery request did not have a valid MX header"); return; } man = soup_message_headers_get_one (headers, "MAN"); if (!man) { g_warning ("Discovery request did not have a valid MAN header"); return; } mx = atoi (mx_str); /* Extract version */ version_str = get_version_for_target ((char *) target); if (version_str != NULL) version = atoi (version_str); else version = 0; /* Find matching resource */ for (l = resource_group->priv->resources; l; l = l->next) { Resource *resource; resource = l->data; if (want_all || (g_regex_match (resource->target_regex, target, 0, NULL) && version <= resource->version)) { /* Match. */ guint timeout; DiscoveryResponse *response; /* Get a random timeout from the interval [0, mx] */ timeout = g_random_int_range (0, mx * 1000); /* Prepare response */ response = g_slice_new (DiscoveryResponse); response->dest_ip = g_strdup (from_ip); response->dest_port = from_port; response->resource = resource; if (want_all) response->target = g_strdup (resource->target); else response->target = g_strdup (target); /* Add timeout */ response->timeout_src = g_timeout_source_new (timeout); g_source_set_callback (response->timeout_src, discovery_response_timeout, response, NULL); g_source_attach (response->timeout_src, g_main_context_get_thread_default ()); g_source_unref (response->timeout_src); /* Add to resource */ resource->responses = g_list_prepend (resource->responses, response); } } }