Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / gst / tcp / gsttcp.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
4  *
5  * gsttcp.c: TCP functions
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <netdb.h>
32 #include <unistd.h>
33 #include <sys/ioctl.h>
34
35 #ifdef HAVE_FIONREAD_IN_SYS_FILIO
36 #include <sys/filio.h>
37 #endif
38
39 #include "gsttcp.h"
40 #include <gst/gst-i18n-plugin.h>
41
42 GST_DEBUG_CATEGORY_EXTERN (tcp_debug);
43 #define GST_CAT_DEFAULT tcp_debug
44
45 #ifndef MSG_NOSIGNAL
46 #define MSG_NOSIGNAL 0
47 #endif
48
49 /* resolve host to IP address, throwing errors if it fails */
50 /* host can already be an IP address */
51 /* returns a newly allocated gchar * with the dotted ip address,
52    or NULL, in which case it already fired an error. */
53 gchar *
54 gst_tcp_host_to_ip (GstElement * element, const gchar * host)
55 {
56   struct hostent *hostinfo;
57   char **addrs;
58   gchar *ip;
59   struct in_addr addr;
60
61   GST_DEBUG_OBJECT (element, "resolving host %s", host);
62
63   /* first check if it already is an IP address */
64   if (inet_aton (host, &addr)) {
65     ip = g_strdup (host);
66     goto beach;
67   }
68   /* FIXME: could do a localhost check here */
69
70   /* perform a name lookup */
71   if (!(hostinfo = gethostbyname (host)))
72     goto resolve_error;
73
74   if (hostinfo->h_addrtype != AF_INET)
75     goto not_ip;
76
77   addrs = hostinfo->h_addr_list;
78
79   /* There could be more than one IP address, but we just return the first */
80   ip = g_strdup (inet_ntoa (*(struct in_addr *) *addrs));
81
82 beach:
83   GST_DEBUG_OBJECT (element, "resolved to IP %s", ip);
84   return ip;
85
86 resolve_error:
87   {
88     GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, (NULL),
89         ("Could not find IP address for host \"%s\".", host));
90     return NULL;
91   }
92 not_ip:
93   {
94     GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, (NULL),
95         ("host \"%s\" is not an IP host", host));
96     return NULL;
97   }
98 }
99
100 /* write buffer to given socket incrementally.
101  * Returns number of bytes written.
102  */
103 gint
104 gst_tcp_socket_write (int socket, const void *buf, size_t count)
105 {
106   size_t bytes_written = 0;
107
108   while (bytes_written < count) {
109     ssize_t wrote = send (socket, (const char *) buf + bytes_written,
110         count - bytes_written, MSG_NOSIGNAL);
111
112     if (wrote <= 0) {
113       GST_WARNING ("error while writing");
114       return bytes_written;
115     }
116     bytes_written += wrote;
117   }
118
119   GST_LOG ("wrote %" G_GSIZE_FORMAT " bytes succesfully", bytes_written);
120   return bytes_written;
121 }
122
123 /* atomically read count bytes into buf, cancellable. return val of GST_FLOW_OK
124  * indicates success, anything else is failure.
125  */
126 static GstFlowReturn
127 gst_tcp_socket_read (GstElement * this, int socket, void *buf, size_t count,
128     GstPoll * fdset)
129 {
130   ssize_t n;
131   size_t bytes_read;
132   int num_to_read;
133   int ret;
134
135   bytes_read = 0;
136
137   while (bytes_read < count) {
138     /* do a blocking select on the socket */
139     /* no action (0) is an error too in our case */
140     if ((ret = gst_poll_wait (fdset, GST_CLOCK_TIME_NONE)) <= 0) {
141       if (ret == -1 && errno == EBUSY)
142         goto cancelled;
143       else
144         goto select_error;
145     }
146
147     /* ask how much is available for reading on the socket */
148     if (ioctl (socket, FIONREAD, &num_to_read) < 0)
149       goto ioctl_error;
150
151     if (num_to_read == 0)
152       goto got_eos;
153
154     /* sizeof(ssize_t) >= sizeof(int), so I know num_to_read <= SSIZE_MAX */
155
156     num_to_read = MIN (num_to_read, count - bytes_read);
157
158     n = read (socket, ((guint8 *) buf) + bytes_read, num_to_read);
159
160     if (n < 0)
161       goto read_error;
162
163     if (n < num_to_read)
164       goto short_read;
165
166     bytes_read += num_to_read;
167   }
168
169   return GST_FLOW_OK;
170
171   /* ERRORS */
172 select_error:
173   {
174     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
175         ("select failed: %s", g_strerror (errno)));
176     return GST_FLOW_ERROR;
177   }
178 cancelled:
179   {
180     GST_DEBUG_OBJECT (this, "Select was cancelled");
181     return GST_FLOW_WRONG_STATE;
182   }
183 ioctl_error:
184   {
185     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
186         ("ioctl failed: %s", g_strerror (errno)));
187     return GST_FLOW_ERROR;
188   }
189 got_eos:
190   {
191     GST_DEBUG_OBJECT (this, "Got EOS on socket stream");
192     return GST_FLOW_UNEXPECTED;
193   }
194 read_error:
195   {
196     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
197         ("read failed: %s", g_strerror (errno)));
198     return GST_FLOW_ERROR;
199   }
200 short_read:
201   {
202     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
203         ("short read: wanted %d bytes, got %" G_GSSIZE_FORMAT, num_to_read, n));
204     return GST_FLOW_ERROR;
205   }
206 }
207
208 /* close the socket and reset the fd.  Used to clean up after errors. */
209 void
210 gst_tcp_socket_close (GstPollFD * socket)
211 {
212   if (socket->fd >= 0) {
213     close (socket->fd);
214     socket->fd = -1;
215   }
216 }
217
218 /* read a buffer from the given socket
219  * returns:
220  * - a GstBuffer in which data should be read
221  * - NULL, indicating a connection close or an error, to be handled with
222  *         EOS
223  */
224 GstFlowReturn
225 gst_tcp_read_buffer (GstElement * this, int socket, GstPoll * fdset,
226     GstBuffer ** buf)
227 {
228   int ret;
229   ssize_t bytes_read;
230   int readsize;
231
232   *buf = NULL;
233
234   /* do a blocking select on the socket */
235   /* no action (0) is an error too in our case */
236   if ((ret = gst_poll_wait (fdset, GST_CLOCK_TIME_NONE)) <= 0) {
237     if (ret == -1 && errno == EBUSY)
238       goto cancelled;
239     else
240       goto select_error;
241   }
242
243   /* ask how much is available for reading on the socket */
244   if (ioctl (socket, FIONREAD, &readsize) < 0)
245     goto ioctl_error;
246
247   if (readsize == 0)
248     goto got_eos;
249
250   /* sizeof(ssize_t) >= sizeof(int), so I know readsize <= SSIZE_MAX */
251
252   *buf = gst_buffer_new_and_alloc (readsize);
253
254   bytes_read = read (socket, GST_BUFFER_DATA (*buf), readsize);
255
256   if (bytes_read < 0)
257     goto read_error;
258
259   if (bytes_read < readsize)
260     /* but mom, you promised to give me readsize bytes! */
261     goto short_read;
262
263   GST_LOG_OBJECT (this, "returning buffer of size %d", GST_BUFFER_SIZE (*buf));
264   return GST_FLOW_OK;
265
266   /* ERRORS */
267 select_error:
268   {
269     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
270         ("select failed: %s", g_strerror (errno)));
271     return GST_FLOW_ERROR;
272   }
273 cancelled:
274   {
275     GST_DEBUG_OBJECT (this, "Select was cancelled");
276     return GST_FLOW_WRONG_STATE;
277   }
278 ioctl_error:
279   {
280     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
281         ("ioctl failed: %s", g_strerror (errno)));
282     return GST_FLOW_ERROR;
283   }
284 got_eos:
285   {
286     GST_DEBUG_OBJECT (this, "Got EOS on socket stream");
287     return GST_FLOW_UNEXPECTED;
288   }
289 read_error:
290   {
291     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
292         ("read failed: %s", g_strerror (errno)));
293     gst_buffer_unref (*buf);
294     *buf = NULL;
295     return GST_FLOW_ERROR;
296   }
297 short_read:
298   {
299     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
300         ("short read: wanted %d bytes, got %" G_GSSIZE_FORMAT, readsize,
301             bytes_read));
302     gst_buffer_unref (*buf);
303     *buf = NULL;
304     return GST_FLOW_ERROR;
305   }
306 }
307
308 /* read a buffer from the given socket
309  * returns:
310  * - a GstBuffer in which data should be read
311  * - NULL, indicating a connection close or an error, to be handled with
312  *         EOS
313  */
314 GstFlowReturn
315 gst_tcp_gdp_read_buffer (GstElement * this, int socket, GstPoll * fdset,
316     GstBuffer ** buf)
317 {
318   GstFlowReturn ret;
319   guint8 *header = NULL;
320
321   GST_LOG_OBJECT (this, "Reading %d bytes for buffer packet header",
322       GST_DP_HEADER_LENGTH);
323
324   *buf = NULL;
325   header = g_malloc (GST_DP_HEADER_LENGTH);
326
327   ret = gst_tcp_socket_read (this, socket, header, GST_DP_HEADER_LENGTH, fdset);
328
329   if (ret != GST_FLOW_OK)
330     goto header_read_error;
331
332   if (!gst_dp_validate_header (GST_DP_HEADER_LENGTH, header))
333     goto validate_error;
334
335   if (gst_dp_header_payload_type (header) != GST_DP_PAYLOAD_BUFFER)
336     goto is_not_buffer;
337
338   GST_LOG_OBJECT (this, "validated buffer packet header");
339
340   *buf = gst_dp_buffer_from_header (GST_DP_HEADER_LENGTH, header);
341
342   g_free (header);
343
344   ret = gst_tcp_socket_read (this, socket, GST_BUFFER_DATA (*buf),
345       GST_BUFFER_SIZE (*buf), fdset);
346
347   if (ret != GST_FLOW_OK)
348     goto data_read_error;
349
350   return GST_FLOW_OK;
351
352   /* ERRORS */
353 header_read_error:
354   {
355     g_free (header);
356     return ret;
357   }
358 validate_error:
359   {
360     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
361         ("GDP buffer packet header does not validate"));
362     g_free (header);
363     return GST_FLOW_ERROR;
364   }
365 is_not_buffer:
366   {
367     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
368         ("GDP packet contains something that is not a buffer (type %d)",
369             gst_dp_header_payload_type (header)));
370     g_free (header);
371     return GST_FLOW_ERROR;
372   }
373 data_read_error:
374   {
375     gst_buffer_unref (*buf);
376     *buf = NULL;
377     return ret;
378   }
379 }
380
381 GstFlowReturn
382 gst_tcp_gdp_read_caps (GstElement * this, int socket, GstPoll * fdset,
383     GstCaps ** caps)
384 {
385   GstFlowReturn ret;
386   guint8 *header = NULL;
387   guint8 *payload = NULL;
388   size_t payload_length;
389
390   GST_LOG_OBJECT (this, "Reading %d bytes for caps packet header",
391       GST_DP_HEADER_LENGTH);
392
393   *caps = NULL;
394   header = g_malloc (GST_DP_HEADER_LENGTH);
395
396   ret = gst_tcp_socket_read (this, socket, header, GST_DP_HEADER_LENGTH, fdset);
397
398   if (ret != GST_FLOW_OK)
399     goto header_read_error;
400
401   if (!gst_dp_validate_header (GST_DP_HEADER_LENGTH, header))
402     goto header_validate_error;
403
404   if (gst_dp_header_payload_type (header) != GST_DP_PAYLOAD_CAPS)
405     goto is_not_caps;
406
407   GST_LOG_OBJECT (this, "validated caps packet header");
408
409   payload_length = gst_dp_header_payload_length (header);
410   payload = g_malloc (payload_length);
411
412   GST_LOG_OBJECT (this,
413       "Reading %" G_GSIZE_FORMAT " bytes for caps packet payload",
414       payload_length);
415
416   ret = gst_tcp_socket_read (this, socket, payload, payload_length, fdset);
417
418   if (ret != GST_FLOW_OK)
419     goto payload_read_error;
420
421   if (!gst_dp_validate_payload (GST_DP_HEADER_LENGTH, header, payload))
422     goto payload_validate_error;
423
424   *caps = gst_dp_caps_from_packet (GST_DP_HEADER_LENGTH, header, payload);
425
426   GST_DEBUG_OBJECT (this, "Got caps over GDP: %" GST_PTR_FORMAT, *caps);
427
428   g_free (header);
429   g_free (payload);
430
431   return GST_FLOW_OK;
432
433   /* ERRORS */
434 header_read_error:
435   {
436     g_free (header);
437     return ret;
438   }
439 header_validate_error:
440   {
441     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
442         ("GDP caps packet header does not validate"));
443     g_free (header);
444     return GST_FLOW_ERROR;
445   }
446 is_not_caps:
447   {
448     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
449         ("GDP packet contains something that is not a caps (type %d)",
450             gst_dp_header_payload_type (header)));
451     g_free (header);
452     return GST_FLOW_ERROR;
453   }
454 payload_read_error:
455   {
456     g_free (header);
457     g_free (payload);
458     return ret;
459   }
460 payload_validate_error:
461   {
462     GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
463         ("GDP caps packet payload does not validate"));
464     g_free (header);
465     g_free (payload);
466     return GST_FLOW_ERROR;
467   }
468 }
469
470 /* write a GDP header to the socket.  Return false if fails. */
471 gboolean
472 gst_tcp_gdp_write_buffer (GstElement * this, int socket, GstBuffer * buffer,
473     gboolean fatal, const gchar * host, int port)
474 {
475   guint length;
476   guint8 *header;
477   size_t wrote;
478
479   if (!gst_dp_header_from_buffer (buffer, 0, &length, &header))
480     goto create_error;
481
482   GST_LOG_OBJECT (this, "writing %d bytes for GDP buffer header", length);
483   wrote = gst_tcp_socket_write (socket, header, length);
484   g_free (header);
485
486   if (wrote != length)
487     goto write_error;
488
489   return TRUE;
490
491   /* ERRORS */
492 create_error:
493   {
494     if (fatal)
495       GST_ELEMENT_ERROR (this, CORE, TOO_LAZY, (NULL),
496           ("Could not create GDP header from buffer"));
497     return FALSE;
498   }
499 write_error:
500   {
501     if (fatal)
502       GST_ELEMENT_ERROR (this, RESOURCE, WRITE,
503           (_("Error while sending data to \"%s:%d\"."), host, port),
504           ("Only %" G_GSIZE_FORMAT " of %u bytes written: %s",
505               wrote, GST_BUFFER_SIZE (buffer), g_strerror (errno)));
506     return FALSE;
507   }
508 }
509
510 /* write GDP header and payload to the given socket for the given caps.
511  * Return false if fails. */
512 gboolean
513 gst_tcp_gdp_write_caps (GstElement * this, int socket, const GstCaps * caps,
514     gboolean fatal, const char *host, int port)
515 {
516   guint length;
517   guint8 *header;
518   guint8 *payload;
519   size_t wrote;
520
521   if (!gst_dp_packet_from_caps (caps, 0, &length, &header, &payload))
522     goto create_error;
523
524   GST_LOG_OBJECT (this, "writing %d bytes for GDP caps header", length);
525   wrote = gst_tcp_socket_write (socket, header, length);
526   if (wrote != length)
527     goto write_header_error;
528
529   length = gst_dp_header_payload_length (header);
530   g_free (header);
531
532   GST_LOG_OBJECT (this, "writing %d bytes for GDP caps payload", length);
533   wrote = gst_tcp_socket_write (socket, payload, length);
534   g_free (payload);
535
536   if (wrote != length)
537     goto write_payload_error;
538
539   return TRUE;
540
541   /* ERRORS */
542 create_error:
543   {
544     if (fatal)
545       GST_ELEMENT_ERROR (this, CORE, TOO_LAZY, (NULL),
546           ("Could not create GDP packet from caps"));
547     return FALSE;
548   }
549 write_header_error:
550   {
551     g_free (header);
552     g_free (payload);
553     if (fatal)
554       GST_ELEMENT_ERROR (this, RESOURCE, WRITE,
555           (_("Error while sending gdp header data to \"%s:%d\"."), host, port),
556           ("Only %" G_GSIZE_FORMAT " of %u bytes written: %s",
557               wrote, length, g_strerror (errno)));
558     return FALSE;
559   }
560 write_payload_error:
561   {
562     if (fatal)
563       GST_ELEMENT_ERROR (this, RESOURCE, WRITE,
564           (_("Error while sending gdp payload data to \"%s:%d\"."), host, port),
565           ("Only %" G_GSIZE_FORMAT " of %u bytes written: %s",
566               wrote, length, g_strerror (errno)));
567     return FALSE;
568   }
569 }