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