/* GStreamer
* Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
+ * Copyright (C) 2010 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2012 Collabora Ltd. <tim.muller@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
*
* 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.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:gstnettimepacket
+ * @title: GstNetTimePacket
+ * @short_description: Helper structure to construct clock packets used
+ * by network clocks.
+ * @see_also: #GstClock, #GstNetClientClock, #GstNetTimeProvider
+ *
+ * Various functions for receiving, sending an serializing #GstNetTimePacket
+ * structures.
*/
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+#include <glib.h>
+
+#ifdef __CYGWIN__
+# include <unistd.h>
+# include <fcntl.h>
+#endif
+
#include "gstnettimepacket.h"
+G_DEFINE_BOXED_TYPE (GstNetTimePacket, gst_net_time_packet,
+ gst_net_time_packet_copy, gst_net_time_packet_free);
/**
* gst_net_time_packet_new:
- * @buffer: a buffer from which to construct the packet, or NULL
+ * @buffer: (array): a buffer from which to construct the packet, or NULL
*
* Creates a new #GstNetTimePacket from a buffer received over the network. The
* caller is responsible for ensuring that @buffer is at least
* If @buffer is #NULL, the local and remote times will be set to
* #GST_CLOCK_TIME_NONE.
*
- * MT safe. Caller owns return value (g_free to free).
+ * MT safe. Caller owns return value (gst_net_time_packet_free to free).
*
* Returns: The new #GstNetTimePacket.
*/
}
/**
+ * gst_net_time_packet_free:
+ * @packet: the #GstNetTimePacket
+ *
+ * Free @packet.
+ */
+void
+gst_net_time_packet_free (GstNetTimePacket * packet)
+{
+ g_free (packet);
+}
+
+/**
+ * gst_net_time_packet_copy:
+ * @packet: the #GstNetTimePacket
+ *
+ * Make a copy of @packet.
+ *
+ * Returns: a copy of @packet, free with gst_net_time_packet_free().
+ */
+GstNetTimePacket *
+gst_net_time_packet_copy (const GstNetTimePacket * packet)
+{
+ GstNetTimePacket *ret;
+
+ ret = g_new0 (GstNetTimePacket, 1);
+ ret->local_time = packet->local_time;
+ ret->remote_time = packet->remote_time;
+
+ return ret;
+}
+
+/**
* gst_net_time_packet_serialize:
* @packet: the #GstNetTimePacket
*
/**
* gst_net_time_packet_receive:
- * @sockfd: a file descriptor created by socket(2)
- * @addr: a pointer to a sockaddr to hold the address of the sender
- * @len: a pointer to the size of the data pointed to by @addr
- *
- * Receives a #GstNetTimePacket over a socket. Handles interrupted system calls,
- * but otherwise returns NULL on error. See recvfrom(2) for more information on
- * how to interpret @sockaddr.
+ * @socket: socket to receive the time packet on
+ * @src_address: (out): address of variable to return sender address
+ * @error: return address for a #GError, or NULL
*
- * MT safe. Caller owns return value (g_free to free).
+ * Receives a #GstNetTimePacket over a socket. Handles interrupted system
+ * calls, but otherwise returns NULL on error.
*
- * Returns: The new #GstNetTimePacket.
+ * Returns: (transfer full): a new #GstNetTimePacket, or NULL on error. Free
+ * with gst_net_time_packet_free() when done.
*/
GstNetTimePacket *
-gst_net_time_packet_receive (gint fd, struct sockaddr * addr, socklen_t * len)
+gst_net_time_packet_receive (GSocket * socket,
+ GSocketAddress ** src_address, GError ** error)
{
- guint8 buffer[GST_NET_TIME_PACKET_SIZE];
- gint ret;
+ gchar buffer[GST_NET_TIME_PACKET_SIZE];
+ GError *err = NULL;
+ gssize ret;
+
+ g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
while (TRUE) {
- ret = recvfrom (fd, buffer, GST_NET_TIME_PACKET_SIZE,
- 0, (struct sockaddr *) addr, len);
+ ret = g_socket_receive_from (socket, src_address, buffer,
+ GST_NET_TIME_PACKET_SIZE, NULL, &err);
+
if (ret < 0) {
- if (errno != EAGAIN && errno != EINTR)
- goto receive_error;
- else
+ if (err->code == G_IO_ERROR_WOULD_BLOCK) {
+ g_error_free (err);
+ err = NULL;
continue;
+ } else {
+ goto receive_error;
+ }
} else if (ret < GST_NET_TIME_PACKET_SIZE) {
goto short_packet;
} else {
- return gst_net_time_packet_new (buffer);
+ return gst_net_time_packet_new ((const guint8 *) buffer);
}
}
receive_error:
{
- GST_DEBUG ("receive error %d: %s (%d)", ret, g_strerror (errno), errno);
+ GST_DEBUG ("receive error: %s", err->message);
+ g_propagate_error (error, err);
return NULL;
}
short_packet:
{
- GST_DEBUG ("someone sent us a short packet (%d < %d)",
+ GST_DEBUG ("someone sent us a short packet (%" G_GSSIZE_FORMAT " < %d)",
ret, GST_NET_TIME_PACKET_SIZE);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
+ "short time packet (%d < %d)", (int) ret, GST_NET_TIME_PACKET_SIZE);
return NULL;
}
}
/**
* gst_net_time_packet_send:
- * @packet: the #GstNetTimePacket
- * @sockfd: a file descriptor created by socket(2)
- * @addr: a pointer to a sockaddr to hold the address of the sender
- * @len: the size of the data pointed to by @addr
+ * @packet: the #GstNetTimePacket to send
+ * @socket: socket to send the time packet on
+ * @dest_address: address to send the time packet to
+ * @error: return address for a #GError, or NULL
*
- * Sends a #GstNetTimePacket over a socket. Essentially a thin wrapper around
- * sendto(2) and gst_net_time_packet_serialize().
+ * Sends a #GstNetTimePacket over a socket.
*
* MT safe.
*
- * Returns: The return value of sendto(2).
+ * Returns: TRUE if successful, FALSE in case an error occurred.
*/
-gint
-gst_net_time_packet_send (const GstNetTimePacket * packet, gint fd,
- struct sockaddr * addr, socklen_t len)
+gboolean
+gst_net_time_packet_send (const GstNetTimePacket * packet,
+ GSocket * socket, GSocketAddress * dest_address, GError ** error)
{
+ gboolean was_blocking;
guint8 *buffer;
- gint ret;
+ gssize res;
+
+ g_return_val_if_fail (packet != NULL, FALSE);
+ g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
+ g_return_val_if_fail (G_IS_SOCKET_ADDRESS (dest_address), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- g_return_val_if_fail (packet != NULL, -EINVAL);
+ was_blocking = g_socket_get_blocking (socket);
+ if (was_blocking)
+ g_socket_set_blocking (socket, FALSE);
+
+ /* FIXME: avoid pointless alloc/free, serialise into stack-allocated buffer */
buffer = gst_net_time_packet_serialize (packet);
- ret = sendto (fd, buffer, GST_NET_TIME_PACKET_SIZE, MSG_DONTWAIT, addr, len);
+ res = g_socket_send_to (socket, dest_address, (const gchar *) buffer,
+ GST_NET_TIME_PACKET_SIZE, NULL, error);
- return ret;
+ /* datagram packets should be sent as a whole or not at all */
+ g_assert (res < 0 || res == GST_NET_TIME_PACKET_SIZE);
+
+ g_free (buffer);
+
+ if (was_blocking)
+ g_socket_set_blocking (socket, TRUE);
+
+ return (res == GST_NET_TIME_PACKET_SIZE);
}