2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
5 * gsttcp.c: TCP functions
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.
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.
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.
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
32 #include <string.h> /* memset, in FD_ZERO macro */
34 #include <sys/ioctl.h>
36 #ifdef HAVE_FIONREAD_IN_SYS_FILIO
37 #include <sys/filio.h>
42 #include <gst/gst-i18n-plugin.h>
43 #include <gst/dataprotocol/dataprotocol.h>
45 GST_DEBUG_CATEGORY_EXTERN (tcp_debug);
46 #define GST_CAT_DEFAULT tcp_debug
49 #define MSG_NOSIGNAL 0
52 /* resolve host to IP address, throwing errors if it fails */
53 /* host can already be an IP address */
54 /* returns a newly allocated gchar * with the dotted ip address,
55 or NULL, in which case it already fired an error. */
57 gst_tcp_host_to_ip (GstElement * element, const gchar * host)
59 struct hostent *hostinfo;
64 GST_DEBUG_OBJECT (element, "resolving host %s", host);
66 /* first check if it already is an IP address */
67 if (inet_aton (host, &addr)) {
71 /* FIXME: could do a localhost check here */
73 /* perform a name lookup */
74 if (!(hostinfo = gethostbyname (host)))
77 if (hostinfo->h_addrtype != AF_INET)
80 addrs = hostinfo->h_addr_list;
82 /* There could be more than one IP address, but we just return the first */
83 ip = g_strdup (inet_ntoa (*(struct in_addr *) *addrs));
86 GST_DEBUG_OBJECT (element, "resolved to IP %s", ip);
91 GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, (NULL),
92 ("Could not find IP address for host \"%s\".", host));
97 GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, (NULL),
98 ("host \"%s\" is not an IP host", host));
103 /* write buffer to given socket incrementally.
104 * Returns number of bytes written.
107 gst_tcp_socket_write (int socket, const void *buf, size_t count)
109 size_t bytes_written = 0;
111 while (bytes_written < count) {
112 ssize_t wrote = send (socket, buf + bytes_written,
113 count - bytes_written, MSG_NOSIGNAL);
116 return bytes_written;
118 bytes_written += wrote;
121 if (bytes_written < 0)
122 GST_WARNING ("error while writing");
124 GST_LOG ("wrote %d bytes succesfully", bytes_written);
125 return bytes_written;
128 /* atomically read count bytes into buf, cancellable. return val of GST_FLOW_OK
129 * indicates success, anything else is failure.
132 gst_tcp_socket_read (GstElement * this, int socket, void *buf, size_t count,
143 while (bytes_read < count) {
144 /* do a blocking select on the socket */
146 FD_SET (socket, &testfds);
148 FD_SET (cancel_fd, &testfds);
149 maxfdp1 = MAX (socket, cancel_fd) + 1;
151 /* no action (0) is an error too in our case */
152 if (select (maxfdp1, &testfds, NULL, NULL, 0) <= 0)
155 if (cancel_fd >= 0 && FD_ISSET (cancel_fd, &testfds))
158 /* ask how much is available for reading on the socket */
159 if (ioctl (socket, FIONREAD, &num_to_read) < 0)
162 if (num_to_read == 0)
165 /* sizeof(ssize_t) >= sizeof(int), so I know num_to_read <= SSIZE_MAX */
167 num_to_read = MIN (num_to_read, count - bytes_read);
169 n = read (socket, ((guint8 *) buf) + bytes_read, num_to_read);
177 bytes_read += num_to_read;
185 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
186 ("select failed: %s", g_strerror (errno)));
187 return GST_FLOW_ERROR;
191 GST_DEBUG_OBJECT (this, "Select was cancelled");
192 return GST_FLOW_WRONG_STATE;
196 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
197 ("ioctl failed: %s", g_strerror (errno)));
198 return GST_FLOW_ERROR;
202 GST_DEBUG_OBJECT (this, "Got EOS on socket stream");
203 return GST_FLOW_UNEXPECTED;
207 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
208 ("read failed: %s", g_strerror (errno)));
209 return GST_FLOW_ERROR;
213 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
214 ("short read: wanted %d bytes, got %d", num_to_read, n));
215 return GST_FLOW_ERROR;
219 /* close the socket and reset the fd. Used to clean up after errors. */
221 gst_tcp_socket_close (int *socket)
227 /* read a buffer from the given socket
229 * - a GstBuffer in which data should be read
230 * - NULL, indicating a connection close or an error, to be handled with
234 gst_tcp_read_buffer (GstElement * this, int socket, int cancel_fd,
245 /* do a blocking select on the socket */
247 FD_SET (socket, &testfds);
249 FD_SET (cancel_fd, &testfds);
250 maxfdp1 = MAX (socket, cancel_fd) + 1;
252 /* no action (0) is an error too in our case */
253 if ((ret = select (maxfdp1, &testfds, NULL, NULL, 0)) <= 0)
256 if (cancel_fd >= 0 && FD_ISSET (cancel_fd, &testfds))
259 /* ask how much is available for reading on the socket */
260 if ((ret = ioctl (socket, FIONREAD, &readsize)) < 0)
266 /* sizeof(ssize_t) >= sizeof(int), so I know readsize <= SSIZE_MAX */
268 *buf = gst_buffer_new_and_alloc (readsize);
270 bytes_read = read (socket, GST_BUFFER_DATA (*buf), readsize);
275 if (bytes_read < readsize)
276 /* but mom, you promised to give me readsize bytes! */
279 GST_DEBUG_OBJECT (this, "returning buffer of size %d", GST_BUFFER_SIZE (buf));
285 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
286 ("select failed: %s", g_strerror (errno)));
287 return GST_FLOW_ERROR;
291 GST_DEBUG_OBJECT (this, "Select was cancelled");
292 return GST_FLOW_WRONG_STATE;
296 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
297 ("ioctl failed: %s", g_strerror (errno)));
298 return GST_FLOW_ERROR;
302 GST_DEBUG_OBJECT (this, "Got EOS on socket stream");
303 return GST_FLOW_WRONG_STATE;
307 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
308 ("read failed: %s", g_strerror (errno)));
309 gst_buffer_unref (*buf);
311 return GST_FLOW_ERROR;
315 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
316 ("short read: wanted %d bytes, got %d", readsize, bytes_read));
317 gst_buffer_unref (*buf);
319 return GST_FLOW_ERROR;
323 /* read a buffer from the given socket
325 * - a GstBuffer in which data should be read
326 * - NULL, indicating a connection close or an error, to be handled with
330 gst_tcp_gdp_read_buffer (GstElement * this, int socket, int cancel_fd,
334 guint8 *header = NULL;
336 GST_LOG_OBJECT (this, "Reading %d bytes for buffer packet header",
337 GST_DP_HEADER_LENGTH);
340 header = g_malloc (GST_DP_HEADER_LENGTH);
342 ret = gst_tcp_socket_read (this, socket, header, GST_DP_HEADER_LENGTH,
345 if (ret != GST_FLOW_OK)
346 goto header_read_error;
348 if (!gst_dp_validate_header (GST_DP_HEADER_LENGTH, header))
351 if (gst_dp_header_payload_type (header) != GST_DP_PAYLOAD_BUFFER)
354 GST_LOG_OBJECT (this, "validated buffer packet header");
356 *buf = gst_dp_buffer_from_header (GST_DP_HEADER_LENGTH, header);
360 ret = gst_tcp_socket_read (this, socket, GST_BUFFER_DATA (*buf),
361 GST_BUFFER_SIZE (*buf), cancel_fd);
363 if (ret != GST_FLOW_OK)
364 goto data_read_error;
376 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
377 ("GDP buffer packet header does not validate"));
379 return GST_FLOW_ERROR;
383 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
384 ("GDP packet contains something that is not a buffer (type %d)",
385 gst_dp_header_payload_type (header)));
387 return GST_FLOW_ERROR;
391 gst_buffer_unref (*buf);
398 gst_tcp_gdp_read_caps (GstElement * this, int socket, int cancel_fd,
402 guint8 *header = NULL;
403 guint8 *payload = NULL;
404 size_t payload_length;
406 GST_LOG_OBJECT (this, "Reading %d bytes for caps packet header",
407 GST_DP_HEADER_LENGTH);
410 header = g_malloc (GST_DP_HEADER_LENGTH);
412 ret = gst_tcp_socket_read (this, socket, header, GST_DP_HEADER_LENGTH,
415 if (ret != GST_FLOW_OK)
416 goto header_read_error;
418 if (!gst_dp_validate_header (GST_DP_HEADER_LENGTH, header))
419 goto header_validate_error;
421 if (gst_dp_header_payload_type (header) != GST_DP_PAYLOAD_CAPS)
424 GST_LOG_OBJECT (this, "validated caps packet header");
426 payload_length = gst_dp_header_payload_length (header);
427 payload = g_malloc (payload_length);
429 GST_LOG_OBJECT (this, "Reading %d bytes for caps packet payload",
432 ret = gst_tcp_socket_read (this, socket, payload, payload_length, cancel_fd);
434 if (ret != GST_FLOW_OK)
435 goto payload_read_error;
437 if (!gst_dp_validate_payload (payload_length, header, payload))
438 goto payload_validate_error;
440 *caps = gst_dp_caps_from_packet (GST_DP_HEADER_LENGTH, header, payload);
442 GST_DEBUG_OBJECT (this, "Got caps over GDP: %" GST_PTR_FORMAT, *caps);
455 header_validate_error:
457 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
458 ("GDP caps packet header does not validate"));
460 return GST_FLOW_ERROR;
464 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
465 ("GDP packet contains something that is not a caps (type %d)",
466 gst_dp_header_payload_type (header)));
468 return GST_FLOW_ERROR;
476 payload_validate_error:
478 GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
479 ("GDP caps packet payload does not validate"));
482 return GST_FLOW_ERROR;
486 /* write a GDP header to the socket. Return false if fails. */
488 gst_tcp_gdp_write_buffer (GstElement * this, int socket, GstBuffer * buffer,
489 gboolean fatal, const gchar * host, int port)
495 if (!gst_dp_header_from_buffer (buffer, 0, &length, &header))
498 GST_LOG_OBJECT (this, "writing %d bytes for GDP buffer header", length);
499 wrote = gst_tcp_socket_write (socket, header, length);
511 GST_ELEMENT_ERROR (this, CORE, TOO_LAZY, (NULL),
512 ("Could not create GDP header from buffer"));
518 GST_ELEMENT_ERROR (this, RESOURCE, WRITE,
519 (_("Error while sending data to \"%s:%d\"."), host, port),
520 ("Only %d of %d bytes written: %s",
521 wrote, GST_BUFFER_SIZE (buffer), g_strerror (errno)));
526 /* write GDP header and payload to the given socket for the given caps.
527 * Return false if fails. */
529 gst_tcp_gdp_write_caps (GstElement * this, int socket, const GstCaps * caps,
530 gboolean fatal, const char *host, int port)
537 if (!gst_dp_packet_from_caps (caps, 0, &length, &header, &payload))
540 GST_LOG_OBJECT (this, "writing %d bytes for GDP caps header", length);
541 wrote = gst_tcp_socket_write (socket, header, length);
543 goto write_header_error;
545 length = gst_dp_header_payload_length (header);
548 GST_LOG_OBJECT (this, "writing %d bytes for GDP caps payload", length);
549 wrote = gst_tcp_socket_write (socket, payload, length);
553 goto write_payload_error;
561 GST_ELEMENT_ERROR (this, CORE, TOO_LAZY, (NULL),
562 ("Could not create GDP packet from caps"));
570 GST_ELEMENT_ERROR (this, RESOURCE, WRITE,
571 (_("Error while sending gdp header data to \"%s:%d\"."), host, port),
572 ("Only %d of %d bytes written: %s",
573 wrote, length, g_strerror (errno)));
579 GST_ELEMENT_ERROR (this, RESOURCE, WRITE,
580 (_("Error while sending gdp payload data to \"%s:%d\"."), host, port),
581 ("Only %d of %d bytes written: %s",
582 wrote, length, g_strerror (errno)));