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