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