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