]> pilppa.org Git - familiar-h63xx-build.git/blob - org.handhelds.familiar/packages/gstreamer/gst-plugins/gst-plugins-0.8.7-httpsrc1.patch
OE tree imported from monotone branch org.openembedded.oz354fam083 at revision 8b12e3...
[familiar-h63xx-build.git] / org.handhelds.familiar / packages / gstreamer / gst-plugins / gst-plugins-0.8.7-httpsrc1.patch
1 diff -urN gst-plugins-0.8.7/gst/tcp/gsthttpclientsrc.c gst-plugins-0.8.7-httpsrc1/gst/tcp/gsthttpclientsrc.c
2 --- gst-plugins-0.8.7/gst/tcp/gsthttpclientsrc.c        1969-12-31 19:00:00.000000000 -0500
3 +++ gst-plugins-0.8.7-httpsrc1/gst/tcp/gsthttpclientsrc.c       2005-03-02 11:08:24.546323513 -0500
4 @@ -0,0 +1,655 @@
5 +/* GStreamer
6 + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
7 + * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
8 + *
9 + * This library is free software; you can redistribute it and/or
10 + * modify it under the terms of the GNU Library General Public
11 + * License as published by the Free Software Foundation; either
12 + * version 2 of the License, or (at your option) any later version.
13 + *
14 + * This library is distributed in the hope that it will be useful,
15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 + * Library General Public License for more details.
18 + *
19 + * You should have received a copy of the GNU Library General Public
20 + * License along with this library; if not, write to the
21 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 + * Boston, MA 02111-1307, USA.
23 + */
24 +
25 +
26 +#ifdef HAVE_CONFIG_H
27 +#include "config.h"
28 +#endif
29 +
30 +#include <gst/gst-i18n-plugin.h>
31 +#include "gsttcp.h"
32 +#include "gsthttpclientsrc.h"
33 +#include <string.h>             /* memset */
34 +#include <unistd.h>
35 +#include <sys/types.h>
36 +#include <sys/socket.h>
37 +#include <netinet/in.h>
38 +#include <arpa/inet.h>
39 +#include <sys/ioctl.h>
40 +#include <netdb.h>
41 +
42 +#ifdef HAVE_FIONREAD_IN_SYS_FILIO
43 +#include <sys/filio.h>
44 +#endif
45 +
46 +GST_DEBUG_CATEGORY (httpclientsrc_debug);
47 +#define GST_CAT_DEFAULT httpclientsrc_debug
48 +
49 +#define MAX_READ_SIZE                  4 * 1024
50 +
51 +/* elementfactory information */
52 +static GstElementDetails gst_httpclientsrc_details =
53 +GST_ELEMENT_DETAILS ("HTTP Client source",
54 +    "Source/Network",
55 +    "Receive data as a client over the network via HTTP",
56 +    "Jamey Hicks <jamey dot hicks at hp dot com> based on tcpclientsrc by Thomas Vander Stichele <thomas at apestaart dot org>");
57 +
58 +/* HttpclientSrc signals and args */
59 +enum
60 +{
61 +  LAST_SIGNAL
62 +};
63 +
64 +enum
65 +{
66 +  ARG_0,
67 +  ARG_LOCATION,
68 +  ARG_METHOD,
69 +  ARG_PROTOCOL
70 +};
71 +
72 +#define HTTP_DEFAULT_METHOD "GET"
73 +
74 +static void gst_httpclientsrc_base_init (gpointer g_class);
75 +static void gst_httpclientsrc_class_init (GstHttpclientSrc * klass);
76 +static void gst_httpclientsrc_init (GstHttpclientSrc * httpclientsrc);
77 +
78 +static GstCaps *gst_httpclientsrc_getcaps (GstPad * pad);
79 +
80 +static GstData *gst_httpclientsrc_get (GstPad * pad);
81 +static GstElementStateReturn gst_httpclientsrc_change_state (GstElement *
82 +    element);
83 +
84 +static void gst_httpclientsrc_set_property (GObject * object, guint prop_id,
85 +    const GValue * value, GParamSpec * pspec);
86 +static void gst_httpclientsrc_get_property (GObject * object, guint prop_id,
87 +    GValue * value, GParamSpec * pspec);
88 +static void gst_httpclientsrc_set_clock (GstElement * element, GstClock * clock);
89 +
90 +static GstElementClass *parent_class = NULL;
91 +
92 +/*static guint gst_httpclientsrc_signals[LAST_SIGNAL] = { 0 }; */
93 +
94 +GType
95 +gst_httpclientsrc_get_type (void)
96 +{
97 +  static GType httpclientsrc_type = 0;
98 +
99 +
100 +  if (!httpclientsrc_type) {
101 +    static const GTypeInfo httpclientsrc_info = {
102 +      sizeof (GstHttpclientSrcClass),
103 +      gst_httpclientsrc_base_init,
104 +      NULL,
105 +      (GClassInitFunc) gst_httpclientsrc_class_init,
106 +      NULL,
107 +      NULL,
108 +      sizeof (GstHttpclientSrc),
109 +      0,
110 +      (GInstanceInitFunc) gst_httpclientsrc_init,
111 +      NULL
112 +    };
113 +
114 +    httpclientsrc_type =
115 +        g_type_register_static (GST_TYPE_ELEMENT, "GstHttpclientSrc",
116 +        &httpclientsrc_info, 0);
117 +  }
118 +  return httpclientsrc_type;
119 +}
120 +
121 +static void
122 +gst_httpclientsrc_base_init (gpointer g_class)
123 +{
124 +  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
125 +
126 +  gst_element_class_set_details (element_class, &gst_httpclientsrc_details);
127 +}
128 +
129 +static void
130 +gst_httpclientsrc_class_init (GstHttpclientSrc * klass)
131 +{
132 +  GObjectClass *gobject_class;
133 +  GstElementClass *gstelement_class;
134 +
135 +  gobject_class = (GObjectClass *) klass;
136 +  gstelement_class = (GstElementClass *) klass;
137 +
138 +  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
139 +
140 +  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION,
141 +      g_param_spec_string ("location", "Source Location (URL)",
142 +          "URL of the data to read", NULL, G_PARAM_READWRITE));
143 +  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_METHOD,
144 +      g_param_spec_string ("method", "HTTP METHOD, defaults to GET",
145 +          "Method of the read request", NULL, G_PARAM_READWRITE));
146 +  g_object_class_install_property (gobject_class, ARG_PROTOCOL,
147 +      g_param_spec_enum ("protocol", "Protocol", "The protocol to wrap data in",
148 +          GST_TYPE_TCP_PROTOCOL_TYPE, GST_TCP_PROTOCOL_TYPE_NONE,
149 +          G_PARAM_READWRITE));
150 +
151 +  gobject_class->set_property = gst_httpclientsrc_set_property;
152 +  gobject_class->get_property = gst_httpclientsrc_get_property;
153 +
154 +  gstelement_class->change_state = gst_httpclientsrc_change_state;
155 +  gstelement_class->set_clock = gst_httpclientsrc_set_clock;
156 +
157 +  GST_DEBUG_CATEGORY_INIT (httpclientsrc_debug, "httpclientsrc", 0,
158 +      "HTTP Client Source");
159 +}
160 +
161 +static void
162 +gst_httpclientsrc_set_clock (GstElement * element, GstClock * clock)
163 +{
164 +  GstHttpclientSrc *httpclientsrc;
165 +
166 +  httpclientsrc = GST_HTTPCLIENTSRC (element);
167 +
168 +  httpclientsrc->clock = clock;
169 +}
170 +
171 +static void
172 +gst_httpclientsrc_init (GstHttpclientSrc * this)
173 +{
174 +  /* create the src pad */
175 +  this->srcpad = gst_pad_new ("src", GST_PAD_SRC);
176 +  gst_element_add_pad (GST_ELEMENT (this), this->srcpad);
177 +  gst_pad_set_get_function (this->srcpad, gst_httpclientsrc_get);
178 +  gst_pad_set_getcaps_function (this->srcpad, gst_httpclientsrc_getcaps);
179 +
180 +  this->port = TCP_DEFAULT_PORT;
181 +  this->method = g_strdup(HTTP_DEFAULT_METHOD);
182 +  this->location = NULL;
183 +  this->host = NULL;
184 +  this->clock = NULL;
185 +  this->sock_fd = -1;
186 +  this->protocol = GST_TCP_PROTOCOL_TYPE_NONE;
187 +  this->curoffset = 0;
188 +  this->caps = NULL;
189 +
190 +  GST_FLAG_UNSET (this, GST_HTTPCLIENTSRC_OPEN);
191 +}
192 +
193 +static GstCaps *
194 +gst_httpclientsrc_getcaps (GstPad * pad)
195 +{
196 +  GstHttpclientSrc *src;
197 +  GstCaps *caps = NULL;
198 +
199 +  src = GST_HTTPCLIENTSRC (GST_OBJECT_PARENT (pad));
200 +
201 +  if (!GST_FLAG_IS_SET (src, GST_HTTPCLIENTSRC_OPEN))
202 +    caps = gst_caps_new_any ();
203 +  else if (src->caps)
204 +    caps = gst_caps_copy (src->caps);
205 +  else
206 +    caps = gst_caps_new_any ();
207 +  GST_DEBUG_OBJECT (src, "returning caps %" GST_PTR_FORMAT, caps);
208 +  g_assert (GST_IS_CAPS (caps));
209 +  return caps;
210 +}
211 +
212 +static GstData *
213 +gst_httpclientsrc_get (GstPad * pad)
214 +{
215 +  GstHttpclientSrc *src;
216 +  size_t readsize;
217 +  int ret;
218 +
219 +  GstData *data = NULL;
220 +  GstBuffer *buf = NULL;
221 +
222 +  g_return_val_if_fail (pad != NULL, NULL);
223 +  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
224 +  src = GST_HTTPCLIENTSRC (GST_OBJECT_PARENT (pad));
225 +  g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_HTTPCLIENTSRC_OPEN), NULL);
226 +
227 +  /* try to negotiate here */
228 +  if (!gst_pad_is_negotiated (pad)) {
229 +    if (GST_PAD_LINK_FAILED (gst_pad_renegotiate (pad))) {
230 +      GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL), GST_ERROR_SYSTEM);
231 +      gst_buffer_unref (buf);
232 +      return GST_DATA (gst_event_new (GST_EVENT_EOS));
233 +    }
234 +  }
235 +
236 +  /* if we have a left over buffer after a discont, return that */
237 +  if (src->buffer_after_discont) {
238 +    buf = src->buffer_after_discont;
239 +    GST_LOG_OBJECT (src,
240 +        "Returning buffer after discont of size %d, ts %"
241 +        GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
242 +        ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
243 +        GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
244 +        GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
245 +        GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf));
246 +    src->buffer_after_discont = NULL;
247 +    return GST_DATA (buf);
248 +  }
249 +
250 +  /* read the buffer header if we're using a protocol */
251 +  switch (src->protocol) {
252 +      fd_set testfds;
253 +
254 +    case GST_TCP_PROTOCOL_TYPE_NONE:
255 +      /* do a blocking select on the socket */
256 +      FD_ZERO (&testfds);
257 +      FD_SET (src->sock_fd, &testfds);
258 +      ret = select (src->sock_fd + 1, &testfds, (fd_set *) 0, (fd_set *) 0, 0);
259 +      /* no action (0) is an error too in our case */
260 +      if (ret <= 0) {
261 +        GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
262 +            ("select failed: %s", g_strerror (errno)));
263 +        return GST_DATA (gst_event_new (GST_EVENT_EOS));
264 +      }
265 +
266 +      /* ask how much is available for reading on the socket */
267 +      ret = ioctl (src->sock_fd, FIONREAD, &readsize);
268 +      if (ret < 0) {
269 +        GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
270 +            ("ioctl failed: %s", g_strerror (errno)));
271 +        return GST_DATA (gst_event_new (GST_EVENT_EOS));
272 +      }
273 +      GST_LOG_OBJECT (src, "ioctl says %d bytes available", readsize);
274 +      buf = gst_buffer_new_and_alloc (readsize);
275 +      break;
276 +    case GST_TCP_PROTOCOL_TYPE_GDP:
277 +      if (!(data = gst_tcp_gdp_read_header (GST_ELEMENT (src), src->sock_fd))) {
278 +        GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
279 +            ("Could not read data header through GDP"));
280 +        return GST_DATA (gst_event_new (GST_EVENT_EOS));
281 +      }
282 +      if (GST_IS_EVENT (data))
283 +        return data;
284 +      buf = GST_BUFFER (data);
285 +
286 +      GST_LOG_OBJECT (src, "Going to read data from socket into buffer %p",
287 +          buf);
288 +      /* use this new buffer to read data into */
289 +      readsize = GST_BUFFER_SIZE (buf);
290 +      break;
291 +    default:
292 +      g_warning ("Unhandled protocol type");
293 +      break;
294 +  }
295 +
296 +  GST_LOG_OBJECT (src, "Reading %d bytes", readsize);
297 +  ret = gst_tcp_socket_read (src->sock_fd, GST_BUFFER_DATA (buf), readsize);
298 +  if (ret < 0) {
299 +    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
300 +    gst_buffer_unref (buf);
301 +    return GST_DATA (gst_event_new (GST_EVENT_EOS));
302 +  }
303 +
304 +  /* if we read 0 bytes, and we're blocking, we hit eos */
305 +  if (ret == 0) {
306 +    GST_DEBUG ("blocking read returns 0, EOS");
307 +    gst_buffer_unref (buf);
308 +    gst_element_set_eos (GST_ELEMENT (src));
309 +    return GST_DATA (gst_event_new (GST_EVENT_EOS));
310 +  }
311 +
312 +  readsize = ret;
313 +  GST_BUFFER_SIZE (buf) = readsize;
314 +  GST_BUFFER_MAXSIZE (buf) = readsize;
315 +
316 +  /* FIXME: we could decide to set OFFSET and OFFSET_END for non-protocol
317 +   * streams to mean the bytes processed */
318 +
319 +  /* if this is our first buffer, we need to send a discont with the
320 +   * given timestamp or the current offset, and store the buffer for
321 +   * the next iteration through the get loop */
322 +  if (src->send_discont) {
323 +    GstClockTime timestamp;
324 +    GstEvent *event;
325 +
326 +    src->send_discont = FALSE;
327 +    src->buffer_after_discont = buf;
328 +    /* if the timestamp is valid, send a timed discont
329 +     * taking into account the incoming buffer's timestamps */
330 +    timestamp = GST_BUFFER_TIMESTAMP (buf);
331 +    if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
332 +      GST_DEBUG_OBJECT (src,
333 +          "sending discontinuous with timestamp %" GST_TIME_FORMAT,
334 +          GST_TIME_ARGS (timestamp));
335 +      event =
336 +          gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, timestamp, NULL);
337 +      return GST_DATA (event);
338 +    }
339 +    /* otherwise, send an offset discont */
340 +    GST_DEBUG_OBJECT (src, "sending discontinuous with offset %d",
341 +        src->curoffset);
342 +    event =
343 +        gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, src->curoffset,
344 +        NULL);
345 +    return GST_DATA (event);
346 +  }
347 +
348 +  src->curoffset += readsize;
349 +  GST_LOG_OBJECT (src,
350 +      "Returning buffer from _get of size %d, ts %"
351 +      GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
352 +      ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
353 +      GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
354 +      GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
355 +      GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf));
356 +  return GST_DATA (buf);
357 +}
358 +
359 +static void
360 +gst_httpclientsrc_set_property (GObject * object, guint prop_id,
361 +                               const GValue * value, GParamSpec * pspec)
362 +{
363 +  GstHttpclientSrc *httpclientsrc;
364 +
365 +
366 +  /* it's not null if we got it, but it might not be ours */
367 +  g_return_if_fail (GST_IS_HTTPCLIENTSRC (object));
368 +  httpclientsrc = GST_HTTPCLIENTSRC (object);
369 +
370 +  GST_DEBUG_OBJECT (httpclientsrc, "setting property %d", prop_id);
371 +
372 +  switch (prop_id) {
373 +  case ARG_LOCATION: {
374 +    gchar *pathstart = NULL;
375 +    gchar *location = NULL;
376 +    gchar *hostport = NULL;
377 +    gchar *portstart = NULL;
378 +    int locationlen;
379 +    g_free (httpclientsrc->location);
380 +    g_free (httpclientsrc->host);
381 +    g_free (httpclientsrc->path);
382 +    httpclientsrc->location = location = g_strdup (g_value_get_string (value));
383 +    GST_DEBUG_OBJECT (httpclientsrc, "setting location=%s", location);
384 +
385 +    if (strncmp(location, "http://", 7) != 0)
386 +      return;
387 +    locationlen = strlen(location);
388 +    hostport = location + 7;
389 +    GST_DEBUG_OBJECT (httpclientsrc, "    hostport=%s", hostport);
390 +
391 +    pathstart = strchr(hostport, '/');
392 +    GST_DEBUG_OBJECT (httpclientsrc, "    pathstart=%s", pathstart);
393 +
394 +    if (pathstart) {
395 +      httpclientsrc->path = g_strdup(pathstart);
396 +    } else {
397 +      httpclientsrc->path = g_strdup("/");
398 +      pathstart = location+locationlen;
399 +    }
400 +    hostport = g_strndup(hostport, pathstart - hostport);
401 +    portstart = strrchr(hostport, ':');
402 +    GST_DEBUG_OBJECT (httpclientsrc, "    hostport=%s portstart=%s", hostport, portstart);
403 +    if (portstart != NULL) {
404 +      httpclientsrc->host = g_strndup(hostport, portstart - hostport);
405 +      httpclientsrc->port = strtoul(portstart+1, NULL, 0);
406 +      g_free(hostport);
407 +    } else {
408 +      httpclientsrc->host = hostport;
409 +      httpclientsrc->port = 80;
410 +    }
411 +    GST_DEBUG_OBJECT (httpclientsrc, "    host=%s port=%d path=%s", httpclientsrc->host, httpclientsrc->port, httpclientsrc->path);
412 +  } break;
413 +  case ARG_METHOD:
414 +    g_free (httpclientsrc->method);
415 +    httpclientsrc->method = g_strdup (g_value_get_string (value));
416 +    break;
417 +  case ARG_PROTOCOL:
418 +    httpclientsrc->protocol = g_value_get_enum (value);
419 +    break;
420 +
421 +  default:
422 +    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
423 +    break;
424 +  }
425 +}
426 +
427 +static void
428 +gst_httpclientsrc_get_property (GObject * object, guint prop_id, GValue * value,
429 +    GParamSpec * pspec)
430 +{
431 +  GstHttpclientSrc *httpclientsrc;
432 +
433 +  g_return_if_fail (GST_IS_HTTPCLIENTSRC (object));
434 +  httpclientsrc = GST_HTTPCLIENTSRC (object);
435 +
436 +  switch (prop_id) {
437 +    case ARG_LOCATION:
438 +      g_value_set_string (value, httpclientsrc->location);
439 +      break;
440 +    case ARG_METHOD:
441 +      g_value_set_string (value, httpclientsrc->method);
442 +      break;
443 +    case ARG_PROTOCOL:
444 +      g_value_set_enum (value, httpclientsrc->protocol);
445 +      break;
446 +
447 +    default:
448 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
449 +      break;
450 +  }
451 +}
452 +
453 +/* create a socket for connecting to remote server */
454 +static gboolean
455 +gst_httpclientsrc_init_receive (GstHttpclientSrc * this)
456 +{
457 +  int ret;
458 +  gchar ip[256];
459 +  struct addrinfo *addrinfo, *top_addrinfo;
460 +  int addr_family;
461 +  gchar *request = NULL;
462 +
463 +  GST_DEBUG_OBJECT (this, "getaddrinfo %s", this->host);
464 +  ret = getaddrinfo(this->host, "http", NULL, &addrinfo);
465 +  top_addrinfo = addrinfo;
466 +
467 + retry:
468 +  this->addr_family = addr_family = addrinfo->ai_family;
469 +  this->server_addrlen = addrinfo->ai_addrlen;
470 +  memset(&this->server_sockaddr, 0, sizeof(this->server_sockaddr));
471 +  memcpy(&this->server_sockaddr, addrinfo->ai_addr, addrinfo->ai_addrlen);
472 +
473 +  /* create receiving client socket */
474 +  GST_DEBUG_OBJECT (this, "opening receiving client socket to %s:%d\n",
475 +      this->host, this->port);
476 +  if ((this->sock_fd = socket (this->addr_family, SOCK_STREAM, 0)) == -1) {
477 +    GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL), GST_ERROR_SYSTEM);
478 +    return FALSE;
479 +  }
480 +  GST_DEBUG_OBJECT (this, "opened receiving client socket with fd %d",
481 +      this->sock_fd);
482 +
483 +  /* look up name if we need to */
484 +  GST_DEBUG_OBJECT (this, "IP address for host %s is %s", this->host, ip);
485 +
486 +  /* fill in port */
487 +  switch (this->addr_family) {
488 +  case AF_INET:
489 +    ((struct sockaddr_in *)&this->server_sockaddr)->sin_port = htons(this->port);
490 +    inet_ntop(this->addr_family, &(((struct sockaddr_in *)&this->server_sockaddr)->sin_addr), ip, sizeof(ip)); 
491 +    break;
492 +  case AF_INET6:
493 +    ((struct sockaddr_in6 *)&this->server_sockaddr)->sin6_port = htons(this->port);
494 +    inet_ntop(this->addr_family, &(((struct sockaddr_in6 *)&this->server_sockaddr)->sin6_addr), ip, sizeof(ip)); 
495 +    break;
496 +  }
497 +  if (this->addr_family == AF_INET6) { 
498 +    int offset = 0;
499 +    int i;
500 +    struct in6_addr *in6_addr = &(((struct sockaddr_in6 *)&this->server_sockaddr)->sin6_addr);
501 +    for (i = 0; i < sizeof(struct in6_addr); i++) {
502 +      int b = in6_addr->s6_addr[i];
503 +      offset += sprintf(ip+offset, ":%02x", b);
504 +    }
505 +  }
506 +
507 +  /* connect to server */
508 +  GST_DEBUG_OBJECT (this, "connecting to server family=%d ip=%s port=%d sockaddrlen=%d",
509 +                   this->addr_family, ip, this->port, this->server_addrlen);
510 +  ret = connect (this->sock_fd, (struct sockaddr *) &this->server_sockaddr, this->server_addrlen);
511 +
512 +  if (ret) {
513 +    switch (errno) {
514 +      case ECONNREFUSED:
515 +        GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ,
516 +            (_("Connection to %s:%d refused."), this->host, this->port),
517 +            (NULL));
518 +        if (addrinfo->ai_next == NULL)
519 +         return FALSE;
520 +        break;
521 +      default:
522 +        GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
523 +            ("connect to %s:%d failed: %s", this->host, this->port,
524 +                g_strerror (errno)));
525 +        if (addrinfo->ai_next == NULL)
526 +         return FALSE;
527 +        break;
528 +    }
529 +    addrinfo = addrinfo->ai_next;
530 +    if (addrinfo) {
531 +      GST_DEBUG_OBJECT(this, "retrying with addrinfo %p", addrinfo);
532 +      goto retry;
533 +    }
534 +  }
535 +
536 +  /* send request and headers */
537 +  request = g_strdup_printf("%s %s HTTP/1.0\r\nHost: %s\r\n\r\n",
538 +                           this->method, this->path, this->host);
539 +  GST_DEBUG_OBJECT(this, "sending request %s", request);
540 +  if (gst_tcp_socket_write(this->sock_fd, request, strlen(request)) < 0) {
541 +        GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
542 +            ("sending HTTP request to %s failed: %s", this->location,
543 +                g_strerror (errno)));
544 +        return FALSE;
545 +  }
546 +  g_free(request);
547 +
548 +  
549 +  /* receive and discard headers */
550 +  {
551 +    char responseline[12];
552 +    int rc;
553 +    /* receive response line (HTTP/1.x NNN) */
554 +    if ((rc = gst_tcp_socket_read(this->sock_fd, responseline, sizeof(responseline))) < 0) {
555 +      GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
556 +                        ("reading HTTP response from %s failed: %s", this->location,
557 +                         g_strerror (errno)));
558 +      return FALSE;
559 +    }
560 +    GST_DEBUG_OBJECT(this, "got %d byte response %s", rc, responseline);
561 +
562 +    enum response_state {
563 +      RESPONSE_CHAR,
564 +      RESPONSE_CR,
565 +      RESPONSE_CRLF,
566 +      RESPONSE_CRLFCR,
567 +      RESPONSE_END_OF_HEADERS /* saw crlfcrlf */
568 +    } response_state = RESPONSE_CHAR;
569 +    while (response_state != RESPONSE_END_OF_HEADERS) {
570 +      gchar ch;
571 +      if (gst_tcp_socket_read(this->sock_fd, &ch, sizeof(ch)) < 0) {
572 +        GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
573 +                          ("reading HTTP response from %s failed: %s", this->location,
574 +                           g_strerror (errno)));
575 +        return FALSE;
576 +      }
577 +      switch (ch) {
578 +      case '\n':
579 +       switch (response_state) {
580 +       case RESPONSE_CR: response_state = RESPONSE_CRLF; break;
581 +       case RESPONSE_CRLFCR: response_state = RESPONSE_END_OF_HEADERS; break;
582 +       default: response_state = RESPONSE_CHAR;
583 +       } break;        
584 +      case '\r':
585 +       switch (response_state) {
586 +       case RESPONSE_CRLF: response_state = RESPONSE_CRLFCR; break;
587 +       default: response_state = RESPONSE_CR;
588 +       } break;
589 +      default:
590 +       response_state = RESPONSE_CHAR;
591 +      }
592 +    }
593 +  }
594 +
595 +  this->send_discont = TRUE;
596 +  this->buffer_after_discont = NULL;
597 +  GST_FLAG_SET (this, GST_HTTPCLIENTSRC_OPEN);
598 +
599 +  /* get the caps if we're using GDP */
600 +  if (this->protocol == GST_TCP_PROTOCOL_TYPE_GDP) {
601 +    /* if we haven't received caps yet, we should get them first */
602 +    if (!this->caps_received) {
603 +      GstCaps *caps;
604 +
605 +      GST_DEBUG_OBJECT (this, "getting caps through GDP");
606 +      if (!(caps = gst_tcp_gdp_read_caps (GST_ELEMENT (this), this->sock_fd))) {
607 +        GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
608 +            ("Could not read caps through GDP"));
609 +        return FALSE;
610 +      }
611 +      if (!GST_IS_CAPS (caps)) {
612 +        GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
613 +            ("Could not read caps through GDP"));
614 +        return FALSE;
615 +      }
616 +      GST_DEBUG_OBJECT (this, "Received caps through GDP: %" GST_PTR_FORMAT,
617 +          caps);
618 +      this->caps_received = TRUE;
619 +      this->caps = caps;
620 +    }
621 +  }
622 +  return TRUE;
623 +}
624 +
625 +static void
626 +gst_httpclientsrc_close (GstHttpclientSrc * this)
627 +{
628 +  if (this->sock_fd != -1) {
629 +    close (this->sock_fd);
630 +    this->sock_fd = -1;
631 +  }
632 +  this->caps_received = FALSE;
633 +  if (this->caps) {
634 +    gst_caps_free (this->caps);
635 +    this->caps = NULL;
636 +  }
637 +  GST_FLAG_UNSET (this, GST_HTTPCLIENTSRC_OPEN);
638 +}
639 +
640 +static GstElementStateReturn
641 +gst_httpclientsrc_change_state (GstElement * element)
642 +{
643 +  g_return_val_if_fail (GST_IS_HTTPCLIENTSRC (element), GST_STATE_FAILURE);
644 +
645 +  if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
646 +    if (GST_FLAG_IS_SET (element, GST_HTTPCLIENTSRC_OPEN))
647 +      gst_httpclientsrc_close (GST_HTTPCLIENTSRC (element));
648 +  } else {
649 +    if (!GST_FLAG_IS_SET (element, GST_HTTPCLIENTSRC_OPEN)) {
650 +      if (!gst_httpclientsrc_init_receive (GST_HTTPCLIENTSRC (element)))
651 +        return GST_STATE_FAILURE;
652 +    }
653 +  }
654 +
655 +  if (GST_ELEMENT_CLASS (parent_class)->change_state)
656 +    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
657 +
658 +  return GST_STATE_SUCCESS;
659 +}
660 diff -urN gst-plugins-0.8.7/gst/tcp/gsthttpclientsrc.h gst-plugins-0.8.7-httpsrc1/gst/tcp/gsthttpclientsrc.h
661 --- gst-plugins-0.8.7/gst/tcp/gsthttpclientsrc.h        1969-12-31 19:00:00.000000000 -0500
662 +++ gst-plugins-0.8.7-httpsrc1/gst/tcp/gsthttpclientsrc.h       2005-03-02 09:47:01.640623151 -0500
663 @@ -0,0 +1,98 @@
664 +/* GStreamer
665 + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
666 + * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
667 + *
668 + * This library is free software; you can redistribute it and/or
669 + * modify it under the terms of the GNU Library General Public
670 + * License as published by the Free Software Foundation; either
671 + * version 2 of the License, or (at your option) any later version.
672 + *
673 + * This library is distributed in the hope that it will be useful,
674 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
675 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
676 + * Library General Public License for more details.
677 + *
678 + * You should have received a copy of the GNU Library General Public
679 + * License along with this library; if not, write to the
680 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
681 + * Boston, MA 02111-1307, USA.
682 + */
683 +
684 +
685 +#ifndef __GST_HTTPCLIENTSRC_H__
686 +#define __GST_HTTPCLIENTSRC_H__
687 +
688 +#include <gst/gst.h>
689 +
690 +#ifdef __cplusplus
691 +extern "C" {
692 +#endif /* __cplusplus */
693 +
694 +#include <netdb.h>                        /* sockaddr_in */
695 +#include <netinet/in.h>                          /* sockaddr_in */
696 +#include <unistd.h>
697 +#include "gsttcp.h"
698 +
699 +#define GST_TYPE_HTTPCLIENTSRC \
700 +  (gst_httpclientsrc_get_type())
701 +#define GST_HTTPCLIENTSRC(obj) \
702 +  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_HTTPCLIENTSRC,GstHttpclientSrc))
703 +#define GST_HTTPCLIENTSRC_CLASS(klass) \
704 +  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_HTTPCLIENTSRC,GstHttpclientSrc))
705 +#define GST_IS_HTTPCLIENTSRC(obj) \
706 +  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_HTTPCLIENTSRC))
707 +#define GST_IS_HTTPCLIENTSRC_CLASS(obj) \
708 +  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_HTTPCLIENTSRC))
709 +
710 +typedef struct _GstHttpclientSrc GstHttpclientSrc;
711 +typedef struct _GstHttpclientSrcClass GstHttpclientSrcClass;
712 +
713 +typedef enum GstHttpclientSrcFlags {
714 +  GST_HTTPCLIENTSRC_OPEN       = GST_ELEMENT_FLAG_LAST,
715 +
716 +  GST_HTTPCLIENTSRC_FLAG_LAST,
717 +} GstHttpclientSrcFlags;
718 +
719 +struct _GstHttpclientSrc {
720 +  GstElement element;
721 +
722 +  /* pad */
723 +  GstPad *srcpad;
724 +
725 +  /* server information */
726 +  int port;
727 +  int addr_family;
728 +  gchar *method;
729 +  gchar *host;
730 +  gchar *path;
731 +  gchar *location; /* url */
732 +  struct sockaddr_storage server_sockaddr;
733 +  int server_addrlen;
734 +
735 +  /* socket */
736 +  int sock_fd;
737 +
738 +  /* number of bytes we've gotten */
739 +  off_t curoffset;
740 +
741 +  GstTCPProtocolType protocol; /* protocol used for reading data */
742 +  gboolean caps_received;      /* if we have received caps yet */
743 +  GstCaps *caps;
744 +  GstClock *clock;
745 +
746 +  gboolean send_discont;       /* TRUE when we need to send a discont */
747 +  GstBuffer *buffer_after_discont; /* temporary storage for buffer */
748 +};
749 +
750 +struct _GstHttpclientSrcClass {
751 +  GstElementClass parent_class;
752 +};
753 +
754 +GType gst_httpclientsrc_get_type (void);
755 +
756 +
757 +#ifdef __cplusplus
758 +}
759 +#endif /* __cplusplus */
760 +
761 +#endif /* __GST_HTTPCLIENTSRC_H__ */
762 diff -urN gst-plugins-0.8.7/gst/tcp/gsttcpplugin.c gst-plugins-0.8.7-httpsrc1/gst/tcp/gsttcpplugin.c
763 --- gst-plugins-0.8.7/gst/tcp/gsttcpplugin.c    2004-11-05 12:15:10.000000000 -0500
764 +++ gst-plugins-0.8.7-httpsrc1/gst/tcp/gsttcpplugin.c   2005-03-02 09:59:33.003801791 -0500
765 @@ -23,6 +23,7 @@
766  
767  #include "gsttcpsrc.h"
768  #include "gsttcpsink.h"
769 +#include "gsthttpclientsrc.h"
770  #include "gsttcpclientsrc.h"
771  #include "gsttcpclientsink.h"
772  #include "gsttcpserversrc.h"
773 @@ -59,6 +60,9 @@
774    if (!gst_element_register (plugin, "multifdsink", GST_RANK_NONE,
775            GST_TYPE_MULTIFDSINK))
776      return FALSE;
777 +  if (!gst_element_register (plugin, "httpclientsrc", GST_RANK_NONE,
778 +          GST_TYPE_HTTPCLIENTSRC))
779 +    return FALSE;
780  
781    GST_DEBUG_CATEGORY_INIT (tcp_debug, "tcp", 0, "TCP calls");
782  
783 diff -urN gst-plugins-0.8.7/gst/tcp/Makefile.am gst-plugins-0.8.7-httpsrc1/gst/tcp/Makefile.am
784 --- gst-plugins-0.8.7/gst/tcp/Makefile.am       2004-11-02 02:41:44.000000000 -0500
785 +++ gst-plugins-0.8.7-httpsrc1/gst/tcp/Makefile.am      2005-03-02 09:29:30.125528594 -0500
786 @@ -18,6 +18,7 @@
787         gsttcp.c \
788         gstfdset.c \
789         gstmultifdsink.c  \
790 +       gsthttpclientsrc.c \
791         gsttcpclientsrc.c gsttcpclientsink.c \
792         gsttcpserversrc.c gsttcpserversink.c
793  
794 @@ -35,6 +36,7 @@
795    gsttcp.h \
796    gstfdset.h \
797    gstmultifdsink.h  \
798 +  gsthttpclientsrc.h \
799    gsttcpclientsrc.h gsttcpclientsink.h \
800    gsttcpserversrc.h gsttcpserversink.h
801  
802 diff -urN gst-plugins-0.8.7/gst/tcp/Makefile.in gst-plugins-0.8.7-httpsrc1/gst/tcp/Makefile.in
803 --- gst-plugins-0.8.7/gst/tcp/Makefile.in       2005-01-05 05:47:55.000000000 -0500
804 +++ gst-plugins-0.8.7-httpsrc1/gst/tcp/Makefile.in      2005-03-02 09:33:30.515512648 -0500
805 @@ -99,7 +99,8 @@
806  am_libgsttcp_la_OBJECTS = libgsttcp_la-gsttcpplugin.lo \
807         libgsttcp_la-gsttcpsrc.lo libgsttcp_la-gsttcpsink.lo \
808         libgsttcp_la-gsttcp.lo libgsttcp_la-gstfdset.lo \
809 -       libgsttcp_la-gstmultifdsink.lo libgsttcp_la-gsttcpclientsrc.lo \
810 +       libgsttcp_la-gstmultifdsink.lo libgsttcp_la-gsthttpclientsrc.lo \
811 +       libgsttcp_la-gsttcpclientsrc.lo \
812         libgsttcp_la-gsttcpclientsink.lo \
813         libgsttcp_la-gsttcpserversrc.lo \
814         libgsttcp_la-gsttcpserversink.lo
815 @@ -730,6 +731,7 @@
816         gsttcp.c \
817         gstfdset.c \
818         gstmultifdsink.c  \
819 +       gsthttpclientsrc.c \
820         gsttcpclientsrc.c gsttcpclientsink.c \
821         gsttcpserversrc.c gsttcpserversink.c
822  
823 @@ -747,7 +749,7 @@
824    gsttcp.h \
825    gstfdset.h \
826    gstmultifdsink.h  \
827 -  gsttcpclientsrc.h gsttcpclientsink.h \
828 +  gsthttpclientsrc.h gsttcpclientsrc.h gsttcpclientsink.h \
829    gsttcpserversrc.h gsttcpserversink.h
830  
831  CLEANFILES = $(BUILT_SOURCES)
832 @@ -844,6 +846,7 @@
833  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsttcp.Plo@am__quote@
834  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsttcpclientsink.Plo@am__quote@
835  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsttcpclientsrc.Plo@am__quote@
836 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsthttpclientsrc.Plo@am__quote@
837  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsttcpplugin.Plo@am__quote@
838  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsttcpserversink.Plo@am__quote@
839  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsttcpserversrc.Plo@am__quote@
840 @@ -913,6 +916,13 @@
841  @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
842  @am__fastdepCC_FALSE@  $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttcp_la_CFLAGS) $(CFLAGS) -c -o libgsttcp_la-gstmultifdsink.lo `test -f 'gstmultifdsink.c' || echo '$(srcdir)/'`gstmultifdsink.c
843  
844 +libgsttcp_la-gsthttpclientsrc.lo: gsthttpclientsrc.c
845 +@am__fastdepCC_TRUE@   if $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttcp_la_CFLAGS) $(CFLAGS) -MT libgsttcp_la-gsthttpclientsrc.lo -MD -MP -MF "$(DEPDIR)/libgsttcp_la-gsthttpclientsrc.Tpo" -c -o libgsttcp_la-gsthttpclientsrc.lo `test -f 'gsthttpclientsrc.c' || echo '$(srcdir)/'`gsthttpclientsrc.c; \
846 +@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/libgsttcp_la-gsthttpclientsrc.Tpo" "$(DEPDIR)/libgsttcp_la-gsthttpclientsrc.Plo"; else rm -f "$(DEPDIR)/libgsttcp_la-gsthttpclientsrc.Tpo"; exit 1; fi
847 +@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='gsthttpclientsrc.c' object='libgsttcp_la-gsthttpclientsrc.lo' libtool=yes @AMDEPBACKSLASH@
848 +@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
849 +@am__fastdepCC_FALSE@  $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttcp_la_CFLAGS) $(CFLAGS) -c -o libgsttcp_la-gsthttpclientsrc.lo `test -f 'gsthttpclientsrc.c' || echo '$(srcdir)/'`gsthttpclientsrc.c
850 +
851  libgsttcp_la-gsttcpclientsrc.lo: gsttcpclientsrc.c
852  @am__fastdepCC_TRUE@   if $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttcp_la_CFLAGS) $(CFLAGS) -MT libgsttcp_la-gsttcpclientsrc.lo -MD -MP -MF "$(DEPDIR)/libgsttcp_la-gsttcpclientsrc.Tpo" -c -o libgsttcp_la-gsttcpclientsrc.lo `test -f 'gsttcpclientsrc.c' || echo '$(srcdir)/'`gsttcpclientsrc.c; \
853  @am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/libgsttcp_la-gsttcpclientsrc.Tpo" "$(DEPDIR)/libgsttcp_la-gsttcpclientsrc.Plo"; else rm -f "$(DEPDIR)/libgsttcp_la-gsttcpclientsrc.Tpo"; exit 1; fi