1 /*
2    (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
3    (c) Copyright 2000-2004  Convergence (integrated media) GmbH
4 
5    All rights reserved.
6 
7    Written by Denis Oliver Kropp <dok@directfb.org>,
8               Andreas Hundt <andi@fischlustig.de>,
9               Sven Neumann <neo@directfb.org>,
10               Ville Syrjälä <syrjala@sci.fi> and
11               Claudio Ciccani <klan@users.sf.net>.
12 
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 2 of the License, or (at your option) any later version.
17 
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22 
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, write to the
25    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26    Boston, MA 02111-1307, USA.
27 */
28 
29 #include <config.h>
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <errno.h>
37 
38 #include <sys/types.h>
39 #include <sys/time.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <netdb.h>
45 
46 #include <direct/build.h>
47 #include <direct/types.h>
48 #include <direct/mem.h>
49 #include <direct/memcpy.h>
50 #include <direct/messages.h>
51 #include <direct/debug.h>
52 #include <direct/util.h>
53 
54 #include <direct/stream.h>
55 
56 struct __D_DirectStream {
57      int                   magic;
58      int                   ref;
59 
60      int                   fd;
61      unsigned int          offset;
62      int                   length;
63 
64      char                 *mime;
65 
66      /* cache for piped streams */
67      void                 *cache;
68      unsigned int          cache_size;
69 
70 #if DIRECT_BUILD_NETWORK
71      /* remote streams data */
72      struct {
73           int              sd;
74 
75           char            *host;
76           int              port;
77           struct addrinfo *addr;
78 
79           char            *user;
80           char            *pass;
81           char            *auth;
82 
83           char            *path;
84 
85           int              redirects;
86 
87           void            *data;
88 
89           bool             real_rtsp;
90           bool             real_pack;
91      } remote;
92 #endif
93 
94      DirectResult  (*wait)  ( DirectStream   *stream,
95                               unsigned int    length,
96                               struct timeval *tv );
97      DirectResult  (*peek)  ( DirectStream *stream,
98                               unsigned int  length,
99                               int           offset,
100                               void         *buf,
101                               unsigned int *read_out );
102      DirectResult  (*read)  ( DirectStream *stream,
103                               unsigned int  length,
104                               void         *buf,
105                               unsigned int *read_out );
106      DirectResult  (*seek)  ( DirectStream *stream,
107                               unsigned int  offset );
108 };
109 
110 
111 static void direct_stream_close( DirectStream *stream );
112 
113 
114 #if DIRECT_BUILD_NETWORK
115 D_DEBUG_DOMAIN( Direct_Stream, "Direct/Stream", "Stream wrapper" );
116 #endif
117 
118 /************************** Begin Network Support ***************************/
119 
120 #if DIRECT_BUILD_NETWORK
121 
122 #define NET_TIMEOUT         15
123 #define HTTP_PORT           80
124 #define FTP_PORT            21
125 #define RTSP_PORT           554
126 #define HTTP_MAX_REDIRECTS  15
127 
128 static DirectResult http_open( DirectStream *stream, const char *filename );
129 static DirectResult ftp_open ( DirectStream *stream, const char *filename );
130 static DirectResult rtsp_open( DirectStream *stream, const char *filename );
131 
132 
trim(char * s)133 static inline char* trim( char *s )
134 {
135      char *e;
136 
137 #define space( c ) ((c) == ' '  || (c) == '\t' || \
138                     (c) == '\r' || (c) == '\n' || \
139                     (c) == '"'  || (c) == '\'')
140 
141      for (; space(*s); s++);
142 
143      e = s + strlen(s) - 1;
144      for (; e > s && space(*e); *e-- = '\0');
145 
146 #undef space
147 
148      return s;
149 }
150 
151 static void
parse_url(const char * url,char ** ret_host,int * ret_port,char ** ret_user,char ** ret_pass,char ** ret_path)152 parse_url( const char *url, char **ret_host, int *ret_port,
153            char **ret_user, char **ret_pass, char **ret_path )
154 {
155      char *host = NULL;
156      int   port = 0;
157      char *user = NULL;
158      char *pass = NULL;
159      char *path;
160      char *tmp;
161 
162      tmp = strchr( url, '/' );
163      if (tmp) {
164           host = alloca( tmp - url + 1 );
165           memcpy( host, url, tmp - url );
166           host[tmp-url] = '\0';
167           path = tmp;
168      } else {
169           host = alloca( strlen( url ) + 1 );
170           memcpy( host, url, strlen( url ) + 1 );
171           path = "/";
172      }
173 
174      tmp = strrchr( host, '@' );
175      if (tmp) {
176           *tmp = '\0';
177           pass = strchr( host, ':' );
178           if (pass) {
179                *pass = '\0';
180                pass++;
181           }
182           user = host;
183           host = tmp + 1;
184      }
185 
186      tmp = strchr( host, ':' );
187      if (tmp) {
188           port = strtol( tmp+1, NULL, 10 );
189           *tmp = '\0';
190      }
191 
192      /* IPv6 variant (host within brackets) */
193      if (*host == '[') {
194           host++;
195           tmp = strchr( host, ']' );
196           if (tmp)
197                *tmp = '\0';
198      }
199 
200      if (ret_host)
201           *ret_host = D_STRDUP( host );
202 
203      if (ret_port && port)
204           *ret_port = port;
205 
206      if (ret_user && user)
207           *ret_user = D_STRDUP( user );
208 
209      if (ret_pass && pass)
210           *ret_pass = D_STRDUP( pass );
211 
212      if (ret_path)
213           *ret_path = D_STRDUP( path );
214 }
215 
216 /*****************************************************************************/
217 
218 static int
net_response(DirectStream * stream,char * buf,size_t size)219 net_response( DirectStream *stream, char *buf, size_t size )
220 {
221      fd_set         set;
222      struct timeval tv;
223      int            i;
224 
225      FD_ZERO( &set );
226      FD_SET( stream->remote.sd, &set );
227 
228      for (i = 0; i < size-1; i++) {
229           tv.tv_sec  = NET_TIMEOUT;
230           tv.tv_usec = 0;
231           select( stream->remote.sd+1, &set, NULL, NULL, &tv );
232 
233           if (recv( stream->remote.sd, buf+i, 1, 0 ) != 1)
234                break;
235 
236           if (buf[i] == '\n') {
237                if (i > 0 && buf[i-1] == '\r')
238                     i--;
239                break;
240           }
241      }
242 
243      buf[i] = '\0';
244 
245      D_DEBUG_AT( Direct_Stream, "got [%s].\n", buf );
246 
247      return i;
248 }
249 
250 static int
net_command(DirectStream * stream,char * buf,size_t size)251 net_command( DirectStream *stream, char *buf, size_t size )
252 {
253      fd_set         s;
254      struct timeval t;
255      int            status;
256      int            version;
257      char           space;
258 
259      FD_ZERO( &s );
260      FD_SET( stream->remote.sd, &s );
261 
262      t.tv_sec  = NET_TIMEOUT;
263      t.tv_usec = 0;
264 
265      switch (select( stream->remote.sd+1, NULL, &s, NULL, &t )) {
266           case 0:
267                D_DEBUG_AT( Direct_Stream, "Timeout!\n" );
268           case -1:
269                return -1;
270      }
271 
272      send( stream->remote.sd, buf, strlen(buf), 0 );
273      send( stream->remote.sd, "\r\n", 2, 0 );
274 
275      D_DEBUG_AT( Direct_Stream, "sent [%s].\n", buf );
276 
277      while (net_response( stream, buf, size ) > 0) {
278           status = 0;
279           if (sscanf( buf, "HTTP/1.%d %3d", &version, &status ) == 2 ||
280               sscanf( buf, "RTSP/1.%d %3d", &version, &status ) == 2 ||
281               sscanf( buf, "ICY %3d", &status )                 == 1 ||
282               sscanf( buf, "%3d%[ ]", &status, &space )         == 2)
283                return status;
284      }
285 
286      return 0;
287 }
288 
289 static DirectResult
net_wait(DirectStream * stream,unsigned int length,struct timeval * tv)290 net_wait( DirectStream   *stream,
291           unsigned int    length,
292           struct timeval *tv )
293 {
294      fd_set s;
295 
296      if (stream->cache_size >= length)
297           return DR_OK;
298 
299      if (stream->fd == -1)
300           return DR_EOF;
301 
302      FD_ZERO( &s );
303      FD_SET( stream->fd, &s );
304 
305      switch (select( stream->fd+1, &s, NULL, NULL, tv )) {
306           case 0:
307                if (!tv && !stream->cache_size)
308                     return DR_EOF;
309                return DR_TIMEOUT;
310           case -1:
311                return errno2result( errno );
312      }
313 
314      return DR_OK;
315 }
316 
317 static DirectResult
net_peek(DirectStream * stream,unsigned int length,int offset,void * buf,unsigned int * read_out)318 net_peek( DirectStream *stream,
319           unsigned int  length,
320           int           offset,
321           void         *buf,
322           unsigned int *read_out )
323 {
324      char *tmp;
325      int   size;
326 
327      if (offset < 0)
328           return DR_UNSUPPORTED;
329 
330      tmp = alloca( length + offset );
331 
332      size = recv( stream->fd, tmp, length+offset, MSG_PEEK );
333      switch (size) {
334           case 0:
335                return DR_EOF;
336           case -1:
337                if (errno == EAGAIN || errno == EWOULDBLOCK)
338                     return DR_BUFFEREMPTY;
339                return errno2result( errno );
340           default:
341                if (size < offset)
342                     return DR_BUFFEREMPTY;
343                size -= offset;
344                break;
345      }
346 
347      direct_memcpy( buf, tmp+offset, size );
348 
349      if (read_out)
350           *read_out = size;
351 
352      return DR_OK;
353 }
354 
355 static DirectResult
net_read(DirectStream * stream,unsigned int length,void * buf,unsigned int * read_out)356 net_read( DirectStream *stream,
357           unsigned int  length,
358           void         *buf,
359           unsigned int *read_out )
360 {
361      int size;
362 
363      size = recv( stream->fd, buf, length, 0 );
364      switch (size) {
365           case 0:
366                return DR_EOF;
367           case -1:
368                if (errno == EAGAIN || errno == EWOULDBLOCK)
369                     return DR_BUFFEREMPTY;
370                return errno2result( errno );
371      }
372 
373      stream->offset += size;
374 
375      if (read_out)
376           *read_out = size;
377 
378      return DR_OK;
379 }
380 
381 static DirectResult
net_connect(struct addrinfo * addr,int sock,int proto,int * ret_fd)382 net_connect( struct addrinfo *addr, int sock, int proto, int *ret_fd )
383 {
384      DirectResult     ret = DR_OK;
385      int              fd  = -1;
386      struct addrinfo *tmp;
387 
388      D_ASSERT( addr != NULL );
389      D_ASSERT( ret_fd != NULL );
390 
391      for (tmp = addr; tmp; tmp = tmp->ai_next) {
392           int err;
393 
394           fd = socket( tmp->ai_family, sock, proto );
395           if (fd < 0) {
396                ret = errno2result( errno );
397                D_DEBUG_AT( Direct_Stream,
398                            "failed to create socket!\n\t->%s",
399                            strerror(errno) );
400                continue;
401           }
402 
403           fcntl( fd, F_SETFL, fcntl( fd, F_GETFL ) | O_NONBLOCK );
404 
405           D_DEBUG_AT( Direct_Stream,
406                       "connecting to %s...\n", tmp->ai_canonname );
407 
408           if (proto == IPPROTO_UDP)
409                err = bind( fd, tmp->ai_addr, tmp->ai_addrlen );
410           else
411                err = connect( fd, tmp->ai_addr, tmp->ai_addrlen );
412 
413           if (err == 0 || errno == EINPROGRESS) {
414                struct timeval t = { NET_TIMEOUT, 0 };
415                fd_set         s;
416 
417                /* Join multicast group? */
418                if (tmp->ai_addr->sa_family == AF_INET) {
419                     struct sockaddr_in *saddr = (struct sockaddr_in *) tmp->ai_addr;
420 
421                     if (IN_MULTICAST( ntohl(saddr->sin_addr.s_addr) )) {
422                          struct ip_mreq req;
423 
424                          D_DEBUG_AT( Direct_Stream,
425                                      "joining multicast group (%u.%u.%u.%u)...\n",
426                                      (u8)tmp->ai_addr->sa_data[2], (u8)tmp->ai_addr->sa_data[3],
427                                      (u8)tmp->ai_addr->sa_data[4], (u8)tmp->ai_addr->sa_data[5] );
428 
429                          req.imr_multiaddr.s_addr = saddr->sin_addr.s_addr;
430                          req.imr_interface.s_addr = 0;
431 
432                          err = setsockopt( fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req, sizeof(req) );
433                          if (err < 0) {
434                               ret = errno2result( errno );
435                               D_PERROR( "Direct/Stream: Could not join multicast group (%u.%u.%u.%u)!\n",
436                                         (u8)tmp->ai_addr->sa_data[2], (u8)tmp->ai_addr->sa_data[3],
437                                         (u8)tmp->ai_addr->sa_data[4], (u8)tmp->ai_addr->sa_data[5] );
438                               close( fd );
439                               continue;
440                          }
441 
442                          setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, saddr, sizeof(*saddr) );
443                     }
444                }
445 
446                FD_ZERO( &s );
447                FD_SET( fd, &s );
448 
449                err = select( fd+1, NULL, &s, NULL, &t );
450                if (err < 1) {
451                     D_DEBUG_AT( Direct_Stream, "...connection failed.\n" );
452 
453                     close( fd );
454                     fd = -1;
455 
456                     if (err == 0) {
457                          ret = DR_TIMEOUT;
458                          continue;
459                     } else {
460                          ret = errno2result( errno );
461                          break;
462                     }
463                }
464 
465                D_DEBUG_AT( Direct_Stream, "...connected.\n" );
466 
467                ret = DR_OK;
468                break;
469           }
470      }
471 
472      *ret_fd = fd;
473 
474      return ret;
475 }
476 
477 static DirectResult
net_open(DirectStream * stream,const char * filename,int proto)478 net_open( DirectStream *stream, const char *filename, int proto )
479 {
480      DirectResult    ret  = DR_OK;
481      int             sock = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
482      struct addrinfo hints;
483      char            port[16];
484 
485      parse_url( filename,
486                 &stream->remote.host,
487                 &stream->remote.port,
488                 &stream->remote.user,
489                 &stream->remote.pass,
490                 &stream->remote.path );
491 
492      snprintf( port, sizeof(port), "%d", stream->remote.port );
493 
494      memset( &hints, 0, sizeof(hints) );
495      hints.ai_flags    = AI_CANONNAME;
496      hints.ai_socktype = sock;
497      hints.ai_family   = PF_UNSPEC;
498 
499      if (getaddrinfo( stream->remote.host, port,
500                       &hints, &stream->remote.addr )) {
501           D_ERROR( "Direct/Stream: "
502                    "failed to resolve host '%s'!\n", stream->remote.host );
503           return DR_FAILURE;
504      }
505 
506      ret = net_connect( stream->remote.addr, sock, proto, &stream->remote.sd );
507      if (ret)
508           return ret;
509 
510      stream->fd     = stream->remote.sd;
511      stream->length = -1;
512      stream->wait   = net_wait;
513      stream->peek   = net_peek;
514      stream->read   = net_read;
515 
516      return ret;
517 }
518 
519 /*****************************************************************************/
520 
521 static DirectResult
http_seek(DirectStream * stream,unsigned int offset)522 http_seek( DirectStream *stream, unsigned int offset )
523 {
524      DirectResult ret;
525      char         buf[1280];
526      int          status, len;
527 
528      close( stream->remote.sd );
529      stream->remote.sd = -1;
530 
531      ret = net_connect( stream->remote.addr,
532                         SOCK_STREAM, IPPROTO_TCP, &stream->remote.sd );
533      if (ret)
534           return ret;
535 
536      stream->fd = stream->remote.sd;
537 
538      len = snprintf( buf, sizeof(buf),
539                      "GET %s HTTP/1.0\r\n"
540                      "Host: %s:%d\r\n",
541                      stream->remote.path,
542                      stream->remote.host,
543                      stream->remote.port );
544      if (stream->remote.auth) {
545           len += snprintf( buf+len, sizeof(buf)-len,
546                            "Authorization: Basic %s\r\n",
547                            stream->remote.auth );
548      }
549      snprintf( buf+len, sizeof(buf)-len,
550                "User-Agent: DirectFB/%s\r\n"
551                "Accept: */*\r\n"
552                "Range: bytes=%d-\r\n"
553                "Connection: Close\r\n",
554                DIRECTFB_VERSION, offset );
555 
556      status = net_command( stream, buf, sizeof(buf) );
557      switch (status) {
558           case 200 ... 299:
559                stream->offset = offset;
560                break;
561           default:
562                if (status)
563                     D_DEBUG_AT( Direct_Stream,
564                                 "server returned status %d.\n", status );
565                return DR_FAILURE;
566      }
567 
568      /* discard remaining headers */
569      while (net_response( stream, buf, sizeof(buf) ) > 0);
570 
571      return DR_OK;
572 }
573 
574 static DirectResult
http_open(DirectStream * stream,const char * filename)575 http_open( DirectStream *stream, const char *filename )
576 {
577      DirectResult ret;
578      char         buf[1280];
579      int          status, len;
580 
581      stream->remote.port = HTTP_PORT;
582 
583      ret = net_open( stream, filename, IPPROTO_TCP );
584      if (ret)
585           return ret;
586 
587      if (stream->remote.user) {
588           char *tmp;
589 
590           if (stream->remote.pass) {
591                tmp = alloca( strlen( stream->remote.user ) +
592                              strlen( stream->remote.pass ) + 2 );
593                len = sprintf( tmp, "%s:%s",
594                               stream->remote.user, stream->remote.pass );
595           } else {
596                tmp = alloca( strlen( stream->remote.user ) + 2 );
597                len = sprintf( tmp, "%s:", stream->remote.user );
598           }
599 
600           stream->remote.auth = direct_base64_encode( tmp, len );
601      }
602 
603      len = snprintf( buf, sizeof(buf),
604                      "GET %s HTTP/1.0\r\n"
605                      "Host: %s:%d\r\n",
606                      stream->remote.path,
607                      stream->remote.host,
608                      stream->remote.port );
609      if (stream->remote.auth) {
610           len += snprintf( buf+len, sizeof(buf)-len,
611                            "Authorization: Basic %s\r\n",
612                            stream->remote.auth );
613      }
614      snprintf( buf+len, sizeof(buf)-len,
615                "User-Agent: DirectFB/%s\r\n"
616                "Accept: */*\r\n"
617                "Connection: Close\r\n",
618                DIRECTFB_VERSION );
619 
620      status = net_command( stream, buf, sizeof(buf) );
621 
622      while (net_response( stream, buf, sizeof(buf) ) > 0) {
623           if (!strncasecmp( buf, "Accept-Ranges:", 14 )) {
624                if (strcmp( trim( buf+14 ), "none" ))
625                     stream->seek = http_seek;
626           }
627           else if (!strncasecmp( buf, "Content-Type:", 13 )) {
628                char *mime = trim( buf+13 );
629                char *tmp  = strchr( mime, ';' );
630                if (tmp)
631                     *tmp = '\0';
632                if (stream->mime)
633                     D_FREE( stream->mime );
634                stream->mime = D_STRDUP( mime );
635           }
636           else if (!strncasecmp( buf, "Content-Length:", 15 )) {
637                char *tmp = trim( buf+15 );
638                if (sscanf( tmp, "%d", &stream->length ) < 1)
639                     sscanf( tmp, "bytes=%d", &stream->length );
640           }
641           else if (!strncasecmp( buf, "Location:", 9 )) {
642                direct_stream_close( stream );
643                stream->seek = NULL;
644 
645                if (++stream->remote.redirects > HTTP_MAX_REDIRECTS) {
646                     D_ERROR( "Direct/Stream: "
647                              "reached maximum number of redirects (%d).\n",
648                              HTTP_MAX_REDIRECTS );
649                     return DR_LIMITEXCEEDED;
650                }
651 
652                filename = trim( buf+9 );
653                if (!strncmp( filename, "http://", 7 ))
654                     return http_open( stream, filename+7 );
655                if (!strncmp( filename, "ftp://", 6 ))
656                     return ftp_open( stream, filename+6 );
657                if (!strncmp( filename, "rtsp://", 7 ))
658                     return rtsp_open( stream, filename+7 );
659 
660                return DR_UNSUPPORTED;
661           }
662      }
663 
664      switch (status) {
665           case 200 ... 299:
666                break;
667           default:
668                if (status)
669                     D_DEBUG_AT( Direct_Stream,
670                                 "server returned status %d.\n", status );
671                return (status == 404) ? DR_FILENOTFOUND : DR_FAILURE;
672      }
673 
674      return DR_OK;
675 }
676 
677 /*****************************************************************************/
678 
679 static DirectResult
ftp_open_pasv(DirectStream * stream,char * buf,size_t size)680 ftp_open_pasv( DirectStream *stream, char *buf, size_t size )
681 {
682      DirectResult ret;
683      int          i, len;
684 
685      snprintf( buf, size, "PASV" );
686      if (net_command( stream, buf, size ) != 227)
687           return DR_FAILURE;
688 
689      /* parse IP and port for passive mode */
690      for (i = 4; buf[i]; i++) {
691           unsigned int d[6];
692 
693           if (sscanf( &buf[i], "%u,%u,%u,%u,%u,%u",
694                       &d[0], &d[1], &d[2], &d[3], &d[4], &d[5] ) == 6)
695           {
696                struct addrinfo hints, *addr;
697 
698                /* address */
699                len = snprintf( buf, size,
700                                "%u.%u.%u.%u",
701                                d[0], d[1], d[2], d[3] );
702                /* port */
703                snprintf( buf+len+1, size-len-1,
704                          "%u", ((d[4] & 0xff) << 8) | (d[5] & 0xff) );
705 
706                memset( &hints, 0, sizeof(hints) );
707                hints.ai_flags    = AI_CANONNAME;
708                hints.ai_socktype = SOCK_STREAM;
709                hints.ai_family   = PF_UNSPEC;
710 
711                if (getaddrinfo( buf, buf+len+1, &hints, &addr )) {
712                     D_DEBUG_AT( Direct_Stream,
713                                 "failed to resolve host '%s'.\n", buf );
714                     return DR_FAILURE;
715                }
716 
717                ret = net_connect( addr, SOCK_STREAM, IPPROTO_TCP, &stream->fd );
718 
719                freeaddrinfo( addr );
720 
721                return ret;
722           }
723      }
724 
725      return DR_FAILURE;
726 }
727 
728 static DirectResult
ftp_seek(DirectStream * stream,unsigned int offset)729 ftp_seek( DirectStream *stream, unsigned int offset )
730 {
731      DirectResult ret = DR_OK;
732      char         buf[512];
733 
734      if (stream->fd > 0) {
735           int status;
736 
737           close( stream->fd );
738           stream->fd = -1;
739 
740           /* ignore response */
741           while (net_response( stream, buf, sizeof(buf) ) > 0) {
742                if (sscanf( buf, "%3d%[ ]", &status, buf ) == 2)
743                     break;
744           }
745      }
746 
747      ret = ftp_open_pasv( stream, buf, sizeof(buf) );
748      if (ret)
749           return ret;
750 
751      snprintf( buf, sizeof(buf), "REST %d", offset );
752      if (net_command( stream, buf, sizeof(buf) ) != 350)
753           goto error;
754 
755      snprintf( buf, sizeof(buf), "RETR %s", stream->remote.path );
756      switch (net_command( stream, buf, sizeof(buf) )) {
757           case 150:
758           case 125:
759                break;
760           default:
761                goto error;
762      }
763 
764      stream->offset = offset;
765 
766      return DR_OK;
767 
768 error:
769      close( stream->fd );
770      stream->fd = -1;
771 
772      return DR_FAILURE;
773 }
774 
775 static DirectResult
ftp_open(DirectStream * stream,const char * filename)776 ftp_open( DirectStream *stream, const char *filename )
777 {
778      DirectResult ret;
779      int          status = 0;
780      char         buf[512];
781 
782      stream->remote.port = FTP_PORT;
783 
784      ret = net_open( stream, filename, IPPROTO_TCP );
785      if (ret)
786           return ret;
787 
788      while (net_response( stream, buf, sizeof(buf) ) > 0) {
789           if (sscanf( buf, "%3d%[ ]", &status, buf ) == 2)
790                break;
791      }
792      if (status != 220)
793           return DR_FAILURE;
794 
795      /* login */
796      snprintf( buf, sizeof(buf), "USER %s", stream->remote.user ? : "anonymous" );
797      switch (net_command( stream, buf, sizeof(buf) )) {
798           case 230:
799           case 331:
800                break;
801           default:
802                return DR_FAILURE;
803      }
804 
805      if (stream->remote.pass) {
806           snprintf( buf, sizeof(buf), "PASS %s", stream->remote.pass );
807           if (net_command( stream, buf, sizeof(buf) ) != 230)
808                return DR_FAILURE;
809      }
810 
811      /* enter binary mode */
812      snprintf( buf, sizeof(buf), "TYPE I" );
813      if (net_command( stream, buf, sizeof(buf) ) != 200)
814           return DR_FAILURE;
815 
816      /* get file size */
817      snprintf( buf, sizeof(buf), "SIZE %s", stream->remote.path );
818      if (net_command( stream, buf, sizeof(buf) ) == 213)
819           stream->length = strtol( buf+4, NULL, 10 );
820 
821      /* enter passive mode by default */
822      ret = ftp_open_pasv( stream, buf, sizeof(buf) );
823      if (ret)
824           return ret;
825 
826      /* retrieve file */
827      snprintf( buf, sizeof(buf), "RETR %s", stream->remote.path );
828      switch (net_command( stream, buf, sizeof(buf) )) {
829           case 125:
830           case 150:
831                break;
832           default:
833                return DR_FAILURE;
834      }
835 
836      stream->seek = ftp_seek;
837 
838      return DR_OK;
839 }
840 
841 /*****************************************************************************/
842 
843 typedef struct {
844      s8          pt;   // payload type (-1: dymanic)
845      u8          type; // codec type
846      const char *name;
847      const char *mime;
848      u32         fcc;
849 } RTPPayload;
850 
851 typedef struct {
852      char              *control;
853 
854      int                pt;
855      const RTPPayload  *payload;
856 
857      int                dur; // duration
858      int                abr; // avg bitrate
859      int                mbr; // max bitrate
860      int                aps; // avg packet size
861      int                mps; // max packet size
862      int                str; // start time
863      int                prl; // preroll
864 
865      char              *mime;
866      int                mime_size;
867 
868      void              *data;
869      int                data_size;
870 } SDPStreamDesc;
871 
872 #define PAYLOAD_VIDEO 1
873 #define PAYLOAD_AUDIO 2
874 
875 #define FCC( a, b, c, d ) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
876 
877 static const RTPPayload payloads[] = {
878      { 31, PAYLOAD_VIDEO, "H261",          "video/h261",   FCC('H','2','6','1') },
879      { 34, PAYLOAD_VIDEO, "H263",          "video/h263",   FCC('H','2','6','3') },
880    //{ -1, PAYLOAD_VIDEO, "H264",          "video/h264",   FCC('H','2','6','4') },
881      { 32, PAYLOAD_VIDEO, "MPV",           "video/mpeg",   FCC('M','P','E','G') },
882      { 33,             0, "MP2T",          "video/mpegts", 0 },
883      { -1, PAYLOAD_VIDEO, "MP4V-ES",       "video/mpeg4",  FCC('M','P','4','S') },
884      { 14, PAYLOAD_AUDIO, "MPA",           "audio/mpeg",   0x0055 },
885    //{ -1, PAYLOAD_AUDIO, "mpeg4-generic", "audio/aac",    0x00ff },
886 };
887 
888 #define NUM_PAYLOADS D_ARRAY_SIZE( payloads )
889 
890 static DirectResult
sdp_parse(DirectStream * stream,int length,SDPStreamDesc ** ret_streams,int * ret_num)891 sdp_parse( DirectStream *stream, int length, SDPStreamDesc **ret_streams, int *ret_num )
892 {
893      char          *buf, *tmp;
894      SDPStreamDesc *desc = NULL;
895      int            num  = 0;
896      fd_set         set;
897      struct timeval tv;
898      int            i;
899 
900      buf = D_CALLOC( 1, length+1 );
901      if (!buf)
902           return D_OOM();
903 
904      FD_ZERO( &set );
905      FD_SET( stream->remote.sd, &set );
906 
907      for (tmp = buf; length;) {
908           int size;
909 
910           tv.tv_sec  = NET_TIMEOUT;
911           tv.tv_usec = 0;
912           select( stream->remote.sd+1, &set, NULL, NULL, &tv );
913 
914           size = recv( stream->remote.sd, tmp, length, MSG_WAITALL );
915           if (size < 1)
916                break;
917           tmp += size;
918           length -= size;
919      }
920 
921      for (tmp = buf; tmp && *tmp;) {
922           char *end;
923 
924           end = strchr( tmp, '\n' );
925           if (end) {
926                if (end > tmp && *(end-1) == '\r')
927                     *(end-1) = '\0';
928                *end = '\0';
929           }
930 
931           D_DEBUG_AT( Direct_Stream, "SDP [%s]\n", tmp );
932 
933           switch (*tmp) {
934                case 'm':
935                     /* media */
936                     if (*(tmp+1) == '=') {
937                          desc = D_REALLOC( desc, ++num*sizeof(SDPStreamDesc) );
938                          memset( &desc[num-1], 0, sizeof(SDPStreamDesc) );
939 
940                          tmp += 2;
941                          if (sscanf( tmp, "audio %d RTP/AVP %d", &i, &desc[num-1].pt ) == 2 ||
942                              sscanf( tmp, "video %d RTP/AVP %d", &i, &desc[num-1].pt ) == 2) {
943                               for (i = 0; i < NUM_PAYLOADS; i++) {
944                                    if (desc[num-1].pt == payloads[i].pt) {
945                                         desc[num-1].payload = &payloads[i];
946                                         desc[num-1].mime = D_STRDUP( payloads[i].mime );
947                                         desc[num-1].mime_size = strlen( payloads[i].mime );
948                                         break;
949                                    }
950                               }
951                          }
952                     }
953                     break;
954                case 'a':
955                     /* attribute */
956                     if (*(tmp+1) == '=' && num) {
957                          tmp += 2;
958                          if (!strncmp( tmp, "control:", 8 )) {
959                               desc[num-1].control = D_STRDUP( trim( tmp+8 ) );
960                          }
961                          else if (!strncmp( tmp, "rtpmap:", 7 )) {
962                               if (!desc[num-1].payload && desc[num-1].pt) {
963                                    char *sep;
964 
965                                    tmp = strchr( trim( tmp+7 ), ' ' );
966                                    if (!tmp) break;
967                                    sep = strchr( ++tmp, '/' );
968                                    if (sep) *sep = '\0';
969 
970                                    for (i = 0; i < NUM_PAYLOADS; i++) {
971                                         if (strcmp( tmp, payloads[i].name ))
972                                              continue;
973                                         desc[num-1].payload = &payloads[i];
974                                         desc[num-1].mime = D_STRDUP( payloads[i].mime );
975                                         desc[num-1].mime_size = strlen( payloads[i].mime );
976                                         break;
977                                    }
978                               }
979                          }
980                          else if (!strncmp( tmp, "length:npt=", 11 )) {
981                               double val = atof( tmp+11 );
982                               desc[num-1].dur = val * 1000.0;
983                          }
984                          else if (!strncmp( tmp, "mimetype:string;", 16 )) {
985                               if (desc[num-1].mime)
986                                    D_FREE( desc[num-1].mime );
987                               desc[num-1].mime = D_STRDUP( trim( tmp+16 ) );
988                               desc[num-1].mime_size = strlen( desc[num-1].mime );
989                          }
990                          else if (!strncmp( tmp, "AvgBitRate:", 11 )) {
991                               sscanf( tmp+11, "integer;%d", &desc[num-1].abr );
992                          }
993                          else if (!strncmp( tmp, "MaxBitRate:", 11 )) {
994                               sscanf( tmp+11, "integer;%d", &desc[num-1].mbr );
995                          }
996                          else if (!strncmp( tmp, "AvgPacketSize:", 14 )) {
997                               sscanf( tmp+14, "integer;%d", &desc[num-1].aps );
998                          }
999                          else if (!strncmp( tmp, "MaxPacketSize:", 14 )) {
1000                               sscanf( tmp+14, "integer;%d", &desc[num-1].mps );
1001                          }
1002                          else if (!strncmp( tmp, "StartTime:", 10 )) {
1003                               sscanf( tmp+10, "integer;%d", &desc[num-1].str );
1004                          }
1005                          else if (!strncmp( tmp, "Preroll:", 8 )) {
1006                               sscanf( tmp+8, "integer;%d", &desc[num-1].prl );
1007                          }
1008                          else if (!strncmp( tmp, "OpaqueData:buffer;", 18 )) {
1009                               desc[num-1].data =
1010                                    direct_base64_decode( trim( tmp+18 ),
1011                                                          &desc[num-1].data_size );
1012                          }
1013                     }
1014                     break;
1015                default:
1016                     break;
1017           }
1018 
1019           tmp = end;
1020           if (tmp) tmp++;
1021      }
1022 
1023      D_FREE( buf );
1024 
1025      *ret_streams = desc;
1026      *ret_num     = num;
1027 
1028      return desc ? DR_OK : DR_EOF;
1029 }
1030 
1031 static void
sdp_free(SDPStreamDesc * streams,int num)1032 sdp_free( SDPStreamDesc *streams, int num )
1033 {
1034      int i;
1035 
1036      for (i = 0; i < num; i++) {
1037           if (streams[i].control)
1038                D_FREE( streams[i].control );
1039           if (streams[i].mime)
1040                D_FREE( streams[i].mime );
1041           if (streams[i].data)
1042                D_FREE( streams[i].data );
1043      }
1044      D_FREE( streams );
1045 }
1046 
1047 static DirectResult
rmf_write_header(SDPStreamDesc * streams,int n_streams,void ** ret_buf,unsigned int * ret_size)1048 rmf_write_header( SDPStreamDesc *streams, int n_streams, void **ret_buf, unsigned int *ret_size )
1049 {
1050      unsigned char *dst, *tmp;
1051      int            abr = 0;
1052      int            mbr = 0;
1053      int            aps = 0;
1054      int            mps = 0;
1055      int            str = 0;
1056      int            prl = 0;
1057      int            dur = 0;
1058      int            i, len;
1059 
1060      len = 86 + n_streams*46;
1061      for (i = 0; i < n_streams; i++) {
1062           abr += streams[i].abr;
1063           aps += streams[i].aps;
1064           if (mbr < streams[i].mbr)
1065                mbr = streams[i].mbr;
1066           if (mps < streams[i].mps)
1067                mps = streams[i].mps;
1068           if (dur < streams[i].dur)
1069                dur = streams[i].dur;
1070           if (streams[i].mime)
1071                len += streams[i].mime_size;
1072           if (streams[i].data)
1073                len += streams[i].data_size;
1074           else if (streams[i].payload)
1075                len += 74;
1076      }
1077 
1078      *ret_buf = dst = D_MALLOC( len );
1079      if (!dst)
1080           return D_OOM();
1081      *ret_size = len;
1082 
1083      /* RMF */
1084      dst[0] = '.'; dst[1] = 'R', dst[2] = 'M'; dst[3] = 'F';
1085      dst[4] = dst[5] = dst[6] = 0; dst[7] = 18;              // size
1086      dst[8] = dst[9] = 0;                                    // version
1087      dst[10] = dst[11] = dst[12] = dst[13] = 0;              // ??
1088      dst[14] = dst[15] = dst[16] = 0; dst[17] = 4+n_streams; // num streams
1089      dst += 18;
1090 
1091      /* PROP */
1092      dst[0] = 'P'; dst[1] = 'R'; dst[2] = 'O'; dst[3] = 'P';
1093      dst[4] = dst[5] = dst[6] = 0; dst[7] = 50;
1094      dst[8] = dst[9] = 0;
1095      dst[10] = mbr>>24; dst[11] = mbr>>16; dst[12] = mbr>>8; dst[13] = mbr;
1096      dst[14] = abr>>24; dst[15] = abr>>16; dst[16] = abr>>8; dst[17] = abr;
1097      dst[18] = mps>>24; dst[19] = mps>>16; dst[20] = mps>>8; dst[21] = mps;
1098      dst[22] = aps>>24; dst[23] = aps>>16; dst[24] = aps>>8; dst[25] = aps;
1099      dst[26] = dst[27] = dst[28] = dst[29] = 0; // num packets
1100      dst[30] = dur>>24; dst[31] = dur>>16; dst[32] = dur>>8; dst[33] = dur;
1101      dst[34] = dst[35] = dst[36] = dst[37] = 0; // preroll
1102      dst[38] = dst[39] = dst[40] = dst[41] = 0; // index offset
1103      dst[42] = len>>24; dst[43] = len>>16; dst[44] = len>>8; dst[45] = len;
1104      dst[46] = 0; dst[47] = n_streams;          // num streams
1105      dst[48] = 0; dst[49] = 7;                  // flags
1106      dst += 50;
1107 
1108      for (i = 0; i < n_streams; i++) {
1109           len = 46 + streams[i].mime_size;
1110           if (streams[i].data)
1111                len += streams[i].data_size;
1112           else if (streams[i].payload)
1113                len += 74;
1114 
1115           abr = streams[i].abr;
1116           mbr = streams[i].mbr;
1117           aps = streams[i].aps;
1118           mps = streams[i].mps;
1119           str = streams[i].str;
1120           prl = streams[i].prl;
1121           dur = streams[i].dur;
1122 
1123           /* MDPR */
1124           dst[0] = 'M'; dst[1] = 'D'; dst[2] = 'P'; dst[3] = 'R';
1125           dst[4] = len>>24; dst[5] = len>>16; dst[6] = len>>8; dst[7] = len;
1126           dst[8] = dst[9] = 0;
1127           dst[10] = 0; dst[11] = i;
1128           dst[12] = mbr>>24; dst[13] = mbr>>16; dst[14] = mbr>>8; dst[15] = mbr;
1129           dst[16] = abr>>24; dst[17] = abr>>16; dst[18] = abr>>8; dst[19] = abr;
1130           dst[20] = mps>>24; dst[21] = mps>>16; dst[22] = mps>>8; dst[23] = mps;
1131           dst[24] = aps>>24; dst[25] = aps>>16; dst[26] = aps>>8; dst[27] = aps;
1132           dst[28] = str>>24; dst[29] = str>>16; dst[30] = str>>8; dst[31] = str;
1133           dst[32] = prl>>24; dst[33] = prl>>16; dst[34] = prl>>8; dst[35] = prl;
1134           dst[36] = dur>>24; dst[37] = dur>>16; dst[38] = dur>>8; dst[39] = dur;
1135           dst += 40;
1136 
1137           /* description */
1138           *dst++ = 0;
1139           /* mimetype */
1140           *dst++ = streams[i].mime_size;
1141           for (tmp = (unsigned char*)streams[i].mime; tmp && *tmp;)
1142                *dst++ = *tmp++;
1143 
1144           /* codec data */
1145           if (streams[i].data) {
1146                len = streams[i].data_size;
1147                dst[0] = len>>24; dst[1] = len>>16; dst[2] = len>>8; dst[3] = len;
1148                direct_memcpy( dst+4, streams[i].data, streams[i].data_size );
1149                dst += len+4;
1150           }
1151           else if (streams[i].payload) {
1152                u32 fcc = streams[i].payload->fcc;
1153 
1154                dst[0] = dst[1] = dst[2] = 0; dst[3] = 74;
1155                dst += 4;
1156                memset( dst, 0, 74 );
1157 
1158                if (streams[i].payload->type == PAYLOAD_AUDIO) {
1159                     dst[0] = '.'; dst[1] = 'r'; dst[2] = 'a'; dst[3] = 0xfd;
1160                     dst[4] = 0; dst[5] = 5; // version
1161                     dst[66] = fcc; dst[67] = fcc>>8; dst[68] = fcc>>16; dst[69] = fcc>>24;
1162                }
1163                else {
1164                     dst[0] = dst[1] = dst[2] = 0; dst[3] = 34;
1165                     dst[4] = 'V'; dst[5] = 'I'; dst[6] = 'D'; dst[7] = 'O';
1166                     dst[8] = fcc; dst[9] = fcc>>8; dst[10] = fcc>>16; dst[11] = fcc>>24;
1167                     dst[30] = 0x10;
1168                }
1169                dst += 74;
1170           }
1171           else {
1172                dst[0] = dst[1] = dst[2] = dst[3] = 0;
1173                dst += 4;
1174           }
1175      }
1176 
1177      /* DATA */
1178      dst[0] = 'D'; dst[1] = 'A'; dst[2] = 'T'; dst[3] = 'A';
1179      dst[4] = dst[5] = dst[6] = 0; dst[7] = 18; // size
1180      dst[8] = dst[9] = 0;                       // version
1181      dst[10] = dst[11] = dst[12] = dst[13] = 0; // num packets
1182      dst[14] = dst[15] = dst[16] = dst[17] = 0; // next data
1183 
1184      return DR_OK;
1185 }
1186 
1187 static int
rmf_write_pheader(unsigned char * dst,int id,int sz,unsigned int ts)1188 rmf_write_pheader( unsigned char *dst, int id, int sz, unsigned int ts )
1189 {
1190      /* version */
1191      dst[0] = dst[1] = 0;
1192      /* length */
1193      dst[2] = (sz+12)>>8; dst[3] = sz+12;
1194      /* indentifier */
1195      dst[4] = id>>8; dst[5] = id;
1196      /* timestamp */
1197      dst[6] = ts>>24; dst[7] = ts>>16; dst[8] = ts>>8; dst[9] = ts;
1198      /* reserved */
1199      dst[10] = 0;
1200      /* flags */
1201      dst[11] = 0;
1202 
1203      return 12;
1204 }
1205 
1206 static void
real_calc_challenge2(char response[64],char checksum[32],char * challenge)1207 real_calc_challenge2( char response[64], char checksum[32], char *challenge )
1208 {
1209      const unsigned char xor_table[37] = {
1210           0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
1211           0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
1212           0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
1213           0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
1214           0x10, 0x57, 0x05, 0x18, 0x54
1215      };
1216      char buf[128];
1217      char md5[16];
1218      int  len;
1219      int  i;
1220 
1221      memset( response, 0, 64 );
1222      memset( checksum, 0, 32 );
1223 
1224      buf[0] = 0xa1; buf[1] = 0xe9; buf[2] = 0x14; buf[3] = 0x9d;
1225      buf[4] = 0x0e; buf[5] = 0x6b; buf[6] = 0x3b; buf[7] = 0x59;
1226      memset( buf+8, 0, 120 );
1227 
1228      len = strlen( challenge );
1229      if (len == 40) {
1230           challenge[32] = '\0';
1231           len = 32;
1232      }
1233      memcpy( buf+8, challenge, MAX(len,56) );
1234 
1235      for (i = 0; i < 37; i++)
1236           buf[8+i] ^= xor_table[i];
1237 
1238      /* compute response */
1239      direct_md5_sum( md5, buf, 64 );
1240      /* convert to ascii */
1241      for (i = 0; i < 16; i++) {
1242           char a, b;
1243           a = (md5[i] >> 4) & 15;
1244           b =  md5[i]       & 15;
1245           response[i*2+0] = ((a < 10) ? (a + 48) : (a + 87)) & 255;
1246           response[i*2+1] = ((b < 10) ? (b + 48) : (b + 87)) & 255;
1247      }
1248      /* tail */
1249      len = strlen( response );
1250      direct_snputs( &response[len], "01d0a8e3", 64-len );
1251 
1252      /* compute checksum */
1253      for (i = 0; i < len/4; i++)
1254           checksum[i] = response[i*4];
1255 }
1256 
1257 static DirectResult
rtsp_session_open(DirectStream * stream)1258 rtsp_session_open( DirectStream *stream )
1259 {
1260      DirectResult   ret;
1261      int            status;
1262      int            cseq        = 0;
1263      SDPStreamDesc *streams     = NULL;
1264      int            n_streams   = 0;
1265      char           session[32] = {0, };
1266      char           challen[64] = {0, };
1267      char           buf[1280];
1268      int            i, len;
1269 
1270      snprintf( buf, sizeof(buf),
1271                "OPTIONS rtsp://%s:%d RTSP/1.0\r\n"
1272                "CSeq: %d\r\n"
1273                "User-Agent: DirectFB/%s\r\n"
1274                "ClientChallenge: 9e26d33f2984236010ef6253fb1887f7\r\n"
1275                "PlayerStarttime: [28/03/2003:22:50:23 00:00]\r\n"
1276                "CompanyID: KnKV4M4I/B2FjJ1TToLycw==\r\n"
1277                "GUID: 00000000-0000-0000-0000-000000000000\r\n"
1278                "RegionData: 0\r\n",
1279                stream->remote.host,
1280                stream->remote.port,
1281                ++cseq, DIRECTFB_VERSION );
1282 
1283      if (net_command( stream, buf, sizeof(buf) ) != 200)
1284           return DR_FAILURE;
1285 
1286      while (net_response( stream, buf, sizeof(buf) ) > 0) {
1287           if (!strncmp( buf, "RealChallenge1:", 15 )) {
1288                snprintf( challen, sizeof(challen), "%s", trim( buf+15 ) );
1289                stream->remote.real_rtsp = true;
1290           }
1291      }
1292 
1293      len = snprintf( buf, sizeof(buf),
1294                      "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n"
1295                      "CSeq: %d\r\n"
1296                      "Accept: application/sdp\r\n"
1297                      "Bandwidth: 10485800\r\n",
1298                      stream->remote.host,
1299                      stream->remote.port,
1300                      stream->remote.path,
1301                      ++cseq );
1302      if (stream->remote.real_rtsp) {
1303           snprintf( buf+len, sizeof(buf)-len,
1304                     "GUID: 00000000-0000-0000-0000-000000000000\r\n"
1305                     "RegionData: 0\r\n"
1306                     "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586\r\n"
1307                     "SupportsMaximumASMBandwidth: 1\r\n"
1308                     "Require: com.real.retain-entity-for-setup\r\n" );
1309      }
1310 
1311      status = net_command( stream, buf, sizeof(buf) );
1312      if (status != 200)
1313           return (status == 404) ? DR_FILENOTFOUND : DR_FAILURE;
1314 
1315      len = 0;
1316      while (net_response( stream, buf, sizeof(buf) ) > 0) {
1317           if (!strncasecmp( buf, "ETag:", 5 )) {
1318                snprintf( session, sizeof(session), "%s", trim( buf+5 ) );
1319           }
1320           else if (!strncasecmp( buf, "Content-Length:", 15 )) {
1321                char *tmp = trim( buf+15 );
1322                if (sscanf( tmp, "%d", &len ) != 1)
1323                     sscanf( tmp, "bytes=%d", &len );
1324           }
1325      }
1326 
1327      if (!len) {
1328           D_DEBUG_AT( Direct_Stream, "Couldn't get sdp length!\n" );
1329           return DR_FAILURE;
1330      }
1331 
1332      ret = sdp_parse( stream, len, &streams, &n_streams );
1333      if (ret)
1334           return ret;
1335 
1336      for (i = 0; i < n_streams; i++) {
1337           /* skip unhandled payload types */
1338           if (!stream->remote.real_rtsp && !streams[i].payload)
1339                continue;
1340 
1341           len = snprintf( buf, sizeof(buf),
1342                          "SETUP rtsp://%s:%d%s/%s RTSP/1.0\r\n"
1343                          "CSeq: %d\r\n",
1344                          stream->remote.host,
1345                          stream->remote.port,
1346                          stream->remote.path,
1347                          streams[i].control, ++cseq );
1348           if (*session) {
1349                if (*challen) {
1350                     char response[64];
1351                     char checksum[32];
1352 
1353                     real_calc_challenge2( response, checksum, challen );
1354                     len += snprintf( buf+len, sizeof(buf)-len,
1355                                      "RealChallenge2: %s, sd=%s\r\n",
1356                                      response, checksum );
1357                     *challen = '\0';
1358                }
1359                len += snprintf( buf+len, sizeof(buf)-len,
1360                                 "%s: %s\r\n",
1361                                 i ? "Session" : "If-Match", session );
1362           }
1363           snprintf( buf+len, sizeof(buf)-len,
1364                     "Transport: %s\r\n",
1365                     stream->remote.real_rtsp
1366                     ? "x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play"
1367                     : "RTP/AVP/TCP;unicast" );
1368 
1369           if (net_command( stream, buf, sizeof(buf) ) != 200) {
1370                sdp_free( streams, n_streams );
1371                return DR_FAILURE;
1372           }
1373 
1374           while (net_response( stream, buf, sizeof(buf) ) > 0) {
1375                if (!strncmp( buf, "Session:", 8 ))
1376                     snprintf( session, sizeof(session), "%s", trim( buf+8 ) );
1377           }
1378      }
1379 
1380      len = snprintf( buf, sizeof(buf),
1381                     "PLAY rtsp://%s:%d%s RTSP/1.0\r\n"
1382                     "CSeq: %d\r\n",
1383                     stream->remote.host,
1384                     stream->remote.port,
1385                     stream->remote.path,
1386                     ++cseq );
1387      if (*session) {
1388           len += snprintf( buf+len, sizeof(buf)-len,
1389                            "Session: %s\r\n", session );
1390      }
1391      snprintf( buf+len, sizeof(buf)-len,
1392                "Range: npt=0-\r\n"
1393                "Connection: Close\r\n" );
1394 
1395      if (net_command( stream, buf, sizeof(buf) ) != 200) {
1396           sdp_free( streams, n_streams );
1397           return DR_FAILURE;
1398      }
1399 
1400      /* discard remaining headers */
1401      while (net_response( stream, buf, sizeof(buf) ) > 0);
1402 
1403      /* revert to blocking mode */
1404      fcntl( stream->fd, F_SETFL,
1405             fcntl( stream->fd, F_GETFL ) & ~O_NONBLOCK );
1406 
1407      if (!stream->remote.real_rtsp) {
1408           RTPPayload *p;
1409 
1410           stream->remote.data = D_CALLOC( 1, (n_streams+1)*sizeof(RTPPayload) );
1411           if (!stream->remote.data) {
1412                sdp_free( streams, n_streams );
1413                return D_OOM();
1414           }
1415 
1416           p = (RTPPayload*) stream->remote.data;
1417           for (i = 0; i < n_streams; i++) {
1418                if (streams[i].payload) {
1419                     *p = *(streams[i].payload);
1420                     p->pt = streams[i].pt;
1421                     p++;
1422                }
1423           }
1424      }
1425 
1426      stream->remote.real_pack = true;
1427      if (n_streams == 1 && streams[0].mime) {
1428           if (!strcmp( streams[0].mime, "audio/mpeg" ) ||
1429               !strcmp( streams[0].mime, "audio/aac" )  ||
1430               !strcmp( streams[0].mime, "video/mpeg" ) ||
1431               !strcmp( streams[0].mime, "video/mpegts" ))
1432           {
1433                stream->mime = D_STRDUP( streams[0].mime );
1434                stream->remote.real_pack = false;
1435           }
1436      }
1437      if (stream->remote.real_pack) {
1438           ret = rmf_write_header( streams, n_streams,
1439                                  &stream->cache, &stream->cache_size );
1440           if (ret) {
1441                sdp_free( streams, n_streams );
1442                return ret;
1443           }
1444           stream->mime = D_STRDUP( "application/vnd.rn-realmedia" );
1445      }
1446 
1447      sdp_free( streams, n_streams );
1448 
1449      return DR_OK;
1450 }
1451 
1452 static DirectResult
rvp_read_packet(DirectStream * stream)1453 rvp_read_packet( DirectStream *stream )
1454 {
1455      unsigned char  buf[9];
1456      int            size;
1457      int            len;
1458      unsigned char  id;
1459      unsigned int   ts;
1460 
1461      while (1) {
1462           do {
1463                size = recv( stream->fd, buf, 1, MSG_WAITALL );
1464                if (size < 1)
1465                     return DR_EOF;
1466           } while (buf[0] != '$');
1467 
1468           size = recv( stream->fd, buf, 7, MSG_WAITALL );
1469           if (size < 7)
1470                return DR_EOF;
1471 
1472           len = (buf[0] << 16) + (buf[1] << 8) + buf[2];
1473           id = buf[3];
1474           if (id != 0x40 && id != 0x42) {
1475                if (buf[5] == 0x06) // EOS
1476                     return DR_EOF;
1477                size = recv( stream->fd, buf, 9, MSG_WAITALL );
1478                if (size < 9)
1479                     return DR_EOF;
1480                id = buf[5];
1481                len -= 9;
1482           }
1483           id = (id >> 1) & 1;
1484 
1485           size = recv( stream->fd, buf, 6, MSG_WAITALL );
1486           if (size < 6)
1487                return DR_EOF;
1488           ts = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
1489 
1490           len -= 10;
1491           if (len > 0) {
1492                unsigned char *dst;
1493 
1494                size = len + 12;
1495                stream->cache = D_REALLOC( stream->cache, stream->cache_size+size );
1496                if (!stream->cache)
1497                     return D_OOM();
1498                dst = stream->cache+stream->cache_size;
1499                stream->cache_size += size;
1500 
1501                dst += rmf_write_pheader( dst, id, len, ts );
1502 
1503                while (len) {
1504                     size = recv( stream->fd, dst, len, MSG_WAITALL );
1505                     if (size < 1)
1506                          return DR_EOF;
1507                     dst += size;
1508                     len -= size;
1509                }
1510                break;
1511           }
1512      }
1513 
1514      return DR_OK;
1515 }
1516 
1517 static DirectResult
rtp_read_packet(DirectStream * stream)1518 rtp_read_packet( DirectStream *stream )
1519 {
1520      RTPPayload    *payloads = (RTPPayload*)stream->remote.data;
1521      unsigned char  buf[12];
1522      int            size;
1523      int            len;
1524      unsigned char  id;
1525      unsigned short seq;
1526      unsigned int   ts;
1527      int            skip;
1528 
1529      while (1) {
1530           RTPPayload *p;
1531 
1532           do {
1533                size = recv( stream->fd, buf, 1, MSG_WAITALL );
1534                if (size < 1)
1535                     return DR_EOF;
1536           } while (buf[0] != '$');
1537 
1538           size = recv( stream->fd, buf, 3, MSG_WAITALL );
1539           if (size < 3)
1540                return DR_EOF;
1541 
1542           id = buf[0];
1543           len = (buf[1] << 8) | buf[2];
1544           if (len < 12)
1545                continue;
1546 
1547           size = recv( stream->fd, buf, 12, MSG_WAITALL );
1548           if (size < 12)
1549                return DR_EOF;
1550           len -= 12;
1551 
1552           if ((buf[0] & 0xc0) != (2 << 6))
1553                D_DEBUG_AT( Direct_Stream, "Bad RTP version %d!\n", buf[0] );
1554           seq = (buf[2] <<  8) |  buf[3];
1555           ts  = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
1556 
1557           for (p = payloads; p->pt; p++) {
1558                if (p->pt == (buf[1] & 0x7f))
1559                     break;
1560           }
1561 
1562           switch (p->pt) {
1563                case  0: // Unhandled
1564                     skip = len;
1565                     break;
1566                case 14: // MPEG Audio
1567                     skip = 4;
1568                     break;
1569                case 32: // MPEG Video
1570                     size = recv( stream->fd, buf, 1, MSG_WAITALL );
1571                     if (size < 1)
1572                          return DR_EOF;
1573                     len--;
1574                     skip = 3;
1575                     if (buf[0] & (1 << 2))
1576                          skip += 4;
1577                     break;
1578                case 34: // H263
1579                     size = recv( stream->fd, buf, 1, MSG_WAITALL );
1580                     if (size < 1)
1581                          return DR_EOF;
1582                     len--;
1583                     skip = 3;
1584                     if (buf[0] & (1 << 7))
1585                          skip += 4;
1586                     if (buf[0] & (1 << 6))
1587                          skip += 4;
1588                     break;
1589                default:
1590                     skip = 0;
1591                     break;
1592           }
1593 
1594           while (skip) {
1595                size = recv( stream->fd, buf, MIN(skip,12), MSG_WAITALL );
1596                if (size < 1)
1597                     return DR_EOF;
1598                len -= size;
1599                skip -= size;
1600           }
1601 
1602           if (len > 0) {
1603                unsigned char *dst;
1604 
1605                size = len;
1606                if (stream->remote.real_pack) {
1607                     size += 12;
1608                     if (p->type == PAYLOAD_VIDEO)
1609                          size += 7;
1610                }
1611 
1612                stream->cache = D_REALLOC( stream->cache, stream->cache_size+size );
1613                if (!stream->cache)
1614                     return D_OOM();
1615                dst = stream->cache+stream->cache_size;
1616                stream->cache_size += size;
1617 
1618                if (stream->remote.real_pack) {
1619                     if (p->type == PAYLOAD_VIDEO) {
1620                          dst += rmf_write_pheader( dst, id, len+7, ts );
1621                          dst[0] = 0x81;
1622                          dst[1] = 0x01;
1623                          dst[2] = (len | 0x4000)>>8; dst[3] = len;
1624                          dst[4] = (len | 0x4000)>>8; dst[5] = len;
1625                          dst[6] = seq;
1626                          dst += 7;
1627                     } else {
1628                          dst += rmf_write_pheader( dst, id, len, ts );
1629                     }
1630                }
1631 
1632                while (len) {
1633                     size = recv( stream->fd, dst, len, MSG_WAITALL );
1634                     if (size < 1)
1635                          return DR_EOF;
1636                     dst += size;
1637                     len -= size;
1638                }
1639                break;
1640           }
1641      }
1642 
1643      return DR_OK;
1644 }
1645 
1646 static DirectResult
rtsp_peek(DirectStream * stream,unsigned int length,int offset,void * buf,unsigned int * read_out)1647 rtsp_peek( DirectStream *stream,
1648            unsigned int  length,
1649            int           offset,
1650            void         *buf,
1651            unsigned int *read_out )
1652 {
1653      DirectResult ret;
1654      unsigned int len;
1655 
1656      if (offset < 0)
1657           return DR_UNSUPPORTED;
1658 
1659      len = length + offset;
1660      while (len > stream->cache_size) {
1661           ret = (stream->remote.real_rtsp)
1662                 ? rvp_read_packet( stream )
1663                 : rtp_read_packet( stream );
1664           if (ret) {
1665                if (stream->cache_size < offset)
1666                     return ret;
1667                break;
1668           }
1669      }
1670 
1671      len = MIN( stream->cache_size-offset, length );
1672      direct_memcpy( buf, stream->cache+offset, len );
1673 
1674      if (read_out)
1675           *read_out = len;
1676 
1677      return DR_OK;
1678 }
1679 
1680 static DirectResult
rtsp_read(DirectStream * stream,unsigned int length,void * buf,unsigned int * read_out)1681 rtsp_read( DirectStream *stream,
1682            unsigned int  length,
1683            void         *buf,
1684            unsigned int *read_out )
1685 {
1686      DirectResult ret;
1687      unsigned int size = 0;
1688 
1689      while (size < length) {
1690           if (stream->cache_size) {
1691                unsigned int len = MIN( stream->cache_size, length-size );
1692 
1693                direct_memcpy( buf+size, stream->cache, len );
1694                size += len;
1695                stream->cache_size -= len;
1696 
1697                if (stream->cache_size) {
1698                     direct_memcpy( stream->cache,
1699                                    stream->cache+len, stream->cache_size );
1700                } else {
1701                     D_FREE( stream->cache );
1702                     stream->cache = NULL;
1703                }
1704           }
1705 
1706           if (size < length) {
1707                ret = (stream->remote.real_rtsp)
1708                      ? rvp_read_packet( stream )
1709                      : rtp_read_packet( stream );
1710                if (ret) {
1711                     if (!size)
1712                          return ret;
1713                     break;
1714                }
1715           }
1716      }
1717 
1718      stream->offset += size;
1719 
1720      if (read_out)
1721           *read_out = size;
1722 
1723      return DR_OK;
1724 }
1725 
1726 static DirectResult
rtsp_open(DirectStream * stream,const char * filename)1727 rtsp_open( DirectStream *stream, const char *filename )
1728 {
1729      DirectResult ret;
1730 
1731      stream->remote.port = RTSP_PORT;
1732 
1733      ret = net_open( stream, filename, IPPROTO_TCP );
1734      if (ret)
1735           return ret;
1736 
1737      ret = rtsp_session_open( stream );
1738      if (ret) {
1739           close( stream->remote.sd );
1740           return ret;
1741      }
1742 
1743      stream->peek = rtsp_peek;
1744      stream->read = rtsp_read;
1745 
1746      return DR_OK;
1747 }
1748 
1749 #endif /* DIRECT_BUILD_NETWORK */
1750 
1751 /************************** End of Network Support ***************************/
1752 
1753 static DirectResult
pipe_wait(DirectStream * stream,unsigned int length,struct timeval * tv)1754 pipe_wait( DirectStream   *stream,
1755            unsigned int    length,
1756            struct timeval *tv )
1757 {
1758      fd_set s;
1759 
1760      if (stream->cache_size >= length)
1761           return DR_OK;
1762 
1763      FD_ZERO( &s );
1764      FD_SET( stream->fd, &s );
1765 
1766      switch (select( stream->fd+1, &s, NULL, NULL, tv )) {
1767           case 0:
1768                if (!tv && !stream->cache_size)
1769                     return DR_EOF;
1770                return DR_TIMEOUT;
1771           case -1:
1772                return errno2result( errno );
1773      }
1774 
1775      return DR_OK;
1776 }
1777 
1778 static DirectResult
pipe_peek(DirectStream * stream,unsigned int length,int offset,void * buf,unsigned int * read_out)1779 pipe_peek( DirectStream *stream,
1780            unsigned int  length,
1781            int           offset,
1782            void         *buf,
1783            unsigned int *read_out )
1784 {
1785      unsigned int size = length;
1786      int          len;
1787 
1788      if (offset < 0)
1789           return DR_UNSUPPORTED;
1790 
1791      len = length + offset;
1792      if (len > stream->cache_size) {
1793           ssize_t s;
1794 
1795           stream->cache = D_REALLOC( stream->cache, len );
1796           if (!stream->cache) {
1797                stream->cache_size = 0;
1798                return D_OOM();
1799           }
1800 
1801           s = read( stream->fd,
1802                     stream->cache + stream->cache_size,
1803                     len - stream->cache_size );
1804           if (s < 0) {
1805                if (errno != EAGAIN || stream->cache_size == 0)
1806                     return errno2result( errno );
1807                s = 0;
1808           }
1809 
1810           stream->cache_size += s;
1811           if (stream->cache_size <= offset)
1812                return DR_BUFFEREMPTY;
1813 
1814           size = stream->cache_size - offset;
1815      }
1816 
1817      direct_memcpy( buf, stream->cache+offset, size );
1818 
1819      if (read_out)
1820           *read_out = size;
1821 
1822      return DR_OK;
1823 }
1824 
1825 static DirectResult
pipe_read(DirectStream * stream,unsigned int length,void * buf,unsigned int * read_out)1826 pipe_read( DirectStream *stream,
1827            unsigned int  length,
1828            void         *buf,
1829            unsigned int *read_out )
1830 {
1831      unsigned int size = 0;
1832 
1833      if (stream->cache_size) {
1834           size = MIN( stream->cache_size, length );
1835 
1836           direct_memcpy( buf, stream->cache, size );
1837 
1838           length -= size;
1839           stream->cache_size -= size;
1840 
1841           if (stream->cache_size) {
1842                direct_memcpy( stream->cache,
1843                               stream->cache+size, stream->cache_size );
1844           } else {
1845                D_FREE( stream->cache );
1846                stream->cache = NULL;
1847           }
1848      }
1849 
1850      if (length) {
1851           ssize_t s;
1852 
1853           s = read( stream->fd, buf+size, length-size );
1854           switch (s) {
1855                case 0:
1856                     if (!size)
1857                          return DR_EOF;
1858                     break;
1859                case -1:
1860                     if (!size) {
1861                          return (errno == EAGAIN)
1862                                 ? DR_BUFFEREMPTY
1863                                 : errno2result( errno );
1864                     }
1865                     break;
1866                default:
1867                     size += s;
1868                     break;
1869           }
1870      }
1871 
1872      stream->offset += size;
1873 
1874      if (read_out)
1875           *read_out = size;
1876 
1877      return DR_OK;
1878 }
1879 
1880 /*****************************************************************************/
1881 
1882 static DirectResult
file_peek(DirectStream * stream,unsigned int length,int offset,void * buf,unsigned int * read_out)1883 file_peek( DirectStream *stream,
1884            unsigned int  length,
1885            int           offset,
1886            void         *buf,
1887            unsigned int *read_out )
1888 {
1889      DirectResult ret = DR_OK;
1890      ssize_t      size;
1891 
1892      if (lseek( stream->fd, offset, SEEK_CUR ) < 0)
1893           return DR_FAILURE;
1894 
1895      size = read( stream->fd, buf, length );
1896      switch (size) {
1897           case 0:
1898                ret = DR_EOF;
1899                break;
1900           case -1:
1901                ret = (errno == EAGAIN)
1902                      ? DR_BUFFEREMPTY
1903                      : errno2result( errno );
1904                size = 0;
1905                break;
1906      }
1907 
1908      if (lseek( stream->fd, - offset - size, SEEK_CUR ) < 0)
1909           return DR_FAILURE;
1910 
1911      if (read_out)
1912           *read_out = size;
1913 
1914      return ret;
1915 }
1916 
1917 static DirectResult
file_read(DirectStream * stream,unsigned int length,void * buf,unsigned int * read_out)1918 file_read( DirectStream *stream,
1919            unsigned int  length,
1920            void         *buf,
1921            unsigned int *read_out )
1922 {
1923      ssize_t size;
1924 
1925      size = read( stream->fd, buf, length );
1926      switch (size) {
1927           case 0:
1928                return DR_EOF;
1929           case -1:
1930                if (errno == EAGAIN)
1931                     return DR_BUFFEREMPTY;
1932                return errno2result( errno );
1933      }
1934 
1935      stream->offset += size;
1936 
1937      if (read_out)
1938           *read_out = size;
1939 
1940      return DR_OK;
1941 }
1942 
1943 static DirectResult
file_seek(DirectStream * stream,unsigned int offset)1944 file_seek( DirectStream *stream, unsigned int offset )
1945 {
1946      off_t off;
1947 
1948      off = lseek( stream->fd, offset, SEEK_SET );
1949      if (off < 0)
1950           return DR_FAILURE;
1951 
1952      stream->offset = off;
1953 
1954      return DR_OK;
1955 }
1956 
1957 static DirectResult
file_open(DirectStream * stream,const char * filename,int fileno)1958 file_open( DirectStream *stream, const char *filename, int fileno )
1959 {
1960      if (filename)
1961           stream->fd = open( filename, O_RDONLY | O_NONBLOCK );
1962      else
1963           stream->fd = dup( fileno );
1964 
1965      if (stream->fd < 0)
1966           return errno2result( errno );
1967 
1968      fcntl( stream->fd, F_SETFL,
1969                fcntl( stream->fd, F_GETFL ) | O_NONBLOCK );
1970 
1971      if (lseek( stream->fd, 0, SEEK_CUR ) < 0 && errno == ESPIPE) {
1972           stream->length = -1;
1973           stream->wait   = pipe_wait;
1974           stream->peek   = pipe_peek;
1975           stream->read   = pipe_read;
1976      }
1977      else {
1978           struct stat s;
1979 
1980           if (fstat( stream->fd, &s ) < 0)
1981                return errno2result( errno );
1982 
1983           stream->length = s.st_size;
1984           stream->peek   = file_peek;
1985           stream->read   = file_read;
1986           stream->seek   = file_seek;
1987      }
1988 
1989      return DR_OK;
1990 }
1991 
1992 /*****************************************************************************/
1993 
1994 DirectResult
direct_stream_create(const char * filename,DirectStream ** ret_stream)1995 direct_stream_create( const char    *filename,
1996                       DirectStream **ret_stream )
1997 {
1998      DirectStream *stream;
1999      DirectResult  ret;
2000 
2001      D_ASSERT( filename != NULL );
2002      D_ASSERT( ret_stream != NULL );
2003 
2004      stream = D_CALLOC( 1, sizeof(DirectStream) );
2005      if (!stream)
2006           return D_OOM();
2007 
2008      D_MAGIC_SET( stream, DirectStream );
2009 
2010      stream->ref =  1;
2011      stream->fd  = -1;
2012 
2013      if (!strncmp( filename, "stdin:/", 7 )) {
2014           ret = file_open( stream, NULL, STDIN_FILENO );
2015      }
2016      else if (!strncmp( filename, "file:/", 6 )) {
2017           ret = file_open( stream, filename+6, -1 );
2018      }
2019      else if (!strncmp( filename, "fd:/", 4 )) {
2020           ret = (filename[4] >= '0' && filename[4] <= '9')
2021                 ? file_open( stream, NULL, atoi(filename+4) ) : DR_INVARG;
2022      }
2023 #if DIRECT_BUILD_NETWORK
2024      else if (!strncmp( filename, "http://", 7 ) ||
2025               !strncmp( filename, "unsv://", 7 )) {
2026           ret = http_open( stream, filename+7 );
2027      }
2028      else if (!strncmp( filename, "ftp://", 6 )) {
2029           ret = ftp_open( stream, filename+6 );
2030      }
2031      else if (!strncmp( filename, "rtsp://", 7 )) {
2032           ret = rtsp_open( stream, filename+7 );
2033      }
2034      else if (!strncmp( filename, "tcp://", 6 )) {
2035           ret = net_open( stream, filename+6, IPPROTO_TCP );
2036      }
2037      else if (!strncmp( filename, "udp://", 6 )) {
2038           ret = net_open( stream, filename+6, IPPROTO_UDP );
2039      }
2040 #endif
2041      else {
2042           ret = file_open( stream, filename, -1 );
2043      }
2044 
2045      if (ret) {
2046           direct_stream_close( stream );
2047           D_FREE( stream );
2048           return ret;
2049      }
2050 
2051      *ret_stream = stream;
2052 
2053      return DR_OK;
2054 }
2055 
2056 DirectStream*
direct_stream_dup(DirectStream * stream)2057 direct_stream_dup( DirectStream *stream )
2058 {
2059      D_ASSERT( stream != NULL );
2060 
2061      D_MAGIC_ASSERT( stream, DirectStream );
2062 
2063      stream->ref++;
2064 
2065      return stream;
2066 }
2067 
2068 int
direct_stream_fileno(DirectStream * stream)2069 direct_stream_fileno( DirectStream  *stream )
2070 {
2071      D_ASSERT( stream != NULL );
2072 
2073      D_MAGIC_ASSERT( stream, DirectStream );
2074 
2075      return stream->fd;
2076 }
2077 
2078 bool
direct_stream_seekable(DirectStream * stream)2079 direct_stream_seekable( DirectStream *stream )
2080 {
2081      D_ASSERT( stream != NULL );
2082 
2083      D_MAGIC_ASSERT( stream, DirectStream );
2084 
2085      return stream->seek ? true : false;
2086 }
2087 
2088 bool
direct_stream_remote(DirectStream * stream)2089 direct_stream_remote( DirectStream *stream )
2090 {
2091      D_ASSERT( stream != NULL );
2092 
2093      D_MAGIC_ASSERT( stream, DirectStream );
2094 
2095 #if DIRECT_BUILD_NETWORK
2096      if (stream->remote.host)
2097           return true;
2098 #endif
2099      return false;
2100 }
2101 
2102 const char*
direct_stream_mime(DirectStream * stream)2103 direct_stream_mime( DirectStream *stream )
2104 {
2105      D_ASSERT( stream != NULL );
2106 
2107      D_MAGIC_ASSERT( stream, DirectStream );
2108 
2109      return stream->mime;
2110 }
2111 
2112 unsigned int
direct_stream_offset(DirectStream * stream)2113 direct_stream_offset( DirectStream *stream )
2114 {
2115      D_ASSERT( stream != NULL );
2116 
2117      D_MAGIC_ASSERT( stream, DirectStream );
2118 
2119      return stream->offset;
2120 }
2121 
2122 unsigned int
direct_stream_length(DirectStream * stream)2123 direct_stream_length( DirectStream *stream )
2124 {
2125      D_ASSERT( stream != NULL );
2126 
2127      D_MAGIC_ASSERT( stream, DirectStream );
2128 
2129      return (stream->length >= 0) ? stream->length : stream->offset;
2130 }
2131 
2132 DirectResult
direct_stream_wait(DirectStream * stream,unsigned int length,struct timeval * tv)2133 direct_stream_wait( DirectStream   *stream,
2134                     unsigned int    length,
2135                     struct timeval *tv )
2136 {
2137      D_ASSERT( stream != NULL );
2138 
2139      D_MAGIC_ASSERT( stream, DirectStream );
2140 
2141      if (length && stream->wait)
2142           return stream->wait( stream, length, tv );
2143 
2144      return DR_OK;
2145 }
2146 
2147 DirectResult
direct_stream_peek(DirectStream * stream,unsigned int length,int offset,void * buf,unsigned int * read_out)2148 direct_stream_peek( DirectStream *stream,
2149                     unsigned int  length,
2150                     int           offset,
2151                     void         *buf,
2152                     unsigned int *read_out )
2153 {
2154      D_ASSERT( stream != NULL );
2155      D_ASSERT( length != 0 );
2156      D_ASSERT( buf != NULL );
2157 
2158      D_MAGIC_ASSERT( stream, DirectStream );
2159 
2160      if (stream->length >= 0 && (stream->offset + offset) >= stream->length)
2161           return DR_EOF;
2162 
2163      if (stream->peek)
2164           return stream->peek( stream, length, offset, buf, read_out );
2165 
2166      return DR_UNSUPPORTED;
2167 }
2168 
2169 DirectResult
direct_stream_read(DirectStream * stream,unsigned int length,void * buf,unsigned int * read_out)2170 direct_stream_read( DirectStream *stream,
2171                     unsigned int  length,
2172                     void         *buf,
2173                     unsigned int *read_out )
2174 {
2175      D_ASSERT( stream != NULL );
2176      D_ASSERT( length != 0 );
2177      D_ASSERT( buf != NULL );
2178 
2179      D_MAGIC_ASSERT( stream, DirectStream );
2180 
2181      if (stream->length >= 0 && stream->offset >= stream->length)
2182           return DR_EOF;
2183 
2184      if (stream->read)
2185           return stream->read( stream, length, buf, read_out );
2186 
2187      return DR_UNSUPPORTED;
2188 }
2189 
2190 DirectResult
direct_stream_seek(DirectStream * stream,unsigned int offset)2191 direct_stream_seek( DirectStream *stream,
2192                     unsigned int  offset )
2193 {
2194      D_ASSERT( stream != NULL );
2195 
2196      D_MAGIC_ASSERT( stream, DirectStream );
2197 
2198      if (stream->offset == offset)
2199           return DR_OK;
2200 
2201      if (stream->length >= 0 && offset > stream->length)
2202           offset = stream->length;
2203 
2204      if (stream->seek)
2205           return stream->seek( stream, offset );
2206 
2207      return DR_UNSUPPORTED;
2208 }
2209 
2210 static void
direct_stream_close(DirectStream * stream)2211 direct_stream_close( DirectStream *stream )
2212 {
2213 #if DIRECT_BUILD_NETWORK
2214      if (stream->remote.host) {
2215           D_FREE( stream->remote.host );
2216           stream->remote.host = NULL;
2217      }
2218 
2219      if (stream->remote.user) {
2220           D_FREE( stream->remote.user );
2221           stream->remote.user = NULL;
2222      }
2223 
2224      if (stream->remote.pass) {
2225           D_FREE( stream->remote.pass );
2226           stream->remote.pass = NULL;
2227      }
2228 
2229      if (stream->remote.auth) {
2230           D_FREE( stream->remote.auth );
2231           stream->remote.auth = NULL;
2232      }
2233 
2234      if (stream->remote.path) {
2235           D_FREE( stream->remote.path );
2236           stream->remote.path = NULL;
2237      }
2238 
2239      if (stream->remote.addr) {
2240           freeaddrinfo( stream->remote.addr );
2241           stream->remote.addr = NULL;
2242      }
2243 
2244      if (stream->remote.data) {
2245           D_FREE( stream->remote.data );
2246           stream->remote.data = NULL;
2247      }
2248 
2249      if (stream->remote.sd > 0) {
2250           close( stream->remote.sd );
2251           stream->remote.sd = -1;
2252      }
2253 #endif
2254 
2255      if (stream->mime) {
2256           D_FREE( stream->mime );
2257           stream->mime = NULL;
2258      }
2259 
2260      if (stream->cache) {
2261           D_FREE( stream->cache );
2262           stream->cache = NULL;
2263           stream->cache_size = 0;
2264      }
2265 
2266      if (stream->fd >= 0) {
2267           fcntl( stream->fd, F_SETFL,
2268                     fcntl( stream->fd, F_GETFL ) & ~O_NONBLOCK );
2269           close( stream->fd );
2270           stream->fd = -1;
2271      }
2272 }
2273 
2274 void
direct_stream_destroy(DirectStream * stream)2275 direct_stream_destroy( DirectStream *stream )
2276 {
2277      D_ASSERT( stream != NULL );
2278 
2279      D_MAGIC_ASSERT( stream, DirectStream );
2280 
2281      if (--stream->ref == 0) {
2282           direct_stream_close( stream );
2283 
2284           D_FREE( stream );
2285      }
2286 }
2287