avtools: parse loglevel before all the other options.
[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>
ea452b54 27#include <strings.h>
0f4e8165 28#include <stdlib.h>
245976da 29#include "libavformat/avformat.h"
3ee53dab 30#include "libavformat/ffm.h"
245976da
DB
31#include "libavformat/network.h"
32#include "libavformat/os_support.h"
302879cb 33#include "libavformat/rtpdec.h"
245976da 34#include "libavformat/rtsp.h"
403ee835
AK
35// XXX for ffio_open_dyn_packet_buffer, to be removed
36#include "libavformat/avio_internal.h"
959da985 37#include "libavutil/avstring.h"
042819c5 38#include "libavutil/lfg.h"
d2d67e42 39#include "libavutil/dict.h"
0ebcdf5c 40#include "libavutil/mathematics.h"
042819c5 41#include "libavutil/random_seed.h"
737eb597 42#include "libavutil/parseutils.h"
41d0eb1c 43#include "libavutil/opt.h"
85f07f22 44#include <stdarg.h>
85f07f22
FB
45#include <unistd.h>
46#include <fcntl.h>
47#include <sys/ioctl.h>
b250f9c6 48#if HAVE_POLL_H
f8cda19e 49#include <poll.h>
b0c858d8 50#endif
85f07f22
FB
51#include <errno.h>
52#include <sys/time.h>
53#include <time.h>
5eb765ef 54#include <sys/wait.h>
85f07f22 55#include <signal.h>
b250f9c6 56#if HAVE_DLFCN_H
2effd274 57#include <dlfcn.h>
6638d424 58#endif
2effd274 59
4ce5df08 60#include "cmdutils.h"
85f07f22 61
4d58e4cb 62const char program_name[] = "avserver";
ea9c581f 63const int program_birth_year = 2000;
86074ed1 64
5a635bc7
SS
65static const OptionDef options[];
66
85f07f22
FB
67enum HTTPState {
68 HTTPSTATE_WAIT_REQUEST,
69 HTTPSTATE_SEND_HEADER,
70 HTTPSTATE_SEND_DATA_HEADER,
2effd274 71 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
85f07f22 72 HTTPSTATE_SEND_DATA_TRAILER,
115329f1 73 HTTPSTATE_RECEIVE_DATA,
2effd274 74 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
2effd274
FB
75 HTTPSTATE_READY,
76
77 RTSPSTATE_WAIT_REQUEST,
78 RTSPSTATE_SEND_REPLY,
bc351386 79 RTSPSTATE_SEND_PACKET,
85f07f22
FB
80};
81
9507a12e 82static const char *http_state[] = {
2effd274
FB
83 "HTTP_WAIT_REQUEST",
84 "HTTP_SEND_HEADER",
85
85f07f22
FB
86 "SEND_DATA_HEADER",
87 "SEND_DATA",
88 "SEND_DATA_TRAILER",
89 "RECEIVE_DATA",
90 "WAIT_FEED",
2effd274
FB
91 "READY",
92
93 "RTSP_WAIT_REQUEST",
94 "RTSP_SEND_REPLY",
bc351386 95 "RTSP_SEND_PACKET",
85f07f22
FB
96};
97
aff88101 98#define MAX_STREAMS 20
aff88101 99
cde25790 100#define IOBUFFER_INIT_SIZE 8192
85f07f22 101
85f07f22 102/* timeouts are in ms */
2effd274
FB
103#define HTTP_REQUEST_TIMEOUT (15 * 1000)
104#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
105
85f07f22
FB
106#define SYNC_TIMEOUT (10 * 1000)
107
b516ecdd
RB
108typedef struct RTSPActionServerSetup {
109 uint32_t ipaddr;
110 char transport_option[512];
111} RTSPActionServerSetup;
112
5eb765ef 113typedef struct {
0c1a9eda 114 int64_t count1, count2;
c3f58185 115 int64_t time1, time2;
5eb765ef
PG
116} DataRateData;
117
85f07f22
FB
118/* context associated with one connection */
119typedef struct HTTPContext {
120 enum HTTPState state;
121 int fd; /* socket file descriptor */
122 struct sockaddr_in from_addr; /* origin */
123 struct pollfd *poll_entry; /* used when polling */
c3f58185 124 int64_t timeout;
0c1a9eda 125 uint8_t *buffer_ptr, *buffer_end;
85f07f22 126 int http_error;
edfdd798 127 int post;
19c8c4ec
RB
128 int chunked_encoding;
129 int chunk_size; /* 0 if it needs to be read */
85f07f22 130 struct HTTPContext *next;
42a63c6a 131 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
0c1a9eda 132 int64_t data_count;
85f07f22
FB
133 /* feed input */
134 int feed_fd;
135 /* input format handling */
136 AVFormatContext *fmt_in;
c3f58185 137 int64_t start_time; /* In milliseconds - this wraps fairly often */
0c1a9eda 138 int64_t first_pts; /* initial pts value */
e240a0bb
FB
139 int64_t cur_pts; /* current pts value from the stream in us */
140 int64_t cur_frame_duration; /* duration of the current frame in us */
141 int cur_frame_bytes; /* output frame size, needed to compute
142 the time at which we send each
143 packet */
144 int pts_stream_index; /* stream we choose as clock reference */
145 int64_t cur_clock; /* current clock reference value in us */
85f07f22
FB
146 /* output format handling */
147 struct FFStream *stream;
cde25790
PG
148 /* -1 is invalid stream */
149 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
150 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
151 int switch_pending;
2effd274 152 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
85f07f22 153 int last_packet_sent; /* true if last data packet was sent */
7434ba6d 154 int suppress_log;
5eb765ef 155 DataRateData datarate;
3120d2a2 156 int wmp_client_id;
7434ba6d
PG
157 char protocol[16];
158 char method[16];
159 char url[128];
cde25790 160 int buffer_size;
0c1a9eda 161 uint8_t *buffer;
2effd274
FB
162 int is_packetized; /* if true, the stream is packetized */
163 int packet_stream_index; /* current stream for output in state machine */
115329f1 164
2effd274 165 /* RTSP state specific */
0c1a9eda 166 uint8_t *pb_buffer; /* XXX: use that in all the code */
ae628ec1 167 AVIOContext *pb;
2effd274 168 int seq; /* RTSP sequence number */
115329f1 169
2effd274 170 /* RTP state specific */
90abbdba 171 enum RTSPLowerTransport rtp_protocol;
2effd274
FB
172 char session_id[32]; /* session id */
173 AVFormatContext *rtp_ctx[MAX_STREAMS];
e240a0bb 174
bc351386
FB
175 /* RTP/UDP specific */
176 URLContext *rtp_handles[MAX_STREAMS];
177
178 /* RTP/TCP specific */
179 struct HTTPContext *rtsp_c;
180 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
85f07f22
FB
181} HTTPContext;
182
183/* each generated stream is described here */
184enum StreamType {
185 STREAM_TYPE_LIVE,
186 STREAM_TYPE_STATUS,
cde25790 187 STREAM_TYPE_REDIRECT,
85f07f22
FB
188};
189
8256c0a3
PG
190enum IPAddressAction {
191 IP_ALLOW = 1,
192 IP_DENY,
193};
194
195typedef struct IPAddressACL {
196 struct IPAddressACL *next;
197 enum IPAddressAction action;
efa04ce2 198 /* These are in host order */
8256c0a3
PG
199 struct in_addr first;
200 struct in_addr last;
201} IPAddressACL;
202
4d58e4cb 203/* description of each stream of the avserver.conf file */
85f07f22
FB
204typedef struct FFStream {
205 enum StreamType stream_type;
206 char filename[1024]; /* stream filename */
2effd274
FB
207 struct FFStream *feed; /* feed we are using (can be null if
208 coming from file) */
50f2dfad 209 AVDictionary *in_opts; /* input parameters */
e240a0bb 210 AVInputFormat *ifmt; /* if non NULL, force input format */
bd7cf6ad 211 AVOutputFormat *fmt;
8256c0a3 212 IPAddressACL *acl;
58f48adb 213 char dynamic_acl[1024];
85f07f22 214 int nb_streams;
42a63c6a 215 int prebuffer; /* Number of millseconds early to start */
c3f58185 216 int64_t max_time; /* Number of milliseconds to run */
79c4ea3c 217 int send_on_key;
85f07f22
FB
218 AVStream *streams[MAX_STREAMS];
219 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
220 char feed_filename[1024]; /* file name of the feed storage, or
221 input file name for a stream */
2ac887ba
PG
222 char author[512];
223 char title[512];
224 char copyright[512];
225 char comment[512];
cde25790 226 pid_t pid; /* Of ffmpeg process */
5eb765ef 227 time_t pid_start; /* Of ffmpeg process */
cde25790 228 char **child_argv;
85f07f22 229 struct FFStream *next;
177d2564 230 unsigned bandwidth; /* bandwidth, in kbits/s */
2effd274
FB
231 /* RTSP options */
232 char *rtsp_option;
829ac53d
FB
233 /* multicast specific */
234 int is_multicast;
235 struct in_addr multicast_ip;
236 int multicast_port; /* first port used for multicast */
6edd6884
FB
237 int multicast_ttl;
238 int loop; /* if true, send the stream in loops (only meaningful if file) */
829ac53d 239
85f07f22 240 /* feed specific */
2effd274 241 int feed_opened; /* true if someone is writing to the feed */
85f07f22 242 int is_feed; /* true if it is a feed */
e322ea48 243 int readonly; /* True if writing is prohibited to the file */
861ec13a 244 int truncate; /* True if feeder connection truncate the feed file */
a6e14edd 245 int conns_served;
0c1a9eda 246 int64_t bytes_served;
6b0bdc75 247 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
8bfb108b 248 int64_t feed_write_index; /* current write position in feed (it wraps around) */
0c1a9eda 249 int64_t feed_size; /* current size of feed */
85f07f22
FB
250 struct FFStream *next_feed;
251} FFStream;
252
253typedef struct FeedData {
254 long long data_count;
8bfb108b 255 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
85f07f22
FB
256} FeedData;
257
18405874
AB
258static struct sockaddr_in my_http_addr;
259static struct sockaddr_in my_rtsp_addr;
2effd274 260
33f5e2ec
AB
261static char logfilename[1024];
262static HTTPContext *first_http_ctx;
263static FFStream *first_feed; /* contains only feeds */
264static FFStream *first_stream; /* contains all streams, including feeds */
85f07f22 265
2effd274
FB
266static void new_connection(int server_fd, int is_rtsp);
267static void close_connection(HTTPContext *c);
268
269/* HTTP handling */
270static int handle_connection(HTTPContext *c);
85f07f22 271static int http_parse_request(HTTPContext *c);
5eb765ef 272static int http_send_data(HTTPContext *c);
dca21085 273static void compute_status(HTTPContext *c);
85f07f22
FB
274static int open_input_stream(HTTPContext *c, const char *info);
275static int http_start_receive_data(HTTPContext *c);
276static int http_receive_data(HTTPContext *c);
2effd274
FB
277
278/* RTSP handling */
279static int rtsp_parse_request(HTTPContext *c);
280static void rtsp_cmd_describe(HTTPContext *c, const char *url);
0df65975 281static void rtsp_cmd_options(HTTPContext *c, const char *url);
a9e534d5
RB
282static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
283static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
284static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
285static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
2effd274 286
829ac53d 287/* SDP handling */
115329f1 288static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
829ac53d
FB
289 struct in_addr my_ip);
290
2effd274 291/* RTP handling */
115329f1 292static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
bc351386 293 FFStream *stream, const char *session_id,
90abbdba 294 enum RTSPLowerTransport rtp_protocol);
115329f1 295static int rtp_new_av_stream(HTTPContext *c,
bc351386
FB
296 int stream_index, struct sockaddr_in *dest_addr,
297 HTTPContext *rtsp_c);
85f07f22 298
cde25790 299static const char *my_program_name;
d6562d2c 300static const char *my_program_dir;
cde25790 301
4d58e4cb 302static const char *config_filename = "/etc/avserver.conf";
6675a5bf 303
4d58e4cb
AK
304static int avserver_debug;
305static int avserver_daemon;
2ac887ba 306static int no_launch;
5eb765ef 307static int need_to_start_children;
2ac887ba 308
1c9ff179
SS
309/* maximum number of simultaneous HTTP connections */
310static unsigned int nb_max_http_connections = 2000;
4af92de6
SS
311static unsigned int nb_max_connections = 5;
312static unsigned int nb_connections;
85f07f22 313
f69bb0cc 314static uint64_t max_bandwidth = 1000;
1ad8289e 315static uint64_t current_bandwidth;
42a63c6a 316
c3f58185 317static int64_t cur_time; // Making this global saves on passing it around everywhere
5eb765ef 318
042819c5 319static AVLFG random_state;
1df93ae9 320
85f07f22
FB
321static FILE *logfile = NULL;
322
dad09ff9
AK
323void exit_program(int ret)
324{
325 exit(ret);
326}
327
4d58e4cb 328/* FIXME: make avserver work with IPv6 */
22f73dcc
MR
329/* resolve host with also IP address parsing */
330static int resolve_host(struct in_addr *sin_addr, const char *hostname)
331{
332
333 if (!ff_inet_aton(hostname, sin_addr)) {
334#if HAVE_GETADDRINFO
335 struct addrinfo *ai, *cur;
336 struct addrinfo hints;
337 memset(&hints, 0, sizeof(hints));
338 hints.ai_family = AF_INET;
339 if (getaddrinfo(hostname, NULL, &hints, &ai))
340 return -1;
341 /* getaddrinfo returns a linked list of addrinfo structs.
342 * Even if we set ai_family = AF_INET above, make sure
343 * that the returned one actually is of the correct type. */
344 for (cur = ai; cur; cur = cur->ai_next) {
345 if (cur->ai_family == AF_INET) {
346 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
347 freeaddrinfo(ai);
348 return 0;
349 }
350 }
351 freeaddrinfo(ai);
352 return -1;
353#else
354 struct hostent *hp;
355 hp = gethostbyname(hostname);
356 if (!hp)
357 return -1;
358 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
359#endif
360 }
361 return 0;
362}
363
9fd3442f
BC
364static char *ctime1(char *buf2)
365{
366 time_t ti;
367 char *p;
368
369 ti = time(NULL);
370 p = ctime(&ti);
371 strcpy(buf2, p);
372 p = buf2 + strlen(p) - 1;
373 if (*p == '\n')
374 *p = '\0';
375 return buf2;
376}
377
bcd3ce59 378static void http_vlog(const char *fmt, va_list vargs)
85f07f22 379{
124ed1c0 380 static int print_prefix = 1;
7434ba6d 381 if (logfile) {
124ed1c0 382 if (print_prefix) {
9fd3442f
BC
383 char buf[32];
384 ctime1(buf);
385 fprintf(logfile, "%s ", buf);
124ed1c0
BC
386 }
387 print_prefix = strstr(fmt, "\n") != NULL;
bcd3ce59 388 vfprintf(logfile, fmt, vargs);
7434ba6d
PG
389 fflush(logfile);
390 }
bcd3ce59
BC
391}
392
efa6ce99
MR
393#ifdef __GNUC__
394__attribute__ ((format (printf, 1, 2)))
395#endif
396static void http_log(const char *fmt, ...)
bcd3ce59
BC
397{
398 va_list vargs;
399 va_start(vargs, fmt);
400 http_vlog(fmt, vargs);
401 va_end(vargs);
402}
403
404static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
405{
406 static int print_prefix = 1;
407 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
49ceb58b 408 if (level > av_log_get_level())
bcd3ce59
BC
409 return;
410 if (print_prefix && avc)
59e7894c 411 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
bcd3ce59
BC
412 print_prefix = strstr(fmt, "\n") != NULL;
413 http_vlog(fmt, vargs);
85f07f22
FB
414}
415
6edd6884
FB
416static void log_connection(HTTPContext *c)
417{
115329f1 418 if (c->suppress_log)
6edd6884
FB
419 return;
420
82e0be62
BC
421 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
422 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
6edd6884 423 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
cde25790
PG
424}
425
0c1a9eda 426static void update_datarate(DataRateData *drd, int64_t count)
5eb765ef
PG
427{
428 if (!drd->time1 && !drd->count1) {
429 drd->time1 = drd->time2 = cur_time;
430 drd->count1 = drd->count2 = count;
eeffbdea 431 } else if (cur_time - drd->time2 > 5000) {
33a4ecbe
AB
432 drd->time1 = drd->time2;
433 drd->count1 = drd->count2;
434 drd->time2 = cur_time;
435 drd->count2 = count;
5eb765ef
PG
436 }
437}
438
439/* In bytes per second */
0c1a9eda 440static int compute_datarate(DataRateData *drd, int64_t count)
5eb765ef
PG
441{
442 if (cur_time == drd->time1)
443 return 0;
115329f1 444
5eb765ef
PG
445 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
446}
447
a782f209 448
cde25790
PG
449static void start_children(FFStream *feed)
450{
2ac887ba
PG
451 if (no_launch)
452 return;
453
cde25790 454 for (; feed; feed = feed->next) {
5eb765ef
PG
455 if (feed->child_argv && !feed->pid) {
456 feed->pid_start = time(0);
457
cde25790
PG
458 feed->pid = fork();
459
460 if (feed->pid < 0) {
b4befb99 461 http_log("Unable to create children\n");
cde25790
PG
462 exit(1);
463 }
464 if (!feed->pid) {
465 /* In child */
466 char pathname[1024];
467 char *slash;
468 int i;
469
40444a59
SS
470 av_strlcpy(pathname, my_program_name, sizeof(pathname));
471
472 slash = strrchr(pathname, '/');
473 if (!slash)
474 slash = pathname;
475 else
476 slash++;
477 strcpy(slash, "ffmpeg");
478
8bf61f5b
SS
479 http_log("Launch commandline: ");
480 http_log("%s ", pathname);
481 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
482 http_log("%s ", feed->child_argv[i]);
483 http_log("\n");
40444a59 484
611c5741 485 for (i = 3; i < 256; i++)
5eb765ef 486 close(i);
cde25790 487
4d58e4cb 488 if (!avserver_debug) {
2ac887ba 489 i = open("/dev/null", O_RDWR);
3296409d 490 if (i != -1) {
2ac887ba 491 dup2(i, 0);
3296409d
BC
492 dup2(i, 1);
493 dup2(i, 2);
5eb765ef 494 close(i);
3296409d 495 }
2ac887ba 496 }
cde25790 497
d6562d2c
PG
498 /* This is needed to make relative pathnames work */
499 chdir(my_program_dir);
500
a4d70941
PG
501 signal(SIGPIPE, SIG_DFL);
502
cde25790
PG
503 execvp(pathname, feed->child_argv);
504
505 _exit(1);
506 }
507 }
508 }
7434ba6d
PG
509}
510
2effd274
FB
511/* open a listening socket */
512static int socket_open_listen(struct sockaddr_in *my_addr)
85f07f22 513{
2effd274 514 int server_fd, tmp;
85f07f22
FB
515
516 server_fd = socket(AF_INET,SOCK_STREAM,0);
517 if (server_fd < 0) {
518 perror ("socket");
519 return -1;
520 }
115329f1 521
85f07f22
FB
522 tmp = 1;
523 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
524
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
FB
851 }
852 av_close_input_file(c->fmt_in);
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'; ) {
1087 if (strncasecmp(p, "Pragma:", 7) == 0) {
1088 const char *q = p + 7;
1089
1090 while (*q && *q != '\n' && isspace(*q))
1091 q++;
1092
1093 if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
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);
1273 if (strcasecmp(arg, "allow") == 0)
1274 acl.action = IP_ALLOW;
1275 else if (strcasecmp(arg, "deny") == 0)
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
1360 if (!strcasecmp(cmd, "ACL"))
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
PG
1501 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1502 if (strncasecmp(p, "User-Agent:", 11) == 0) {
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") &&
cde25790
PG
1520 (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
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
PG
1614 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1615 if (strncasecmp(p, "Host:", 5) == 0) {
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
PG
1743 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1744 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1745 logline = p;
1746 break;
1747 }
611c5741 1748 if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
3120d2a2 1749 client_id = strtol(p + 18, 0, 10);
7434ba6d
PG
1750 p = strchr(p, '\n');
1751 if (!p)
1752 break;
1753
1754 p++;
1755 }
1756
1757 if (logline) {
1758 char *eol = strchr(logline, '\n');
1759
1760 logline += 17;
1761
1762 if (eol) {
1763 if (eol[-1] == '\r')
1764 eol--;
7906085f 1765 http_log("%.*s\n", (int) (eol - logline), logline);
7434ba6d
PG
1766 c->suppress_log = 1;
1767 }
1768 }
3120d2a2 1769
f190f676 1770#ifdef DEBUG
cde25790 1771 http_log("\nGot request:\n%s\n", c->buffer);
3120d2a2
PG
1772#endif
1773
1774 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1775 HTTPContext *wmpc;
1776
1777 /* Now we have to find the client_id */
1778 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1779 if (wmpc->wmp_client_id == client_id)
1780 break;
1781 }
1782
2d563d2f
AB
1783 if (wmpc && modify_current_stream(wmpc, ratebuf))
1784 wmpc->switch_pending = 1;
3120d2a2 1785 }
115329f1 1786
d445a7e9 1787 snprintf(msg, sizeof(msg), "POST command not handled");
cb275dd9 1788 c->stream = 0;
85f07f22
FB
1789 goto send_error;
1790 }
1791 if (http_start_receive_data(c) < 0) {
d445a7e9 1792 snprintf(msg, sizeof(msg), "could not open feed");
85f07f22
FB
1793 goto send_error;
1794 }
1795 c->http_error = 0;
1796 c->state = HTTPSTATE_RECEIVE_DATA;
1797 return 0;
1798 }
1799
f190f676 1800#ifdef DEBUG
611c5741 1801 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
cde25790 1802 http_log("\nGot request:\n%s\n", c->buffer);
3120d2a2
PG
1803#endif
1804
85f07f22 1805 if (c->stream->stream_type == STREAM_TYPE_STATUS)
dca21085 1806 goto send_status;
85f07f22
FB
1807
1808 /* open input stream */
1809 if (open_input_stream(c, info) < 0) {
d445a7e9 1810 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
85f07f22
FB
1811 goto send_error;
1812 }
1813
1814 /* prepare http header */
1815 q = c->buffer;
d445a7e9 1816 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
85f07f22
FB
1817 mime_type = c->stream->fmt->mime_type;
1818 if (!mime_type)
087fa475 1819 mime_type = "application/x-octet-stream";
d445a7e9 1820 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
85f07f22
FB
1821
1822 /* for asf, we need extra headers */
8256c0a3 1823 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
3120d2a2 1824 /* Need to allocate a client id */
3120d2a2 1825
042819c5 1826 c->wmp_client_id = av_lfg_get(&random_state);
3120d2a2 1827
d445a7e9 1828 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
85f07f22 1829 }
d445a7e9
PG
1830 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1831 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
115329f1 1832
85f07f22
FB
1833 /* prepare output buffer */
1834 c->http_error = 0;
1835 c->buffer_ptr = c->buffer;
1836 c->buffer_end = q;
1837 c->state = HTTPSTATE_SEND_HEADER;
1838 return 0;
1839 send_error:
1840 c->http_error = 404;
1841 q = c->buffer;
a3aa4fed
BC
1842 q += snprintf(q, c->buffer_size,
1843 "HTTP/1.0 404 Not Found\r\n"
1844 "Content-type: text/html\r\n"
1845 "\r\n"
5e567aae
DB
1846 "<html>\n"
1847 "<head><title>404 Not Found</title></head>\n"
1848 "<body>%s</body>\n"
1849 "</html>\n", msg);
85f07f22
FB
1850 /* prepare output buffer */
1851 c->buffer_ptr = c->buffer;
1852 c->buffer_end = q;
1853 c->state = HTTPSTATE_SEND_HEADER;
1854 return 0;
dca21085
SS
1855 send_status:
1856 compute_status(c);
85f07f22
FB
1857 c->http_error = 200; /* horrible : we use this value to avoid
1858 going to the send data state */
1859 c->state = HTTPSTATE_SEND_HEADER;
1860 return 0;
1861}
1862
ae628ec1 1863static void fmt_bytecount(AVIOContext *pb, int64_t count)
2ac887ba
PG
1864{
1865 static const char *suffix = " kMGTP";
1866 const char *s;
1867
611c5741 1868 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
2ac887ba 1869
d9d86e00 1870 avio_printf(pb, "%"PRId64"%c", count, *s);
2ac887ba
PG
1871}
1872
dca21085 1873static void compute_status(HTTPContext *c)
85f07f22
FB
1874{
1875 HTTPContext *c1;
1876 FFStream *stream;
2effd274 1877 char *p;
85f07f22 1878 time_t ti;
2effd274 1879 int i, len;
ae628ec1 1880 AVIOContext *pb;
cde25790 1881
b92c5452 1882 if (avio_open_dyn_buf(&pb) < 0) {
2effd274 1883 /* XXX: return an error ? */
cde25790 1884 c->buffer_ptr = c->buffer;
2effd274
FB
1885 c->buffer_end = c->buffer;
1886 return;
cde25790 1887 }
85f07f22 1888
d9d86e00
AK
1889 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1890 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1891 avio_printf(pb, "Pragma: no-cache\r\n");
1892 avio_printf(pb, "\r\n");
115329f1 1893
d9d86e00 1894 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
0679719d 1895 if (c->stream->feed_filename[0])
d9d86e00
AK
1896 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1897 avio_printf(pb, "</head>\n<body>");
1898 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
85f07f22 1899 /* format status */
d9d86e00
AK
1900 avio_printf(pb, "<h2>Available Streams</h2>\n");
1901 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1902 avio_printf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbits/s<th align=left>Video<br>kbits/s<th><br>Codec<th align=left>Audio<br>kbits/s<th><br>Codec<th align=left valign=top>Feed\n");
85f07f22
FB
1903 stream = first_stream;
1904 while (stream != NULL) {
42a63c6a
PG
1905 char sfilename[1024];
1906 char *eosf;
1907
a6e14edd 1908 if (stream->feed != stream) {
f7d78f36 1909 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
a6e14edd
PG
1910 eosf = sfilename + strlen(sfilename);
1911 if (eosf - sfilename >= 4) {
611c5741 1912 if (strcmp(eosf - 4, ".asf") == 0)
a6e14edd 1913 strcpy(eosf - 4, ".asx");
611c5741 1914 else if (strcmp(eosf - 3, ".rm") == 0)
a6e14edd 1915 strcpy(eosf - 3, ".ram");
25e3e53d 1916 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
829ac53d
FB
1917 /* generate a sample RTSP director if
1918 unicast. Generate an SDP redirector if
1919 multicast */
2effd274
FB
1920 eosf = strrchr(sfilename, '.');
1921 if (!eosf)
1922 eosf = sfilename + strlen(sfilename);
829ac53d
FB
1923 if (stream->is_multicast)
1924 strcpy(eosf, ".sdp");
1925 else
1926 strcpy(eosf, ".rtsp");
a6e14edd 1927 }
42a63c6a 1928 }
115329f1 1929
d9d86e00 1930 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
a6e14edd 1931 sfilename, stream->filename);
d9d86e00 1932 avio_printf(pb, "<td align=right> %d <td align=right> ",
2ac887ba 1933 stream->conns_served);
2effd274 1934 fmt_bytecount(pb, stream->bytes_served);
a6e14edd 1935 switch(stream->stream_type) {
ace21da3 1936 case STREAM_TYPE_LIVE: {
a6e14edd
PG
1937 int audio_bit_rate = 0;
1938 int video_bit_rate = 0;
58445440
ZK
1939 const char *audio_codec_name = "";
1940 const char *video_codec_name = "";
1941 const char *audio_codec_name_extra = "";
1942 const char *video_codec_name_extra = "";
a6e14edd
PG
1943
1944 for(i=0;i<stream->nb_streams;i++) {
1945 AVStream *st = stream->streams[i];
01f4895c
MN
1946 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1947 switch(st->codec->codec_type) {
72415b2a 1948 case AVMEDIA_TYPE_AUDIO:
01f4895c 1949 audio_bit_rate += st->codec->bit_rate;
a6e14edd
PG
1950 if (codec) {
1951 if (*audio_codec_name)
1952 audio_codec_name_extra = "...";
1953 audio_codec_name = codec->name;
1954 }
1955 break;
72415b2a 1956 case AVMEDIA_TYPE_VIDEO:
01f4895c 1957 video_bit_rate += st->codec->bit_rate;
a6e14edd
PG
1958 if (codec) {
1959 if (*video_codec_name)
1960 video_codec_name_extra = "...";
1961 video_codec_name = codec->name;
1962 }
1963 break;
72415b2a 1964 case AVMEDIA_TYPE_DATA:
01f4895c 1965 video_bit_rate += st->codec->bit_rate;
e240a0bb 1966 break;
a6e14edd 1967 default:
0f4e8165 1968 abort();
79c4ea3c 1969 }
85f07f22 1970 }
d9d86e00 1971 avio_printf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
a6e14edd 1972 stream->fmt->name,
6edd6884 1973 stream->bandwidth,
a6e14edd
PG
1974 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1975 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
611c5741 1976 if (stream->feed)
d9d86e00 1977 avio_printf(pb, "<td>%s", stream->feed->filename);
611c5741 1978 else
d9d86e00
AK
1979 avio_printf(pb, "<td>%s", stream->feed_filename);
1980 avio_printf(pb, "\n");
85f07f22 1981 }
a6e14edd
PG
1982 break;
1983 default:
d9d86e00 1984 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
a6e14edd 1985 break;
85f07f22 1986 }
85f07f22
FB
1987 }
1988 stream = stream->next;
1989 }
d9d86e00 1990 avio_printf(pb, "</table>\n");
a6e14edd
PG
1991
1992 stream = first_stream;
1993 while (stream != NULL) {
1994 if (stream->feed == stream) {
d9d86e00 1995 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
cde25790 1996 if (stream->pid) {
d9d86e00 1997 avio_printf(pb, "Running as pid %d.\n", stream->pid);
cde25790 1998
2effd274
FB
1999#if defined(linux) && !defined(CONFIG_NOCUTILS)
2000 {
2001 FILE *pid_stat;
2002 char ps_cmd[64];
2003
2004 /* This is somewhat linux specific I guess */
115329f1
DB
2005 snprintf(ps_cmd, sizeof(ps_cmd),
2006 "ps -o \"%%cpu,cputime\" --no-headers %d",
2effd274 2007 stream->pid);
115329f1 2008
2effd274
FB
2009 pid_stat = popen(ps_cmd, "r");
2010 if (pid_stat) {
2011 char cpuperc[10];
2012 char cpuused[64];
115329f1
DB
2013
2014 if (fscanf(pid_stat, "%10s %64s", cpuperc,
2effd274 2015 cpuused) == 2) {
d9d86e00 2016 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2effd274
FB
2017 cpuperc, cpuused);
2018 }
2019 fclose(pid_stat);
cde25790 2020 }
cde25790
PG
2021 }
2022#endif
2023
d9d86e00 2024 avio_printf(pb, "<p>");
cde25790 2025 }
d9d86e00 2026 avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
a6e14edd
PG
2027
2028 for (i = 0; i < stream->nb_streams; i++) {
2029 AVStream *st = stream->streams[i];
01f4895c 2030 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
b29f97d1 2031 const char *type = "unknown";
b582f314
PG
2032 char parameters[64];
2033
2034 parameters[0] = 0;
a6e14edd 2035
01f4895c 2036 switch(st->codec->codec_type) {
72415b2a 2037 case AVMEDIA_TYPE_AUDIO:
a6e14edd 2038 type = "audio";
acdc8520 2039 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
a6e14edd 2040 break;
72415b2a 2041 case AVMEDIA_TYPE_VIDEO:
a6e14edd 2042 type = "video";
01f4895c
MN
2043 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2044 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
a6e14edd
PG
2045 break;
2046 default:
0f4e8165 2047 abort();
a6e14edd 2048 }
d9d86e00 2049 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
01f4895c 2050 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
a6e14edd 2051 }
d9d86e00 2052 avio_printf(pb, "</table>\n");
a6e14edd 2053
115329f1 2054 }
a6e14edd
PG
2055 stream = stream->next;
2056 }
115329f1 2057
85f07f22 2058 /* connection status */
d9d86e00 2059 avio_printf(pb, "<h2>Connection Status</h2>\n");
85f07f22 2060
d9d86e00 2061 avio_printf(pb, "Number of connections: %d / %d<br>\n",
85f07f22
FB
2062 nb_connections, nb_max_connections);
2063
d9d86e00 2064 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
6edd6884 2065 current_bandwidth, max_bandwidth);
42a63c6a 2066
d9d86e00
AK
2067 avio_printf(pb, "<table>\n");
2068 avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
85f07f22
FB
2069 c1 = first_http_ctx;
2070 i = 0;
2effd274 2071 while (c1 != NULL) {
cde25790
PG
2072 int bitrate;
2073 int j;
2074
2075 bitrate = 0;
2effd274
FB
2076 if (c1->stream) {
2077 for (j = 0; j < c1->stream->nb_streams; j++) {
2d563d2f 2078 if (!c1->stream->feed)
01f4895c 2079 bitrate += c1->stream->streams[j]->codec->bit_rate;
2d563d2f
AB
2080 else if (c1->feed_streams[j] >= 0)
2081 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
cde25790
PG
2082 }
2083 }
2084
85f07f22
FB
2085 i++;
2086 p = inet_ntoa(c1->from_addr.sin_addr);
d9d86e00 2087 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
115329f1
DB
2088 i,
2089 c1->stream ? c1->stream->filename : "",
2effd274 2090 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
115329f1 2091 p,
2effd274
FB
2092 c1->protocol,
2093 http_state[c1->state]);
2094 fmt_bytecount(pb, bitrate);
d9d86e00 2095 avio_printf(pb, "<td align=right>");
2effd274 2096 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
d9d86e00 2097 avio_printf(pb, "<td align=right>");
2effd274 2098 fmt_bytecount(pb, c1->data_count);
d9d86e00 2099 avio_printf(pb, "\n");
85f07f22
FB
2100 c1 = c1->next;
2101 }
d9d86e00 2102 avio_printf(pb, "</table>\n");
115329f1 2103
85f07f22
FB
2104 /* date */
2105 ti = time(NULL);
2106 p = ctime(&ti);
d9d86e00
AK
2107 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2108 avio_printf(pb, "</body>\n</html>\n");
85f07f22 2109
6dc7d80d 2110 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2effd274
FB
2111 c->buffer_ptr = c->pb_buffer;
2112 c->buffer_end = c->pb_buffer + len;
85f07f22
FB
2113}
2114
2effd274
FB
2115/* check if the parser needs to be opened for stream i */
2116static void open_parser(AVFormatContext *s, int i)
85f07f22 2117{
2effd274
FB
2118 AVStream *st = s->streams[i];
2119 AVCodec *codec;
31def229 2120
01f4895c
MN
2121 if (!st->codec->codec) {
2122 codec = avcodec_find_decoder(st->codec->codec_id);
2effd274 2123 if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
01f4895c 2124 st->codec->parse_only = 1;
0b950fe2 2125 if (avcodec_open2(st->codec, codec, NULL) < 0)
01f4895c 2126 st->codec->parse_only = 0;
cde25790
PG
2127 }
2128 }
85f07f22
FB
2129}
2130
2131static int open_input_stream(HTTPContext *c, const char *info)
2132{
2133 char buf[128];
2134 char input_filename[1024];
50f2dfad 2135 AVFormatContext *s = NULL;
f02f745e 2136 int i, ret;
0c1a9eda 2137 int64_t stream_pos;
85f07f22
FB
2138
2139 /* find file name */
2140 if (c->stream->feed) {
2141 strcpy(input_filename, c->stream->feed->feed_filename);
85f07f22 2142 /* compute position (absolute time) */
ab0287fc 2143 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
9fcae973
AK
2144 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2145 return ret;
ab0287fc 2146 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
f747e6d3 2147 int prebuffer = strtol(buf, 0, 10);
0c1a9eda 2148 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
611c5741 2149 } else
0c1a9eda 2150 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
85f07f22
FB
2151 } else {
2152 strcpy(input_filename, c->stream->feed_filename);
85f07f22 2153 /* compute position (relative time) */
ab0287fc 2154 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
9fcae973
AK
2155 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2156 return ret;
ace21da3 2157 } else
85f07f22 2158 stream_pos = 0;
85f07f22
FB
2159 }
2160 if (input_filename[0] == '\0')
2161 return -1;
2162
2163 /* open stream */
50f2dfad 2164 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
c351cc7f 2165 http_log("could not open %s: %d\n", input_filename, ret);
85f07f22 2166 return -1;
2effd274 2167 }
9dc0bc3d 2168 s->flags |= AVFMT_FLAG_GENPTS;
85f07f22 2169 c->fmt_in = s;
c960e67a 2170 if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
20f93c3c
BC
2171 http_log("Could not find stream info '%s'\n", input_filename);
2172 av_close_input_file(s);
2173 return -1;
2174 }
115329f1 2175
2effd274
FB
2176 /* open each parser */
2177 for(i=0;i<s->nb_streams;i++)
2178 open_parser(s, i);
2179
2180 /* choose stream as clock source (we favorize video stream if
2181 present) for packet sending */
2182 c->pts_stream_index = 0;
2183 for(i=0;i<c->stream->nb_streams;i++) {
115329f1 2184 if (c->pts_stream_index == 0 &&
72415b2a 2185 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2effd274
FB
2186 c->pts_stream_index = i;
2187 }
2188 }
85f07f22 2189
611c5741 2190 if (c->fmt_in->iformat->read_seek)
60a04f7f 2191 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2effd274
FB
2192 /* set the start time (needed for maxtime and RTP packet timing) */
2193 c->start_time = cur_time;
2194 c->first_pts = AV_NOPTS_VALUE;
85f07f22
FB
2195 return 0;
2196}
2197
e240a0bb
FB
2198/* return the server clock (in us) */
2199static int64_t get_server_clock(HTTPContext *c)
2effd274 2200{
e240a0bb 2201 /* compute current pts value from system time */
c3f58185 2202 return (cur_time - c->start_time) * 1000;
2effd274
FB
2203}
2204
e240a0bb
FB
2205/* return the estimated time at which the current packet must be sent
2206 (in us) */
2207static int64_t get_packet_send_clock(HTTPContext *c)
2effd274 2208{
e240a0bb 2209 int bytes_left, bytes_sent, frame_bytes;
115329f1 2210
e240a0bb 2211 frame_bytes = c->cur_frame_bytes;
611c5741 2212 if (frame_bytes <= 0)
e240a0bb 2213 return c->cur_pts;
611c5741 2214 else {
e240a0bb
FB
2215 bytes_left = c->buffer_end - c->buffer_ptr;
2216 bytes_sent = frame_bytes - bytes_left;
2217 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2effd274 2218 }
2effd274 2219}
2effd274 2220
2effd274 2221
2effd274
FB
2222static int http_prepare_data(HTTPContext *c)
2223{
2224 int i, len, ret;
2225 AVFormatContext *ctx;
2226
bc351386 2227 av_freep(&c->pb_buffer);
2effd274
FB
2228 switch(c->state) {
2229 case HTTPSTATE_SEND_DATA_HEADER:
2230 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
d2d67e42
AK
2231 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2232 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2233 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2234 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2effd274 2235
db3262b7
MW
2236 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2237
3d9cc27d 2238 for(i=0;i<c->stream->nb_streams;i++) {
bb270c08 2239 AVStream *src;
db3262b7 2240 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2effd274 2241 /* if file or feed, then just take streams from FFStream struct */
115329f1 2242 if (!c->stream->feed ||
2effd274 2243 c->stream->feed == c->stream)
7c054ea7 2244 src = c->stream->streams[i];
2effd274 2245 else
7c054ea7
PG
2246 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2247
db3262b7
MW
2248 *(c->fmt_ctx.streams[i]) = *src;
2249 c->fmt_ctx.streams[i]->priv_data = 0;
2250 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2effd274
FB
2251 AVStream, not in codec */
2252 }
3d9cc27d
BC
2253 /* set output format parameters */
2254 c->fmt_ctx.oformat = c->stream->fmt;
2255 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2256
2effd274
FB
2257 c->got_key_frame = 0;
2258
2259 /* prepare header and save header data in a stream */
b92c5452 2260 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2effd274
FB
2261 /* XXX: potential leak */
2262 return -1;
2263 }
8978feda 2264 c->fmt_ctx.pb->seekable = 0;
2effd274 2265
8aae202e
BC
2266 /*
2267 * HACK to avoid mpeg ps muxer to spit many underflow errors
43fb279f 2268 * Default value from Libav
8aae202e
BC
2269 * Try to set it use configuration option
2270 */
2271 c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2272 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2273
50f2dfad 2274 if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
929a9b75 2275 http_log("Error writing output header\n");
f75cdda7 2276 return -1;
929a9b75 2277 }
d2d67e42 2278 av_dict_free(&c->fmt_ctx.metadata);
2effd274 2279
6dc7d80d 2280 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2effd274
FB
2281 c->buffer_ptr = c->pb_buffer;
2282 c->buffer_end = c->pb_buffer + len;
2283
2284 c->state = HTTPSTATE_SEND_DATA;
85f07f22
FB
2285 c->last_packet_sent = 0;
2286 break;
2287 case HTTPSTATE_SEND_DATA:
2288 /* find a new packet */
3b371676
BC
2289 /* read a packet from the input stream */
2290 if (c->stream->feed)
2291 ffm_set_write_index(c->fmt_in,
2292 c->stream->feed->feed_write_index,
2293 c->stream->feed->feed_size);
2294
2295 if (c->stream->max_time &&
2296 c->stream->max_time + c->start_time - cur_time < 0)
2297 /* We have timed out */
2298 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2299 else {
2300 AVPacket pkt;
2301 redo:
d9aac267
HC
2302 ret = av_read_frame(c->fmt_in, &pkt);
2303 if (ret < 0) {
2304 if (c->stream->feed) {
3b371676
BC
2305 /* if coming from feed, it means we reached the end of the
2306 ffm file, so must wait for more data */
2307 c->state = HTTPSTATE_WAIT_FEED;
2308 return 1; /* state changed */
d9aac267
HC
2309 } else if (ret == AVERROR(EAGAIN)) {
2310 /* input not ready, come back later */
2311 return 0;
2effd274 2312 } else {
3b371676
BC
2313 if (c->stream->loop) {
2314 av_close_input_file(c->fmt_in);
2315 c->fmt_in = NULL;
2316 if (open_input_stream(c, "") < 0)
2317 goto no_loop;
2318 goto redo;
2319 } else {
2320 no_loop:
2321 /* must send trailer now because eof or error */
2322 c->state = HTTPSTATE_SEND_DATA_TRAILER;
1bc1cfdd 2323 }
3b371676
BC
2324 }
2325 } else {
084a8912 2326 int source_index = pkt.stream_index;
3b371676
BC
2327 /* update first pts if needed */
2328 if (c->first_pts == AV_NOPTS_VALUE) {
2329 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2330 c->start_time = cur_time;
2331 }
2332 /* send it to the appropriate stream */
2333 if (c->stream->feed) {
2334 /* if coming from a feed, select the right stream */
2335 if (c->switch_pending) {
2336 c->switch_pending = 0;
cde25790 2337 for(i=0;i<c->stream->nb_streams;i++) {
3b371676 2338 if (c->switch_feed_streams[i] == pkt.stream_index)
cc947f04 2339 if (pkt.flags & AV_PKT_FLAG_KEY)
305ca590 2340 c->switch_feed_streams[i] = -1;
3b371676
BC
2341 if (c->switch_feed_streams[i] >= 0)
2342 c->switch_pending = 1;
cde25790 2343 }
3b371676
BC
2344 }
2345 for(i=0;i<c->stream->nb_streams;i++) {
a5ba4ced 2346 if (c->stream->feed_streams[i] == pkt.stream_index) {
78728064 2347 AVStream *st = c->fmt_in->streams[source_index];
3b371676 2348 pkt.stream_index = i;
cc947f04 2349 if (pkt.flags & AV_PKT_FLAG_KEY &&
72415b2a 2350 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
180b7026 2351 c->stream->nb_streams == 1))
0332f549
BC
2352 c->got_key_frame = 1;
2353 if (!c->stream->send_on_key || c->got_key_frame)
3b371676
BC
2354 goto send_it;
2355 }
2356 }
2357 } else {
2358 AVCodecContext *codec;
dc3a6a36
BC
2359 AVStream *ist, *ost;
2360 send_it:
2361 ist = c->fmt_in->streams[source_index];
3b371676
BC
2362 /* specific handling for RTP: we use several
2363 output stream (one for each RTP
2364 connection). XXX: need more abstract handling */
2365 if (c->is_packetized) {
3b371676 2366 /* compute send time and duration */
8f56ccca 2367 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
f475f35f 2368 c->cur_pts -= c->first_pts;
8f56ccca 2369 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
3b371676
BC
2370 /* find RTP context */
2371 c->packet_stream_index = pkt.stream_index;
2372 ctx = c->rtp_ctx[c->packet_stream_index];
2373 if(!ctx) {
8a0b55ff 2374 av_free_packet(&pkt);
3b371676 2375 break;
8a0b55ff 2376 }
3b371676
BC
2377 codec = ctx->streams[0]->codec;
2378 /* only one stream per RTP connection */
2379 pkt.stream_index = 0;
2380 } else {
2381 ctx = &c->fmt_ctx;
2382 /* Fudge here */
3ab29d8e 2383 codec = ctx->streams[pkt.stream_index]->codec;
3b371676
BC
2384 }
2385
2386 if (c->is_packetized) {
2387 int max_packet_size;
90abbdba 2388 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
3b371676
BC
2389 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2390 else
2391 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
403ee835 2392 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
3b371676 2393 } else {
b92c5452 2394 ret = avio_open_dyn_buf(&ctx->pb);
3b371676
BC
2395 }
2396 if (ret < 0) {
2397 /* XXX: potential leak */
2398 return -1;
2399 }
3ab29d8e
BC
2400 ost = ctx->streams[pkt.stream_index];
2401
8978feda 2402 ctx->pb->seekable = 0;
3b371676 2403 if (pkt.dts != AV_NOPTS_VALUE)
d80904cc 2404 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
3b371676 2405 if (pkt.pts != AV_NOPTS_VALUE)
d80904cc
BC
2406 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2407 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
3766ed72
BC
2408 if (av_write_frame(ctx, &pkt) < 0) {
2409 http_log("Error writing frame to output\n");
3b371676 2410 c->state = HTTPSTATE_SEND_DATA_TRAILER;
3766ed72 2411 }
3b371676 2412
6dc7d80d 2413 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
3b371676
BC
2414 c->cur_frame_bytes = len;
2415 c->buffer_ptr = c->pb_buffer;
2416 c->buffer_end = c->pb_buffer + len;
2417
2418 codec->frame_number++;
2419 if (len == 0) {
2420 av_free_packet(&pkt);
2421 goto redo;
f747e6d3 2422 }
85f07f22 2423 }
3b371676 2424 av_free_packet(&pkt);
85f07f22 2425 }
3b371676 2426 }
85f07f22
FB
2427 break;
2428 default:
2429 case HTTPSTATE_SEND_DATA_TRAILER:
2430 /* last packet test ? */
2effd274 2431 if (c->last_packet_sent || c->is_packetized)
85f07f22 2432 return -1;
2effd274 2433 ctx = &c->fmt_ctx;
85f07f22 2434 /* prepare header */
b92c5452 2435 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2effd274
FB
2436 /* XXX: potential leak */
2437 return -1;
2438 }
8978feda 2439 c->fmt_ctx.pb->seekable = 0;
2effd274 2440 av_write_trailer(ctx);
6dc7d80d 2441 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2effd274
FB
2442 c->buffer_ptr = c->pb_buffer;
2443 c->buffer_end = c->pb_buffer + len;
2444
85f07f22
FB
2445 c->last_packet_sent = 1;
2446 break;
2447 }
2448 return 0;
2449}
2450
2451/* should convert the format at the same time */
bc351386
FB
2452/* send data starting at c->buffer_ptr to the output connection
2453 (either UDP or TCP connection) */
5eb765ef 2454static int http_send_data(HTTPContext *c)
85f07f22 2455{
e240a0bb 2456 int len, ret;
85f07f22 2457
bc351386
FB
2458 for(;;) {
2459 if (c->buffer_ptr >= c->buffer_end) {
2460 ret = http_prepare_data(c);
2461 if (ret < 0)
2462 return -1;
611c5741 2463 else if (ret != 0)
bc351386
FB
2464 /* state change requested */
2465 break;
2effd274 2466 } else {
bc351386
FB
2467 if (c->is_packetized) {
2468 /* RTP data output */
2469 len = c->buffer_end - c->buffer_ptr;
2470 if (len < 4) {
2471 /* fail safe - should never happen */
2472 fail1:
2473 c->buffer_ptr = c->buffer_end;
2effd274
FB
2474 return 0;
2475 }
bc351386
FB
2476 len = (c->buffer_ptr[0] << 24) |
2477 (c->buffer_ptr[1] << 16) |
2478 (c->buffer_ptr[2] << 8) |
2479 (c->buffer_ptr[3]);
2480 if (len > (c->buffer_end - c->buffer_ptr))
2481 goto fail1;
e240a0bb
FB
2482 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2483 /* nothing to send yet: we can wait */
2484 return 0;
2485 }
2486
2487 c->data_count += len;
2488 update_datarate(&c->datarate, c->data_count);
2489 if (c->stream)
2490 c->stream->bytes_served += len;
2491
90abbdba 2492 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
bc351386 2493 /* RTP packets are sent inside the RTSP TCP connection */
ae628ec1 2494 AVIOContext *pb;
bc351386
FB
2495 int interleaved_index, size;
2496 uint8_t header[4];
2497 HTTPContext *rtsp_c;
115329f1 2498
bc351386
FB
2499 rtsp_c = c->rtsp_c;
2500 /* if no RTSP connection left, error */
2501 if (!rtsp_c)
2502 return -1;
2503 /* if already sending something, then wait. */
611c5741 2504 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
bc351386 2505 break;
b92c5452 2506 if (avio_open_dyn_buf(&pb) < 0)
bc351386
FB
2507 goto fail1;
2508 interleaved_index = c->packet_stream_index * 2;
2509 /* RTCP packets are sent at odd indexes */
2510 if (c->buffer_ptr[1] == 200)
2511 interleaved_index++;
2512 /* write RTSP TCP header */
2513 header[0] = '$';
2514 header[1] = interleaved_index;
2515 header[2] = len >> 8;
2516 header[3] = len;
77eb5504 2517 avio_write(pb, header, 4);
bc351386
FB
2518 /* write RTP packet data */
2519 c->buffer_ptr += 4;
77eb5504 2520 avio_write(pb, c->buffer_ptr, len);
6dc7d80d 2521 size = avio_close_dyn_buf(pb, &c->packet_buffer);
bc351386
FB
2522 /* prepare asynchronous TCP sending */
2523 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2524 rtsp_c->packet_buffer_end = c->packet_buffer + size;
e240a0bb 2525 c->buffer_ptr += len;
115329f1 2526
e240a0bb 2527 /* send everything we can NOW */
c60202df
AB
2528 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2529 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
611c5741 2530 if (len > 0)
e240a0bb 2531 rtsp_c->packet_buffer_ptr += len;
e240a0bb
FB
2532 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2533 /* if we could not send all the data, we will
2534 send it later, so a new state is needed to
2535 "lock" the RTSP TCP connection */
2536 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2537 break;
611c5741 2538 } else
e240a0bb
FB
2539 /* all data has been sent */
2540 av_freep(&c->packet_buffer);
e240a0bb
FB
2541 } else {
2542 /* send RTP packet directly in UDP */
bc351386 2543 c->buffer_ptr += 4;
115329f1 2544 url_write(c->rtp_handles[c->packet_stream_index],
bc351386 2545 c->buffer_ptr, len);
e240a0bb
FB
2546 c->buffer_ptr += len;
2547 /* here we continue as we can send several packets per 10 ms slot */
bc351386 2548 }
bc351386
FB
2549 } else {
2550 /* TCP data output */
c60202df 2551 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
bc351386 2552 if (len < 0) {
28c4741a
MS
2553 if (ff_neterrno() != AVERROR(EAGAIN) &&
2554 ff_neterrno() != AVERROR(EINTR))
bc351386
FB
2555 /* error : close connection */
2556 return -1;
611c5741 2557 else
bc351386 2558 return 0;
611c5741 2559 } else
bc351386 2560 c->buffer_ptr += len;
611c5741 2561
e240a0bb
FB
2562 c->data_count += len;
2563 update_datarate(&c->datarate, c->data_count);
2564 if (c->stream)
2565 c->stream->bytes_served += len;
2566 break;
2effd274 2567 }
85f07f22 2568 }
bc351386 2569 } /* for(;;) */
85f07f22
FB
2570 return 0;
2571}
2572
2573static int http_start_receive_data(HTTPContext *c)
2574{
2575 int fd;
2576
2577 if (c->stream->feed_opened)
2578 return -1;
2579
e322ea48
PG
2580 /* Don't permit writing to this one */
2581 if (c->stream->readonly)
2582 return -1;
2583
85f07f22
FB
2584 /* open feed */
2585 fd = open(c->stream->feed_filename, O_RDWR);
929a9b75
BC
2586 if (fd < 0) {
2587 http_log("Error opening feeder file: %s\n", strerror(errno));
85f07f22 2588 return -1;
929a9b75 2589 }
85f07f22 2590 c->feed_fd = fd;
115329f1 2591
861ec13a
BC
2592 if (c->stream->truncate) {
2593 /* truncate feed file */
2594 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2595 ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2596 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2597 } else {
1f611549
BC
2598 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2599 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2600 return -1;
2601 }
861ec13a
BC
2602 }
2603
7e24aa0c 2604 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
85f07f22
FB
2605 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2606 lseek(fd, 0, SEEK_SET);
2607
2608 /* init buffer input */
2609 c->buffer_ptr = c->buffer;
2610 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2611 c->stream->feed_opened = 1;
fd7bec5e 2612 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
85f07f22
FB
2613 return 0;
2614}
115329f1 2615
85f07f22
FB
2616static int http_receive_data(HTTPContext *c)
2617{
85f07f22 2618 HTTPContext *c1;
19c8c4ec 2619 int len, loop_run = 0;
85f07f22 2620
19c8c4ec
RB
2621 while (c->chunked_encoding && !c->chunk_size &&
2622 c->buffer_end > c->buffer_ptr) {
2623 /* read chunk header, if present */
2624 len = recv(c->fd, c->buffer_ptr, 1, 0);
2625
2626 if (len < 0) {
28c4741a
MS
2627 if (ff_neterrno() != AVERROR(EAGAIN) &&
2628 ff_neterrno() != AVERROR(EINTR))
19c8c4ec
RB
2629 /* error : close connection */
2630 goto fail;
686d6f40 2631 return 0;
19c8c4ec
RB
2632 } else if (len == 0) {
2633 /* end of connection : close it */
2634 goto fail;
2635 } else if (c->buffer_ptr - c->buffer >= 2 &&
2636 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2637 c->chunk_size = strtol(c->buffer, 0, 16);
2638 if (c->chunk_size == 0) // end of stream
2639 goto fail;
2640 c->buffer_ptr = c->buffer;
2641 break;
2642 } else if (++loop_run > 10) {
2643 /* no chunk header, abort */
2644 goto fail;
2645 } else {
2646 c->buffer_ptr++;
2647 }
2648 }
a6e14edd 2649
19c8c4ec
RB
2650 if (c->buffer_end > c->buffer_ptr) {
2651 len = recv(c->fd, c->buffer_ptr,
2652 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
a6e14edd 2653 if (len < 0) {
28c4741a
MS
2654 if (ff_neterrno() != AVERROR(EAGAIN) &&
2655 ff_neterrno() != AVERROR(EINTR))
a6e14edd
PG
2656 /* error : close connection */
2657 goto fail;
611c5741 2658 } else if (len == 0)
a6e14edd
PG
2659 /* end of connection : close it */
2660 goto fail;
611c5741 2661 else {
19c8c4ec 2662 c->chunk_size -= len;
a6e14edd
PG
2663 c->buffer_ptr += len;
2664 c->data_count += len;
5eb765ef 2665 update_datarate(&c->datarate, c->data_count);
a6e14edd
PG
2666 }
2667 }
2668
d445a7e9
PG
2669 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2670 if (c->buffer[0] != 'f' ||
2671 c->buffer[1] != 'm') {
2672 http_log("Feed stream has become desynchronized -- disconnecting\n");
2673 goto fail;
2674 }
2675 }
2676
85f07f22 2677 if (c->buffer_ptr >= c->buffer_end) {
f747e6d3 2678 FFStream *feed = c->stream;
85f07f22
FB
2679 /* a packet has been received : write it in the store, except
2680 if header */
2681 if (c->data_count > FFM_PACKET_SIZE) {
115329f1 2682
949b1a13 2683 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
85f07f22
FB
2684 /* XXX: use llseek or url_seek */
2685 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
929a9b75
BC
2686 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2687 http_log("Error writing to feed file: %s\n", strerror(errno));
2688 goto fail;
2689 }
115329f1 2690
85f07f22
FB
2691 feed->feed_write_index += FFM_PACKET_SIZE;
2692 /* update file size */
2693 if (feed->feed_write_index > c->stream->feed_size)
2694 feed->feed_size = feed->feed_write_index;
2695
2696 /* handle wrap around if max file size reached */
6b0bdc75 2697 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
85f07f22
FB
2698 feed->feed_write_index = FFM_PACKET_SIZE;
2699
2700 /* write index */
2779cdad
PK
2701 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2702 http_log("Error writing index to feed file: %s\n", strerror(errno));
2703 goto fail;
2704 }
85f07f22
FB
2705
2706 /* wake up any waiting connections */
2707 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
115329f1 2708 if (c1->state == HTTPSTATE_WAIT_FEED &&
611c5741 2709 c1->stream->feed == c->stream->feed)
85f07f22 2710 c1->state = HTTPSTATE_SEND_DATA;
85f07f22 2711 }
f747e6d3
PG
2712 } else {
2713 /* We have a header in our hands that contains useful data */
50f2dfad 2714 AVFormatContext *s = avformat_alloc_context();
ae628ec1 2715 AVIOContext *pb;
bd7cf6ad 2716 AVInputFormat *fmt_in;
f747e6d3
PG
2717 int i;
2718
50f2dfad
AK
2719 if (!s)
2720 goto fail;
2721
bd7cf6ad
FB
2722 /* use feed output format name to find corresponding input format */
2723 fmt_in = av_find_input_format(feed->fmt->name);
2724 if (!fmt_in)
2725 goto fail;
2726
83fddaeb
AK
2727 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2728 0, NULL, NULL, NULL, NULL);
8978feda 2729 pb->seekable = 0;
697efa36 2730
50f2dfad
AK
2731 s->pb = pb;
2732 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
e6f0deab
BC
2733 av_free(pb);
2734 goto fail;
2735 }
f747e6d3
PG
2736
2737 /* Now we have the actual streams */
f2972c8c
BC
2738 if (s->nb_streams != feed->nb_streams) {
2739 av_close_input_stream(s);
86771c68 2740 av_free(pb);
77553ae3
BC
2741 http_log("Feed '%s' stream number does not match registered feed\n",
2742 c->stream->feed_filename);
f747e6d3
PG
2743 goto fail;
2744 }
f2972c8c 2745
cb51aef1
BC
2746 for (i = 0; i < s->nb_streams; i++) {
2747 AVStream *fst = feed->streams[i];
2748 AVStream *st = s->streams[i];
5634f30c 2749 avcodec_copy_context(fst->codec, st->codec);
cb51aef1 2750 }
f2972c8c
BC
2751
2752 av_close_input_stream(s);
86771c68 2753 av_free(pb);
85f07f22
FB
2754 }
2755 c->buffer_ptr = c->buffer;
2756 }
2757
85f07f22
FB
2758 return 0;
2759 fail:
2760 c->stream->feed_opened = 0;
2761 close(c->feed_fd);
c1593d0e
BC
2762 /* wake up any waiting connections to stop waiting for feed */
2763 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2764 if (c1->state == HTTPSTATE_WAIT_FEED &&
2765 c1->stream->feed == c->stream->feed)
2766 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2767 }
85f07f22
FB
2768 return -1;
2769}
2770
2effd274
FB
2771/********************************************************************/
2772/* RTSP handling */
2773
2774static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2775{
2776 const char *str;
2777 time_t ti;
0156fcf2 2778 struct tm *tm;
2effd274
FB
2779 char buf2[32];
2780
2781 switch(error_number) {
7e665cd3
LA
2782 case RTSP_STATUS_OK:
2783 str = "OK";
2784 break;
2785 case RTSP_STATUS_METHOD:
2786 str = "Method Not Allowed";
2787 break;
2788 case RTSP_STATUS_BANDWIDTH:
2789 str = "Not Enough Bandwidth";
2790 break;
2791 case RTSP_STATUS_SESSION:
2792 str = "Session Not Found";
2793 break;
2794 case RTSP_STATUS_STATE:
2795 str = "Method Not Valid in This State";
2796 break;
2797 case RTSP_STATUS_AGGREGATE:
2798 str = "Aggregate operation not allowed";
2799 break;
2800 case RTSP_STATUS_ONLY_AGGREGATE:
2801 str = "Only aggregate operation allowed";
2802 break;
2803 case RTSP_STATUS_TRANSPORT:
2804 str = "Unsupported transport";
2805 break;
2806 case RTSP_STATUS_INTERNAL:
2807 str = "Internal Server Error";
2808 break;
2809 case RTSP_STATUS_SERVICE:
2810 str = "Service Unavailable";
2811 break;
2812 case RTSP_STATUS_VERSION:
2813 str = "RTSP Version not supported";
2814 break;
2effd274
FB
2815 default:
2816 str = "Unknown Error";
2817 break;
2818 }
115329f1 2819
d9d86e00
AK
2820 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2821 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2effd274
FB
2822
2823 /* output GMT time */
2824 ti = time(NULL);
0156fcf2
HC
2825 tm = gmtime(&ti);
2826 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
d9d86e00 2827 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2effd274
FB
2828}
2829
2830static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2831{
2832 rtsp_reply_header(c, error_number);
d9d86e00 2833 avio_printf(c->pb, "\r\n");
2effd274
FB
2834}
2835
2836static int rtsp_parse_request(HTTPContext *c)
2837{
2838 const char *p, *p1, *p2;
2839 char cmd[32];
2840 char url[1024];
2841 char protocol[32];
2842 char line[1024];
2effd274 2843 int len;
a9e534d5 2844 RTSPMessageHeader header1, *header = &header1;
115329f1 2845
2effd274
FB
2846 c->buffer_ptr[0] = '\0';
2847 p = c->buffer;
115329f1 2848
2effd274
FB
2849 get_word(cmd, sizeof(cmd), &p);
2850 get_word(url, sizeof(url), &p);
2851 get_word(protocol, sizeof(protocol), &p);
2852
f7d78f36
MR
2853 av_strlcpy(c->method, cmd, sizeof(c->method));
2854 av_strlcpy(c->url, url, sizeof(c->url));
2855 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2effd274 2856
b92c5452 2857 if (avio_open_dyn_buf(&c->pb) < 0) {
2effd274
FB
2858 /* XXX: cannot do more */
2859 c->pb = NULL; /* safety */
2860 return -1;
2861 }
2862
2863 /* check version name */
2864 if (strcmp(protocol, "RTSP/1.0") != 0) {
2865 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2866 goto the_end;
2867 }
2868
2869 /* parse each header line */
d541a7d2 2870 memset(header, 0, sizeof(*header));
2effd274
FB
2871 /* skip to next line */
2872 while (*p != '\n' && *p != '\0')
2873 p++;
2874 if (*p == '\n')
2875 p++;
2876 while (*p != '\0') {
c966c912 2877 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2effd274
FB
2878 if (!p1)
2879 break;
2880 p2 = p1;
2881 if (p2 > p && p2[-1] == '\r')
2882 p2--;
2883 /* skip empty line */
2884 if (p2 == p)
2885 break;
2886 len = p2 - p;
2887 if (len > sizeof(line) - 1)
2888 len = sizeof(line) - 1;
2889 memcpy(line, p, len);
2890 line[len] = '\0';
77223c53 2891 ff_rtsp_parse_line(header, line, NULL, NULL);
2effd274
FB
2892 p = p1 + 1;
2893 }
2894
2895 /* handle sequence number */
2896 c->seq = header->seq;
2897
611c5741 2898 if (!strcmp(cmd, "DESCRIBE"))
2effd274 2899 rtsp_cmd_describe(c, url);
611c5741 2900 else if (!strcmp(cmd, "OPTIONS"))
0df65975 2901 rtsp_cmd_options(c, url);
611c5741 2902 else if (!strcmp(cmd, "SETUP"))
2effd274 2903 rtsp_cmd_setup(c, url, header);
611c5741 2904 else if (!strcmp(cmd, "PLAY"))
2effd274 2905 rtsp_cmd_play(c, url, header);
611c5741 2906 else if (!strcmp(cmd, "PAUSE"))
2effd274 2907 rtsp_cmd_pause(c, url, header);
611c5741 2908 else if (!strcmp(cmd, "TEARDOWN"))
2effd274 2909 rtsp_cmd_teardown(c, url, header);
611c5741 2910 else
2effd274 2911 rtsp_reply_error(c, RTSP_STATUS_METHOD);
611c5741 2912
2effd274 2913 the_end:
6dc7d80d 2914 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2effd274
FB
2915 c->pb = NULL; /* safety */
2916 if (len < 0) {
2917 /* XXX: cannot do more */
2918 return -1;
2919 }
2920 c->buffer_ptr = c->pb_buffer;
2921 c->buffer_end = c->pb_buffer + len;
2922 c->state = RTSPSTATE_SEND_REPLY;
2923 return 0;
2924}
2925
115329f1 2926static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
829ac53d 2927 struct in_addr my_ip)
2effd274 2928{
dd723472 2929 AVFormatContext *avc;
9389b925 2930 AVStream *avs = NULL;
dd723472 2931 int i;
115329f1 2932
8e2fd8e1 2933 avc = avformat_alloc_context();
dd723472 2934 if (avc == NULL) {
2effd274 2935 return -1;
dd723472 2936 }
d2d67e42
AK
2937 av_dict_set(&avc->metadata, "title",
2938 stream->title[0] ? stream->title : "No Title", 0);
dd723472
LA
2939 avc->nb_streams = stream->nb_streams;
2940 if (stream->is_multicast) {
2941 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2942 inet_ntoa(stream->multicast_ip),
2943 stream->multicast_port, stream->multicast_ttl);
43d09faf
MS
2944 } else {
2945 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
dd723472 2946 }
115329f1 2947
9389b925
AJ
2948 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2949 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2950 goto sdp_done;
9389b925
AJ
2951 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2952 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2953 goto sdp_done;
2954
2effd274 2955 for(i = 0; i < stream->nb_streams; i++) {
dd723472
LA
2956 avc->streams[i] = &avs[i];
2957 avc->streams[i]->codec = stream->streams[i]->codec;
2effd274 2958 }
dd723472 2959 *pbuffer = av_mallocz(2048);
c3675dfe 2960 av_sdp_create(&avc, 1, *pbuffer, 2048);
9389b925
AJ
2961
2962 sdp_done:
9389b925 2963 av_free(avc->streams);
d2d67e42 2964 av_dict_free(&avc->metadata);
dd723472 2965 av_free(avc);
9389b925 2966 av_free(avs);
dd723472
LA
2967
2968 return strlen(*pbuffer);
2effd274
FB
2969}
2970
0df65975
AR
2971static void rtsp_cmd_options(HTTPContext *c, const char *url)
2972{
2973// rtsp_reply_header(c, RTSP_STATUS_OK);
d9d86e00
AK
2974 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2975 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2976 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2977 avio_printf(c->pb, "\r\n");
0df65975
AR
2978}
2979
2effd274
FB
2980static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2981{
2982 FFStream *stream;
2983 char path1[1024];
2984 const char *path;
0c1a9eda 2985 uint8_t *content;
829ac53d
FB
2986 int content_length, len;
2987 struct sockaddr_in my_addr;
115329f1 2988
2effd274 2989 /* find which url is asked */
f3bfe388 2990 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2effd274
FB
2991 path = path1;
2992 if (*path == '/')
2993 path++;
2994
2995 for(stream = first_stream; stream != NULL; stream = stream->next) {
25e3e53d
LA
2996 if (!stream->is_feed &&
2997 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2effd274
FB
2998 !strcmp(path, stream->filename)) {
2999 goto found;
3000 }
3001 }
3002 /* no stream found */
3003 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3004 return;
3005
3006 found:
3007 /* prepare the media description in sdp format */
829ac53d
FB
3008
3009 /* get the host IP */
3010 len = sizeof(my_addr);
3011 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
829ac53d 3012 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2effd274
FB
3013 if (content_length < 0) {
3014 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3015 return;
3016 }
3017 rtsp_reply_header(c, RTSP_STATUS_OK);
d9d86e00
AK
3018 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3019 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3020 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3021 avio_printf(c->pb, "\r\n");
77eb5504 3022 avio_write(c->pb, content, content_length);
ea4f8aab 3023 av_free(content);
2effd274
FB
3024}
3025
3026static HTTPContext *find_rtp_session(const char *session_id)
3027{
3028 HTTPContext *c;
3029
3030 if (session_id[0] == '\0')
3031 return NULL;
3032
3033 for(c = first_http_ctx; c != NULL; c = c->next) {
3034 if (!strcmp(c->session_id, session_id))
3035 return c;
3036 }
3037 return NULL;
3038}
3039
a9e534d5 3040static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2effd274
FB
3041{
3042 RTSPTransportField *th;
3043 int i;
3044
3045 for(i=0;i<h->nb_transports;i++) {
3046 th = &h->transports[i];
90abbdba 3047 if (th->lower_transport == lower_transport)
2effd274
FB
3048 return th;
3049 }
3050 return NULL;
3051}
3052
115329f1 3053static void rtsp_cmd_setup(HTTPContext *c, const char *url,
a9e534d5 3054 RTSPMessageHeader *h)
2effd274
FB
3055{
3056 FFStream *stream;
bacde646 3057 int stream_index, rtp_port, rtcp_port;
2effd274
FB
3058 char buf[1024];
3059 char path1[1024];
3060 const char *path;
3061 HTTPContext *rtp_c;
3062 RTSPTransportField *th;
3063 struct sockaddr_in dest_addr;
3064 RTSPActionServerSetup setup;
115329f1 3065
2effd274 3066 /* find which url is asked */
f3bfe388 3067 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2effd274
FB
3068 path = path1;
3069 if (*path == '/')
3070 path++;
3071
3072 /* now check each stream */
3073 for(stream = first_stream; stream != NULL; stream = stream->next) {
25e3e53d
LA
3074 if (!stream->is_feed &&
3075 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2effd274
FB
3076 /* accept aggregate filenames only if single stream */
3077 if (!strcmp(path, stream->filename)) {
3078 if (stream->nb_streams != 1) {
3079 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3080 return;
3081 }
3082 stream_index = 0;
3083 goto found;
3084 }
115329f1 3085
2effd274
FB
3086 for(stream_index = 0; stream_index < stream->nb_streams;
3087 stream_index++) {
115329f1 3088 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2effd274
FB
3089 stream->filename, stream_index);
3090 if (!strcmp(path, buf))
3091 goto found;
3092 }
3093 }
3094 }
3095 /* no stream found */
3096 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3097 return;
3098 found:
3099
3100 /* generate session id if needed */
611c5741 3101 if (h->session_id[0] == '\0')
1df93ae9 3102 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
042819c5 3103 av_lfg_get(&random_state), av_lfg_get(&random_state));
2effd274
FB
3104
3105 /* find rtp session, and create it if none found */
3106 rtp_c = find_rtp_session(h->session_id);
3107 if (!rtp_c) {
bc351386 3108 /* always prefer UDP */
90abbdba 3109 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
bc351386 3110 if (!th) {
90abbdba 3111 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
bc351386
FB
3112 if (!th) {
3113 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3114 return;
3115 }
3116 }
3117
3118 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
90abbdba 3119 th->lower_transport);
2effd274
FB
3120 if (!rtp_c) {
3121 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3122 return;
3123 }
3124
3125 /* open input stream */
3126 if (open_input_stream(rtp_c, "") < 0) {
3127 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3128 return;
3129 }
2effd274 3130 }
115329f1 3131
2effd274
FB
3132 /* test if stream is OK (test needed because several SETUP needs
3133 to be done for a given file) */
3134 if (rtp_c->stream != stream) {
3135 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3136 return;
3137 }
115329f1 3138
2effd274
FB
3139 /* test if stream is already set up */
3140 if (rtp_c->rtp_ctx[stream_index]) {
3141 rtsp_reply_error(c, RTSP_STATUS_STATE);
3142 return;
3143 }
3144
3145 /* check transport */
3146 th = find_transport(h, rtp_c->rtp_protocol);
90abbdba 3147 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2effd274
FB
3148 th->client_port_min <= 0)) {
3149 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3150 return;
3151 }
3152
3153 /* setup default options */
3154 setup.transport_option[0] = '\0';
3155 dest_addr = rtp_c->from_addr;
3156 dest_addr.sin_port = htons(th->client_port_min);
115329f1 3157
2effd274 3158 /* setup stream */
bc351386 3159 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2effd274
FB
3160 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3161 return;
3162 }
3163
3164 /* now everything is OK, so we can send the connection parameters */
3165 rtsp_reply_header(c, RTSP_STATUS_OK);
3166 /* session ID */
d9d86e00 3167 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2effd274
FB
3168
3169 switch(rtp_c->rtp_protocol) {
90abbdba 3170 case RTSP_LOWER_TRANSPORT_UDP:
bacde646
LB
3171 rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3172 rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
d9d86e00 3173 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2effd274 3174 "client_port=%d-%d;server_port=%d-%d",
bacde646
LB
3175 th->client_port_min, th->client_port_max,
3176 rtp_port, rtcp_port);
2effd274 3177 break;
90abbdba 3178 case RTSP_LOWER_TRANSPORT_TCP:
d9d86e00 3179 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2effd274
FB
3180 stream_index * 2, stream_index * 2 + 1);
3181 break;
3182 default:
3183 break;
3184 }
611c5741 3185 if (setup.transport_option[0] != '\0')
d9d86e00
AK
3186 avio_printf(c->pb, ";%s", setup.transport_option);
3187 avio_printf(c->pb, "\r\n");
115329f1 3188
2effd274 3189
d9d86e00 3190 avio_printf(c->pb, "\r\n");
2effd274
FB
3191}
3192
3193
3194/* find an rtp connection by using the session ID. Check consistency
3195 with filename */
115329f1 3196static HTTPContext *find_rtp_session_with_url(const char *url,
2effd274
FB
3197 const char *session_id)
3198{
3199 HTTPContext *rtp_c;
3200 char path1[1024];
3201 const char *path;
94d9ad5f 3202 char buf[1024];
c2ca851b 3203 int s, len;
2effd274
FB
3204
3205 rtp_c = find_rtp_session(session_id);
3206 if (!rtp_c)
3207 return NULL;
3208
3209 /* find which url is asked */
f3bfe388 3210 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2effd274
FB
3211 path = path1;
3212 if (*path == '/')
3213 path++;
94d9ad5f
GF
3214 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3215 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3216 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3217 rtp_c->stream->filename, s);
3218 if(!strncmp(path, buf, sizeof(buf))) {
3219 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3220 return rtp_c;
3221 }
3222 }
c2ca851b
MS
3223 len = strlen(path);
3224 if (len > 0 && path[len - 1] == '/' &&
3225 !strncmp(path, rtp_c->stream->filename, len - 1))
3226 return rtp_c;
94d9ad5f 3227 return NULL;
2effd274
FB
3228}
3229
a9e534d5 3230static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
2effd274
FB
3231{
3232 HTTPContext *rtp_c;
3233
3234 rtp_c = find_rtp_session_with_url(url, h->session_id);
3235 if (!rtp_c) {
3236 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3237 return;
3238 }
115329f1 3239
2effd274
FB
3240 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3241 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3242 rtp_c->state != HTTPSTATE_READY) {
3243 rtsp_reply_error(c, RTSP_STATUS_STATE);
3244 return;
3245 }
3246
3247 rtp_c->state = HTTPSTATE_SEND_DATA;
115329f1 3248
2effd274
FB
3249 /* now everything is OK, so we can send the connection parameters */
3250 rtsp_reply_header(c, RTSP_STATUS_OK);
3251 /* session ID */
d9d86e00
AK
3252 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3253 avio_printf(c->pb, "\r\n");
2effd274
FB
3254}
3255
a9e534d5 3256static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
2effd274
FB
3257{
3258 HTTPContext *rtp_c;
3259
3260 rtp_c = find_rtp_session_with_url(url, h->session_id);
3261 if (!rtp_c) {
3262 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3263 return;
3264 }
115329f1 3265
2effd274
FB
3266 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3267 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3268 rtsp_reply_error(c, RTSP_STATUS_STATE);
3269 return;
3270 }
115329f1 3271
2effd274 3272 rtp_c->state = HTTPSTATE_READY;
1bc1cfdd 3273 rtp_c->first_pts = AV_NOPTS_VALUE;
2effd274
FB
3274 /* now everything is OK, so we can send the connection parameters */
3275 rtsp_reply_header(c, RTSP_STATUS_OK);
3276 /* session ID */
d9d86e00
AK
3277 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3278 avio_printf(c->pb, "\r\n");
2effd274
FB
3279}
3280
a9e534d5 3281static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
2effd274
FB
3282{
3283 HTTPContext *rtp_c;
3284
3285 rtp_c = find_rtp_session_with_url(url, h->session_id);
3286 if (!rtp_c) {
3287 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3288 return;
3289 }
115329f1 3290
2effd274
FB
3291 /* now everything is OK, so we can send the connection parameters */
3292 rtsp_reply_header(c, RTSP_STATUS_OK);
3293 /* session ID */
e2d7dc87 3294 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
d9d86e00 3295 avio_printf(c->pb, "\r\n");
e2d7dc87
MW
3296
3297 /* abort the session */
3298 close_connection(rtp_c);
2effd274
FB
3299}
3300
3301
3302/********************************************************************/
3303/* RTP handling */
3304
115329f1 3305static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
bc351386 3306 FFStream *stream, const char *session_id,
90abbdba 3307 enum RTSPLowerTransport rtp_protocol)
2effd274
FB
3308{
3309 HTTPContext *c = NULL;
bc351386 3310 const char *proto_str;
115329f1 3311
2effd274
FB
3312 /* XXX: should output a warning page when coming
3313 close to the connection limit */
3314 if (nb_connections >= nb_max_connections)
3315 goto fail;
115329f1 3316
2effd274
FB
3317 /* add a new connection */
3318 c = av_mallocz(sizeof(HTTPContext));
3319 if (!c)
3320 goto fail;
115329f1 3321
2effd274
FB
3322 c->fd = -1;
3323 c->poll_entry = NULL;
6edd6884 3324 c->from_addr = *from_addr;
2effd274
FB
3325 c->buffer_size = IOBUFFER_INIT_SIZE;
3326 c->buffer = av_malloc(c->buffer_size);
3327 if (!c->buffer)
3328 goto fail;
3329 nb_connections++;
3330 c->stream = stream;
f7d78f36 3331 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
2effd274
FB
3332 c->state = HTTPSTATE_READY;
3333 c->is_packetized = 1;
bc351386
FB
3334 c->rtp_protocol = rtp_protocol;
3335
2effd274 3336 /* protocol is shown in statistics */
bc351386 3337 switch(c->rtp_protocol) {
90abbdba 3338 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
bc351386
FB
3339 proto_str = "MCAST";
3340 break;
90abbdba 3341 case RTSP_LOWER_TRANSPORT_UDP:
bc351386
FB
3342 proto_str = "UDP";
3343 break;
90abbdba 3344 case RTSP_LOWER_TRANSPORT_TCP:
bc351386
FB
3345 proto_str = "TCP";
3346 break;
3347 default:
3348 proto_str = "???";
3349 break;
3350 }
f7d78f36
MR
3351 av_st