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