Merge remote-tracking branch 'origin/master' into 0.11
[platform/upstream/gstreamer.git] / libs / gst / net / gstnettimepacket.c
1 /* GStreamer
2  * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 /**
20  * SECTION:gstnettimepacket
21  * @short_description: Helper structure to construct clock packets used
22  *                     by network clocks.
23  * @see_also: #GstClock, #GstNetClientClock, #GstNetTimeProvider
24  *
25  * Various functions for receiving, sending an serializing #GstNetTimePacket
26  * structures.
27  *
28  * Last reviewed on 2005-11-23 (0.9.5)
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <glib.h>
36
37 #ifdef __CYGWIN__
38 # include <unistd.h>
39 # include <fcntl.h>
40 #endif
41
42 #include "gstnettimepacket.h"
43
44
45 /**
46  * gst_net_time_packet_new:
47  * @buffer: a buffer from which to construct the packet, or NULL
48  *
49  * Creates a new #GstNetTimePacket from a buffer received over the network. The
50  * caller is responsible for ensuring that @buffer is at least
51  * #GST_NET_TIME_PACKET_SIZE bytes long.
52  *
53  * If @buffer is #NULL, the local and remote times will be set to
54  * #GST_CLOCK_TIME_NONE.
55  *
56  * MT safe. Caller owns return value (g_free to free).
57  *
58  * Returns: The new #GstNetTimePacket.
59  */
60 GstNetTimePacket *
61 gst_net_time_packet_new (const guint8 * buffer)
62 {
63   GstNetTimePacket *ret;
64
65   g_assert (sizeof (GstClockTime) == 8);
66
67   ret = g_new0 (GstNetTimePacket, 1);
68
69   if (buffer) {
70     ret->local_time = GST_READ_UINT64_BE (buffer);
71     ret->remote_time = GST_READ_UINT64_BE (buffer + sizeof (GstClockTime));
72   } else {
73     ret->local_time = GST_CLOCK_TIME_NONE;
74     ret->remote_time = GST_CLOCK_TIME_NONE;
75   }
76
77   return ret;
78 }
79
80 /**
81  * gst_net_time_packet_serialize:
82  * @packet: the #GstNetTimePacket
83  *
84  * Serialized a #GstNetTimePacket into a newly-allocated sequence of
85  * #GST_NET_TIME_PACKET_SIZE bytes, in network byte order. The value returned is
86  * suitable for passing to write(2) or sendto(2) for communication over the
87  * network.
88  *
89  * MT safe. Caller owns return value (g_free to free).
90  *
91  * Returns: A newly allocated sequence of #GST_NET_TIME_PACKET_SIZE bytes.
92  */
93 guint8 *
94 gst_net_time_packet_serialize (const GstNetTimePacket * packet)
95 {
96   guint8 *ret;
97
98   g_assert (sizeof (GstClockTime) == 8);
99
100   ret = g_new0 (guint8, GST_NET_TIME_PACKET_SIZE);
101
102   GST_WRITE_UINT64_BE (ret, packet->local_time);
103   GST_WRITE_UINT64_BE (ret + sizeof (GstClockTime), packet->remote_time);
104
105   return ret;
106 }
107
108 /**
109  * gst_net_time_packet_receive:
110  * @fd: a file descriptor created by socket(2)
111  * @addr: a pointer to a sockaddr to hold the address of the sender
112  * @len: a pointer to the size of the data pointed to by @addr
113  *
114  * Receives a #GstNetTimePacket over a socket. Handles interrupted system calls,
115  * but otherwise returns NULL on error. See recvfrom(2) for more information on
116  * how to interpret @sockaddr.
117  *
118  * MT safe. Caller owns return value (g_free to free).
119  *
120  * Returns: The new #GstNetTimePacket.
121  */
122 GstNetTimePacket *
123 gst_net_time_packet_receive (gint fd, struct sockaddr * addr, socklen_t * len)
124 {
125   guint8 buffer[GST_NET_TIME_PACKET_SIZE];
126   gint ret;
127
128   while (TRUE) {
129 #ifdef G_OS_WIN32
130     ret = recvfrom (fd, (char *) buffer, GST_NET_TIME_PACKET_SIZE,
131 #else
132     ret = recvfrom (fd, buffer, GST_NET_TIME_PACKET_SIZE,
133 #endif
134         0, (struct sockaddr *) addr, len);
135     if (ret < 0) {
136       if (errno != EAGAIN && errno != EINTR)
137         goto receive_error;
138       else
139         continue;
140     } else if (ret < GST_NET_TIME_PACKET_SIZE) {
141       goto short_packet;
142     } else {
143       return gst_net_time_packet_new (buffer);
144     }
145   }
146
147 receive_error:
148   {
149     GST_DEBUG ("receive error %d: %s (%d)", ret, g_strerror (errno), errno);
150     return NULL;
151   }
152 short_packet:
153   {
154     GST_DEBUG ("someone sent us a short packet (%d < %d)",
155         ret, GST_NET_TIME_PACKET_SIZE);
156     return NULL;
157   }
158 }
159
160 /**
161  * gst_net_time_packet_send:
162  * @packet: the #GstNetTimePacket
163  * @fd: a file descriptor created by socket(2)
164  * @addr: a pointer to a sockaddr to hold the address of the sender
165  * @len: the size of the data pointed to by @addr
166  *
167  * Sends a #GstNetTimePacket over a socket. Essentially a thin wrapper around
168  * sendto(2) and gst_net_time_packet_serialize(). 
169  *
170  * MT safe.
171  *
172  * Returns: The return value of sendto(2).
173  */
174 gint
175 gst_net_time_packet_send (const GstNetTimePacket * packet, gint fd,
176     struct sockaddr * addr, socklen_t len)
177 {
178 #if defined __CYGWIN__
179   gint fdflags;
180 #elif defined G_OS_WIN32
181   gulong flags;
182 #endif
183
184   guint8 *buffer;
185   gint ret, send_flags;
186
187   g_return_val_if_fail (packet != NULL, -EINVAL);
188
189 #ifdef __CYGWIN__
190   send_flags = 0;
191   fdflags = fcntl (fd, F_GETFL);
192   fcntl (fd, F_SETFL, fdflags | O_NONBLOCK);
193 #elif defined G_OS_WIN32
194   flags = 1;
195   send_flags = 0;
196 #else
197   send_flags = MSG_DONTWAIT;
198 #endif
199
200   buffer = gst_net_time_packet_serialize (packet);
201
202 #ifdef G_OS_WIN32
203   ioctlsocket (fd, FIONBIO, &flags);    /* Set nonblocking mode */
204   ret =
205       sendto (fd, (char *) buffer, GST_NET_TIME_PACKET_SIZE, send_flags, addr,
206       len);
207 #else
208   ret = sendto (fd, buffer, GST_NET_TIME_PACKET_SIZE, send_flags, addr, len);
209 #endif
210
211 #ifdef __CYGWIN__
212   fcntl (fd, F_SETFL, fdflags);
213 #endif
214
215   g_free (buffer);
216
217   return ret;
218 }