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