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