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