6091c15c2c8687ded495df05bc080e476722c474
[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 #ifdef __CYGWIN__
36 # include <unistd.h>
37 # include <fcntl.h>
38 #endif
39
40 #include "gstnettimepacket.h"
41
42
43 /**
44  * gst_net_time_packet_new:
45  * @buffer: a buffer from which to construct the packet, or NULL
46  *
47  * Creates a new #GstNetTimePacket from a buffer received over the network. The
48  * caller is responsible for ensuring that @buffer is at least
49  * #GST_NET_TIME_PACKET_SIZE bytes long.
50  *
51  * If @buffer is #NULL, the local and remote times will be set to
52  * #GST_CLOCK_TIME_NONE.
53  *
54  * MT safe. Caller owns return value (g_free to free).
55  *
56  * Returns: The new #GstNetTimePacket.
57  */
58 GstNetTimePacket *
59 gst_net_time_packet_new (const guint8 * buffer)
60 {
61   GstNetTimePacket *ret;
62
63   g_assert (sizeof (GstClockTime) == 8);
64
65   ret = g_new0 (GstNetTimePacket, 1);
66
67   if (buffer) {
68     ret->local_time = GST_READ_UINT64_BE (buffer);
69     ret->remote_time = GST_READ_UINT64_BE (buffer + sizeof (GstClockTime));
70   } else {
71     ret->local_time = GST_CLOCK_TIME_NONE;
72     ret->remote_time = GST_CLOCK_TIME_NONE;
73   }
74
75   return ret;
76 }
77
78 /**
79  * gst_net_time_packet_serialize:
80  * @packet: the #GstNetTimePacket
81  *
82  * Serialized a #GstNetTimePacket into a newly-allocated sequence of
83  * #GST_NET_TIME_PACKET_SIZE bytes, in network byte order. The value returned is
84  * suitable for passing to write(2) or sendto(2) for communication over the
85  * network.
86  *
87  * MT safe. Caller owns return value (g_free to free).
88  *
89  * Returns: A newly allocated sequence of #GST_NET_TIME_PACKET_SIZE bytes.
90  */
91 guint8 *
92 gst_net_time_packet_serialize (const GstNetTimePacket * packet)
93 {
94   guint8 *ret;
95
96   g_assert (sizeof (GstClockTime) == 8);
97
98   ret = g_new0 (guint8, GST_NET_TIME_PACKET_SIZE);
99
100   GST_WRITE_UINT64_BE (ret, packet->local_time);
101   GST_WRITE_UINT64_BE (ret + sizeof (GstClockTime), packet->remote_time);
102
103   return ret;
104 }
105
106 /**
107  * gst_net_time_packet_receive:
108  * @fd: a file descriptor created by socket(2)
109  * @addr: a pointer to a sockaddr to hold the address of the sender
110  * @len: a pointer to the size of the data pointed to by @addr
111  *
112  * Receives a #GstNetTimePacket over a socket. Handles interrupted system calls,
113  * but otherwise returns NULL on error. See recvfrom(2) for more information on
114  * how to interpret @sockaddr.
115  *
116  * MT safe. Caller owns return value (g_free to free).
117  *
118  * Returns: The new #GstNetTimePacket.
119  */
120 GstNetTimePacket *
121 gst_net_time_packet_receive (gint fd, struct sockaddr * addr, socklen_t * len)
122 {
123   guint8 buffer[GST_NET_TIME_PACKET_SIZE];
124   gint ret;
125
126   while (TRUE) {
127     ret = recvfrom (fd, buffer, GST_NET_TIME_PACKET_SIZE,
128         0, (struct sockaddr *) addr, len);
129     if (ret < 0) {
130       if (errno != EAGAIN && errno != EINTR)
131         goto receive_error;
132       else
133         continue;
134     } else if (ret < GST_NET_TIME_PACKET_SIZE) {
135       goto short_packet;
136     } else {
137       return gst_net_time_packet_new (buffer);
138     }
139   }
140
141 receive_error:
142   {
143     GST_DEBUG ("receive error %d: %s (%d)", ret, g_strerror (errno), errno);
144     return NULL;
145   }
146 short_packet:
147   {
148     GST_DEBUG ("someone sent us a short packet (%d < %d)",
149         ret, GST_NET_TIME_PACKET_SIZE);
150     return NULL;
151   }
152 }
153
154 /**
155  * gst_net_time_packet_send:
156  * @packet: the #GstNetTimePacket
157  * @fd: a file descriptor created by socket(2)
158  * @addr: a pointer to a sockaddr to hold the address of the sender
159  * @len: the size of the data pointed to by @addr
160  *
161  * Sends a #GstNetTimePacket over a socket. Essentially a thin wrapper around
162  * sendto(2) and gst_net_time_packet_serialize(). 
163  *
164  * MT safe.
165  *
166  * Returns: The return value of sendto(2).
167  */
168 gint
169 gst_net_time_packet_send (const GstNetTimePacket * packet, gint fd,
170     struct sockaddr * addr, socklen_t len)
171 {
172 #ifdef __CYGWIN__
173   gint fdflags;
174 #endif
175   guint8 *buffer;
176   gint ret, send_flags;
177
178   g_return_val_if_fail (packet != NULL, -EINVAL);
179
180 #ifdef __CYGWIN__
181   send_flags = 0;
182   fdflags = fcntl (fd, F_GETFL);
183   fcntl (fd, F_SETFL, fdflags | O_NONBLOCK);
184 #else
185   send_flags = MSG_DONTWAIT;
186 #endif
187
188   buffer = gst_net_time_packet_serialize (packet);
189
190   ret = sendto (fd, buffer, GST_NET_TIME_PACKET_SIZE, send_flags, addr, len);
191
192 #ifdef __CYGWIN__
193   fcntl (fd, F_SETFL, fdflags);
194 #endif
195
196   g_free (buffer);
197
198   return ret;
199 }