AC_PROG_LIBTOOL
AC_CONFIG_MACRO_DIR([m4])
-PKG_CHECK_MODULES(LIBGSSDP, glib-2.0 >= 2.18 \
- gobject-2.0 >= 2.18 \
+PKG_CHECK_MODULES(LIBGSSDP, glib-2.0 >= 2.22 \
+ gobject-2.0 >= 2.22 \
+ gio-2.0 >= 2.22 \
libsoup-2.4)
LIBGTK_REQUIRED=2.12.0
gssdp-resource-group.c \
gssdp-socket-source.c \
gssdp-socket-source.h \
+ gssdp-socket-functions.c \
+ gssdp-socket-functions.h \
$(BUILT_SOURCES)
libgssdp_1_0_la_LIBADD = $(LIBGSSDP_LIBS)
static char *
make_server_id (void);
static gboolean
-request_socket_source_cb (gpointer user_data);
+request_socket_source_cb (GIOChannel *source,
+ GIOCondition condition,
+ gpointer user_data);
static gboolean
-multicast_socket_source_cb (gpointer user_data);
+multicast_socket_source_cb (GIOChannel *source,
+ GIOCondition condition,
+ gpointer user_data);
static gboolean
init_network_info (GSSDPClient *client);
gssdp_client_constructed (GObject *object)
{
GSSDPClient *client = GSSDP_CLIENT (object);
+ GError *error = NULL;
/* Make sure all network info is available to us */
if (!init_network_info (client))
/* Set up sockets (Will set errno if it failed) */
client->priv->request_socket =
gssdp_socket_source_new (GSSDP_SOCKET_SOURCE_TYPE_REQUEST,
- gssdp_client_get_host_ip (client));
+ gssdp_client_get_host_ip (client),
+ &error);
if (client->priv->request_socket != NULL) {
g_source_set_callback
- ((GSource *) client->priv->request_socket,
- request_socket_source_cb,
+ (client->priv->request_socket->source,
+ (GSourceFunc) request_socket_source_cb,
client,
NULL);
} else {
client->priv->multicast_socket =
gssdp_socket_source_new (GSSDP_SOCKET_SOURCE_TYPE_MULTICAST,
- gssdp_client_get_host_ip (client));
+ gssdp_client_get_host_ip (client),
+ &error);
if (client->priv->multicast_socket != NULL) {
g_source_set_callback
- ((GSource *) client->priv->multicast_socket,
- multicast_socket_source_cb,
+ (client->priv->multicast_socket->source,
+ (GSourceFunc) multicast_socket_source_cb,
client,
NULL);
}
errors:
if (!client->priv->request_socket || !client->priv->multicast_socket) {
- if (client->priv->error)
- g_set_error_literal (client->priv->error,
- GSSDP_ERROR,
- GSSDP_ERROR_FAILED,
- g_strerror (errno));
-
+ if (client->priv->error) {
+ g_propagate_error (client->priv->error, error);
+ }
return;
}
- g_source_attach ((GSource *) client->priv->request_socket,
+ g_source_attach (client->priv->request_socket->source,
client->priv->main_context);
- g_source_unref ((GSource *) client->priv->request_socket);
+ g_source_unref (client->priv->request_socket->source);
- g_source_attach ((GSource *) client->priv->multicast_socket,
+ g_source_attach (client->priv->multicast_socket->source,
client->priv->main_context);
- g_source_unref ((GSource *) client->priv->multicast_socket);
+ g_source_unref (client->priv->multicast_socket->source);
}
static void
/* Destroy the SocketSources */
if (client->priv->request_socket) {
- g_source_destroy ((GSource *) client->priv->request_socket);
+ gssdp_socket_source_destroy (client->priv->request_socket);
client->priv->request_socket = NULL;
}
if (client->priv->multicast_socket) {
- g_source_destroy ((GSource *) client->priv->multicast_socket);
+ gssdp_socket_source_destroy (client->priv->multicast_socket);
client->priv->multicast_socket = NULL;
}
gushort dest_port,
const char *message)
{
- struct sockaddr_in addr;
- int socket_fd, res;
+ gssize res;
+ GError *error = NULL;
+ GSocket *socket = NULL;
+ GInetAddress *inet_address = NULL;
+ GSocketAddress *address = NULL;
g_return_if_fail (GSSDP_IS_CLIENT (client));
g_return_if_fail (message != NULL);
if (dest_port == 0)
dest_port = SSDP_PORT;
- socket_fd = gssdp_socket_source_get_fd (client->priv->request_socket);
-
- memset (&addr, 0, sizeof (addr));
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons (dest_port);
- addr.sin_addr.s_addr = inet_addr (dest_ip);
-
- res = sendto (socket_fd,
- message,
- strlen (message),
- 0,
- (struct sockaddr *) &addr,
- sizeof (addr));
+ inet_address = g_inet_address_new_from_string (dest_ip);
+ address = g_inet_socket_address_new (inet_address, dest_port);
+ socket = gssdp_socket_source_get_socket (client->priv->request_socket);
+ res = g_socket_send_to (socket,
+ address,
+ message,
+ strlen (message),
+ NULL,
+ &error);
if (res == -1) {
- g_warning ("sendto: Error %d sending message: %s",
- errno, strerror (errno));
+ g_warning ("g_socket_sendto: Error sending message %s: %s",
+ message, error->message);
+ g_error_free (error);
}
+
+ g_object_unref (address);
+ g_object_unref (inet_address);
}
/**
* Called when data can be read from the socket
**/
static gboolean
-socket_source_cb (GSSDPSocketSource *socket, GSSDPClient *client)
+socket_source_cb (GSSDPSocketSource *socket_source, GSSDPClient *client)
{
- int fd, type, len;
- ssize_t bytes;
+ int type, len;
char buf[BUF_SIZE], *end;
- struct sockaddr_in addr;
- socklen_t addr_size;
SoupMessageHeaders *headers;
- struct in_addr our_addr;
- in_addr_t our_network;
+ GSocket *socket;
+ GSocketAddress *address = NULL;
+ gssize bytes;
+ GInetAddress *inetaddr;
+ char *ip_string;
+ guint16 port;
+ GError *error = NULL;
in_addr_t recv_network;
+ in_addr_t our_network;
+ struct in_addr our_addr;
+ struct sockaddr_in addr;
- /* Get FD */
- fd = gssdp_socket_source_get_fd (socket);
-
- /* Read data */
- addr_size = sizeof (addr);
-
- bytes = recvfrom (fd,
- buf,
- BUF_SIZE - 1, /* Leave space for trailing \0 */
- MSG_TRUNC,
- (struct sockaddr *) &addr,
- &addr_size);
+ /* Get Socket */
+ socket = gssdp_socket_source_get_socket (socket_source);
+ bytes = g_socket_receive_from (socket,
+ &address,
+ buf,
+ BUF_SIZE - 1,
+ NULL,
+ &error);
if (bytes == -1) {
- g_warning ("Failed to read from socket: %d (%s)",
- errno,
- strerror (errno));
+ g_warning ("Failed to receive from socket: %s",
+ error->message);
+ g_error_free (error);
return TRUE;
}
* on this socket from a particular interface but AFAIK that is not
* possible, at least not in a portable way.
*/
+
+ if (!g_socket_address_to_native (address,
+ &addr,
+ sizeof (struct sockaddr_in),
+ &error)) {
+ g_warning ("Could not convert address to native: %s",
+ error->message);
+ g_error_free (error);
+
+ return TRUE;
+ }
+
recv_network = inet_netof (addr.sin_addr);
our_addr.s_addr = inet_addr (gssdp_client_get_host_ip (client));
our_network = inet_netof (our_addr);
return TRUE;
if (bytes >= BUF_SIZE) {
+ g_object_unref (address);
g_warning ("Received packet of %u bytes, but the maximum "
"buffer size is %d. Packed dropped.",
(unsigned int) bytes, BUF_SIZE);
/* Find length */
end = strstr (buf, "\r\n\r\n");
if (!end) {
+ g_object_unref (address);
g_warning ("Received packet lacks \"\\r\\n\\r\\n\" sequence. "
"Packed dropped.");
}
/* Emit signal if parsing succeeded */
+ inetaddr = g_inet_socket_address_get_address (
+ G_INET_SOCKET_ADDRESS (address));
+ ip_string = g_inet_address_to_string (inetaddr);
+ port = g_inet_socket_address_get_port (
+ G_INET_SOCKET_ADDRESS (address));
if (type >= 0) {
g_signal_emit (client,
signals[MESSAGE_RECEIVED],
0,
- inet_ntoa (addr.sin_addr),
- ntohs (addr.sin_port),
+ ip_string,
+ port,
type,
headers);
}
+ if (ip_string)
+ g_free (ip_string);
+
if (headers)
soup_message_headers_free (headers);
+ g_object_unref (address);
+
return TRUE;
}
static gboolean
-request_socket_source_cb (gpointer user_data)
+request_socket_source_cb (GIOChannel *source,
+ GIOCondition condition,
+ gpointer user_data)
{
GSSDPClient *client;
}
static gboolean
-multicast_socket_source_cb (gpointer user_data)
+multicast_socket_source_cb (GIOChannel *source,
+ GIOCondition condition,
+ gpointer user_data)
{
GSSDPClient *client;
--- /dev/null
+/*
+ * Copyright (C) 2010 Jens Georg <mail@jensge.org>
+ *
+ * Author: Jens Georg <mail@jensge.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+
+#ifdef G_OS_WIN32
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+ typedef int socklen_t;
+#else
+ #include <sys/socket.h>
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+#endif
+
+#include "gssdp-error.h"
+#include "gssdp-socket-functions.h"
+
+static char*
+gssdp_socket_error_message (int error) {
+#ifdef G_OS_WIN32
+ return g_win32_error_message (error);
+#else
+ return g_strdup (g_strerror (error));
+#endif
+}
+
+static int
+gssdp_socket_errno () {
+#ifdef G_OS_WIN32
+ return WSAGetLastError ();
+#else
+ return errno;
+#endif
+}
+
+
+static gboolean
+gssdp_socket_option_set (GSocket *socket,
+ int level,
+ int option,
+ const void *optval,
+ socklen_t optlen,
+ GError **error) {
+ int res;
+
+ res = setsockopt (g_socket_get_fd (socket),
+ level,
+ option,
+ optval,
+ optlen);
+
+ if (res == -1) {
+ char *message;
+ int error_code;
+
+ error_code = gssdp_socket_errno ();
+ message = gssdp_socket_error_message (error_code);
+ g_set_error_literal (error,
+ GSSDP_ERROR,
+ GSSDP_ERROR_FAILED,
+ message);
+ g_free (message);
+ }
+
+ return res != -1;
+}
+
+gboolean
+gssdp_socket_enable_loop (GSocket *socket,
+ gboolean enable,
+ GError **error) {
+ return gssdp_socket_option_set (socket,
+ IPPROTO_IP,
+ IP_MULTICAST_LOOP,
+ (char *) &enable,
+ sizeof (enable),
+ error);
+}
+
+gboolean
+gssdp_socket_set_ttl (GSocket *socket,
+ int ttl,
+ GError **error) {
+ return gssdp_socket_option_set (socket,
+ IPPROTO_IP,
+ IP_MULTICAST_TTL,
+ (char *) &ttl,
+ sizeof (ttl),
+ error);
+}
+
+gboolean
+gssdp_socket_enable_broadcast (GSocket *socket,
+ gboolean enable,
+ GError **error) {
+ return gssdp_socket_option_set (socket,
+ SOL_SOCKET,
+ SO_BROADCAST,
+ (char *) &enable,
+ sizeof (enable),
+ error);
+}
+
+gboolean
+gssdp_socket_mcast_interface_set (GSocket *socket,
+ GInetAddress *iface_address,
+ GError **error) {
+
+ const guint8 *address;
+ gsize native_size;
+
+ address = g_inet_address_to_bytes (iface_address);
+ native_size = g_inet_address_get_native_size (iface_address);
+
+ return gssdp_socket_option_set (socket,
+ IPPROTO_IP,
+ IP_MULTICAST_IF,
+ (char *) address,
+ native_size,
+ error);
+}
+
+/*
+ * Iface may be NULL if no special interface is wanted
+ */
+gboolean
+gssdp_socket_mcast_group_join (GSocket *socket,
+ GInetAddress *group,
+ GInetAddress *iface,
+ GError **error) {
+ struct ip_mreq mreq;
+ GError *inner_error = NULL;
+ gboolean result;
+#ifdef G_OS_WIN32
+ GSocketAddress *local_address;
+#endif
+ if (group == NULL || ! G_IS_INET_ADDRESS (group)) {
+ g_set_error_literal (error,
+ GSSDP_ERROR,
+ GSSDP_ERROR_NO_IP_ADDRESS,
+ "Address is not a valid address");
+
+ return FALSE;
+ }
+
+ if (!g_inet_address_get_is_multicast (group)) {
+ char *address;
+
+ address = g_inet_address_to_string (group);
+ g_set_error (error,
+ GSSDP_ERROR,
+ GSSDP_ERROR_FAILED,
+ "Address '%s' is not a multicast address",
+ address);
+ g_free (address);
+
+ return FALSE;
+ }
+
+ if (g_inet_address_get_family (group) != G_SOCKET_FAMILY_IPV4) {
+ g_set_error_literal (error,
+ GSSDP_ERROR,
+ GSSDP_ERROR_FAILED,
+ "IPv6 not supported");
+
+ return FALSE;
+ }
+#ifdef G_OS_WIN32
+ /* On Window, it is only possible to join multicast groups on a bound
+ * socket
+ * Note: This test is valid on Windows only. On linux, local_addres
+ * will be the ANY address (0.0.0.0 for IPv4)
+ */
+ local_address = g_socket_get_local_address (socket, &inner_error);
+ if (local_address == NULL) {
+ g_set_error_literal (error,
+ GSSDP_ERROR,
+ GSSDP_ERROR_FAILED,
+ "Cannot join multicast group;"
+ "socket is not bound");
+
+ return FALSE;
+ }
+ g_object_unref (local_address);
+#endif
+
+ memset (&mreq, 0, sizeof (struct ip_mreq));
+ memcpy (&(mreq.imr_multiaddr),
+ g_inet_address_to_bytes (group),
+ g_inet_address_get_native_size (group));
+
+ /* if omitted, join will fail if there isn't an explicit multicast
+ * route or a default route
+ */
+ if (iface != NULL)
+ memcpy (&(mreq.imr_interface),
+ g_inet_address_to_bytes (iface),
+ g_inet_address_get_native_size (iface));
+
+ result = gssdp_socket_option_set (socket,
+ IPPROTO_IP,
+ IP_ADD_MEMBERSHIP,
+ (char *) &mreq,
+ sizeof (mreq),
+ &inner_error);
+ if (!result)
+ g_propagate_error (error, inner_error);
+
+ return result;
+}
+
+
--- /dev/null
+/*
+ * Copyright (C) 2010 Jens Georg <mail@jensge.org>
+ *
+ * Author: Jens Georg <mail@jensge.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GSSDP_SOCKET_FUNCTIONS_H
+#define __GSSDP_SOCKET_FUNCTIONS_H
+
+#include <gio/gio.h>
+
+G_GNUC_INTERNAL gboolean
+gssdp_socket_enable_loop (GSocket *socket,
+ gboolean enable,
+ GError **error);
+G_GNUC_INTERNAL gboolean
+gssdp_socket_set_ttl (GSocket *socket,
+ int ttl,
+ GError **error);
+G_GNUC_INTERNAL gboolean
+gssdp_socket_enable_broadcast (GSocket *socket,
+ gboolean enable,
+ GError **error);
+G_GNUC_INTERNAL gboolean
+gssdp_socket_mcast_interface_set (GSocket *socket,
+ GInetAddress *iface_address,
+ GError **error);
+G_GNUC_INTERNAL gboolean
+gssdp_socket_mcast_group_join (GSocket *socket,
+ GInetAddress *group,
+ GInetAddress *iface,
+ GError **error);
+#endif
/*
* Copyright (C) 2006, 2007, 2008 OpenedHand Ltd.
* Copyright (C) 2009 Nokia Corporation, all rights reserved.
+ * Copyright (C) 2010 Jens Georg <mail@jensge.org>
*
* Author: Jorn Baayen <jorn@openedhand.com>
* Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
* <zeeshan.ali@nokia.com>
+ * Jens Georg <mail@jensge.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#include <config.h>
#include <glib.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
+#include "gssdp-socket-functions.h"
#include "gssdp-socket-source.h"
#include "gssdp-protocol.h"
-
-struct _GSSDPSocketSource {
- GSource source;
-
- GPollFD poll_fd;
-};
-
-static gboolean
-gssdp_socket_source_prepare (GSource *source,
- int *timeout);
-static gboolean
-gssdp_socket_source_check (GSource *source);
-static gboolean
-gssdp_socket_source_dispatch (GSource *source,
- GSourceFunc callback,
- gpointer user_data);
-static void
-gssdp_socket_source_finalize (GSource *source);
-
-static const GSourceFuncs gssdp_socket_source_funcs = {
- gssdp_socket_source_prepare,
- gssdp_socket_source_check,
- gssdp_socket_source_dispatch,
- gssdp_socket_source_finalize
-};
+#include "gssdp-error.h"
/**
* gssdp_socket_source_new
**/
GSSDPSocketSource *
gssdp_socket_source_new (GSSDPSocketSourceType type,
- const char *host_ip)
+ const char *host_ip,
+ GError **error)
{
- GSource *source;
- GSSDPSocketSource *socket_source;
- struct sockaddr_in bind_addr;
- struct in_addr iface_addr;
- struct ip_mreq mreq;
- gboolean boolean = TRUE;
- guchar ttl = 4;
- int res;
+ GSSDPSocketSource *socket_source = NULL;
+ GInetAddress *iface_address = NULL;
+ GSocketAddress *bind_address = NULL;
+ GInetAddress *group = NULL;
+ GError *inner_error = NULL;
+ GSocketFamily family;
+
+ iface_address = g_inet_address_new_from_string (host_ip);
+ if (iface_address == NULL) {
+ if (error != NULL) {
+ *error = g_error_new (GSSDP_ERROR,
+ GSSDP_ERROR_FAILED,
+ "Invalid host ip: %s",
+ host_ip);
+ inner_error = *error;
+ }
- /* Create source */
- source = g_source_new ((GSourceFuncs*)&gssdp_socket_source_funcs,
- sizeof (GSSDPSocketSource));
+ goto error;
+ }
- socket_source = (GSSDPSocketSource *) source;
+ family = g_inet_address_get_family (iface_address);
+
+ if (family == G_SOCKET_FAMILY_IPV4)
+ group = g_inet_address_new_from_string (SSDP_ADDR);
+ else {
+ if (error != NULL) {
+ *error = g_error_new_literal (GSSDP_ERROR,
+ GSSDP_ERROR_FAILED,
+ "IPv6 address");
+ inner_error = *error;
+ }
- /* Create socket */
- socket_source->poll_fd.fd = socket (AF_INET,
- SOCK_DGRAM,
- IPPROTO_UDP);
- if (socket_source->poll_fd.fd == -1)
goto error;
-
- socket_source->poll_fd.events = G_IO_IN | G_IO_ERR;
+ }
- g_source_add_poll (source, &socket_source->poll_fd);
- /* Enable broadcasting */
- res = setsockopt (socket_source->poll_fd.fd,
- SOL_SOCKET,
- SO_BROADCAST,
- &boolean,
- sizeof (boolean));
- if (res == -1)
- goto error;
+ /* Create source */
+ socket_source = g_slice_new0 (GSSDPSocketSource);
- /* TTL */
- res = setsockopt (socket_source->poll_fd.fd,
- IPPROTO_IP,
- IP_MULTICAST_TTL,
- &ttl,
- sizeof (ttl));
- if (res == -1)
- goto error;
+ /* Create socket */
+ socket_source->socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
+ G_SOCKET_TYPE_DATAGRAM,
+ G_SOCKET_PROTOCOL_UDP,
+ &inner_error);
- memset (&bind_addr, 0, sizeof (bind_addr));
- bind_addr.sin_family = AF_INET;
+ if (!socket_source->socket) {
+ g_propagate_prefixed_error (error,
+ inner_error,
+ "Could not create socket");
- res = inet_aton (host_ip, &iface_addr);
- if (res == 0)
goto error;
+ }
+
+ /* Enable broadcasting */
+ if (!gssdp_socket_enable_broadcast (socket_source->socket,
+ TRUE,
+ &inner_error)) {
+ g_propagate_prefixed_error (error,
+ inner_error,
+ "Failed to enable broadcast");
+ goto error;
+ }
+
+ /* TTL */
+ if (!gssdp_socket_set_ttl (socket_source->socket,
+ 4,
+ &inner_error)) {
+ g_propagate_prefixed_error (error,
+ inner_error,
+ "Failed to set TTL");
+ }
/* Set up additional things according to the type of socket desired */
if (type == GSSDP_SOCKET_SOURCE_TYPE_MULTICAST) {
- /* Allow multiple sockets to use the same PORT number */
- res = setsockopt (socket_source->poll_fd.fd,
- SOL_SOCKET,
-#ifdef SO_REUSEPORT
- SO_REUSEPORT,
-#else
- SO_REUSEADDR,
-#endif
- &boolean,
- sizeof (boolean));
- if (res == -1)
- goto error;
-
/* Enable multicast loopback */
- res = setsockopt (socket_source->poll_fd.fd,
- IPPROTO_IP,
- IP_MULTICAST_LOOP,
- &boolean,
- sizeof (boolean));
- if (res == -1)
- goto error;
-
- /* Set the interface */
- res = setsockopt (socket_source->poll_fd.fd,
- IPPROTO_IP,
- IP_MULTICAST_IF,
- &iface_addr,
- sizeof (struct in_addr));
- if (res == -1)
- goto error;
+ if (!gssdp_socket_enable_loop (socket_source->socket,
+ TRUE,
+ &inner_error)) {
+ g_propagate_prefixed_error (
+ error,
+ inner_error,
+ "Failed to enable loop-back");
- /* Subscribe to multicast channel */
- res = inet_aton (SSDP_ADDR, &(mreq.imr_multiaddr));
- if (res == 0)
goto error;
+ }
- memcpy (&(mreq.imr_interface),
- &iface_addr,
- sizeof (struct in_addr));
+ if (!gssdp_socket_mcast_interface_set (socket_source->socket,
+ iface_address,
+ &inner_error)) {
+ g_propagate_prefixed_error (
+ error,
+ inner_error,
+ "Failed to set multicast interface");
- res = setsockopt (socket_source->poll_fd.fd,
- IPPROTO_IP,
- IP_ADD_MEMBERSHIP,
- &mreq,
- sizeof (mreq));
- if (res == -1)
goto error;
+ }
- bind_addr.sin_port = htons (SSDP_PORT);
- res = inet_aton (SSDP_ADDR, &(bind_addr.sin_addr));
- if (res == 0)
- goto error;
+#ifdef G_OS_WIN32
+ bind_address = g_inet_socket_address_new (iface_address,
+ SSDP_PORT);
+#else
+ bind_address = g_inet_socket_address_new (group,
+ SSDP_PORT);
+#endif
} else {
- bind_addr.sin_port = 0;
- memcpy (&(bind_addr.sin_addr),
- &iface_addr,
- sizeof (struct in_addr));
+ bind_address = g_inet_socket_address_new (iface_address,
+ SSDP_PORT);
}
/* Bind to requested port and address */
- res = bind (socket_source->poll_fd.fd,
- (struct sockaddr *) &bind_addr,
- sizeof (bind_addr));
- if (res == -1)
- goto error;
-
- return socket_source;
-
-error:
- g_source_destroy (source);
-
- return NULL;
-}
-
-static gboolean
-gssdp_socket_source_prepare (GSource *source,
- int *timeout)
-{
- return FALSE;
-}
-
-static gboolean
-gssdp_socket_source_check (GSource *source)
-{
- GSSDPSocketSource *socket_source;
+ if (!g_socket_bind (socket_source->socket,
+ bind_address,
+ TRUE,
+ &inner_error)) {
+ g_propagate_prefixed_error (error,
+ inner_error,
+ "Failed to bind socket");
- socket_source = (GSSDPSocketSource *) source;
-
- return socket_source->poll_fd.revents & (G_IO_IN | G_IO_ERR);
-}
-
-static gboolean
-gssdp_socket_source_dispatch (GSource *source,
- GSourceFunc callback,
- gpointer user_data)
-{
- GSSDPSocketSource *socket_source;
+ goto error;
+ }
- socket_source = (GSSDPSocketSource *) source;
+ if (type == GSSDP_SOCKET_SOURCE_TYPE_MULTICAST) {
- if (socket_source->poll_fd.revents & G_IO_IN) {
- /* Ready to read */
- if (callback)
- callback (user_data);
- } else if (socket_source->poll_fd.revents & G_IO_ERR) {
- /* Error */
- int value;
- socklen_t size_int;
+ /* Subscribe to multicast channel */
+ if (!gssdp_socket_mcast_group_join (socket_source->socket,
+ group,
+ iface_address,
+ &inner_error)) {
+ char *address = g_inet_address_to_string (group);
+ g_propagate_prefixed_error (error,
+ inner_error,
+ "Failed to join group %s",
+ address);
+ g_free (address);
- value = EINVAL;
- size_int = sizeof (int);
-
- /* Get errno from socket */
- getsockopt (socket_source->poll_fd.fd,
- SOL_SOCKET,
- SO_ERROR,
- &value,
- &size_int);
+ goto error;
+ }
+ }
- g_warning ("Socket error %d received: %s",
- value,
- strerror (value));
+ socket_source->source = g_socket_create_source (socket_source->socket,
+ G_IO_IN | G_IO_ERR,
+ NULL);
+error:
+ if (iface_address != NULL)
+ g_object_unref (iface_address);
+ if (bind_address != NULL)
+ g_object_unref (bind_address);
+ if (group != NULL)
+ g_object_unref (group);
+ if (inner_error != NULL) {
+ if (error == NULL) {
+ g_warning ("Failed to create socket source: %s",
+ inner_error->message);
+ g_error_free (inner_error);
+ }
+
+ return NULL;
}
- return TRUE;
+ return socket_source;
}
-static void
-gssdp_socket_source_finalize (GSource *source)
+GSocket *
+gssdp_socket_source_get_socket (GSSDPSocketSource *socket_source)
{
- GSSDPSocketSource *socket_source;
+ g_return_val_if_fail (socket_source != NULL, NULL);
- socket_source = (GSSDPSocketSource *) source;
-
- /* Close the socket */
- close (socket_source->poll_fd.fd);
+ return socket_source->socket;
}
-/**
- * gssdp_socket_source_get_fd
- *
- * Return value: The socket's FD.
- **/
-int
-gssdp_socket_source_get_fd (GSSDPSocketSource *socket_source)
+void
+gssdp_socket_source_destroy (GSSDPSocketSource *socket_source)
{
- g_return_val_if_fail (socket_source != NULL, -1);
-
- return socket_source->poll_fd.fd;
+ g_return_if_fail (socket_source != NULL);
+ g_source_destroy (socket_source->source);
+ g_socket_close (socket_source->socket, NULL);
+ g_object_unref (socket_source->socket);
+ g_slice_free (GSSDPSocketSource, socket_source);
}
/*
* Copyright (C) 2006, 2007, 2008 OpenedHand Ltd.
+ * Copyright (C) 2010 Jens Georg <mail@jensge.org>
*
* Author: Jorn Baayen <jorn@openedhand.com>
+ * Jens Georg <mail@jensge.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#ifndef __GSSDP_SOCKET_SOURCE_H__
#define __GSSDP_SOCKET_SOURCE_H__
+#include <gio/gio.h>
+
G_BEGIN_DECLS
+struct _GSSDPSocketSource {
+ GSource *source;
+ GSocket *socket;
+};
+
typedef struct _GSSDPSocketSource GSSDPSocketSource;
typedef enum {
} GSSDPSocketSourceType;
G_GNUC_INTERNAL GSSDPSocketSource *
-gssdp_socket_source_new (GSSDPSocketSourceType type,
- const char *host_ip);
-
-G_GNUC_INTERNAL int
-gssdp_socket_source_get_fd (GSSDPSocketSource *socket_source);
+gssdp_socket_source_new (GSSDPSocketSourceType type,
+ const char *host_ip,
+ GError **error);
+G_GNUC_INTERNAL void
+gssdp_socket_source_destroy (GSSDPSocketSource *socket_source);
+
+G_GNUC_INTERNAL GSocket*
+gssdp_socket_source_get_socket (GSSDPSocketSource *socket_source);
G_END_DECLS