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