mp3dec: move XING/Info and VBRI parsing into their own functions
[libav.git] / avserver.c
CommitLineData
85f07f22
FB
1/*
2 * Multiple format streaming server
773a21b8 3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
85f07f22 4 *
2912e87a 5 * This file is part of Libav.
b78e7197 6 *
2912e87a 7 * Libav is free software; you can redistribute it and/or
773a21b8
FB
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
b78e7197 10 * version 2.1 of the License, or (at your option) any later version.
85f07f22 11 *
2912e87a 12 * Libav is distributed in the hope that it will be useful,
85f07f22 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
773a21b8
FB
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
85f07f22 16 *
773a21b8 17 * You should have received a copy of the GNU Lesser General Public
2912e87a 18 * License along with Libav; if not, write to the Free Software
5509bffa 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
85f07f22 20 */
364a9607 21
0f4e8165 22#include "config.h"
b250f9c6 23#if !HAVE_CLOSESOCKET
0f4e8165
RB
24#define closesocket close
25#endif
26#include <string.h>
27#include <stdlib.h>
a4cd2ad8 28#include <stdio.h>
245976da 29#include "libavformat/avformat.h"
b263bf66 30// FIXME those are internal headers, avserver _really_ shouldn't use them
3ee53dab 31#include "libavformat/ffm.h"
245976da
DB
32#include "libavformat/network.h"
33#include "libavformat/os_support.h"
302879cb 34#include "libavformat/rtpdec.h"
b7e6da98 35#include "libavformat/rtpproto.h"
245976da 36#include "libavformat/rtsp.h"
403ee835 37#include "libavformat/avio_internal.h"
b263bf66
AK
38#include "libavformat/internal.h"
39#include "libavformat/url.h"
40
959da985 41#include "libavutil/avstring.h"
042819c5 42#include "libavutil/lfg.h"
d2d67e42 43#include "libavutil/dict.h"
3b20eb25 44#include "libavutil/intreadwrite.h"
0ebcdf5c 45#include "libavutil/mathematics.h"
042819c5 46#include "libavutil/random_seed.h"
737eb597 47#include "libavutil/parseutils.h"
41d0eb1c 48#include "libavutil/opt.h"
676ea8fa
DB
49#include "libavutil/time.h"
50
85f07f22 51#include <stdarg.h>
85f07f22
FB
52#include <unistd.h>
53#include <fcntl.h>
54#include <sys/ioctl.h>
b250f9c6 55#if HAVE_POLL_H
f8cda19e 56#include <poll.h>
b0c858d8 57#endif
85f07f22 58#include <errno.h>
85f07f22 59#include <time.h>
5eb765ef 60#include <sys/wait.h>
85f07f22 61#include <signal.h>
2effd274 62
4ce5df08 63#include "cmdutils.h"
85f07f22 64
4d58e4cb 65const char program_name[] = "avserver";
ea9c581f 66const int program_birth_year = 2000;
86074ed1 67
5a635bc7
SS
68static const OptionDef options[];
69
85f07f22
FB
70enum HTTPState {
71 HTTPSTATE_WAIT_REQUEST,
72 HTTPSTATE_SEND_HEADER,
73 HTTPSTATE_SEND_DATA_HEADER,
2effd274 74 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
85f07f22 75 HTTPSTATE_SEND_DATA_TRAILER,
115329f1 76 HTTPSTATE_RECEIVE_DATA,
2effd274 77 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
2effd274
FB
78 HTTPSTATE_READY,
79
80 RTSPSTATE_WAIT_REQUEST,
81 RTSPSTATE_SEND_REPLY,
bc351386 82 RTSPSTATE_SEND_PACKET,
85f07f22
FB
83};
84
9507a12e 85static const char *http_state[] = {
2effd274
FB
86 "HTTP_WAIT_REQUEST",
87 "HTTP_SEND_HEADER",
88
85f07f22
FB
89 "SEND_DATA_HEADER",
90 "SEND_DATA",
91 "SEND_DATA_TRAILER",
92 "RECEIVE_DATA",
93 "WAIT_FEED",
2effd274
FB
94 "READY",
95
96 "RTSP_WAIT_REQUEST",
97 "RTSP_SEND_REPLY",
bc351386 98 "RTSP_SEND_PACKET",
85f07f22
FB
99};
100
aff88101 101#define MAX_STREAMS 20
aff88101 102
cde25790 103#define IOBUFFER_INIT_SIZE 8192
85f07f22 104
85f07f22 105/* timeouts are in ms */
2effd274
FB
106#define HTTP_REQUEST_TIMEOUT (15 * 1000)
107#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
108
85f07f22
FB
109#define SYNC_TIMEOUT (10 * 1000)
110
b516ecdd
RB
111typedef struct RTSPActionServerSetup {
112 uint32_t ipaddr;
113 char transport_option[512];
114} RTSPActionServerSetup;
115
5eb765ef 116typedef struct {
0c1a9eda 117 int64_t count1, count2;
c3f58185 118 int64_t time1, time2;
5eb765ef
PG
119} DataRateData;
120
85f07f22
FB
121/* context associated with one connection */
122typedef struct HTTPContext {
123 enum HTTPState state;
124 int fd; /* socket file descriptor */
125 struct sockaddr_in from_addr; /* origin */
126 struct pollfd *poll_entry; /* used when polling */
c3f58185 127 int64_t timeout;
0c1a9eda 128 uint8_t *buffer_ptr, *buffer_end;
85f07f22 129 int http_error;
edfdd798 130 int post;
19c8c4ec
RB
131 int chunked_encoding;
132 int chunk_size; /* 0 if it needs to be read */
85f07f22 133 struct HTTPContext *next;
42a63c6a 134 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
0c1a9eda 135 int64_t data_count;
85f07f22
FB
136 /* feed input */
137 int feed_fd;
138 /* input format handling */
139 AVFormatContext *fmt_in;
c3f58185 140 int64_t start_time; /* In milliseconds - this wraps fairly often */
0c1a9eda 141 int64_t first_pts; /* initial pts value */
e240a0bb
FB
142 int64_t cur_pts; /* current pts value from the stream in us */
143 int64_t cur_frame_duration; /* duration of the current frame in us */
144 int cur_frame_bytes; /* output frame size, needed to compute
145 the time at which we send each
146 packet */
147 int pts_stream_index; /* stream we choose as clock reference */
148 int64_t cur_clock; /* current clock reference value in us */
85f07f22
FB
149 /* output format handling */
150 struct FFStream *stream;
cde25790
PG
151 /* -1 is invalid stream */
152 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
153 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
154 int switch_pending;
2effd274 155 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
85f07f22 156 int last_packet_sent; /* true if last data packet was sent */
7434ba6d 157 int suppress_log;
5eb765ef 158 DataRateData datarate;
3120d2a2 159 int wmp_client_id;
7434ba6d
PG
160 char protocol[16];
161 char method[16];
162 char url[128];
cde25790 163 int buffer_size;
0c1a9eda 164 uint8_t *buffer;
2effd274
FB
165 int is_packetized; /* if true, the stream is packetized */
166 int packet_stream_index; /* current stream for output in state machine */
115329f1 167
2effd274 168 /* RTSP state specific */
0c1a9eda 169 uint8_t *pb_buffer; /* XXX: use that in all the code */
ae628ec1 170 AVIOContext *pb;
2effd274 171 int seq; /* RTSP sequence number */
115329f1 172
2effd274 173 /* RTP state specific */
90abbdba 174 enum RTSPLowerTransport rtp_protocol;
2effd274
FB
175 char session_id[32]; /* session id */
176 AVFormatContext *rtp_ctx[MAX_STREAMS];
e240a0bb 177
bc351386
FB
178 /* RTP/UDP specific */
179 URLContext *rtp_handles[MAX_STREAMS];
180
181 /* RTP/TCP specific */
182 struct HTTPContext *rtsp_c;
183 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
85f07f22
FB
184} HTTPContext;
185
186/* each generated stream is described here */
187enum StreamType {
188 STREAM_TYPE_LIVE,
189 STREAM_TYPE_STATUS,
cde25790 190 STREAM_TYPE_REDIRECT,
85f07f22
FB
191};
192
8256c0a3
PG
193enum IPAddressAction {
194 IP_ALLOW = 1,
195 IP_DENY,
196};
197
198typedef struct IPAddressACL {
199 struct IPAddressACL *next;
200 enum IPAddressAction action;
efa04ce2 201 /* These are in host order */
8256c0a3
PG
202 struct in_addr first;
203 struct in_addr last;
204} IPAddressACL;
205
4d58e4cb 206/* description of each stream of the avserver.conf file */
85f07f22
FB
207typedef struct FFStream {
208 enum StreamType stream_type;
209 char filename[1024]; /* stream filename */
2effd274
FB
210 struct FFStream *feed; /* feed we are using (can be null if
211 coming from file) */
50f2dfad 212 AVDictionary *in_opts; /* input parameters */
e240a0bb 213 AVInputFormat *ifmt; /* if non NULL, force input format */
bd7cf6ad 214 AVOutputFormat *fmt;
8256c0a3 215 IPAddressACL *acl;
58f48adb 216 char dynamic_acl[1024];
85f07f22 217 int nb_streams;
42a63c6a 218 int prebuffer; /* Number of millseconds early to start */
c3f58185 219 int64_t max_time; /* Number of milliseconds to run */
79c4ea3c 220 int send_on_key;
85f07f22
FB
221 AVStream *streams[MAX_STREAMS];
222 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
223 char feed_filename[1024]; /* file name of the feed storage, or
224 input file name for a stream */
2ac887ba
PG
225 char author[512];
226 char title[512];
227 char copyright[512];
228 char comment[512];
20566eb0
DB
229 pid_t pid; /* of avconv process */
230 time_t pid_start; /* of avconv process */
cde25790 231 char **child_argv;
85f07f22 232 struct FFStream *next;
177d2564 233 unsigned bandwidth; /* bandwidth, in kbits/s */
2effd274
FB
234 /* RTSP options */
235 char *rtsp_option;
829ac53d
FB
236 /* multicast specific */
237 int is_multicast;
238 struct in_addr multicast_ip;
239 int multicast_port; /* first port used for multicast */
6edd6884
FB
240 int multicast_ttl;
241 int loop; /* if true, send the stream in loops (only meaningful if file) */
829ac53d 242
85f07f22 243 /* feed specific */
2effd274 244 int feed_opened; /* true if someone is writing to the feed */
85f07f22 245 int is_feed; /* true if it is a feed */
e322ea48 246 int readonly; /* True if writing is prohibited to the file */
861ec13a 247 int truncate; /* True if feeder connection truncate the feed file */
a6e14edd 248 int conns_served;
0c1a9eda 249 int64_t bytes_served;
6b0bdc75 250 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
8bfb108b 251 int64_t feed_write_index; /* current write position in feed (it wraps around) */
0c1a9eda 252 int64_t feed_size; /* current size of feed */
85f07f22
FB
253 struct FFStream *next_feed;
254} FFStream;
255
256typedef struct FeedData {
257 long long data_count;
8bfb108b 258 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
85f07f22
FB
259} FeedData;
260
18405874
AB
261static struct sockaddr_in my_http_addr;
262static struct sockaddr_in my_rtsp_addr;
2effd274 263
33f5e2ec
AB
264static char logfilename[1024];
265static HTTPContext *first_http_ctx;
266static FFStream *first_feed; /* contains only feeds */
267static FFStream *first_stream; /* contains all streams, including feeds */
85f07f22 268
2effd274
FB
269static void new_connection(int server_fd, int is_rtsp);
270static void close_connection(HTTPContext *c);
271
272/* HTTP handling */
273static int handle_connection(HTTPContext *c);
85f07f22 274static int http_parse_request(HTTPContext *c);
5eb765ef 275static int http_send_data(HTTPContext *c);
dca21085 276static void compute_status(HTTPContext *c);
85f07f22
FB
277static int open_input_stream(HTTPContext *c, const char *info);
278static int http_start_receive_data(HTTPContext *c);
279static int http_receive_data(HTTPContext *c);
2effd274
FB
280
281/* RTSP handling */
282static int rtsp_parse_request(HTTPContext *c);
283static void rtsp_cmd_describe(HTTPContext *c, const char *url);
0df65975 284static void rtsp_cmd_options(HTTPContext *c, const char *url);
a9e534d5
RB
285static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
286static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
287static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
288static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
2effd274 289
829ac53d 290/* SDP handling */
115329f1 291static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
829ac53d
FB
292 struct in_addr my_ip);
293
2effd274 294/* RTP handling */
115329f1 295static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
bc351386 296 FFStream *stream, const char *session_id,
90abbdba 297 enum RTSPLowerTransport rtp_protocol);
115329f1 298static int rtp_new_av_stream(HTTPContext *c,
bc351386
FB
299 int stream_index, struct sockaddr_in *dest_addr,
300 HTTPContext *rtsp_c);
85f07f22 301
cde25790
PG
302static const char *my_program_name;
303
612a5049 304static const char *config_filename;
6675a5bf 305
4d58e4cb 306static int avserver_debug;
2ac887ba 307static int no_launch;
5eb765ef 308static int need_to_start_children;
2ac887ba 309
1c9ff179
SS
310/* maximum number of simultaneous HTTP connections */
311static unsigned int nb_max_http_connections = 2000;
4af92de6
SS
312static unsigned int nb_max_connections = 5;
313static unsigned int nb_connections;
85f07f22 314
f69bb0cc 315static uint64_t max_bandwidth = 1000;
1ad8289e 316static uint64_t current_bandwidth;
42a63c6a 317
c3f58185 318static int64_t cur_time; // Making this global saves on passing it around everywhere
5eb765ef 319
042819c5 320static AVLFG random_state;
1df93ae9 321
85f07f22
FB
322static FILE *logfile = NULL;
323
3b20eb25
MR
324static int64_t ffm_read_write_index(int fd)
325{
326 uint8_t buf[8];
327
328 lseek(fd, 8, SEEK_SET);
329 if (read(fd, buf, 8) != 8)
330 return AVERROR(EIO);
331 return AV_RB64(buf);
332}
333
334static int ffm_write_write_index(int fd, int64_t pos)
335{
336 uint8_t buf[8];
337 int i;
338
339 for(i=0;i<8;i++)
340 buf[i] = (pos >> (56 - i * 8)) & 0xff;
341 lseek(fd, 8, SEEK_SET);
342 if (write(fd, buf, 8) != 8)
343 return AVERROR(EIO);
344 return 8;
345}
346
347static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
348 int64_t file_size)
349{
350 FFMContext *ffm = s->priv_data;
351 ffm->write_index = pos;
352 ffm->file_size = file_size;
353}
354
4d58e4cb 355/* FIXME: make avserver work with IPv6 */
22f73dcc
MR
356/* resolve host with also IP address parsing */
357static int resolve_host(struct in_addr *sin_addr, const char *hostname)
358{
359
360 if (!ff_inet_aton(hostname, sin_addr)) {
361#if HAVE_GETADDRINFO
362 struct addrinfo *ai, *cur;
a92be9b8 363 struct addrinfo hints = { 0 };
22f73dcc
MR
364 hints.ai_family = AF_INET;
365 if (getaddrinfo(hostname, NULL, &hints, &ai))
366 return -1;
367 /* getaddrinfo returns a linked list of addrinfo structs.
368 * Even if we set ai_family = AF_INET above, make sure
369 * that the returned one actually is of the correct type. */
370 for (cur = ai; cur; cur = cur->ai_next) {
371 if (cur->ai_family == AF_INET) {
372 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
373 freeaddrinfo(ai);
374 return 0;
375 }
376 }
377 freeaddrinfo(ai);
378 return -1;
379#else
380 struct hostent *hp;
381 hp = gethostbyname(hostname);
382 if (!hp)
383 return -1;
384 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
385#endif
386 }
387 return 0;
388}
389
9fd3442f
BC
390static char *ctime1(char *buf2)
391{
392 time_t ti;
393 char *p;
394
395 ti = time(NULL);
396 p = ctime(&ti);
397 strcpy(buf2, p);
398 p = buf2 + strlen(p) - 1;
399 if (*p == '\n')
400 *p = '\0';
401 return buf2;
402}
403
bcd3ce59 404static void http_vlog(const char *fmt, va_list vargs)
85f07f22 405{
124ed1c0 406 static int print_prefix = 1;
7434ba6d 407 if (logfile) {
124ed1c0 408 if (print_prefix) {
9fd3442f
BC
409 char buf[32];
410 ctime1(buf);
411 fprintf(logfile, "%s ", buf);
124ed1c0
BC
412 }
413 print_prefix = strstr(fmt, "\n") != NULL;
bcd3ce59 414 vfprintf(logfile, fmt, vargs);
7434ba6d
PG
415 fflush(logfile);
416 }
bcd3ce59
BC
417}
418
efa6ce99
MR
419#ifdef __GNUC__
420__attribute__ ((format (printf, 1, 2)))
421#endif
422static void http_log(const char *fmt, ...)
bcd3ce59
BC
423{
424 va_list vargs;
425 va_start(vargs, fmt);
426 http_vlog(fmt, vargs);
427 va_end(vargs);
428}
429
430static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
431{
432 static int print_prefix = 1;
433 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
49ceb58b 434 if (level > av_log_get_level())
bcd3ce59
BC
435 return;
436 if (print_prefix && avc)
59e7894c 437 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
bcd3ce59
BC
438 print_prefix = strstr(fmt, "\n") != NULL;
439 http_vlog(fmt, vargs);
85f07f22
FB
440}
441
6edd6884
FB
442static void log_connection(HTTPContext *c)
443{
115329f1 444 if (c->suppress_log)
6edd6884
FB
445 return;
446
82e0be62
BC
447 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
448 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
6edd6884 449 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
cde25790
PG
450}
451
0c1a9eda 452static void update_datarate(DataRateData *drd, int64_t count)
5eb765ef
PG
453{
454 if (!drd->time1 && !drd->count1) {
455 drd->time1 = drd->time2 = cur_time;
456 drd->count1 = drd->count2 = count;
eeffbdea 457 } else if (cur_time - drd->time2 > 5000) {
33a4ecbe
AB
458 drd->time1 = drd->time2;
459 drd->count1 = drd->count2;
460 drd->time2 = cur_time;
461 drd->count2 = count;
5eb765ef
PG
462 }
463}
464
465/* In bytes per second */
0c1a9eda 466static int compute_datarate(DataRateData *drd, int64_t count)
5eb765ef
PG
467{
468 if (cur_time == drd->time1)
469 return 0;
115329f1 470
5eb765ef
PG
471 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
472}
473
a782f209 474
cde25790
PG
475static void start_children(FFStream *feed)
476{
2ac887ba
PG
477 if (no_launch)
478 return;
479
cde25790 480 for (; feed; feed = feed->next) {
5eb765ef
PG
481 if (feed->child_argv && !feed->pid) {
482 feed->pid_start = time(0);
483
cde25790
PG
484 feed->pid = fork();
485
486 if (feed->pid < 0) {
b4befb99 487 http_log("Unable to create children\n");
cde25790
PG
488 exit(1);
489 }
490 if (!feed->pid) {
491 /* In child */
492 char pathname[1024];
493 char *slash;
494 int i;
495
40444a59
SS
496 av_strlcpy(pathname, my_program_name, sizeof(pathname));
497
498 slash = strrchr(pathname, '/');
499 if (!slash)
500 slash = pathname;
501 else
502 slash++;
20566eb0 503 strcpy(slash, "avconv");
40444a59 504
da9cea77 505 http_log("Launch command line: ");
8bf61f5b
SS
506 http_log("%s ", pathname);
507 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
508 http_log("%s ", feed->child_argv[i]);
509 http_log("\n");
40444a59 510
611c5741 511 for (i = 3; i < 256; i++)
5eb765ef 512 close(i);
cde25790 513
4d58e4cb 514 if (!avserver_debug) {
a4cd2ad8
JG
515 if (!freopen("/dev/null", "r", stdin))
516 http_log("failed to redirect STDIN to /dev/null\n;");
517 if (!freopen("/dev/null", "w", stdout))
518 http_log("failed to redirect STDOUT to /dev/null\n;");
519 if (!freopen("/dev/null", "w", stderr))
520 http_log("failed to redirect STDERR to /dev/null\n;");
2ac887ba 521 }
cde25790 522
a4d70941
PG
523 signal(SIGPIPE, SIG_DFL);
524
cde25790
PG
525 execvp(pathname, feed->child_argv);
526
527 _exit(1);
528 }
529 }
530 }
7434ba6d
PG
531}
532
2effd274
FB
533/* open a listening socket */
534static int socket_open_listen(struct sockaddr_in *my_addr)
85f07f22 535{
2effd274 536 int server_fd, tmp;
85f07f22
FB
537
538 server_fd = socket(AF_INET,SOCK_STREAM,0);
539 if (server_fd < 0) {
540 perror ("socket");
541 return -1;
542 }
115329f1 543
85f07f22
FB
544 tmp = 1;
545 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
546
f5e717f3 547 my_addr->sin_family = AF_INET;
2effd274 548 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
b17d099d
PG
549 char bindmsg[32];
550 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
551 perror (bindmsg);
d96633bb 552 closesocket(server_fd);
85f07f22
FB
553 return -1;
554 }
115329f1 555
85f07f22
FB
556 if (listen (server_fd, 5) < 0) {
557 perror ("listen");
d96633bb 558 closesocket(server_fd);
85f07f22
FB
559 return -1;
560 }
ba472aaf 561 ff_socket_nonblock(server_fd, 1);
2effd274
FB
562
563 return server_fd;
564}
565
6edd6884
FB
566/* start all multicast streams */
567static void start_multicast(void)
568{
569 FFStream *stream;
570 char session_id[32];
571 HTTPContext *rtp_c;
572 struct sockaddr_in dest_addr;
573 int default_port, stream_index;
574
575 default_port = 6000;
576 for(stream = first_stream; stream != NULL; stream = stream->next) {
577 if (stream->is_multicast) {
578 /* open the RTP connection */
1df93ae9 579 snprintf(session_id, sizeof(session_id), "%08x%08x",
042819c5 580 av_lfg_get(&random_state), av_lfg_get(&random_state));
6edd6884
FB
581
582 /* choose a port if none given */
583 if (stream->multicast_port == 0) {
584 stream->multicast_port = default_port;
585 default_port += 100;
586 }
587
588 dest_addr.sin_family = AF_INET;
589 dest_addr.sin_addr = stream->multicast_ip;
590 dest_addr.sin_port = htons(stream->multicast_port);
591
115329f1 592 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
90abbdba 593 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
611c5741 594 if (!rtp_c)
6edd6884 595 continue;
611c5741 596
6edd6884 597 if (open_input_stream(rtp_c, "") < 0) {
b4befb99
BC
598 http_log("Could not open input stream for stream '%s'\n",
599 stream->filename);
6edd6884
FB
600 continue;
601 }
602
6edd6884 603 /* open each RTP stream */
115329f1 604 for(stream_index = 0; stream_index < stream->nb_streams;
6edd6884 605 stream_index++) {
115329f1 606 dest_addr.sin_port = htons(stream->multicast_port +
6edd6884 607 2 * stream_index);
bc351386 608 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
b4befb99
BC
609 http_log("Could not open output stream '%s/streamid=%d'\n",
610 stream->filename, stream_index);
0fa45e19 611 exit(1);
6edd6884
FB
612 }
613 }
614
615 /* change state to send data */
616 rtp_c->state = HTTPSTATE_SEND_DATA;
617 }
618 }
619}
2effd274
FB
620
621/* main loop of the http server */
622static int http_server(void)
623{
d2a1ea1d
BC
624 int server_fd = 0, rtsp_server_fd = 0;
625 int ret, delay, delay1;
1c9ff179 626 struct pollfd *poll_table, *poll_entry;
2effd274
FB
627 HTTPContext *c, *c_next;
628
a7f361eb 629 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
1c9ff179
SS
630 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
631 return -1;
632 }
633
d2a1ea1d 634 if (my_http_addr.sin_port) {
2b9cd1e7
BC
635 server_fd = socket_open_listen(&my_http_addr);
636 if (server_fd < 0)
637 return -1;
d2a1ea1d 638 }
85f07f22 639
d2a1ea1d 640 if (my_rtsp_addr.sin_port) {
2b9cd1e7
BC
641 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
642 if (rtsp_server_fd < 0)
643 return -1;
d2a1ea1d
BC
644 }
645
646 if (!rtsp_server_fd && !server_fd) {
647 http_log("HTTP and RTSP disabled.\n");
648 return -1;
649 }
115329f1 650
4d58e4cb 651 http_log("AVserver started.\n");
85f07f22 652
cde25790
PG
653 start_children(first_feed);
654
6edd6884
FB
655 start_multicast();
656
85f07f22
FB
657 for(;;) {
658 poll_entry = poll_table;
d2a1ea1d 659 if (server_fd) {
2b9cd1e7
BC
660 poll_entry->fd = server_fd;
661 poll_entry->events = POLLIN;
662 poll_entry++;
d2a1ea1d
BC
663 }
664 if (rtsp_server_fd) {
2b9cd1e7
BC
665 poll_entry->fd = rtsp_server_fd;
666 poll_entry->events = POLLIN;
667 poll_entry++;
d2a1ea1d 668 }
2effd274 669
85f07f22
FB
670 /* wait for events on each HTTP handle */
671 c = first_http_ctx;
2effd274 672 delay = 1000;
85f07f22
FB
673 while (c != NULL) {
674 int fd;
675 fd = c->fd;
676 switch(c->state) {
2effd274
FB
677 case HTTPSTATE_SEND_HEADER:
678 case RTSPSTATE_SEND_REPLY:
bc351386 679 case RTSPSTATE_SEND_PACKET:
85f07f22
FB
680 c->poll_entry = poll_entry;
681 poll_entry->fd = fd;
2effd274 682 poll_entry->events = POLLOUT;
85f07f22
FB
683 poll_entry++;
684 break;
85f07f22
FB
685 case HTTPSTATE_SEND_DATA_HEADER:
686 case HTTPSTATE_SEND_DATA:
687 case HTTPSTATE_SEND_DATA_TRAILER:
2effd274
FB
688 if (!c->is_packetized) {
689 /* for TCP, we output as much as we can (may need to put a limit) */
690 c->poll_entry = poll_entry;
691 poll_entry->fd = fd;
692 poll_entry->events = POLLOUT;
693 poll_entry++;
694 } else {
4d58e4cb 695 /* when avserver is doing the timing, we work by
e240a0bb
FB
696 looking at which packet need to be sent every
697 10 ms */
698 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
699 if (delay1 < delay)
700 delay = delay1;
2effd274 701 }
85f07f22 702 break;
2effd274 703 case HTTPSTATE_WAIT_REQUEST:
85f07f22 704 case HTTPSTATE_RECEIVE_DATA:
85f07f22 705 case HTTPSTATE_WAIT_FEED:
2effd274 706 case RTSPSTATE_WAIT_REQUEST:
85f07f22
FB
707 /* need to catch errors */
708 c->poll_entry = poll_entry;
709 poll_entry->fd = fd;
a6e14edd 710 poll_entry->events = POLLIN;/* Maybe this will work */
85f07f22
FB
711 poll_entry++;
712 break;
713 default:
714 c->poll_entry = NULL;
715 break;
716 }
717 c = c->next;
718 }
719
720 /* wait for an event on one connection. We poll at least every
721 second to handle timeouts */
722 do {
2effd274 723 ret = poll(poll_table, poll_entry - poll_table, delay);
28c4741a
MS
724 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
725 ff_neterrno() != AVERROR(EINTR))
53e2f9ca 726 return -1;
e8d658df 727 } while (ret < 0);
115329f1 728
c3f58185 729 cur_time = av_gettime() / 1000;
85f07f22 730
5eb765ef
PG
731 if (need_to_start_children) {
732 need_to_start_children = 0;
733 start_children(first_feed);
734 }
735
85f07f22 736 /* now handle the events */
2effd274
FB
737 for(c = first_http_ctx; c != NULL; c = c_next) {
738 c_next = c->next;
739 if (handle_connection(c) < 0) {
85f07f22 740 /* close and free the connection */
7434ba6d 741 log_connection(c);
2effd274 742 close_connection(c);
85f07f22
FB
743 }
744 }
745
85f07f22 746 poll_entry = poll_table;
d2a1ea1d 747 if (server_fd) {
2b9cd1e7
BC
748 /* new HTTP connection request ? */
749 if (poll_entry->revents & POLLIN)
750 new_connection(server_fd, 0);
751 poll_entry++;
d2a1ea1d
BC
752 }
753 if (rtsp_server_fd) {
2b9cd1e7
BC
754 /* new RTSP connection request ? */
755 if (poll_entry->revents & POLLIN)
756 new_connection(rtsp_server_fd, 1);
d2a1ea1d 757 }
85f07f22
FB
758 }
759}
760
2effd274
FB
761/* start waiting for a new HTTP/RTSP request */
762static void start_wait_request(HTTPContext *c, int is_rtsp)
85f07f22 763{
2effd274
FB
764 c->buffer_ptr = c->buffer;
765 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
766
767 if (is_rtsp) {
768 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
769 c->state = RTSPSTATE_WAIT_REQUEST;
770 } else {
771 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
772 c->state = HTTPSTATE_WAIT_REQUEST;
773 }
774}
775
0bdd8b85
BC
776static void http_send_too_busy_reply(int fd)
777{
778 char buffer[300];
779 int len = snprintf(buffer, sizeof(buffer),
2a22187f 780 "HTTP/1.0 503 Server too busy\r\n"
0bdd8b85
BC
781 "Content-type: text/html\r\n"
782 "\r\n"
783 "<html><head><title>Too busy</title></head><body>\r\n"
784 "<p>The server is too busy to serve your request at this time.</p>\r\n"
785 "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
786 "</body></html>\r\n",
787 nb_connections, nb_max_connections);
788 send(fd, buffer, len, 0);
789}
790
791
2effd274
FB
792static void new_connection(int server_fd, int is_rtsp)
793{
794 struct sockaddr_in from_addr;
cc64ec57
MR
795 socklen_t len;
796 int fd;
2effd274
FB
797 HTTPContext *c = NULL;
798
799 len = sizeof(from_addr);
115329f1 800 fd = accept(server_fd, (struct sockaddr *)&from_addr,
2effd274 801 &len);
050056d0
BC
802 if (fd < 0) {
803 http_log("error during accept %s\n", strerror(errno));
2effd274 804 return;
050056d0 805 }
ba472aaf 806 ff_socket_nonblock(fd, 1);
2effd274 807
0bdd8b85
BC
808 if (nb_connections >= nb_max_connections) {
809 http_send_too_busy_reply(fd);
2effd274 810 goto fail;
0bdd8b85 811 }
115329f1 812
2effd274
FB
813 /* add a new connection */
814 c = av_mallocz(sizeof(HTTPContext));
815 if (!c)
816 goto fail;
115329f1 817
2effd274
FB
818 c->fd = fd;
819 c->poll_entry = NULL;
820 c->from_addr = from_addr;
821 c->buffer_size = IOBUFFER_INIT_SIZE;
822 c->buffer = av_malloc(c->buffer_size);
823 if (!c->buffer)
824 goto fail;
8bc80f8b
PG
825
826 c->next = first_http_ctx;
827 first_http_ctx = c;
2effd274 828 nb_connections++;
115329f1 829
2effd274
FB
830 start_wait_request(c, is_rtsp);
831
832 return;
833
834 fail:
835 if (c) {
836 av_free(c->buffer);
837 av_free(c);
838 }
d96633bb 839 closesocket(fd);
2effd274
FB
840}
841
842static void close_connection(HTTPContext *c)
843{
844 HTTPContext **cp, *c1;
845 int i, nb_streams;
846 AVFormatContext *ctx;
847 URLContext *h;
848 AVStream *st;
849
850 /* remove connection from list */
851 cp = &first_http_ctx;
852 while ((*cp) != NULL) {
853 c1 = *cp;
611c5741 854 if (c1 == c)
2effd274 855 *cp = c->next;
611c5741 856 else
2effd274 857 cp = &c1->next;
2effd274
FB
858 }
859
bc351386
FB
860 /* remove references, if any (XXX: do it faster) */
861 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
862 if (c1->rtsp_c == c)
863 c1->rtsp_c = NULL;
864 }
865
2effd274
FB
866 /* remove connection associated resources */
867 if (c->fd >= 0)
d96633bb 868 closesocket(c->fd);
2effd274
FB
869 if (c->fmt_in) {
870 /* close each frame parser */
871 for(i=0;i<c->fmt_in->nb_streams;i++) {
872 st = c->fmt_in->streams[i];
611c5741 873 if (st->codec->codec)
01f4895c 874 avcodec_close(st->codec);
2effd274 875 }
cd3716b9 876 avformat_close_input(&c->fmt_in);
2effd274
FB
877 }
878
879 /* free RTP output streams if any */
880 nb_streams = 0;
115329f1 881 if (c->stream)
2effd274 882 nb_streams = c->stream->nb_streams;
115329f1 883
2effd274
FB
884 for(i=0;i<nb_streams;i++) {
885 ctx = c->rtp_ctx[i];
886 if (ctx) {
887 av_write_trailer(ctx);
d2d67e42 888 av_dict_free(&ctx->metadata);
ea4f8aab 889 av_free(ctx->streams[0]);
2effd274
FB
890 av_free(ctx);
891 }
892 h = c->rtp_handles[i];
611c5741 893 if (h)
b263bf66 894 ffurl_close(h);
2effd274 895 }
115329f1 896
b88ba823
MH
897 ctx = &c->fmt_ctx;
898
637b638e 899 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
87638494
PG
900 if (ctx->oformat) {
901 /* prepare header */
b92c5452 902 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
87638494 903 av_write_trailer(ctx);
f8b06be9 904 av_freep(&c->pb_buffer);
6dc7d80d 905 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
87638494
PG
906 }
907 }
908 }
909
115329f1 910 for(i=0; i<ctx->nb_streams; i++)
0bd53967 911 av_free(ctx->streams[i]);
f0ef6240 912
edfdd798 913 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
6edd6884 914 current_bandwidth -= c->stream->bandwidth;
5400e092
AB
915
916 /* signal that there is no feed if we are the feeder socket */
917 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
918 c->stream->feed_opened = 0;
919 close(c->feed_fd);
920 }
921
2effd274 922 av_freep(&c->pb_buffer);
bc351386 923 av_freep(&c->packet_buffer);
2effd274
FB
924 av_free(c->buffer);
925 av_free(c);
926 nb_connections--;
927}
928
929static int handle_connection(HTTPContext *c)
930{
931 int len, ret;
115329f1 932
85f07f22
FB
933 switch(c->state) {
934 case HTTPSTATE_WAIT_REQUEST:
2effd274 935 case RTSPSTATE_WAIT_REQUEST:
85f07f22
FB
936 /* timeout ? */
937 if ((c->timeout - cur_time) < 0)
938 return -1;
939 if (c->poll_entry->revents & (POLLERR | POLLHUP))
940 return -1;
941
942 /* no need to read if no events */
943 if (!(c->poll_entry->revents & POLLIN))
944 return 0;
945 /* read the data */
1bc1cfdd 946 read_loop:
c60202df 947 len = recv(c->fd, c->buffer_ptr, 1, 0);
85f07f22 948 if (len < 0) {
28c4741a
MS
949 if (ff_neterrno() != AVERROR(EAGAIN) &&
950 ff_neterrno() != AVERROR(EINTR))
85f07f22
FB
951 return -1;
952 } else if (len == 0) {
953 return -1;
954 } else {
94d9ad5f 955 /* search for end of request. */
0c1a9eda 956 uint8_t *ptr;
85f07f22
FB
957 c->buffer_ptr += len;
958 ptr = c->buffer_ptr;
959 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
960 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
961 /* request found : parse it and reply */
2effd274
FB
962 if (c->state == HTTPSTATE_WAIT_REQUEST) {
963 ret = http_parse_request(c);
964 } else {
965 ret = rtsp_parse_request(c);
966 }
967 if (ret < 0)
85f07f22
FB
968 return -1;
969 } else if (ptr >= c->buffer_end) {
970 /* request too long: cannot do anything */
971 return -1;
1bc1cfdd 972 } else goto read_loop;
85f07f22
FB
973 }
974 break;
975
976 case HTTPSTATE_SEND_HEADER:
977 if (c->poll_entry->revents & (POLLERR | POLLHUP))
978 return -1;
979
2effd274 980 /* no need to write if no events */
85f07f22
FB
981 if (!(c->poll_entry->revents & POLLOUT))
982 return 0;
c60202df 983 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
85f07f22 984 if (len < 0) {
28c4741a
MS
985 if (ff_neterrno() != AVERROR(EAGAIN) &&
986 ff_neterrno() != AVERROR(EINTR)) {
85f07f22 987 /* error : close connection */
2effd274 988 av_freep(&c->pb_buffer);
85f07f22
FB
989 return -1;
990 }
991 } else {
992 c->buffer_ptr += len;
2e04edb3
PG
993 if (c->stream)
994 c->stream->bytes_served += len;
a6e14edd 995 c->data_count += len;
85f07f22 996 if (c->buffer_ptr >= c->buffer_end) {
2effd274 997 av_freep(&c->pb_buffer);
85f07f22 998 /* if error, exit */
611c5741 999 if (c->http_error)
85f07f22 1000 return -1;
2effd274 1001 /* all the buffer was sent : synchronize to the incoming stream */
85f07f22
FB
1002 c->state = HTTPSTATE_SEND_DATA_HEADER;
1003 c->buffer_ptr = c->buffer_end = c->buffer;
1004 }
1005 }
1006 break;
1007
1008 case HTTPSTATE_SEND_DATA:
1009 case HTTPSTATE_SEND_DATA_HEADER:
1010 case HTTPSTATE_SEND_DATA_TRAILER:
2effd274
FB
1011 /* for packetized output, we consider we can always write (the
1012 input streams sets the speed). It may be better to verify
1013 that we do not rely too much on the kernel queues */
1014 if (!c->is_packetized) {
1015 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1016 return -1;
115329f1 1017
2effd274
FB
1018 /* no need to read if no events */
1019 if (!(c->poll_entry->revents & POLLOUT))
1020 return 0;
1021 }
5eb765ef 1022 if (http_send_data(c) < 0)
85f07f22 1023 return -1;
638831aa
AB
1024 /* close connection if trailer sent */
1025 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1026 return -1;
85f07f22
FB
1027 break;
1028 case HTTPSTATE_RECEIVE_DATA:
1029 /* no need to read if no events */
1030 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1031 return -1;
1032 if (!(c->poll_entry->revents & POLLIN))
1033 return 0;
1034 if (http_receive_data(c) < 0)
1035 return -1;
1036 break;
1037 case HTTPSTATE_WAIT_FEED:
1038 /* no need to read if no events */
a6e14edd 1039 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
85f07f22
FB
1040 return -1;
1041
1042 /* nothing to do, we'll be waken up by incoming feed packets */
1043 break;
2effd274 1044
2effd274
FB
1045 case RTSPSTATE_SEND_REPLY:
1046 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1047 av_freep(&c->pb_buffer);
1048 return -1;
1049 }
1050 /* no need to write if no events */
1051 if (!(c->poll_entry->revents & POLLOUT))
1052 return 0;
c60202df 1053 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2effd274 1054 if (len < 0) {
28c4741a
MS
1055 if (ff_neterrno() != AVERROR(EAGAIN) &&
1056 ff_neterrno() != AVERROR(EINTR)) {
2effd274
FB
1057 /* error : close connection */
1058 av_freep(&c->pb_buffer);
1059 return -1;
1060 }
1061 } else {
1062 c->buffer_ptr += len;
1063 c->data_count += len;
1064 if (c->buffer_ptr >= c->buffer_end) {
1065 /* all the buffer was sent : wait for a new request */
1066 av_freep(&c->pb_buffer);
1067 start_wait_request(c, 1);
1068 }
1069 }
1070 break;
bc351386
FB
1071 case RTSPSTATE_SEND_PACKET:
1072 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1073 av_freep(&c->packet_buffer);
1074 return -1;
1075 }
1076 /* no need to write if no events */
1077 if (!(c->poll_entry->revents & POLLOUT))
1078 return 0;
c60202df
AB
1079 len = send(c->fd, c->packet_buffer_ptr,
1080 c->packet_buffer_end - c->packet_buffer_ptr, 0);
bc351386 1081 if (len < 0) {
28c4741a
MS
1082 if (ff_neterrno() != AVERROR(EAGAIN) &&
1083 ff_neterrno() != AVERROR(EINTR)) {
bc351386
FB
1084 /* error : close connection */
1085 av_freep(&c->packet_buffer);
1086 return -1;
1087 }
1088 } else {
1089 c->packet_buffer_ptr += len;
1090 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1091 /* all the buffer was sent : wait for a new request */
1092 av_freep(&c->packet_buffer);
1093 c->state = RTSPSTATE_WAIT_REQUEST;
1094 }
1095 }
1096 break;
2effd274
FB
1097 case HTTPSTATE_READY:
1098 /* nothing to do */
1099 break;
85f07f22
FB
1100 default:
1101 return -1;
1102 }
1103 return 0;
1104}
1105
3120d2a2
PG
1106static int extract_rates(char *rates, int ratelen, const char *request)
1107{
1108 const char *p;
1109
1110 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
bb3244de 1111 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
3120d2a2
PG
1112 const char *q = p + 7;
1113
efa7f420 1114 while (*q && *q != '\n' && av_isspace(*q))
3120d2a2
PG
1115 q++;
1116
bb3244de 1117 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
3120d2a2
PG
1118 int stream_no;
1119 int rate_no;
1120
1121 q += 20;
1122
cde25790 1123 memset(rates, 0xff, ratelen);
3120d2a2
PG
1124
1125 while (1) {
1126 while (*q && *q != '\n' && *q != ':')
1127 q++;
1128
611c5741 1129 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
3120d2a2 1130 break;
611c5741 1131
3120d2a2 1132 stream_no--;
611c5741 1133 if (stream_no < ratelen && stream_no >= 0)
3120d2a2 1134 rates[stream_no] = rate_no;
3120d2a2 1135
efa7f420 1136 while (*q && *q != '\n' && !av_isspace(*q))
3120d2a2
PG
1137 q++;
1138 }
1139
1140 return 1;
1141 }
1142 }
1143 p = strchr(p, '\n');
1144 if (!p)
1145 break;
1146
1147 p++;
1148 }
1149
1150 return 0;
1151}
1152
cde25790 1153static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
3120d2a2
PG
1154{
1155 int i;
cde25790
PG
1156 int best_bitrate = 100000000;
1157 int best = -1;
1158
1159 for (i = 0; i < feed->nb_streams; i++) {
01f4895c 1160 AVCodecContext *feed_codec = feed->streams[i]->codec;
cde25790
PG
1161
1162 if (feed_codec->codec_id != codec->codec_id ||
1163 feed_codec->sample_rate != codec->sample_rate ||
1164 feed_codec->width != codec->width ||
611c5741 1165 feed_codec->height != codec->height)
cde25790 1166 continue;
cde25790
PG
1167
1168 /* Potential stream */
1169
115329f1 1170 /* We want the fastest stream less than bit_rate, or the slowest
cde25790
PG
1171 * faster than bit_rate
1172 */
1173
1174 if (feed_codec->bit_rate <= bit_rate) {
1175 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1176 best_bitrate = feed_codec->bit_rate;
1177 best = i;
1178 }
1179 } else {
1180 if (feed_codec->bit_rate < best_bitrate) {
1181 best_bitrate = feed_codec->bit_rate;
1182 best = i;
1183 }
1184 }
1185 }
1186
1187 return best;
1188}
1189
1190static int modify_current_stream(HTTPContext *c, char *rates)
1191{
1192 int i;
1193 FFStream *req = c->stream;
1194 int action_required = 0;
3120d2a2 1195
001bcd29
PG
1196 /* Not much we can do for a feed */
1197 if (!req->feed)
1198 return 0;
1199
3120d2a2 1200 for (i = 0; i < req->nb_streams; i++) {
01f4895c 1201 AVCodecContext *codec = req->streams[i]->codec;
3120d2a2 1202
3120d2a2
PG
1203 switch(rates[i]) {
1204 case 0:
cde25790 1205 c->switch_feed_streams[i] = req->feed_streams[i];
3120d2a2
PG
1206 break;
1207 case 1:
cde25790 1208 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
3120d2a2
PG
1209 break;
1210 case 2:
cde25790
PG
1211 /* Wants off or slow */
1212 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1213#ifdef WANTS_OFF
1214 /* This doesn't work well when it turns off the only stream! */
1215 c->switch_feed_streams[i] = -2;
1216 c->feed_streams[i] = -2;
1217#endif
3120d2a2
PG
1218 break;
1219 }
3120d2a2 1220
cde25790
PG
1221 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1222 action_required = 1;
1223 }
3120d2a2 1224
cde25790
PG
1225 return action_required;
1226}
3120d2a2 1227
2effd274
FB
1228/* XXX: factorize in utils.c ? */
1229/* XXX: take care with different space meaning */
1230static void skip_spaces(const char **pp)
1231{
1232 const char *p;
1233 p = *pp;
1234 while (*p == ' ' || *p == '\t')
1235 p++;
1236 *pp = p;
1237}
1238
1239static void get_word(char *buf, int buf_size, const char **pp)
1240{
1241 const char *p;
1242 char *q;
1243
1244 p = *pp;
1245 skip_spaces(&p);
1246 q = buf;
efa7f420 1247 while (!av_isspace(*p) && *p != '\0') {
2effd274
FB
1248 if ((q - buf) < buf_size - 1)
1249 *q++ = *p;
1250 p++;
1251 }
1252 if (buf_size > 0)
1253 *q = '\0';
1254 *pp = p;
1255}
1256
c64c0a9b
BL
1257static void get_arg(char *buf, int buf_size, const char **pp)
1258{
1259 const char *p;
1260 char *q;
1261 int quote;
1262
1263 p = *pp;
efa7f420 1264 while (av_isspace(*p)) p++;
c64c0a9b
BL
1265 q = buf;
1266 quote = 0;
1267 if (*p == '\"' || *p == '\'')
1268 quote = *p++;
1269 for(;;) {
1270 if (quote) {
1271 if (*p == quote)
1272 break;
1273 } else {
efa7f420 1274 if (av_isspace(*p))
c64c0a9b
BL
1275 break;
1276 }
1277 if (*p == '\0')
1278 break;
1279 if ((q - buf) < buf_size - 1)
1280 *q++ = *p;
1281 p++;
1282 }
1283 *q = '\0';
1284 if (quote && *p == quote)
1285 p++;
1286 *pp = p;
1287}
1288
58f48adb
BL
1289static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1290 const char *p, const char *filename, int line_num)
1291{
1292 char arg[1024];
1293 IPAddressACL acl;
1294 int errors = 0;
1295
1296 get_arg(arg, sizeof(arg), &p);
bb3244de 1297 if (av_strcasecmp(arg, "allow") == 0)
58f48adb 1298 acl.action = IP_ALLOW;
bb3244de 1299 else if (av_strcasecmp(arg, "deny") == 0)
58f48adb
BL
1300 acl.action = IP_DENY;
1301 else {
1302 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1303 filename, line_num, arg);
1304 errors++;
1305 }
1306
1307 get_arg(arg, sizeof(arg), &p);
1308
1309 if (resolve_host(&acl.first, arg) != 0) {
1310 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1311 filename, line_num, arg);
1312 errors++;
1313 } else
1314 acl.last = acl.first;
1315
1316 get_arg(arg, sizeof(arg), &p);
1317
1318 if (arg[0]) {
1319 if (resolve_host(&acl.last, arg) != 0) {
1320 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1321 filename, line_num, arg);
1322 errors++;
1323 }
1324 }
1325
1326 if (!errors) {
1327 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1328 IPAddressACL **naclp = 0;
1329
1330 acl.next = 0;
1331 *nacl = acl;
1332
1333 if (stream)
1334 naclp = &stream->acl;
1335 else if (feed)
1336 naclp = &feed->acl;
1337 else if (ext_acl)
1338 naclp = &ext_acl;
1339 else {
1340 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1341 filename, line_num);
1342 errors++;
1343 }
1344
1345 if (naclp) {
1346 while (*naclp)
1347 naclp = &(*naclp)->next;
1348
1349 *naclp = nacl;
1350 }
1351 }
1352}
1353
1354
1355static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1356{
1357 FILE* f;
1358 char line[1024];
1359 char cmd[1024];
1360 IPAddressACL *acl = NULL;
1361 int line_num = 0;
1362 const char *p;
1363
1364 f = fopen(stream->dynamic_acl, "r");
1365 if (!f) {
1366 perror(stream->dynamic_acl);
1367 return NULL;
1368 }
1369
1370 acl = av_mallocz(sizeof(IPAddressACL));
1371
1372 /* Build ACL */
1373 for(;;) {
1374 if (fgets(line, sizeof(line), f) == NULL)
1375 break;
1376 line_num++;
1377 p = line;
efa7f420 1378 while (av_isspace(*p))
58f48adb
BL
1379 p++;
1380 if (*p == '\0' || *p == '#')
1381 continue;
1382 get_arg(cmd, sizeof(cmd), &p);
1383
bb3244de 1384 if (!av_strcasecmp(cmd, "ACL"))
58f48adb
BL
1385 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1386 }
1387 fclose(f);
1388 return acl;
1389}
1390
1391
1392static void free_acl_list(IPAddressACL *in_acl)
1393{
1394 IPAddressACL *pacl,*pacl2;
1395
1396 pacl = in_acl;
1397 while(pacl) {
1398 pacl2 = pacl;
1399 pacl = pacl->next;
1400 av_freep(pacl2);
1401 }
1402}
1403
1404static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
8256c0a3
PG
1405{
1406 enum IPAddressAction last_action = IP_DENY;
1407 IPAddressACL *acl;
1408 struct in_addr *src = &c->from_addr.sin_addr;
2bd8416e 1409 unsigned long src_addr = src->s_addr;
8256c0a3 1410
58f48adb 1411 for (acl = in_acl; acl; acl = acl->next) {
611c5741 1412 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
8256c0a3 1413 return (acl->action == IP_ALLOW) ? 1 : 0;
8256c0a3
PG
1414 last_action = acl->action;
1415 }
1416
1417 /* Nothing matched, so return not the last action */
1418 return (last_action == IP_DENY) ? 1 : 0;
1419}
1420
58f48adb
BL
1421static int validate_acl(FFStream *stream, HTTPContext *c)
1422{
1423 int ret = 0;
1424 IPAddressACL *acl;
1425
1426
1427 /* if stream->acl is null validate_acl_list will return 1 */
1428 ret = validate_acl_list(stream->acl, c);
1429
1430 if (stream->dynamic_acl[0]) {
1431 acl = parse_dynamic_acl(stream, c);
1432
1433 ret = validate_acl_list(acl, c);
1434
1435 free_acl_list(acl);
1436 }
1437
1438 return ret;
1439}
1440
829ac53d
FB
1441/* compute the real filename of a file by matching it without its
1442 extensions to all the stream filenames */
1443static void compute_real_filename(char *filename, int max_size)
1444{
1445 char file1[1024];
1446 char file2[1024];
1447 char *p;
1448 FFStream *stream;
1449
1450 /* compute filename by matching without the file extensions */
f7d78f36 1451 av_strlcpy(file1, filename, sizeof(file1));
829ac53d
FB
1452 p = strrchr(file1, '.');
1453 if (p)
1454 *p = '\0';
1455 for(stream = first_stream; stream != NULL; stream = stream->next) {
f7d78f36 1456 av_strlcpy(file2, stream->filename, sizeof(file2));
829ac53d
FB
1457 p = strrchr(file2, '.');
1458 if (p)
1459 *p = '\0';
1460 if (!strcmp(file1, file2)) {
f7d78f36 1461 av_strlcpy(filename, stream->filename, max_size);
829ac53d
FB
1462 break;
1463 }
1464 }
1465}
1466
1467enum RedirType {
1468 REDIR_NONE,
1469 REDIR_ASX,
1470 REDIR_RAM,
1471 REDIR_ASF,
1472 REDIR_RTSP,
1473 REDIR_SDP,
1474};
1475
85f07f22
FB
1476/* parse http request and prepare header */
1477static int http_parse_request(HTTPContext *c)
1478{
39c4afd9
JG
1479 const char *p;
1480 char *p1;
829ac53d 1481 enum RedirType redir_type;
85f07f22 1482 char cmd[32];
bae79c04 1483 char info[1024], filename[1024];
85f07f22
FB
1484 char url[1024], *q;
1485 char protocol[32];
1486 char msg[1024];
1487 const char *mime_type;
1488 FFStream *stream;
42a63c6a 1489 int i;
3120d2a2 1490 char ratebuf[32];
39c4afd9 1491 const char *useragent = 0;
85f07f22
FB
1492
1493 p = c->buffer;
39c4afd9 1494 get_word(cmd, sizeof(cmd), &p);
f7d78f36 1495 av_strlcpy(c->method, cmd, sizeof(c->method));
7434ba6d 1496
85f07f22 1497 if (!strcmp(cmd, "GET"))
edfdd798 1498 c->post = 0;
85f07f22 1499 else if (!strcmp(cmd, "POST"))
edfdd798 1500 c->post = 1;
85f07f22
FB
1501 else
1502 return -1;
1503
39c4afd9 1504 get_word(url, sizeof(url), &p);
f7d78f36 1505 av_strlcpy(c->url, url, sizeof(c->url));
7434ba6d 1506
2effd274 1507 get_word(protocol, sizeof(protocol), (const char **)&p);
85f07f22
FB
1508 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1509 return -1;
7434ba6d 1510
f7d78f36 1511 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
90f9c440 1512
4d58e4cb 1513 if (avserver_debug)
77553ae3 1514 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
115329f1 1515
85f07f22 1516 /* find the filename and the optional info string in the request */
39c4afd9
JG
1517 p1 = strchr(url, '?');
1518 if (p1) {
1519 av_strlcpy(info, p1, sizeof(info));
1520 *p1 = '\0';
611c5741 1521 } else
85f07f22 1522 info[0] = '\0';
85f07f22 1523
f7d78f36 1524 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
bae79c04 1525
cde25790 1526 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
bb3244de 1527 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
cde25790 1528 useragent = p + 11;
efa7f420 1529 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
cde25790
PG
1530 useragent++;
1531 break;
1532 }
1533 p = strchr(p, '\n');
1534 if (!p)
1535 break;
1536
1537 p++;
1538 }
1539
829ac53d 1540 redir_type = REDIR_NONE;
aa13b573 1541 if (av_match_ext(filename, "asx")) {
829ac53d 1542 redir_type = REDIR_ASX;
7434ba6d 1543 filename[strlen(filename)-1] = 'f';
aa13b573 1544 } else if (av_match_ext(filename, "asf") &&
bb3244de 1545 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
cde25790 1546 /* if this isn't WMP or lookalike, return the redirector file */
829ac53d 1547 redir_type = REDIR_ASF;
aa13b573 1548 } else if (av_match_ext(filename, "rpm,ram")) {
829ac53d 1549 redir_type = REDIR_RAM;
42a63c6a 1550 strcpy(filename + strlen(filename)-2, "m");
aa13b573 1551 } else if (av_match_ext(filename, "rtsp")) {
829ac53d 1552 redir_type = REDIR_RTSP;
bae79c04 1553 compute_real_filename(filename, sizeof(filename) - 1);
aa13b573 1554 } else if (av_match_ext(filename, "sdp")) {
829ac53d 1555 redir_type = REDIR_SDP;
bae79c04 1556 compute_real_filename(filename, sizeof(filename) - 1);
42a63c6a 1557 }
115329f1 1558
bae79c04
AB
1559 // "redirect" / request to index.html
1560 if (!strlen(filename))
f7d78f36 1561 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
bae79c04 1562
85f07f22
FB
1563 stream = first_stream;
1564 while (stream != NULL) {
8256c0a3 1565 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
85f07f22
FB
1566 break;
1567 stream = stream->next;
1568 }
1569 if (stream == NULL) {
d445a7e9 1570 snprintf(msg, sizeof(msg), "File '%s' not found", url);
77553ae3 1571 http_log("File '%s' not found\n", url);
85f07f22
FB
1572 goto send_error;
1573 }
42a63c6a 1574
cde25790
PG
1575 c->stream = stream;
1576 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1577 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1578
1579 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1580 c->http_error = 301;
1581 q = c->buffer;
a3aa4fed
BC
1582 q += snprintf(q, c->buffer_size,
1583 "HTTP/1.0 301 Moved\r\n"
1584 "Location: %s\r\n"
1585 "Content-type: text/html\r\n"
1586 "\r\n"
1587 "<html><head><title>Moved</title></head><body>\r\n"
1588 "You should be <a href=\"%s\">redirected</a>.\r\n"
1589 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
cde25790
PG
1590 /* prepare output buffer */
1591 c->buffer_ptr = c->buffer;
1592 c->buffer_end = q;
1593 c->state = HTTPSTATE_SEND_HEADER;
1594 return 0;
1595 }
1596
3120d2a2
PG
1597 /* If this is WMP, get the rate information */
1598 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
cde25790 1599 if (modify_current_stream(c, ratebuf)) {
37d3e066 1600 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
cde25790 1601 if (c->switch_feed_streams[i] >= 0)
305ca590 1602 c->switch_feed_streams[i] = -1;
cde25790
PG
1603 }
1604 }
3120d2a2
PG
1605 }
1606
d8f28a77
BC
1607 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1608 current_bandwidth += stream->bandwidth;
1609
755bfeab 1610 /* If already streaming this feed, do not let start another feeder. */
d0a5513b
AB
1611 if (stream->feed_opened) {
1612 snprintf(msg, sizeof(msg), "This feed is already being received.");
77553ae3 1613 http_log("Feed '%s' already being received\n", stream->feed_filename);
d0a5513b
AB
1614 goto send_error;
1615 }
1616
edfdd798 1617 if (c->post == 0 && max_bandwidth < current_bandwidth) {
0aee2a57 1618 c->http_error = 503;
42a63c6a 1619 q = c->buffer;
a3aa4fed 1620 q += snprintf(q, c->buffer_size,
0aee2a57 1621 "HTTP/1.0 503 Server too busy\r\n"
a3aa4fed
BC
1622 "Content-type: text/html\r\n"
1623 "\r\n"
1624 "<html><head><title>Too busy</title></head><body>\r\n"
1625 "<p>The server is too busy to serve your request at this time.</p>\r\n"
0be4b8d9
BC
1626 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1627 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
a3aa4fed 1628 "</body></html>\r\n", current_bandwidth, max_bandwidth);
42a63c6a
PG
1629 /* prepare output buffer */
1630 c->buffer_ptr = c->buffer;
1631 c->buffer_end = q;
1632 c->state = HTTPSTATE_SEND_HEADER;
1633 return 0;
1634 }
115329f1 1635
829ac53d 1636 if (redir_type != REDIR_NONE) {
39c4afd9 1637 const char *hostinfo = 0;
115329f1 1638
7434ba6d 1639 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
bb3244de 1640 if (av_strncasecmp(p, "Host:", 5) == 0) {
7434ba6d
PG
1641 hostinfo = p + 5;
1642 break;
1643 }
1644 p = strchr(p, '\n');
1645 if (!p)
1646 break;
1647
1648 p++;
1649 }
1650
1651 if (hostinfo) {
1652 char *eoh;
1653 char hostbuf[260];
1654
efa7f420 1655 while (av_isspace(*hostinfo))
7434ba6d
PG
1656 hostinfo++;
1657
1658 eoh = strchr(hostinfo, '\n');
1659 if (eoh) {
1660 if (eoh[-1] == '\r')
1661 eoh--;
1662
1663 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1664 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1665 hostbuf[eoh - hostinfo] = 0;
1666
1667 c->http_error = 200;
1668 q = c->buffer;
829ac53d
FB
1669 switch(redir_type) {
1670 case REDIR_ASX:
a3aa4fed
BC
1671 q += snprintf(q, c->buffer_size,
1672 "HTTP/1.0 200 ASX Follows\r\n"
1673 "Content-type: video/x-ms-asf\r\n"
1674 "\r\n"
1675 "<ASX Version=\"3\">\r\n"
4d58e4cb 1676 //"<!-- Autogenerated by avserver -->\r\n"
a3aa4fed
BC
1677 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1678 "</ASX>\r\n", hostbuf, filename, info);
829ac53d
FB
1679 break;
1680 case REDIR_RAM:
a3aa4fed
BC
1681 q += snprintf(q, c->buffer_size,
1682 "HTTP/1.0 200 RAM Follows\r\n"
1683 "Content-type: audio/x-pn-realaudio\r\n"
1684 "\r\n"
4d58e4cb 1685 "# Autogenerated by avserver\r\n"
a3aa4fed 1686 "http://%s/%s%s\r\n", hostbuf, filename, info);
829ac53d
FB
1687 break;
1688 case REDIR_ASF:
a3aa4fed
BC
1689 q += snprintf(q, c->buffer_size,
1690 "HTTP/1.0 200 ASF Redirect follows\r\n"
1691 "Content-type: video/x-ms-asf\r\n"
1692 "\r\n"
1693 "[Reference]\r\n"
1694 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
829ac53d
FB
1695 break;
1696 case REDIR_RTSP:
1697 {
1698 char hostname[256], *p;
1699 /* extract only hostname */
f7d78f36 1700 av_strlcpy(hostname, hostbuf, sizeof(hostname));
829ac53d
FB
1701 p = strrchr(hostname, ':');
1702 if (p)
1703 *p = '\0';
a3aa4fed
BC
1704 q += snprintf(q, c->buffer_size,
1705 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1706 /* XXX: incorrect mime type ? */
1707 "Content-type: application/x-rtsp\r\n"
1708 "\r\n"
1709 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
829ac53d
FB
1710 }
1711 break;
1712 case REDIR_SDP:
1713 {
0c1a9eda 1714 uint8_t *sdp_data;
cc64ec57
MR
1715 int sdp_data_size;
1716 socklen_t len;
829ac53d
FB
1717 struct sockaddr_in my_addr;
1718
a3aa4fed
BC
1719 q += snprintf(q, c->buffer_size,
1720 "HTTP/1.0 200 OK\r\n"
1721 "Content-type: application/sdp\r\n"
1722 "\r\n");
829ac53d
FB
1723
1724 len = sizeof(my_addr);
1725 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
115329f1 1726
829ac53d 1727 /* XXX: should use a dynamic buffer */
115329f1
DB
1728 sdp_data_size = prepare_sdp_description(stream,
1729 &sdp_data,
829ac53d
FB
1730 my_addr.sin_addr);
1731 if (sdp_data_size > 0) {
1732 memcpy(q, sdp_data, sdp_data_size);
1733 q += sdp_data_size;
1734 *q = '\0';
1735 av_free(sdp_data);
1736 }
1737 }
1738 break;
1739 default:
0f4e8165 1740 abort();
829ac53d 1741 break;
2effd274 1742 }
7434ba6d
PG
1743
1744 /* prepare output buffer */
1745 c->buffer_ptr = c->buffer;
1746 c->buffer_end = q;
1747 c->state = HTTPSTATE_SEND_HEADER;
1748 return 0;
1749 }
1750 }
1751 }
1752
d445a7e9 1753 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
7434ba6d 1754 goto send_error;
85f07f22
FB
1755 }
1756
a6e14edd 1757 stream->conns_served++;
7434ba6d 1758
85f07f22
FB
1759 /* XXX: add there authenticate and IP match */
1760
edfdd798 1761 if (c->post) {
85f07f22
FB
1762 /* if post, it means a feed is being sent */
1763 if (!stream->is_feed) {
e16190fa
DB
1764 /* However it might be a status report from WMP! Let us log the
1765 * data as it might come in handy one day. */
39c4afd9 1766 const char *logline = 0;
3120d2a2 1767 int client_id = 0;
115329f1 1768
7434ba6d 1769 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
bb3244de 1770 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
7434ba6d
PG
1771 logline = p;
1772 break;
1773 }
bb3244de 1774 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
3120d2a2 1775 client_id = strtol(p + 18, 0, 10);
7434ba6d
PG
1776 p = strchr(p, '\n');
1777 if (!p)
1778 break;
1779
1780 p++;
1781 }
1782
1783 if (logline) {
1784 char *eol = strchr(logline, '\n');
1785
1786 logline += 17;
1787
1788 if (eol) {
1789 if (eol[-1] == '\r')
1790 eol--;
7906085f 1791 http_log("%.*s\n", (int) (eol - logline), logline);
7434ba6d
PG
1792 c->suppress_log = 1;
1793 }
1794 }
3120d2a2 1795
f190f676 1796#ifdef DEBUG
cde25790 1797 http_log("\nGot request:\n%s\n", c->buffer);
3120d2a2
PG
1798#endif
1799
1800 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1801 HTTPContext *wmpc;
1802
1803 /* Now we have to find the client_id */
1804 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1805 if (wmpc->wmp_client_id == client_id)
1806 break;
1807 }
1808
2d563d2f
AB
1809 if (wmpc && modify_current_stream(wmpc, ratebuf))
1810 wmpc->switch_pending = 1;
3120d2a2 1811 }
115329f1 1812
d445a7e9 1813 snprintf(msg, sizeof(msg), "POST command not handled");
cb275dd9 1814 c->stream = 0;
85f07f22
FB
1815 goto send_error;
1816 }
1817 if (http_start_receive_data(c) < 0) {
d445a7e9 1818 snprintf(msg, sizeof(msg), "could not open feed");
85f07f22
FB
1819 goto send_error;
1820 }
1821 c->http_error = 0;
1822 c->state = HTTPSTATE_RECEIVE_DATA;
1823 return 0;
1824 }
1825
f190f676 1826#ifdef DEBUG
611c5741 1827 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
cde25790 1828 http_log("\nGot request:\n%s\n", c->buffer);
3120d2a2
PG
1829#endif
1830
85f07f22 1831 if (c->stream->stream_type == STREAM_TYPE_STATUS)
dca21085 1832 goto send_status;
85f07f22
FB
1833
1834 /* open input stream */
1835 if (open_input_stream(c, info) < 0) {
d445a7e9 1836 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
85f07f22
FB
1837 goto send_error;
1838 }
1839
1840 /* prepare http header */
1841 q = c->buffer;
d445a7e9 1842 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
85f07f22
FB
1843 mime_type = c->stream->fmt->mime_type;
1844 if (!mime_type)
087fa475 1845 mime_type = "application/x-octet-stream";
d445a7e9 1846 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
85f07f22
FB
1847
1848 /* for asf, we need extra headers */
8256c0a3 1849 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
3120d2a2 1850 /* Need to allocate a client id */
3120d2a2 1851
042819c5 1852 c->wmp_client_id = av_lfg_get(&random_state);
3120d2a2 1853
d445a7e9 1854 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
85f07f22 1855 }
d445a7e9
PG
1856 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1857 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
115329f1 1858
85f07f22
FB
1859 /* prepare output buffer */
1860 c->http_error = 0;
1861 c->buffer_ptr = c->buffer;
1862 c->buffer_end = q;
1863 c->state = HTTPSTATE_SEND_HEADER;
1864 return 0;
1865 send_error:
1866 c->http_error = 404;
1867 q = c->buffer;
a3aa4fed
BC
1868 q += snprintf(q, c->buffer_size,
1869 "HTTP/1.0 404 Not Found\r\n"
1870 "Content-type: text/html\r\n"
1871 "\r\n"
5e567aae
DB
1872 "<html>\n"
1873 "<head><title>404 Not Found</title></head>\n"
1874 "<body>%s</body>\n"
1875 "</html>\n", msg);
85f07f22
FB
1876 /* prepare output buffer */
1877 c->buffer_ptr = c->buffer;
1878 c->buffer_end = q;
1879 c->state = HTTPSTATE_SEND_HEADER;
1880 return 0;
dca21085
SS
1881 send_status:
1882 compute_status(c);
85f07f22
FB
1883 c->http_error = 200; /* horrible : we use this value to avoid
1884 going to the send data state */
1885 c->state = HTTPSTATE_SEND_HEADER;
1886 return 0;
1887}
1888
ae628ec1 1889static void fmt_bytecount(AVIOContext *pb, int64_t count)
2ac887ba 1890{
b0f29db5 1891 static const char suffix[] = " kMGTP";
2ac887ba
PG
1892 const char *s;
1893
611c5741 1894 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
2ac887ba 1895
d9d86e00 1896 avio_printf(pb, "%"PRId64"%c", count, *s);
2ac887ba
PG
1897}
1898
dca21085 1899static void compute_status(HTTPContext *c)
85f07f22
FB
1900{
1901 HTTPContext *c1;
1902 FFStream *stream;
2effd274 1903 char *p;
85f07f22 1904 time_t ti;
2effd274 1905 int i, len;
ae628ec1 1906 AVIOContext *pb;
cde25790 1907
b92c5452 1908 if (avio_open_dyn_buf(&pb) < 0) {
2effd274 1909 /* XXX: return an error ? */
cde25790 1910 c->buffer_ptr = c->buffer;
2effd274
FB
1911 c->buffer_end = c->buffer;
1912 return;
cde25790 1913 }
85f07f22 1914
d9d86e00
AK
1915 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1916 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1917 avio_printf(pb, "Pragma: no-cache\r\n");
1918 avio_printf(pb, "\r\n");
115329f1 1919
d9d86e00 1920 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
0679719d 1921 if (c->stream->feed_filename[0])
d9d86e00
AK
1922 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1923 avio_printf(pb, "</head>\n<body>");
1924 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
85f07f22 1925 /* format status */
d9d86e00
AK
1926 avio_printf(pb, "<h2>Available Streams</h2>\n");
1927 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1928 avio_printf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbits/s<th align=left>Video<br>kbits/s<th><br>Codec<th align=left>Audio<br>kbits/s<th><br>Codec<th align=left valign=top>Feed\n");
85f07f22
FB
1929 stream = first_stream;
1930 while (stream != NULL) {
42a63c6a
PG
1931 char sfilename[1024];
1932 char *eosf;
1933
a6e14edd 1934 if (stream->feed != stream) {
f7d78f36 1935 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
a6e14edd
PG
1936 eosf = sfilename + strlen(sfilename);
1937 if (eosf - sfilename >= 4) {
611c5741 1938 if (strcmp(eosf - 4, ".asf") == 0)
a6e14edd 1939 strcpy(eosf - 4, ".asx");
611c5741 1940 else if (strcmp(eosf - 3, ".rm") == 0)
a6e14edd 1941 strcpy(eosf - 3, ".ram");
25e3e53d 1942 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
829ac53d
FB
1943 /* generate a sample RTSP director if
1944 unicast. Generate an SDP redirector if
1945 multicast */
2effd274
FB
1946 eosf = strrchr(sfilename, '.');
1947 if (!eosf)
1948 eosf = sfilename + strlen(sfilename);
829ac53d
FB
1949 if (stream->is_multicast)
1950 strcpy(eosf, ".sdp");
1951 else
1952 strcpy(eosf, ".rtsp");
a6e14edd 1953 }
42a63c6a 1954 }
115329f1 1955
d9d86e00 1956 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
a6e14edd 1957 sfilename, stream->filename);
d9d86e00 1958 avio_printf(pb, "<td align=right> %d <td align=right> ",
2ac887ba 1959 stream->conns_served);
2effd274 1960 fmt_bytecount(pb, stream->bytes_served);
a6e14edd 1961 switch(stream->stream_type) {
ace21da3 1962 case STREAM_TYPE_LIVE: {
a6e14edd
PG
1963 int audio_bit_rate = 0;
1964 int video_bit_rate = 0;
58445440
ZK
1965 const char *audio_codec_name = "";
1966 const char *video_codec_name = "";
1967 const char *audio_codec_name_extra = "";
1968 const char *video_codec_name_extra = "";
a6e14edd
PG
1969
1970 for(i=0;i<stream->nb_streams;i++) {
1971 AVStream *st = stream->streams[i];
01f4895c
MN
1972 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1973 switch(st->codec->codec_type) {
72415b2a 1974 case AVMEDIA_TYPE_AUDIO:
01f4895c 1975 audio_bit_rate += st->codec->bit_rate;
a6e14edd
PG
1976 if (codec) {
1977 if (*audio_codec_name)
1978 audio_codec_name_extra = "...";
1979 audio_codec_name = codec->name;
1980 }
1981 break;
72415b2a 1982 case AVMEDIA_TYPE_VIDEO:
01f4895c 1983 video_bit_rate += st->codec->bit_rate;
a6e14edd
PG
1984 if (codec) {
1985 if (*video_codec_name)
1986 video_codec_name_extra = "...";
1987 video_codec_name = codec->name;
1988 }
1989 break;
72415b2a 1990 case AVMEDIA_TYPE_DATA:
01f4895c 1991 video_bit_rate += st->codec->bit_rate;
e240a0bb 1992 break;
a6e14edd 1993 default:
0f4e8165 1994 abort();
79c4ea3c 1995 }
85f07f22 1996 }
d9d86e00 1997 avio_printf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
a6e14edd 1998 stream->fmt->name,
6edd6884 1999 stream->bandwidth,
a6e14edd
PG
2000 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2001 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
611c5741 2002 if (stream->feed)
d9d86e00 2003 avio_printf(pb, "<td>%s", stream->feed->filename);
611c5741 2004 else
d9d86e00
AK
2005 avio_printf(pb, "<td>%s", stream->feed_filename);
2006 avio_printf(pb, "\n");
85f07f22 2007 }
a6e14edd
PG
2008 break;
2009 default:
d9d86e00 2010 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
a6e14edd 2011 break;
85f07f22 2012 }
85f07f22
FB
2013 }
2014 stream = stream->next;
2015 }
d9d86e00 2016 avio_printf(pb, "</table>\n");
a6e14edd
PG
2017
2018 stream = first_stream;
2019 while (stream != NULL) {
2020 if (stream->feed == stream) {
d9d86e00 2021 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
cde25790 2022 if (stream->pid) {
d9d86e00 2023 avio_printf(pb, "Running as pid %d.\n", stream->pid);
cde25790 2024
2effd274
FB
2025#if defined(linux) && !defined(CONFIG_NOCUTILS)
2026 {
2027 FILE *pid_stat;
2028 char ps_cmd[64];
2029
2030 /* This is somewhat linux specific I guess */
115329f1
DB
2031 snprintf(ps_cmd, sizeof(ps_cmd),
2032 "ps -o \"%%cpu,cputime\" --no-headers %d",
2effd274 2033 stream->pid);
115329f1 2034
2effd274
FB
2035 pid_stat = popen(ps_cmd, "r");
2036 if (pid_stat) {
2037 char cpuperc[10];
2038 char cpuused[64];
115329f1
DB
2039
2040 if (fscanf(pid_stat, "%10s %64s", cpuperc,
2effd274 2041 cpuused) == 2) {
d9d86e00 2042 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2effd274
FB
2043 cpuperc, cpuused);
2044 }
2045 fclose(pid_stat);
cde25790 2046 }
cde25790
PG
2047 }
2048#endif
2049
d9d86e00 2050 avio_printf(pb, "<p>");
cde25790 2051 }
d9d86e00 2052 avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
a6e14edd
PG
2053
2054 for (i = 0; i < stream->nb_streams; i++) {
2055 AVStream *st = stream->streams[i];
01f4895c 2056 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
b29f97d1 2057 const char *type = "unknown";
b582f314
PG
2058 char parameters[64];
2059
2060 parameters[0] = 0;
a6e14edd 2061
01f4895c 2062 switch(st->codec->codec_type) {
72415b2a 2063 case AVMEDIA_TYPE_AUDIO:
a6e14edd 2064 type = "audio";
acdc8520 2065 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
a6e14edd 2066 break;
72415b2a 2067 case AVMEDIA_TYPE_VIDEO:
a6e14edd 2068 type = "video";
01f4895c
MN
2069 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2070 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
a6e14edd
PG
2071 break;
2072 default:
0f4e8165 2073 abort();
a6e14edd 2074 }
d9d86e00 2075 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
01f4895c 2076 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
a6e14edd 2077 }
d9d86e00 2078 avio_printf(pb, "</table>\n");
a6e14edd 2079
115329f1 2080 }
a6e14edd
PG
2081 stream = stream->next;
2082 }
115329f1 2083
85f07f22 2084 /* connection status */
d9d86e00 2085 avio_printf(pb, "<h2>Connection Status</h2>\n");
85f07f22 2086
d9d86e00 2087 avio_printf(pb, "Number of connections: %d / %d<br>\n",
85f07f22
FB
2088 nb_connections, nb_max_connections);
2089
d9d86e00 2090 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
6edd6884 2091 current_bandwidth, max_bandwidth);
42a63c6a 2092
d9d86e00
AK
2093 avio_printf(pb, "<table>\n");
2094 avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
85f07f22
FB
2095 c1 = first_http_ctx;
2096 i = 0;
2effd274 2097 while (c1 != NULL) {
cde25790
PG
2098 int bitrate;
2099 int j;
2100
2101 bitrate = 0;
2effd274
FB
2102 if (c1->stream) {
2103 for (j = 0; j < c1->stream->nb_streams; j++) {
2d563d2f 2104 if (!c1->stream->feed)
01f4895c 2105 bitrate += c1->stream->streams[j]->codec->bit_rate;
2d563d2f
AB
2106 else if (c1->feed_streams[j] >= 0)
2107 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
cde25790
PG
2108 }
2109 }
2110
85f07f22
FB
2111 i++;
2112 p = inet_ntoa(c1->from_addr.sin_addr);
d9d86e00 2113 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
115329f1
DB
2114 i,
2115 c1->stream ? c1->stream->filename : "",
2effd274 2116 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
115329f1 2117 p,
2effd274
FB
2118 c1->protocol,
2119 http_state[c1->state]);
2120 fmt_bytecount(pb, bitrate);
d9d86e00 2121 avio_printf(pb, "<td align=right>");
2effd274 2122 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
d9d86e00 2123 avio_printf(pb, "<td align=right>");
2effd274 2124 fmt_bytecount(pb, c1->data_count);
d9d86e00 2125 avio_printf(pb, "\n");
85f07f22
FB
2126 c1 = c1->next;
2127 }
d9d86e00 2128 avio_printf(pb, "</table>\n");
115329f1 2129
85f07f22
FB
2130 /* date */
2131 ti = time(NULL);
2132 p = ctime(&ti);
d9d86e00
AK
2133 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2134 avio_printf(pb, "</body>\n</html>\n");
85f07f22 2135
6dc7d80d 2136 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2effd274
FB
2137 c->buffer_ptr = c->pb_buffer;
2138 c->buffer_end = c->pb_buffer + len;
85f07f22
FB
2139}
2140
85f07f22
FB
2141static int open_input_stream(HTTPContext *c, const char *info)
2142{
2143 char buf[128];
2144 char input_filename[1024];
50f2dfad 2145 AVFormatContext *s = NULL;
f02f745e 2146 int i, ret;
0c1a9eda 2147 int64_t stream_pos;
85f07f22
FB
2148
2149 /* find file name */
2150 if (c->stream->feed) {
2151 strcpy(input_filename, c->stream->feed->feed_filename);
85f07f22 2152 /* compute position (absolute time) */
ab0287fc 2153 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
9fcae973
AK
2154 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2155 return ret;
ab0287fc 2156 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
f747e6d3 2157 int prebuffer = strtol(buf, 0, 10);
0c1a9eda 2158 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
611c5741 2159 } else
0c1a9eda 2160 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
85f07f22
FB
2161 } else {
2162 strcpy(input_filename, c->stream->feed_filename);
85f07f22 2163 /* compute position (relative time) */
ab0287fc 2164 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
9fcae973
AK
2165 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2166 return ret;
ace21da3 2167 } else
85f07f22 2168 stream_pos = 0;
85f07f22
FB
2169 }
2170 if (input_filename[0] == '\0')
2171 return -1;
2172
2173 /* open stream */
50f2dfad 2174 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
c351cc7f 2175 http_log("could not open %s: %d\n", input_filename, ret);
85f07f22 2176 return -1;
2effd274 2177 }
9dc0bc3d 2178 s->flags |= AVFMT_FLAG_GENPTS;
85f07f22 2179 c->fmt_in = s;
c960e67a 2180 if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
20f93c3c 2181 http_log("Could not find stream info '%s'\n", input_filename);
cd3716b9 2182 avformat_close_input(&s);
20f93c3c
BC
2183 return -1;
2184 }
115329f1 2185
2effd274
FB
2186 /* choose stream as clock source (we favorize video stream if
2187 present) for packet sending */
2188 c->pts_stream_index = 0;
2189 for(i=0;i<c->stream->nb_streams;i++) {
115329f1 2190 if (c->pts_stream_index == 0 &&
72415b2a 2191 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2effd274
FB
2192 c->pts_stream_index = i;
2193 }
2194 }
85f07f22 2195
611c5741 2196 if (c->fmt_in->iformat->read_seek)
60a04f7f 2197 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2effd274
FB
2198 /* set the start time (needed for maxtime and RTP packet timing) */
2199 c->start_time = cur_time;
2200 c->first_pts = AV_NOPTS_VALUE;
85f07f22
FB
2201 return 0;
2202}
2203
e240a0bb
FB
2204/* return the server clock (in us) */
2205static int64_t get_server_clock(HTTPContext *c)
2effd274 2206{
e240a0bb 2207 /* compute current pts value from system time */
c3f58185 2208 return (cur_time - c->start_time) * 1000;
2effd274
FB
2209}
2210
e240a0bb
FB
2211/* return the estimated time at which the current packet must be sent
2212 (in us) */
2213static int64_t get_packet_send_clock(HTTPContext *c)
2effd274 2214{
e240a0bb 2215 int bytes_left, bytes_sent, frame_bytes;
115329f1 2216
e240a0bb 2217 frame_bytes = c->cur_frame_bytes;
611c5741 2218 if (frame_bytes <= 0)
e240a0bb 2219 return c->cur_pts;
611c5741 2220 else {
e240a0bb
FB
2221 bytes_left = c->buffer_end - c->buffer_ptr;
2222 bytes_sent = frame_bytes - bytes_left;
2223 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2effd274 2224 }
2effd274 2225}
2effd274 2226
2effd274 2227
2effd274
FB
2228static int http_prepare_data(HTTPContext *c)
2229{
2230 int i, len, ret;
2231 AVFormatContext *ctx;
2232
bc351386 2233 av_freep(&c->pb_buffer);
2effd274
FB
2234 switch(c->state) {
2235 case HTTPSTATE_SEND_DATA_HEADER:
2236 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
d2d67e42
AK
2237 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2238 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2239 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2240 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2effd274 2241
db3262b7
MW
2242 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2243
3d9cc27d 2244 for(i=0;i<c->stream->nb_streams;i++) {
bb270c08 2245 AVStream *src;
db3262b7 2246 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2effd274 2247 /* if file or feed, then just take streams from FFStream struct */
115329f1 2248 if (!c->stream->feed ||
2effd274 2249 c->stream->feed == c->stream)
7c054ea7 2250 src = c->stream->streams[i];
2effd274 2251 else
7c054ea7
PG
2252 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2253
db3262b7
MW
2254 *(c->fmt_ctx.streams[i]) = *src;
2255 c->fmt_ctx.streams[i]->priv_data = 0;
2256 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2effd274
FB
2257 AVStream, not in codec */
2258 }
3d9cc27d
BC
2259 /* set output format parameters */
2260 c->fmt_ctx.oformat = c->stream->fmt;
2261 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2262
2effd274
FB
2263 c->got_key_frame = 0;
2264
2265 /* prepare header and save header data in a stream */
b92c5452 2266 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2effd274
FB
2267 /* XXX: potential leak */
2268 return -1;
2269 }
8978feda 2270 c->fmt_ctx.pb->seekable = 0;
2effd274 2271
8aae202e
BC
2272 /*
2273 * HACK to avoid mpeg ps muxer to spit many underflow errors
43fb279f 2274 * Default value from Libav
8aae202e
BC
2275 * Try to set it use configuration option
2276 */
8aae202e
BC
2277 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2278
50f2dfad 2279 if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
929a9b75 2280 http_log("Error writing output header\n");
f75cdda7 2281 return -1;
929a9b75 2282 }
d2d67e42 2283 av_dict_free(&c->fmt_ctx.metadata);
2effd274 2284
6dc7d80d 2285 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2effd274
FB
2286 c->buffer_ptr = c->pb_buffer;
2287 c->buffer_end = c->pb_buffer + len;
2288
2289 c->state = HTTPSTATE_SEND_DATA;
85f07f22
FB
2290 c->last_packet_sent = 0;
2291 break;
2292 case HTTPSTATE_SEND_DATA:
2293 /* find a new packet */
3b371676
BC
2294 /* read a packet from the input stream */
2295 if (c->stream->feed)
2296 ffm_set_write_index(c->fmt_in,
2297 c->stream->feed->feed_write_index,
2298 c->stream->feed->feed_size);
2299
2300 if (c->stream->max_time &&
2301 c->stream->max_time + c->start_time - cur_time < 0)
2302 /* We have timed out */
2303 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2304 else {
2305 AVPacket pkt;
2306 redo:
d9aac267
HC
2307 ret = av_read_frame(c->fmt_in, &pkt);
2308 if (ret < 0) {
2309 if (c->stream->feed) {
3b371676
BC
2310 /* if coming from feed, it means we reached the end of the
2311 ffm file, so must wait for more data */
2312 c->state = HTTPSTATE_WAIT_FEED;
2313 return 1; /* state changed */
d9aac267
HC
2314 } else if (ret == AVERROR(EAGAIN)) {
2315 /* input not ready, come back later */
2316 return 0;
2effd274 2317 } else {
3b371676 2318 if (c->stream->loop) {
cd3716b9 2319 avformat_close_input(&c->fmt_in);
3b371676
BC
2320 if (open_input_stream(c, "") < 0)
2321 goto no_loop;
2322 goto redo;
2323 } else {
2324 no_loop:
2325 /* must send trailer now because eof or error */
2326 c->state = HTTPSTATE_SEND_DATA_TRAILER;
1bc1cfdd 2327 }
3b371676
BC
2328 }
2329 } else {
084a8912 2330 int source_index = pkt.stream_index;
3b371676
BC
2331 /* update first pts if needed */
2332 if (c->first_pts == AV_NOPTS_VALUE) {
2333 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2334 c->start_time = cur_time;
2335 }
2336 /* send it to the appropriate stream */
2337 if (c->stream->feed) {
2338 /* if coming from a feed, select the right stream */
2339 if (c->switch_pending) {
2340 c->switch_pending = 0;
cde25790 2341 for(i=0;i<c->stream->nb_streams;i++) {
3b371676 2342 if (c->switch_feed_streams[i] == pkt.stream_index)
cc947f04 2343 if (pkt.flags & AV_PKT_FLAG_KEY)
305ca590 2344 c->switch_feed_streams[i] = -1;
3b371676
BC
2345 if (c->switch_feed_streams[i] >= 0)
2346 c->switch_pending = 1;
cde25790 2347 }
3b371676
BC
2348 }
2349 for(i=0;i<c->stream->nb_streams;i++) {
a5ba4ced 2350 if (c->stream->feed_streams[i] == pkt.stream_index) {
78728064 2351 AVStream *st = c->fmt_in->streams[source_index];
3b371676 2352 pkt.stream_index = i;
cc947f04 2353 if (pkt.flags & AV_PKT_FLAG_KEY &&
72415b2a 2354 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
180b7026 2355 c->stream->nb_streams == 1))
0332f549
BC
2356 c->got_key_frame = 1;
2357 if (!c->stream->send_on_key || c->got_key_frame)
3b371676
BC
2358 goto send_it;
2359 }
2360 }
2361 } else {
2362 AVCodecContext *codec;
dc3a6a36
BC
2363 AVStream *ist, *ost;
2364 send_it:
2365 ist = c->fmt_in->streams[source_index];
3b371676
BC
2366 /* specific handling for RTP: we use several
2367 output stream (one for each RTP
2368 connection). XXX: need more abstract handling */
2369 if (c->is_packetized) {
3b371676 2370 /* compute send time and duration */
8f56ccca 2371 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
f475f35f 2372 c->cur_pts -= c->first_pts;
8f56ccca 2373 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
3b371676
BC
2374 /* find RTP context */
2375 c->packet_stream_index = pkt.stream_index;
2376 ctx = c->rtp_ctx[c->packet_stream_index];
2377 if(!ctx) {
8a0b55ff 2378 av_free_packet(&pkt);
3b371676 2379 break;
8a0b55ff 2380 }
3b371676
BC
2381 codec = ctx->streams[0]->codec;
2382 /* only one stream per RTP connection */
2383 pkt.stream_index = 0;
2384 } else {
2385 ctx = &c->fmt_ctx;
2386 /* Fudge here */
3ab29d8e 2387 codec = ctx->streams[pkt.stream_index]->codec;
3b371676
BC
2388 }
2389
2390 if (c->is_packetized) {
2391 int max_packet_size;
90abbdba 2392 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
3b371676
BC
2393 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2394 else
b263bf66 2395 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
403ee835 2396 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
3b371676 2397 } else {
b92c5452 2398 ret = avio_open_dyn_buf(&ctx->pb);
3b371676
BC
2399 }
2400 if (ret < 0) {
2401 /* XXX: potential leak */
2402 return -1;
2403 }
3ab29d8e
BC
2404 ost = ctx->streams[pkt.stream_index];
2405
8978feda 2406 ctx->pb->seekable = 0;
3b371676 2407 if (pkt.dts != AV_NOPTS_VALUE)
d80904cc 2408 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
3b371676 2409 if (pkt.pts != AV_NOPTS_VALUE)
d80904cc
BC
2410 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2411 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
3766ed72
BC
2412 if (av_write_frame(ctx, &pkt) < 0) {
2413 http_log("Error writing frame to output\n");
3b371676 2414 c->state = HTTPSTATE_SEND_DATA_TRAILER;
3766ed72 2415 }
3b371676 2416
6dc7d80d 2417 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
3b371676
BC
2418 c->cur_frame_bytes = len;
2419 c->buffer_ptr = c->pb_buffer;
2420 c->buffer_end = c->pb_buffer + len;
2421
2422 codec->frame_number++;
2423 if (len == 0) {
2424 av_free_packet(&pkt);
2425 goto redo;
f747e6d3 2426 }
85f07f22 2427 }
3b371676 2428 av_free_packet(&pkt);
85f07f22 2429 }
3b371676 2430 }
85f07f22
FB
2431 break;
2432 default:
2433 case HTTPSTATE_SEND_DATA_TRAILER:
2434 /* last packet test ? */
2effd274 2435 if (c->last_packet_sent || c->is_packetized)
85f07f22 2436 return -1;
2effd274 2437 ctx = &c->fmt_ctx;
85f07f22 2438 /* prepare header */
b92c5452 2439 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2effd274
FB
2440 /* XXX: potential leak */
2441 return -1;
2442 }
8978feda 2443 c->fmt_ctx.pb->seekable = 0;
2effd274 2444 av_write_trailer(ctx);
6dc7d80d 2445 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2effd274
FB
2446 c->buffer_ptr = c->pb_buffer;
2447 c->buffer_end = c->pb_buffer + len;
2448
85f07f22
FB
2449 c->last_packet_sent = 1;
2450 break;
2451 }
2452 return 0;
2453}
2454
2455/* should convert the format at the same time */
bc351386
FB
2456/* send data starting at c->buffer_ptr to the output connection
2457 (either UDP or TCP connection) */
5eb765ef 2458static int http_send_data(HTTPContext *c)
85f07f22 2459{
e240a0bb 2460 int len, ret;
85f07f22 2461
bc351386
FB
2462 for(;;) {
2463 if (c->buffer_ptr >= c->buffer_end) {
2464 ret = http_prepare_data(c);
2465 if (ret < 0)
2466 return -1;
611c5741 2467 else if (ret != 0)
bc351386
FB
2468 /* state change requested */
2469 break;
2effd274 2470 } else {
bc351386
FB
2471 if (c->is_packetized) {
2472 /* RTP data output */
2473 len = c->buffer_end - c->buffer_ptr;
2474 if (len < 4) {
2475 /* fail safe - should never happen */
2476 fail1:
2477 c->buffer_ptr = c->buffer_end;
2effd274
FB
2478 return 0;
2479 }
bc351386
FB
2480 len = (c->buffer_ptr[0] << 24) |
2481 (c->buffer_ptr[1] << 16) |
2482 (c->buffer_ptr[2] << 8) |
2483 (c->buffer_ptr[3]);
2484 if (len > (c->buffer_end - c->buffer_ptr))
2485 goto fail1;
e240a0bb
FB
2486 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2487 /* nothing to send yet: we can wait */
2488 return 0;
2489 }
2490
2491 c->data_count += len;
2492 update_datarate(&c->datarate, c->data_count);
2493 if (c->stream)
2494 c->stream->bytes_served += len;
2495
90abbdba 2496 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
bc351386 2497 /* RTP packets are sent inside the RTSP TCP connection */
ae628ec1 2498 AVIOContext *pb;
bc351386
FB
2499 int interleaved_index, size;
2500 uint8_t header[4];
2501 HTTPContext *rtsp_c;
115329f1 2502
bc351386
FB
2503 rtsp_c = c->rtsp_c;
2504 /* if no RTSP connection left, error */
2505 if (!rtsp_c)
2506 return -1;
2507 /* if already sending something, then wait. */
611c5741 2508 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
bc351386 2509 break;
b92c5452 2510 if (avio_open_dyn_buf(&pb) < 0)
bc351386
FB
2511 goto fail1;
2512 interleaved_index = c->packet_stream_index * 2;
2513 /* RTCP packets are sent at odd indexes */
2514 if (c->buffer_ptr[1] == 200)
2515 interleaved_index++;
2516 /* write RTSP TCP header */
2517 header[0] = '$';
2518 header[1] = interleaved_index;
2519 header[2] = len >> 8;
2520 header[3] = len;
77eb5504 2521 avio_write(pb, header, 4);
bc351386
FB
2522 /* write RTP packet data */
2523 c->buffer_ptr += 4;
77eb5504 2524 avio_write(pb, c->buffer_ptr, len);
6dc7d80d 2525 size = avio_close_dyn_buf(pb, &c->packet_buffer);
bc351386
FB
2526 /* prepare asynchronous TCP sending */
2527 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2528 rtsp_c->packet_buffer_end = c->packet_buffer + size;
e240a0bb 2529 c->buffer_ptr += len;
115329f1 2530
e240a0bb 2531 /* send everything we can NOW */
c60202df
AB
2532 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2533 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
611c5741 2534 if (len > 0)
e240a0bb 2535 rtsp_c->packet_buffer_ptr += len;
e240a0bb
FB
2536 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2537 /* if we could not send all the data, we will
2538 send it later, so a new state is needed to
2539 "lock" the RTSP TCP connection */
2540 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2541 break;
611c5741 2542 } else
e240a0bb
FB
2543 /* all data has been sent */
2544 av_freep(&c->packet_buffer);
e240a0bb
FB
2545 } else {
2546 /* send RTP packet directly in UDP */
bc351386 2547 c->buffer_ptr += 4;
b263bf66
AK
2548 ffurl_write(c->rtp_handles[c->packet_stream_index],
2549 c->buffer_ptr, len);
e240a0bb
FB
2550 c->buffer_ptr += len;
2551 /* here we continue as we can send several packets per 10 ms slot */
bc351386 2552 }
bc351386
FB
2553 } else {
2554 /* TCP data output */
c60202df 2555 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
bc351386 2556 if (len < 0) {
28c4741a
MS
2557 if (ff_neterrno() != AVERROR(EAGAIN) &&
2558 ff_neterrno() != AVERROR(EINTR))
bc351386
FB
2559 /* error : close connection */
2560 return -1;
611c5741 2561 else
bc351386 2562 return 0;
611c5741 2563 } else
bc351386 2564 c->buffer_ptr += len;
611c5741 2565
e240a0bb
FB
2566 c->data_count += len;
2567 update_datarate(&c->datarate, c->data_count);
2568 if (c->stream)
2569 c->stream->bytes_served += len;
2570 break;
2effd274 2571 }
85f07f22 2572 }
bc351386 2573 } /* for(;;) */
85f07f22
FB
2574 return 0;
2575}
2576
2577static int http_start_receive_data(HTTPContext *c)
2578{
2579 int fd;
2580
2581 if (c->stream->feed_opened)
2582 return -1;
2583
e322ea48
PG
2584 /* Don't permit writing to this one */
2585 if (c->stream->readonly)
2586 return -1;
2587
85f07f22
FB
2588 /* open feed */
2589 fd = open(c->stream->feed_filename, O_RDWR);
929a9b75
BC
2590 if (fd < 0) {
2591 http_log("Error opening feeder file: %s\n", strerror(errno));
85f07f22 2592 return -1;
929a9b75 2593 }
85f07f22 2594 c->feed_fd = fd;
115329f1 2595
861ec13a
BC
2596 if (c->stream->truncate) {
2597 /* truncate feed file */
2598 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
861ec13a 2599 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
0de1319e
MR
2600 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2601 http_log("Error truncating feed file: %s\n", strerror(errno));
2602 return -1;
2603 }
861ec13a 2604 } else {
1f611549
BC
2605 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2606 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2607 return -1;
2608 }
861ec13a
BC
2609 }
2610
7e24aa0c 2611 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
85f07f22
FB
2612 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2613 lseek(fd, 0, SEEK_SET);
2614
2615 /* init buffer input */
2616 c->buffer_ptr = c->buffer;
2617 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2618 c->stream->feed_opened = 1;
fd7bec5e 2619 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
85f07f22
FB
2620 return 0;
2621}
115329f1 2622
85f07f22
FB
2623static int http_receive_data(HTTPContext *c)
2624{
85f07f22 2625 HTTPContext *c1;
19c8c4ec 2626 int len, loop_run = 0;
85f07f22 2627
19c8c4ec
RB
2628 while (c->chunked_encoding && !c->chunk_size &&
2629 c->buffer_end > c->buffer_ptr) {
2630 /* read chunk header, if present */
2631 len = recv(c->fd, c->buffer_ptr, 1, 0);
2632
2633 if (len < 0) {
28c4741a
MS
2634 if (ff_neterrno() != AVERROR(EAGAIN) &&
2635 ff_neterrno() != AVERROR(EINTR))
19c8c4ec
RB
2636 /* error : close connection */
2637 goto fail;
686d6f40 2638 return 0;
19c8c4ec
RB
2639 } else if (len == 0) {
2640 /* end of connection : close it */
2641 goto fail;
2642 } else if (c->buffer_ptr - c->buffer >= 2 &&
2643 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2644 c->chunk_size = strtol(c->buffer, 0, 16);
2645 if (c->chunk_size == 0) // end of stream
2646 goto fail;
2647 c->buffer_ptr = c->buffer;
2648 break;
2649 } else if (++loop_run > 10) {
2650 /* no chunk header, abort */
2651 goto fail;
2652 } else {
2653 c->buffer_ptr++;
2654 }
2655 }
a6e14edd 2656
19c8c4ec
RB
2657 if (c->buffer_end > c->buffer_ptr) {
2658 len = recv(c->fd, c->buffer_ptr,
2659 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
a6e14edd 2660 if (len < 0) {
28c4741a
MS
2661 if (ff_neterrno() != AVERROR(EAGAIN) &&
2662 ff_neterrno() != AVERROR(EINTR))
a6e14edd
PG
2663 /* error : close connection */
2664 goto fail;
611c5741 2665 } else if (len == 0)
a6e14edd
PG
2666 /* end of connection : close it */
2667 goto fail;
611c5741 2668 else {
19c8c4ec 2669 c->chunk_size -= len;
a6e14edd
PG
2670 c->buffer_ptr += len;
2671 c->data_count += len;
5eb765ef 2672 update_datarate(&c->datarate, c->data_count);
a6e14edd
PG
2673 }
2674 }
2675
d445a7e9
PG
2676 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2677 if (c->buffer[0] != 'f' ||
2678 c->buffer[1] != 'm') {
2679 http_log("Feed stream has become desynchronized -- disconnecting\n");
2680 goto fail;
2681 }
2682 }
2683
85f07f22 2684 if (c->buffer_ptr >= c->buffer_end) {
f747e6d3 2685 FFStream *feed = c->stream;
85f07f22
FB
2686 /* a packet has been received : write it in the store, except
2687 if header */
2688 if (c->data_count > FFM_PACKET_SIZE) {
85f07f22
FB
2689 /* XXX: use llseek or url_seek */
2690 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
929a9b75
BC
2691 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2692 http_log("Error writing to feed file: %s\n", strerror(errno));
2693 goto fail;
2694 }
115329f1 2695
85f07f22
FB
2696 feed->feed_write_index += FFM_PACKET_SIZE;
2697 /* update file size */
2698 if (feed->feed_write_index > c->stream->feed_size)
2699 feed->feed_size = feed->feed_write_index;
2700
2701 /* handle wrap around if max file size reached */
6b0bdc75 2702 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
85f07f22
FB
2703 feed->feed_write_index = FFM_PACKET_SIZE;
2704
2705 /* write index */
2779cdad
PK
2706 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2707 http_log("Error writing index to feed file: %s\n", strerror(errno));
2708 goto fail;
2709 }
85f07f22
FB
2710
2711 /* wake up any waiting connections */
2712 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
115329f1 2713 if (c1->state == HTTPSTATE_WAIT_FEED &&
611c5741 2714 c1->stream->feed == c->stream->feed)
85f07f22 2715 c1->state = HTTPSTATE_SEND_DATA;
85f07f22 2716 }
f747e6d3
PG
2717 } else {
2718 /* We have a header in our hands that contains useful data */
50f2dfad 2719 AVFormatContext *s = avformat_alloc_context();
ae628ec1 2720 AVIOContext *pb;
bd7cf6ad 2721 AVInputFormat *fmt_in;
f747e6d3
PG
2722 int i;
2723
50f2dfad
AK
2724 if (!s)
2725 goto fail;
2726
bd7cf6ad
FB
2727 /* use feed output format name to find corresponding input format */
2728 fmt_in = av_find_input_format(feed->fmt->name);
2729 if (!fmt_in)
2730 goto fail;
2731
83fddaeb
AK
2732 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2733 0, NULL, NULL, NULL, NULL);
8978feda 2734 pb->seekable = 0;
697efa36 2735
50f2dfad
AK
2736 s->pb = pb;
2737 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
e6f0deab
BC
2738 av_free(pb);
2739 goto fail;
2740 }
f747e6d3
PG
2741
2742 /* Now we have the actual streams */
f2972c8c 2743 if (s->nb_streams != feed->nb_streams) {
cd3716b9 2744 avformat_close_input(&s);
86771c68 2745 av_free(pb);
77553ae3
BC
2746 http_log("Feed '%s' stream number does not match registered feed\n",
2747 c->stream->feed_filename);
f747e6d3
PG
2748 goto fail;
2749 }
f2972c8c 2750
cb51aef1
BC
2751 for (i = 0; i < s->nb_streams; i++) {
2752 AVStream *fst = feed->streams[i];
2753 AVStream *st = s->streams[i];
5634f30c 2754 avcodec_copy_context(fst->codec, st->codec);
cb51aef1 2755 }
f2972c8c 2756
cd3716b9 2757 avformat_close_input(&s);
86771c68 2758 av_free(pb);
85f07f22
FB
2759 }
2760 c->buffer_ptr = c->buffer;
2761 }
2762
85f07f22
FB
2763 return 0;
2764 fail:
2765 c->stream->feed_opened = 0;
2766 close(c->feed_fd);
c1593d0e
BC
2767 /* wake up any waiting connections to stop waiting for feed */
2768 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2769 if (c1->state == HTTPSTATE_WAIT_FEED &&
2770 c1->stream->feed == c->stream->feed)
2771 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2772 }
85f07f22
FB
2773 return -1;
2774}
2775
2effd274
FB
2776/********************************************************************/
2777/* RTSP handling */
2778
2779static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2780{
2781 const char *str;
2782 time_t ti;
0156fcf2 2783 struct tm *tm;
2effd274
FB
2784 char buf2[32];
2785
2786 switch(error_number) {
7e665cd3
LA
2787 case RTSP_STATUS_OK:
2788 str = "OK";
2789 break;
2790 case RTSP_STATUS_METHOD:
2791 str = "Method Not Allowed";
2792 break;
2793 case RTSP_STATUS_BANDWIDTH:
2794 str = "Not Enough Bandwidth";
2795 break;
2796 case RTSP_STATUS_SESSION:
2797 str = "Session Not Found";
2798 break;
2799 case RTSP_STATUS_STATE:
2800 str = "Method Not Valid in This State";
2801 break;
2802 case RTSP_STATUS_AGGREGATE:
2803 str = "Aggregate operation not allowed";
2804 break;
2805 case RTSP_STATUS_ONLY_AGGREGATE:
2806 str = "Only aggregate operation allowed";
2807 break;
2808 case RTSP_STATUS_TRANSPORT:
2809 str = "Unsupported transport";
2810 break;
2811 case RTSP_STATUS_INTERNAL:
2812 str = "Internal Server Error";
2813 break;
2814 case RTSP_STATUS_SERVICE:
2815 str = "Service Unavailable";
2816 break;
2817 case RTSP_STATUS_VERSION:
2818 str = "RTSP Version not supported";
2819 break;
2effd274
FB
2820 default:
2821 str = "Unknown Error";
2822 break;
2823 }
115329f1 2824
d9d86e00
AK
2825 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2826 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2effd274
FB
2827
2828 /* output GMT time */
2829 ti = time(NULL);
0156fcf2
HC
2830 tm = gmtime(&ti);
2831 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
d9d86e00 2832 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2effd274
FB
2833}
2834
2835static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2836{
2837 rtsp_reply_header(c, error_number);
d9d86e00 2838 avio_printf(c->pb, "\r\n");
2effd274
FB
2839}
2840
2841static int rtsp_parse_request(HTTPContext *c)
2842{
2843 const char *p, *p1, *p2;
2844 char cmd[32];
2845 char url[1024];
2846 char protocol[32];
2847 char line[1024];
2effd274 2848 int len;
a92be9b8 2849 RTSPMessageHeader header1 = { 0 }, *header = &header1;
115329f1 2850
2effd274
FB
2851 c->buffer_ptr[0] = '\0';
2852 p = c->buffer;
115329f1 2853
2effd274
FB
2854 get_word(cmd, sizeof(cmd), &p);
2855 get_word(url, sizeof(url), &p);
2856 get_word(protocol, sizeof(protocol), &p);
2857
f7d78f36
MR
2858 av_strlcpy(c->method, cmd, sizeof(c->method));
2859 av_strlcpy(c->url, url, sizeof(c->url));
2860 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2effd274 2861
b92c5452 2862 if (avio_open_dyn_buf(&c->pb) < 0) {
2effd274
FB
2863 /* XXX: cannot do more */
2864 c->pb = NULL; /* safety */
2865 return -1;
2866 }
2867
2868 /* check version name */
2869 if (strcmp(protocol, "RTSP/1.0") != 0) {
2870 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2871 goto the_end;
2872 }
2873
2874 /* parse each header line */
2effd274
FB
2875 /* skip to next line */
2876 while (*p != '\n' && *p != '\0')
2877 p++;
2878 if (*p == '\n')
2879 p++;
2880 while (*p != '\0') {
c966c912 2881 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2effd274
FB
2882 if (!p1)
2883 break;
2884 p2 = p1;
2885 if (p2 > p && p2[-1] == '\r')
2886 p2--;
2887 /* skip empty line */
2888 if (p2 == p)
2889 break;
2890 len = p2 - p;
2891 if (len > sizeof(line) - 1)
2892 len = sizeof(line) - 1;
2893 memcpy(line, p, len);
2894 line[len] = '\0';
77223c53 2895 ff_rtsp_parse_line(header, line, NULL, NULL);
2effd274
FB
2896 p = p1 + 1;
2897 }
2898
2899 /* handle sequence number */
2900 c->seq = header->seq;
2901
611c5741 2902 if (!strcmp(cmd, "DESCRIBE"))
2effd274 2903 rtsp_cmd_describe(c, url);
611c5741 2904 else if (!strcmp(cmd, "OPTIONS"))
0df65975 2905 rtsp_cmd_options(c, url);
611c5741 2906 else if (!strcmp(cmd, "SETUP"))
2effd274 2907 rtsp_cmd_setup(c, url, header);
611c5741 2908 else if (!strcmp(cmd, "PLAY"))
2effd274 2909 rtsp_cmd_play(c, url, header);
611c5741 2910 else if (!strcmp(cmd, "PAUSE"))
2effd274 2911 rtsp_cmd_pause(c, url, header);
611c5741 2912 else if (!strcmp(cmd, "TEARDOWN"))
2effd274 2913 rtsp_cmd_teardown(c, url, header);
611c5741 2914 else
2effd274 2915 rtsp_reply_error(c, RTSP_STATUS_METHOD);
611c5741 2916
2effd274 2917 the_end:
6dc7d80d 2918 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2effd274
FB
2919 c->pb = NULL; /* safety */
2920 if (len < 0) {
2921 /* XXX: cannot do more */
2922 return -1;
2923 }
2924 c->buffer_ptr = c->pb_buffer;
2925 c->buffer_end = c->pb_buffer + len;
2926 c->state = RTSPSTATE_SEND_REPLY;
2927 return 0;
2928}
2929
115329f1 2930static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
829ac53d 2931 struct in_addr my_ip)
2effd274 2932{
dd723472 2933 AVFormatContext *avc;
9389b925 2934 AVStream *avs = NULL;
dd723472 2935 int i;
115329f1 2936
8e2fd8e1 2937 avc = avformat_alloc_context();
dd723472 2938 if (avc == NULL) {
2effd274 2939 return -1;
dd723472 2940 }
d2d67e42
AK
2941 av_dict_set(&avc->metadata, "title",
2942 stream->title[0] ? stream->title : "No Title", 0);
dd723472
LA
2943 avc->nb_streams = stream->nb_streams;
2944 if (stream->is_multicast) {
2945 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2946 inet_ntoa(stream->multicast_ip),
2947 stream->multicast_port, stream->multicast_ttl);
43d09faf
MS
2948 } else {
2949 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
dd723472 2950 }
115329f1 2951
9389b925
AJ
2952 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2953 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2954 goto sdp_done;
9389b925
AJ
2955 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2956 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2957 goto sdp_done;
2958
2effd274 2959 for(i = 0; i < stream->nb_streams; i++) {
dd723472
LA
2960 avc->streams[i] = &avs[i];
2961 avc->streams[i]->codec = stream->streams[i]->codec;
2effd274 2962 }
dd723472 2963 *pbuffer = av_mallocz(2048);
c3675dfe 2964 av_sdp_create(&avc, 1, *pbuffer, 2048);
9389b925
AJ
2965
2966 sdp_done:
9389b925 2967 av_free(avc->streams);
d2d67e42 2968 av_dict_free(&avc->metadata);
dd723472 2969 av_free(avc);
9389b925 2970 av_free(avs);
dd723472
LA
2971
2972 return strlen(*pbuffer);
2effd274
FB
2973}
2974
0df65975
AR
2975static void rtsp_cmd_options(HTTPContext *c, const char *url)
2976{
2977// rtsp_reply_header(c, RTSP_STATUS_OK);
d9d86e00
AK
2978 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2979 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2980 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2981 avio_printf(c->pb, "\r\n");
0df65975
AR
2982}
2983
2effd274
FB
2984static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2985{
2986 FFStream *stream;
2987 char path1[1024];
2988 const char *path;
0c1a9eda 2989 uint8_t *content;
cc64ec57
MR
2990 int content_length;
2991 socklen_t len;
829ac53d 2992 struct sockaddr_in my_addr;
115329f1 2993
2effd274 2994 /* find which url is asked */
f3bfe388 2995 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2effd274
FB
2996 path = path1;
2997 if (*path == '/')
2998 path++;
2999
3000 for(stream = first_stream; stream != NULL; stream = stream->next) {
25e3e53d
LA
3001 if (!stream->is_feed &&
3002 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2effd274
FB
3003 !strcmp(path, stream->filename)) {
3004 goto found;
3005 }
3006 }
3007 /* no stream found */
3008 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3009 return;
3010
3011 found:
3012 /* prepare the media description in sdp format */
829ac53d
FB
3013
3014 /* get the host IP */
3015 len = sizeof(my_addr);
3016 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
829ac53d 3017 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2effd274
FB
3018 if (content_length < 0) {
3019 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3020 return;
3021 }
3022 rtsp_reply_header(c, RTSP_STATUS_OK);
d9d86e00
AK
3023 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3024 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3025 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3026 avio_printf(c->pb, "\r\n");
77eb5504 3027 avio_write(c->pb, content, content_length);
ea4f8aab 3028 av_free(content);
2effd274
FB
3029}
3030
3031static HTTPContext *find_rtp_session(const char *session_id)
3032{
3033 HTTPContext *c;
3034
3035 if (session_id[0] == '\0')
3036 return NULL;
3037
3038 for(c = first_http_ctx; c != NULL; c = c->next) {
3039 if (!strcmp(c->session_id, session_id))
3040 return c;
3041 }
3042 return NULL;
3043}
3044
a9e534d5 3045static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2effd274
FB
3046{
3047 RTSPTransportField *th;
3048 int i;
3049
3050 for(i=0;i<h->nb_transports;i++) {
3051 th = &h->transports[i];
90abbdba 3052 if (th->lower_transport == lower_transport)
2effd274
FB
3053 return th;
3054 }
3055 return NULL;
3056}
3057
115329f1 3058static void rtsp_cmd_setup(HTTPContext *c, const char *url,
a9e534d5 3059 RTSPMessageHeader *h)
2effd274
FB
3060{
3061 FFStream *stream;
bacde646 3062 int stream_index, rtp_port, rtcp_port;
2effd274
FB
3063 char buf[1024];
3064 char path1[1024];
3065 const char *path;
3066 HTTPContext *rtp_c;
3067 RTSPTransportField *th;
3068 struct sockaddr_in dest_addr;
3069 RTSPActionServerSetup setup;
115329f1 3070
2effd274 3071 /* find which url is asked */
f3bfe388 3072 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2effd274
FB
3073 path = path1;
3074 if (*path == '/')
3075 path++;
3076
3077 /* now check each stream */
3078 for(stream = first_stream; stream != NULL; stream = stream->next) {
25e3e53d
LA
3079 if (!stream->is_feed &&
3080 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2effd274
FB
3081 /* accept aggregate filenames only if single stream */
3082 if (!strcmp(path, stream->filename)) {
3083 if (stream->nb_streams != 1) {
3084 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3085 return;
3086 }
3087 stream_index = 0;
3088 goto found;
3089 }
115329f1 3090
2effd274
FB
3091 for(stream_index = 0; stream_index < stream->nb_streams;
3092 stream_index++) {
115329f1 3093 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2effd274
FB
3094 stream->filename, stream_index);
3095 if (!strcmp(path, buf))
3096 goto found;
3097 }
3098 }
3099 }
3100 /* no stream found */
3101 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3102 return;
3103 found:
3104
3105 /* generate session id if needed */
611c5741 3106 if (h->session_id[0] == '\0')
1df93ae9 3107 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
042819c5 3108 av_lfg_get(&random_state), av_lfg_get(&random_state));
2effd274
FB
3109
3110 /* find rtp session, and create it if none found */
3111 rtp_c = find_rtp_session(h->session_id);
3112 if (!rtp_c) {
bc351386 3113 /* always prefer UDP */
90abbdba 3114 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
bc351386 3115 if (!th) {
90abbdba 3116 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
bc351386
FB
3117 if (!th) {
3118 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3119 return;
3120 }
3121 }
3122
3123 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
90abbdba 3124 th->lower_transport);
2effd274
FB
3125 if (!rtp_c) {
3126 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3127 return;
3128 }
3129
3130 /* open input stream */
3131 if (open_input_stream(rtp_c, "") < 0) {
3132 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3133 return;
3134 }
2effd274 3135 }
115329f1 3136
2effd274
FB
3137 /* test if stream is OK (test needed because several SETUP needs
3138 to be done for a given file) */
3139 if (rtp_c->stream != stream) {
3140 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3141 return;
3142 }
115329f1 3143
2effd274
FB
3144 /* test if stream is already set up */
3145 if (rtp_c->rtp_ctx[stream_index]) {
3146 rtsp_reply_error(c, RTSP_STATUS_STATE);
3147 return;
3148 }
3149
3150 /* check transport */
3151 th = find_transport(h, rtp_c->rtp_protocol);
90abbdba 3152 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2effd274
FB
3153 th->client_port_min <= 0)) {
3154 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3155 return;
3156 }
3157
3158 /* setup default options */
3159 setup.transport_option[0] = '\0';
3160 dest_addr = rtp_c->from_addr;
3161 dest_addr.sin_port = htons(th->client_port_min);
115329f1 3162
2effd274 3163 /* setup stream */
bc351386 3164 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2effd274
FB
3165 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3166 return;
3167 }
3168
3169 /* now everything is OK, so we can send the connection parameters */
3170 rtsp_reply_header(c, RTSP_STATUS_OK);
3171 /* session ID */
d9d86e00 3172 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2effd274
FB
3173
3174 switch(rtp_c->rtp_protocol) {
90abbdba 3175 case RTSP_LOWER_TRANSPORT_UDP:
bfc6db44
MS
3176 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3177 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
d9d86e00 3178 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2effd274 3179 "client_port=%d-%d;server_port=%d-%d",
bacde646
LB
3180 th->client_port_min, th->client_port_max,
3181 rtp_port, rtcp_port);
2effd274 3182 break;
90abbdba 3183 case RTSP_LOWER_TRANSPORT_TCP:
d9d86e00 3184 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2effd274
FB
3185 stream_index * 2, stream_index * 2 + 1);
3186 break;
3187 default:
3188 break;
3189 }
611c5741 3190 if (setup.transport_option[0] != '\0')
d9d86e00
AK
3191 avio_printf(c->pb, ";%s", setup.transport_option);
3192 avio_printf(c->pb, "\r\n");
115329f1 3193
2effd274 3194
d9d86e00 3195 avio_printf(c->pb, "\r\n");
2effd274
FB
3196}
3197
3198
3199/* find an rtp connection by using the session ID. Check consistency
3200 with filename */
115329f1 3201static HTTPContext *find_rtp_session_with_url(const char *url,
2effd274
FB
3202 const char *session_id)
3203{
3204 HTTPContext *rtp_c;
3205 char path1[1024];
3206 const char *path;
94d9ad5f 3207 char buf[1024];
c2ca851b 3208 int s, len;
2effd274
FB
3209
3210 rtp_c = find_rtp_session(session_id);
3211 if (!rtp_c)
3212 return NULL;
3213
3214 /* find which url is asked */
f3bfe388 3215 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2effd274
FB
3216 path = path1;
3217 if (*path == '/')
3218 path++;
94d9ad5f
GF
3219 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3220 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3221 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3222 rtp_c->stream->filename, s);
3223 if(!strncmp(path, buf, sizeof(buf))) {
3224 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3225 return rtp_c;
3226 }
3227 }
c2ca851b
MS
3228 len = strlen(path);
3229 if (len > 0 && path[len - 1] == '/' &&
3230 !strncmp(path, rtp_c->stream->filename, len - 1))
3231 return rtp_c;
94d9ad5f 3232 return NULL;
2effd274
FB
3233}
3234
a9e534d5 3235static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
2effd274
FB
3236{
3237 HTTPContext *rtp_c;
3238
3239 rtp_c = find_rtp_session_with_url(url, h->session_id);
3240 if (!rtp_c) {
3241 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3242 return;
3243 }
115329f1 3244
2effd274
FB
3245 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3246 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3247 rtp_c->state != HTTPSTATE_READY) {
3248 rtsp_reply_error(c, RTSP_STATUS_STATE);
3249 return;
3250 }
3251
3252 rtp_c->state = HTTPSTATE_SEND_DATA;
115329f1 3253
2effd274
FB
3254 /* now everything is OK, so we can send the connection parameters */
3255 rtsp_reply_header(c, RTSP_STATUS_OK);
3256 /* session ID */
d9d86e00
AK
3257 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3258 avio_printf(c->pb, "\r\n");
2effd274
FB
3259}
3260
a9e534d5 3261static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
2effd274
FB
3262{
3263 HTTPContext *rtp_c;
3264
3265 rtp_c = find_rtp_session_with_url(url, h->session_id);
3266 if (!rtp_c) {
3267 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3268 return;
3269 }
115329f1 3270
2effd274
FB
3271 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3272 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3273 rtsp_reply_error(c, RTSP_STATUS_STATE);
3274 return;
3275 }
115329f1 3276
2effd274 3277 rtp_c->state = HTTPSTATE_READY;
1bc1cfdd 3278 rtp_c->first_pts = AV_NOPTS_VALUE;
2effd274
FB
3279 /* now everything is OK, so we can send the connection parameters */
3280 rtsp_reply_header(c, RTSP_STATUS_OK);
3281 /* session ID */
d9d86e00
AK
3282 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3283 avio_printf(c->pb, "\r\n");
2effd274
FB
3284}
3285
a9e534d5 3286static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
2effd274
FB
3287{
3288 HTTPContext *rtp_c;
3289
3290 rtp_c = find_rtp_session_with_url(url, h->session_id);
3291 if (!rtp_c) {
3292 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3293 return;
3294 }
115329f1 3295
2effd274
FB
3296 /* now everything is OK, so we can send the connection parameters */
3297 rtsp_reply_header(c, RTSP_STATUS_OK);
3298 /* session ID */
e2d7dc87 3299 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
d9d86e00 3300 avio_printf(c->pb, "\r\n");
e2d7dc87
MW
3301
3302 /* abort the session */
3303 close_connection(rtp_c);
2effd274
FB
3304}
3305
3306
3307/********************************************************************/
3308/* RTP handling */
3309
115329f1 3310static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
bc351386 3311 FFStream *stream, const char *session_id,
90abbdba 3312 enum RTSPLowerTransport rtp_protocol)
2effd274
FB
3313{
3314 HTTPContext *c = NULL;
bc351386 3315 const char *proto_str;
115329f1 3316
2effd274
FB
3317 /* XXX: should output a warning page when coming
3318 close to the connection limit */
3319 if (nb_connections >= nb_max_connections)
3320 goto fail;
115329f1 3321
2effd274
FB
3322 /* add a new connection */
3323 c = av_mallocz(sizeof(HTTPContext));
3324 if (!c)
3325 goto fail;
115329f1 3326
2effd274
FB
3327 c->fd = -1;
3328 c->poll_entry = NULL;
6edd6884 3329 c->from_addr = *from_addr;
2effd274
FB
3330 c->buffer_size = IOBUFFER_INIT_SIZE;
3331 c->buffer = av_malloc(c->buffer_size);