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