]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - ffserver.c
add missing html start tag to ffserver status html page
[frescor/ffmpeg.git] / ffserver.c
1 /*
2  * Multiple format streaming server
3  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #define _XOPEN_SOURCE 600
23
24 #include "config.h"
25 #ifndef HAVE_CLOSESOCKET
26 #define closesocket close
27 #endif
28 #include <string.h>
29 #include <strings.h>
30 #include <stdlib.h>
31 #include "libavutil/random.h"
32 #include "libavutil/avstring.h"
33 #include "libavformat/avformat.h"
34 #include "libavformat/network.h"
35 #include "libavformat/os_support.h"
36 #include "libavformat/rtp.h"
37 #include "libavformat/rtsp.h"
38 #include "libavcodec/opt.h"
39 #include <stdarg.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <sys/ioctl.h>
43 #ifdef HAVE_POLL_H
44 #include <poll.h>
45 #endif
46 #include <errno.h>
47 #include <sys/time.h>
48 #undef time //needed because HAVE_AV_CONFIG_H is defined on top
49 #include <time.h>
50 #include <sys/wait.h>
51 #include <signal.h>
52 #ifdef HAVE_DLFCN_H
53 #include <dlfcn.h>
54 #endif
55
56 #include "cmdutils.h"
57
58 #undef exit
59
60 const char program_name[] = "FFserver";
61 const int program_birth_year = 2000;
62
63 static const OptionDef options[];
64
65 enum HTTPState {
66     HTTPSTATE_WAIT_REQUEST,
67     HTTPSTATE_SEND_HEADER,
68     HTTPSTATE_SEND_DATA_HEADER,
69     HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
70     HTTPSTATE_SEND_DATA_TRAILER,
71     HTTPSTATE_RECEIVE_DATA,
72     HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
73     HTTPSTATE_READY,
74
75     RTSPSTATE_WAIT_REQUEST,
76     RTSPSTATE_SEND_REPLY,
77     RTSPSTATE_SEND_PACKET,
78 };
79
80 static const char *http_state[] = {
81     "HTTP_WAIT_REQUEST",
82     "HTTP_SEND_HEADER",
83
84     "SEND_DATA_HEADER",
85     "SEND_DATA",
86     "SEND_DATA_TRAILER",
87     "RECEIVE_DATA",
88     "WAIT_FEED",
89     "READY",
90
91     "RTSP_WAIT_REQUEST",
92     "RTSP_SEND_REPLY",
93     "RTSP_SEND_PACKET",
94 };
95
96 #define IOBUFFER_INIT_SIZE 8192
97
98 /* timeouts are in ms */
99 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
100 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
101
102 #define SYNC_TIMEOUT (10 * 1000)
103
104 typedef struct {
105     int64_t count1, count2;
106     int64_t time1, time2;
107 } DataRateData;
108
109 /* context associated with one connection */
110 typedef struct HTTPContext {
111     enum HTTPState state;
112     int fd; /* socket file descriptor */
113     struct sockaddr_in from_addr; /* origin */
114     struct pollfd *poll_entry; /* used when polling */
115     int64_t timeout;
116     uint8_t *buffer_ptr, *buffer_end;
117     int http_error;
118     int post;
119     struct HTTPContext *next;
120     int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
121     int64_t data_count;
122     /* feed input */
123     int feed_fd;
124     /* input format handling */
125     AVFormatContext *fmt_in;
126     int64_t start_time;            /* In milliseconds - this wraps fairly often */
127     int64_t first_pts;            /* initial pts value */
128     int64_t cur_pts;             /* current pts value from the stream in us */
129     int64_t cur_frame_duration;  /* duration of the current frame in us */
130     int cur_frame_bytes;       /* output frame size, needed to compute
131                                   the time at which we send each
132                                   packet */
133     int pts_stream_index;        /* stream we choose as clock reference */
134     int64_t cur_clock;           /* current clock reference value in us */
135     /* output format handling */
136     struct FFStream *stream;
137     /* -1 is invalid stream */
138     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
139     int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
140     int switch_pending;
141     AVFormatContext fmt_ctx; /* instance of FFStream for one user */
142     int last_packet_sent; /* true if last data packet was sent */
143     int suppress_log;
144     DataRateData datarate;
145     int wmp_client_id;
146     char protocol[16];
147     char method[16];
148     char url[128];
149     int buffer_size;
150     uint8_t *buffer;
151     int is_packetized; /* if true, the stream is packetized */
152     int packet_stream_index; /* current stream for output in state machine */
153
154     /* RTSP state specific */
155     uint8_t *pb_buffer; /* XXX: use that in all the code */
156     ByteIOContext *pb;
157     int seq; /* RTSP sequence number */
158
159     /* RTP state specific */
160     enum RTSPProtocol rtp_protocol;
161     char session_id[32]; /* session id */
162     AVFormatContext *rtp_ctx[MAX_STREAMS];
163
164     /* RTP/UDP specific */
165     URLContext *rtp_handles[MAX_STREAMS];
166
167     /* RTP/TCP specific */
168     struct HTTPContext *rtsp_c;
169     uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
170 } HTTPContext;
171
172 /* each generated stream is described here */
173 enum StreamType {
174     STREAM_TYPE_LIVE,
175     STREAM_TYPE_STATUS,
176     STREAM_TYPE_REDIRECT,
177 };
178
179 enum IPAddressAction {
180     IP_ALLOW = 1,
181     IP_DENY,
182 };
183
184 typedef struct IPAddressACL {
185     struct IPAddressACL *next;
186     enum IPAddressAction action;
187     /* These are in host order */
188     struct in_addr first;
189     struct in_addr last;
190 } IPAddressACL;
191
192 /* description of each stream of the ffserver.conf file */
193 typedef struct FFStream {
194     enum StreamType stream_type;
195     char filename[1024];     /* stream filename */
196     struct FFStream *feed;   /* feed we are using (can be null if
197                                 coming from file) */
198     AVFormatParameters *ap_in; /* input parameters */
199     AVInputFormat *ifmt;       /* if non NULL, force input format */
200     AVOutputFormat *fmt;
201     IPAddressACL *acl;
202     int nb_streams;
203     int prebuffer;      /* Number of millseconds early to start */
204     int64_t max_time;      /* Number of milliseconds to run */
205     int send_on_key;
206     AVStream *streams[MAX_STREAMS];
207     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
208     char feed_filename[1024]; /* file name of the feed storage, or
209                                  input file name for a stream */
210     char author[512];
211     char title[512];
212     char copyright[512];
213     char comment[512];
214     pid_t pid;  /* Of ffmpeg process */
215     time_t pid_start;  /* Of ffmpeg process */
216     char **child_argv;
217     struct FFStream *next;
218     unsigned bandwidth; /* bandwidth, in kbits/s */
219     /* RTSP options */
220     char *rtsp_option;
221     /* multicast specific */
222     int is_multicast;
223     struct in_addr multicast_ip;
224     int multicast_port; /* first port used for multicast */
225     int multicast_ttl;
226     int loop; /* if true, send the stream in loops (only meaningful if file) */
227
228     /* feed specific */
229     int feed_opened;     /* true if someone is writing to the feed */
230     int is_feed;         /* true if it is a feed */
231     int readonly;        /* True if writing is prohibited to the file */
232     int conns_served;
233     int64_t bytes_served;
234     int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
235     int64_t feed_write_index;   /* current write position in feed (it wraps around) */
236     int64_t feed_size;          /* current size of feed */
237     struct FFStream *next_feed;
238 } FFStream;
239
240 typedef struct FeedData {
241     long long data_count;
242     float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
243 } FeedData;
244
245 static struct sockaddr_in my_http_addr;
246 static struct sockaddr_in my_rtsp_addr;
247
248 static char logfilename[1024];
249 static HTTPContext *first_http_ctx;
250 static FFStream *first_feed;   /* contains only feeds */
251 static FFStream *first_stream; /* contains all streams, including feeds */
252
253 static void new_connection(int server_fd, int is_rtsp);
254 static void close_connection(HTTPContext *c);
255
256 /* HTTP handling */
257 static int handle_connection(HTTPContext *c);
258 static int http_parse_request(HTTPContext *c);
259 static int http_send_data(HTTPContext *c);
260 static void compute_status(HTTPContext *c);
261 static int open_input_stream(HTTPContext *c, const char *info);
262 static int http_start_receive_data(HTTPContext *c);
263 static int http_receive_data(HTTPContext *c);
264
265 /* RTSP handling */
266 static int rtsp_parse_request(HTTPContext *c);
267 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
268 static void rtsp_cmd_options(HTTPContext *c, const char *url);
269 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
270 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
271 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
272 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
273
274 /* SDP handling */
275 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
276                                    struct in_addr my_ip);
277
278 /* RTP handling */
279 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
280                                        FFStream *stream, const char *session_id,
281                                        enum RTSPProtocol rtp_protocol);
282 static int rtp_new_av_stream(HTTPContext *c,
283                              int stream_index, struct sockaddr_in *dest_addr,
284                              HTTPContext *rtsp_c);
285
286 static const char *my_program_name;
287 static const char *my_program_dir;
288
289 static const char *config_filename;
290 static int ffserver_debug;
291 static int ffserver_daemon;
292 static int no_launch;
293 static int need_to_start_children;
294
295 /* maximum number of simultaneous HTTP connections */
296 static unsigned int nb_max_http_connections = 2000;
297 static unsigned int nb_max_connections = 5;
298 static unsigned int nb_connections;
299
300 static uint64_t max_bandwidth = 1000;
301 static uint64_t current_bandwidth;
302
303 static int64_t cur_time;           // Making this global saves on passing it around everywhere
304
305 static AVRandomState random_state;
306
307 static FILE *logfile = NULL;
308
309 static char *ctime1(char *buf2)
310 {
311     time_t ti;
312     char *p;
313
314     ti = time(NULL);
315     p = ctime(&ti);
316     strcpy(buf2, p);
317     p = buf2 + strlen(p) - 1;
318     if (*p == '\n')
319         *p = '\0';
320     return buf2;
321 }
322
323 static void http_vlog(const char *fmt, va_list vargs)
324 {
325     static int print_prefix = 1;
326     if (logfile) {
327         if (print_prefix) {
328             char buf[32];
329             ctime1(buf);
330             fprintf(logfile, "%s ", buf);
331         }
332         print_prefix = strstr(fmt, "\n") != NULL;
333         vfprintf(logfile, fmt, vargs);
334         fflush(logfile);
335     }
336 }
337
338 void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
339 {
340     va_list vargs;
341     va_start(vargs, fmt);
342     http_vlog(fmt, vargs);
343     va_end(vargs);
344 }
345
346 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
347 {
348     static int print_prefix = 1;
349     AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
350     if (level > av_log_level)
351         return;
352     if (print_prefix && avc)
353         http_log("[%s @ %p]", avc->item_name(ptr), ptr);
354     print_prefix = strstr(fmt, "\n") != NULL;
355     http_vlog(fmt, vargs);
356 }
357
358 static void log_connection(HTTPContext *c)
359 {
360     if (c->suppress_log)
361         return;
362
363     http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
364              inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
365              c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
366 }
367
368 static void update_datarate(DataRateData *drd, int64_t count)
369 {
370     if (!drd->time1 && !drd->count1) {
371         drd->time1 = drd->time2 = cur_time;
372         drd->count1 = drd->count2 = count;
373     } else if (cur_time - drd->time2 > 5000) {
374         drd->time1 = drd->time2;
375         drd->count1 = drd->count2;
376         drd->time2 = cur_time;
377         drd->count2 = count;
378     }
379 }
380
381 /* In bytes per second */
382 static int compute_datarate(DataRateData *drd, int64_t count)
383 {
384     if (cur_time == drd->time1)
385         return 0;
386
387     return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
388 }
389
390
391 static void start_children(FFStream *feed)
392 {
393     if (no_launch)
394         return;
395
396     for (; feed; feed = feed->next) {
397         if (feed->child_argv && !feed->pid) {
398             feed->pid_start = time(0);
399
400             feed->pid = fork();
401
402             if (feed->pid < 0) {
403                 http_log("Unable to create children\n");
404                 exit(1);
405             }
406             if (!feed->pid) {
407                 /* In child */
408                 char pathname[1024];
409                 char *slash;
410                 int i;
411
412                 av_strlcpy(pathname, my_program_name, sizeof(pathname));
413
414                 slash = strrchr(pathname, '/');
415                 if (!slash)
416                     slash = pathname;
417                 else
418                     slash++;
419                 strcpy(slash, "ffmpeg");
420
421                 http_log("Launch commandline: ");
422                 http_log("%s ", pathname);
423                 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
424                     http_log("%s ", feed->child_argv[i]);
425                 http_log("\n");
426
427                 for (i = 3; i < 256; i++)
428                     close(i);
429
430                 if (!ffserver_debug) {
431                     i = open("/dev/null", O_RDWR);
432                     if (i != -1) {
433                         dup2(i, 0);
434                         dup2(i, 1);
435                         dup2(i, 2);
436                         close(i);
437                     }
438                 }
439
440                 /* This is needed to make relative pathnames work */
441                 chdir(my_program_dir);
442
443                 signal(SIGPIPE, SIG_DFL);
444
445                 execvp(pathname, feed->child_argv);
446
447                 _exit(1);
448             }
449         }
450     }
451 }
452
453 /* open a listening socket */
454 static int socket_open_listen(struct sockaddr_in *my_addr)
455 {
456     int server_fd, tmp;
457
458     server_fd = socket(AF_INET,SOCK_STREAM,0);
459     if (server_fd < 0) {
460         perror ("socket");
461         return -1;
462     }
463
464     tmp = 1;
465     setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
466
467     if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
468         char bindmsg[32];
469         snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
470         perror (bindmsg);
471         closesocket(server_fd);
472         return -1;
473     }
474
475     if (listen (server_fd, 5) < 0) {
476         perror ("listen");
477         closesocket(server_fd);
478         return -1;
479     }
480     ff_socket_nonblock(server_fd, 1);
481
482     return server_fd;
483 }
484
485 /* start all multicast streams */
486 static void start_multicast(void)
487 {
488     FFStream *stream;
489     char session_id[32];
490     HTTPContext *rtp_c;
491     struct sockaddr_in dest_addr;
492     int default_port, stream_index;
493
494     default_port = 6000;
495     for(stream = first_stream; stream != NULL; stream = stream->next) {
496         if (stream->is_multicast) {
497             /* open the RTP connection */
498             snprintf(session_id, sizeof(session_id), "%08x%08x",
499                      av_random(&random_state), av_random(&random_state));
500
501             /* choose a port if none given */
502             if (stream->multicast_port == 0) {
503                 stream->multicast_port = default_port;
504                 default_port += 100;
505             }
506
507             dest_addr.sin_family = AF_INET;
508             dest_addr.sin_addr = stream->multicast_ip;
509             dest_addr.sin_port = htons(stream->multicast_port);
510
511             rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
512                                        RTSP_PROTOCOL_RTP_UDP_MULTICAST);
513             if (!rtp_c)
514                 continue;
515
516             if (open_input_stream(rtp_c, "") < 0) {
517                 http_log("Could not open input stream for stream '%s'\n",
518                          stream->filename);
519                 continue;
520             }
521
522             /* open each RTP stream */
523             for(stream_index = 0; stream_index < stream->nb_streams;
524                 stream_index++) {
525                 dest_addr.sin_port = htons(stream->multicast_port +
526                                            2 * stream_index);
527                 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
528                     http_log("Could not open output stream '%s/streamid=%d'\n",
529                              stream->filename, stream_index);
530                     exit(1);
531                 }
532             }
533
534             /* change state to send data */
535             rtp_c->state = HTTPSTATE_SEND_DATA;
536         }
537     }
538 }
539
540 /* main loop of the http server */
541 static int http_server(void)
542 {
543     int server_fd = 0, rtsp_server_fd = 0;
544     int ret, delay, delay1;
545     struct pollfd *poll_table, *poll_entry;
546     HTTPContext *c, *c_next;
547
548     if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
549         http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
550         return -1;
551     }
552
553     if (my_http_addr.sin_port) {
554         server_fd = socket_open_listen(&my_http_addr);
555         if (server_fd < 0)
556             return -1;
557     }
558
559     if (my_rtsp_addr.sin_port) {
560         rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
561         if (rtsp_server_fd < 0)
562             return -1;
563     }
564
565     if (!rtsp_server_fd && !server_fd) {
566         http_log("HTTP and RTSP disabled.\n");
567         return -1;
568     }
569
570     http_log("ffserver started.\n");
571
572     start_children(first_feed);
573
574     start_multicast();
575
576     for(;;) {
577         poll_entry = poll_table;
578         if (server_fd) {
579             poll_entry->fd = server_fd;
580             poll_entry->events = POLLIN;
581             poll_entry++;
582         }
583         if (rtsp_server_fd) {
584             poll_entry->fd = rtsp_server_fd;
585             poll_entry->events = POLLIN;
586             poll_entry++;
587         }
588
589         /* wait for events on each HTTP handle */
590         c = first_http_ctx;
591         delay = 1000;
592         while (c != NULL) {
593             int fd;
594             fd = c->fd;
595             switch(c->state) {
596             case HTTPSTATE_SEND_HEADER:
597             case RTSPSTATE_SEND_REPLY:
598             case RTSPSTATE_SEND_PACKET:
599                 c->poll_entry = poll_entry;
600                 poll_entry->fd = fd;
601                 poll_entry->events = POLLOUT;
602                 poll_entry++;
603                 break;
604             case HTTPSTATE_SEND_DATA_HEADER:
605             case HTTPSTATE_SEND_DATA:
606             case HTTPSTATE_SEND_DATA_TRAILER:
607                 if (!c->is_packetized) {
608                     /* for TCP, we output as much as we can (may need to put a limit) */
609                     c->poll_entry = poll_entry;
610                     poll_entry->fd = fd;
611                     poll_entry->events = POLLOUT;
612                     poll_entry++;
613                 } else {
614                     /* when ffserver is doing the timing, we work by
615                        looking at which packet need to be sent every
616                        10 ms */
617                     delay1 = 10; /* one tick wait XXX: 10 ms assumed */
618                     if (delay1 < delay)
619                         delay = delay1;
620                 }
621                 break;
622             case HTTPSTATE_WAIT_REQUEST:
623             case HTTPSTATE_RECEIVE_DATA:
624             case HTTPSTATE_WAIT_FEED:
625             case RTSPSTATE_WAIT_REQUEST:
626                 /* need to catch errors */
627                 c->poll_entry = poll_entry;
628                 poll_entry->fd = fd;
629                 poll_entry->events = POLLIN;/* Maybe this will work */
630                 poll_entry++;
631                 break;
632             default:
633                 c->poll_entry = NULL;
634                 break;
635             }
636             c = c->next;
637         }
638
639         /* wait for an event on one connection. We poll at least every
640            second to handle timeouts */
641         do {
642             ret = poll(poll_table, poll_entry - poll_table, delay);
643             if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
644                 ff_neterrno() != FF_NETERROR(EINTR))
645                 return -1;
646         } while (ret < 0);
647
648         cur_time = av_gettime() / 1000;
649
650         if (need_to_start_children) {
651             need_to_start_children = 0;
652             start_children(first_feed);
653         }
654
655         /* now handle the events */
656         for(c = first_http_ctx; c != NULL; c = c_next) {
657             c_next = c->next;
658             if (handle_connection(c) < 0) {
659                 /* close and free the connection */
660                 log_connection(c);
661                 close_connection(c);
662             }
663         }
664
665         poll_entry = poll_table;
666         if (server_fd) {
667             /* new HTTP connection request ? */
668             if (poll_entry->revents & POLLIN)
669                 new_connection(server_fd, 0);
670             poll_entry++;
671         }
672         if (rtsp_server_fd) {
673             /* new RTSP connection request ? */
674             if (poll_entry->revents & POLLIN)
675                 new_connection(rtsp_server_fd, 1);
676         }
677     }
678 }
679
680 /* start waiting for a new HTTP/RTSP request */
681 static void start_wait_request(HTTPContext *c, int is_rtsp)
682 {
683     c->buffer_ptr = c->buffer;
684     c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
685
686     if (is_rtsp) {
687         c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
688         c->state = RTSPSTATE_WAIT_REQUEST;
689     } else {
690         c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
691         c->state = HTTPSTATE_WAIT_REQUEST;
692     }
693 }
694
695 static void new_connection(int server_fd, int is_rtsp)
696 {
697     struct sockaddr_in from_addr;
698     int fd, len;
699     HTTPContext *c = NULL;
700
701     len = sizeof(from_addr);
702     fd = accept(server_fd, (struct sockaddr *)&from_addr,
703                 &len);
704     if (fd < 0) {
705         http_log("error during accept %s\n", strerror(errno));
706         return;
707     }
708     ff_socket_nonblock(fd, 1);
709
710     /* XXX: should output a warning page when coming
711        close to the connection limit */
712     if (nb_connections >= nb_max_connections)
713         goto fail;
714
715     /* add a new connection */
716     c = av_mallocz(sizeof(HTTPContext));
717     if (!c)
718         goto fail;
719
720     c->fd = fd;
721     c->poll_entry = NULL;
722     c->from_addr = from_addr;
723     c->buffer_size = IOBUFFER_INIT_SIZE;
724     c->buffer = av_malloc(c->buffer_size);
725     if (!c->buffer)
726         goto fail;
727
728     c->next = first_http_ctx;
729     first_http_ctx = c;
730     nb_connections++;
731
732     start_wait_request(c, is_rtsp);
733
734     return;
735
736  fail:
737     if (c) {
738         av_free(c->buffer);
739         av_free(c);
740     }
741     closesocket(fd);
742 }
743
744 static void close_connection(HTTPContext *c)
745 {
746     HTTPContext **cp, *c1;
747     int i, nb_streams;
748     AVFormatContext *ctx;
749     URLContext *h;
750     AVStream *st;
751
752     /* remove connection from list */
753     cp = &first_http_ctx;
754     while ((*cp) != NULL) {
755         c1 = *cp;
756         if (c1 == c)
757             *cp = c->next;
758         else
759             cp = &c1->next;
760     }
761
762     /* remove references, if any (XXX: do it faster) */
763     for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
764         if (c1->rtsp_c == c)
765             c1->rtsp_c = NULL;
766     }
767
768     /* remove connection associated resources */
769     if (c->fd >= 0)
770         closesocket(c->fd);
771     if (c->fmt_in) {
772         /* close each frame parser */
773         for(i=0;i<c->fmt_in->nb_streams;i++) {
774             st = c->fmt_in->streams[i];
775             if (st->codec->codec)
776                 avcodec_close(st->codec);
777         }
778         av_close_input_file(c->fmt_in);
779     }
780
781     /* free RTP output streams if any */
782     nb_streams = 0;
783     if (c->stream)
784         nb_streams = c->stream->nb_streams;
785
786     for(i=0;i<nb_streams;i++) {
787         ctx = c->rtp_ctx[i];
788         if (ctx) {
789             av_write_trailer(ctx);
790             av_free(ctx);
791         }
792         h = c->rtp_handles[i];
793         if (h)
794             url_close(h);
795     }
796
797     ctx = &c->fmt_ctx;
798
799     if (!c->last_packet_sent) {
800         if (ctx->oformat) {
801             /* prepare header */
802             if (url_open_dyn_buf(&ctx->pb) >= 0) {
803                 av_write_trailer(ctx);
804                 av_freep(&c->pb_buffer);
805                 url_close_dyn_buf(ctx->pb, &c->pb_buffer);
806             }
807         }
808     }
809
810     for(i=0; i<ctx->nb_streams; i++)
811         av_free(ctx->streams[i]);
812
813     if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
814         current_bandwidth -= c->stream->bandwidth;
815
816     /* signal that there is no feed if we are the feeder socket */
817     if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
818         c->stream->feed_opened = 0;
819         close(c->feed_fd);
820     }
821
822     av_freep(&c->pb_buffer);
823     av_freep(&c->packet_buffer);
824     av_free(c->buffer);
825     av_free(c);
826     nb_connections--;
827 }
828
829 static int handle_connection(HTTPContext *c)
830 {
831     int len, ret;
832
833     switch(c->state) {
834     case HTTPSTATE_WAIT_REQUEST:
835     case RTSPSTATE_WAIT_REQUEST:
836         /* timeout ? */
837         if ((c->timeout - cur_time) < 0)
838             return -1;
839         if (c->poll_entry->revents & (POLLERR | POLLHUP))
840             return -1;
841
842         /* no need to read if no events */
843         if (!(c->poll_entry->revents & POLLIN))
844             return 0;
845         /* read the data */
846     read_loop:
847         len = recv(c->fd, c->buffer_ptr, 1, 0);
848         if (len < 0) {
849             if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
850                 ff_neterrno() != FF_NETERROR(EINTR))
851                 return -1;
852         } else if (len == 0) {
853             return -1;
854         } else {
855             /* search for end of request. */
856             uint8_t *ptr;
857             c->buffer_ptr += len;
858             ptr = c->buffer_ptr;
859             if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
860                 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
861                 /* request found : parse it and reply */
862                 if (c->state == HTTPSTATE_WAIT_REQUEST) {
863                     ret = http_parse_request(c);
864                 } else {
865                     ret = rtsp_parse_request(c);
866                 }
867                 if (ret < 0)
868                     return -1;
869             } else if (ptr >= c->buffer_end) {
870                 /* request too long: cannot do anything */
871                 return -1;
872             } else goto read_loop;
873         }
874         break;
875
876     case HTTPSTATE_SEND_HEADER:
877         if (c->poll_entry->revents & (POLLERR | POLLHUP))
878             return -1;
879
880         /* no need to write if no events */
881         if (!(c->poll_entry->revents & POLLOUT))
882             return 0;
883         len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
884         if (len < 0) {
885             if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
886                 ff_neterrno() != FF_NETERROR(EINTR)) {
887                 /* error : close connection */
888                 av_freep(&c->pb_buffer);
889                 return -1;
890             }
891         } else {
892             c->buffer_ptr += len;
893             if (c->stream)
894                 c->stream->bytes_served += len;
895             c->data_count += len;
896             if (c->buffer_ptr >= c->buffer_end) {
897                 av_freep(&c->pb_buffer);
898                 /* if error, exit */
899                 if (c->http_error)
900                     return -1;
901                 /* all the buffer was sent : synchronize to the incoming stream */
902                 c->state = HTTPSTATE_SEND_DATA_HEADER;
903                 c->buffer_ptr = c->buffer_end = c->buffer;
904             }
905         }
906         break;
907
908     case HTTPSTATE_SEND_DATA:
909     case HTTPSTATE_SEND_DATA_HEADER:
910     case HTTPSTATE_SEND_DATA_TRAILER:
911         /* for packetized output, we consider we can always write (the
912            input streams sets the speed). It may be better to verify
913            that we do not rely too much on the kernel queues */
914         if (!c->is_packetized) {
915             if (c->poll_entry->revents & (POLLERR | POLLHUP))
916                 return -1;
917
918             /* no need to read if no events */
919             if (!(c->poll_entry->revents & POLLOUT))
920                 return 0;
921         }
922         if (http_send_data(c) < 0)
923             return -1;
924         /* close connection if trailer sent */
925         if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
926             return -1;
927         break;
928     case HTTPSTATE_RECEIVE_DATA:
929         /* no need to read if no events */
930         if (c->poll_entry->revents & (POLLERR | POLLHUP))
931             return -1;
932         if (!(c->poll_entry->revents & POLLIN))
933             return 0;
934         if (http_receive_data(c) < 0)
935             return -1;
936         break;
937     case HTTPSTATE_WAIT_FEED:
938         /* no need to read if no events */
939         if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
940             return -1;
941
942         /* nothing to do, we'll be waken up by incoming feed packets */
943         break;
944
945     case RTSPSTATE_SEND_REPLY:
946         if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
947             av_freep(&c->pb_buffer);
948             return -1;
949         }
950         /* no need to write if no events */
951         if (!(c->poll_entry->revents & POLLOUT))
952             return 0;
953         len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
954         if (len < 0) {
955             if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
956                 ff_neterrno() != FF_NETERROR(EINTR)) {
957                 /* error : close connection */
958                 av_freep(&c->pb_buffer);
959                 return -1;
960             }
961         } else {
962             c->buffer_ptr += len;
963             c->data_count += len;
964             if (c->buffer_ptr >= c->buffer_end) {
965                 /* all the buffer was sent : wait for a new request */
966                 av_freep(&c->pb_buffer);
967                 start_wait_request(c, 1);
968             }
969         }
970         break;
971     case RTSPSTATE_SEND_PACKET:
972         if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
973             av_freep(&c->packet_buffer);
974             return -1;
975         }
976         /* no need to write if no events */
977         if (!(c->poll_entry->revents & POLLOUT))
978             return 0;
979         len = send(c->fd, c->packet_buffer_ptr,
980                     c->packet_buffer_end - c->packet_buffer_ptr, 0);
981         if (len < 0) {
982             if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
983                 ff_neterrno() != FF_NETERROR(EINTR)) {
984                 /* error : close connection */
985                 av_freep(&c->packet_buffer);
986                 return -1;
987             }
988         } else {
989             c->packet_buffer_ptr += len;
990             if (c->packet_buffer_ptr >= c->packet_buffer_end) {
991                 /* all the buffer was sent : wait for a new request */
992                 av_freep(&c->packet_buffer);
993                 c->state = RTSPSTATE_WAIT_REQUEST;
994             }
995         }
996         break;
997     case HTTPSTATE_READY:
998         /* nothing to do */
999         break;
1000     default:
1001         return -1;
1002     }
1003     return 0;
1004 }
1005
1006 static int extract_rates(char *rates, int ratelen, const char *request)
1007 {
1008     const char *p;
1009
1010     for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1011         if (strncasecmp(p, "Pragma:", 7) == 0) {
1012             const char *q = p + 7;
1013
1014             while (*q && *q != '\n' && isspace(*q))
1015                 q++;
1016
1017             if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1018                 int stream_no;
1019                 int rate_no;
1020
1021                 q += 20;
1022
1023                 memset(rates, 0xff, ratelen);
1024
1025                 while (1) {
1026                     while (*q && *q != '\n' && *q != ':')
1027                         q++;
1028
1029                     if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1030                         break;
1031
1032                     stream_no--;
1033                     if (stream_no < ratelen && stream_no >= 0)
1034                         rates[stream_no] = rate_no;
1035
1036                     while (*q && *q != '\n' && !isspace(*q))
1037                         q++;
1038                 }
1039
1040                 return 1;
1041             }
1042         }
1043         p = strchr(p, '\n');
1044         if (!p)
1045             break;
1046
1047         p++;
1048     }
1049
1050     return 0;
1051 }
1052
1053 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1054 {
1055     int i;
1056     int best_bitrate = 100000000;
1057     int best = -1;
1058
1059     for (i = 0; i < feed->nb_streams; i++) {
1060         AVCodecContext *feed_codec = feed->streams[i]->codec;
1061
1062         if (feed_codec->codec_id != codec->codec_id ||
1063             feed_codec->sample_rate != codec->sample_rate ||
1064             feed_codec->width != codec->width ||
1065             feed_codec->height != codec->height)
1066             continue;
1067
1068         /* Potential stream */
1069
1070         /* We want the fastest stream less than bit_rate, or the slowest
1071          * faster than bit_rate
1072          */
1073
1074         if (feed_codec->bit_rate <= bit_rate) {
1075             if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1076                 best_bitrate = feed_codec->bit_rate;
1077                 best = i;
1078             }
1079         } else {
1080             if (feed_codec->bit_rate < best_bitrate) {
1081                 best_bitrate = feed_codec->bit_rate;
1082                 best = i;
1083             }
1084         }
1085     }
1086
1087     return best;
1088 }
1089
1090 static int modify_current_stream(HTTPContext *c, char *rates)
1091 {
1092     int i;
1093     FFStream *req = c->stream;
1094     int action_required = 0;
1095
1096     /* Not much we can do for a feed */
1097     if (!req->feed)
1098         return 0;
1099
1100     for (i = 0; i < req->nb_streams; i++) {
1101         AVCodecContext *codec = req->streams[i]->codec;
1102
1103         switch(rates[i]) {
1104             case 0:
1105                 c->switch_feed_streams[i] = req->feed_streams[i];
1106                 break;
1107             case 1:
1108                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1109                 break;
1110             case 2:
1111                 /* Wants off or slow */
1112                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1113 #ifdef WANTS_OFF
1114                 /* This doesn't work well when it turns off the only stream! */
1115                 c->switch_feed_streams[i] = -2;
1116                 c->feed_streams[i] = -2;
1117 #endif
1118                 break;
1119         }
1120
1121         if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1122             action_required = 1;
1123     }
1124
1125     return action_required;
1126 }
1127
1128
1129 static void do_switch_stream(HTTPContext *c, int i)
1130 {
1131     if (c->switch_feed_streams[i] >= 0) {
1132 #ifdef PHILIP
1133         c->feed_streams[i] = c->switch_feed_streams[i];
1134 #endif
1135
1136         /* Now update the stream */
1137     }
1138     c->switch_feed_streams[i] = -1;
1139 }
1140
1141 /* XXX: factorize in utils.c ? */
1142 /* XXX: take care with different space meaning */
1143 static void skip_spaces(const char **pp)
1144 {
1145     const char *p;
1146     p = *pp;
1147     while (*p == ' ' || *p == '\t')
1148         p++;
1149     *pp = p;
1150 }
1151
1152 static void get_word(char *buf, int buf_size, const char **pp)
1153 {
1154     const char *p;
1155     char *q;
1156
1157     p = *pp;
1158     skip_spaces(&p);
1159     q = buf;
1160     while (!isspace(*p) && *p != '\0') {
1161         if ((q - buf) < buf_size - 1)
1162             *q++ = *p;
1163         p++;
1164     }
1165     if (buf_size > 0)
1166         *q = '\0';
1167     *pp = p;
1168 }
1169
1170 static int validate_acl(FFStream *stream, HTTPContext *c)
1171 {
1172     enum IPAddressAction last_action = IP_DENY;
1173     IPAddressACL *acl;
1174     struct in_addr *src = &c->from_addr.sin_addr;
1175     unsigned long src_addr = src->s_addr;
1176
1177     for (acl = stream->acl; acl; acl = acl->next) {
1178         if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1179             return (acl->action == IP_ALLOW) ? 1 : 0;
1180         last_action = acl->action;
1181     }
1182
1183     /* Nothing matched, so return not the last action */
1184     return (last_action == IP_DENY) ? 1 : 0;
1185 }
1186
1187 /* compute the real filename of a file by matching it without its
1188    extensions to all the stream filenames */
1189 static void compute_real_filename(char *filename, int max_size)
1190 {
1191     char file1[1024];
1192     char file2[1024];
1193     char *p;
1194     FFStream *stream;
1195
1196     /* compute filename by matching without the file extensions */
1197     av_strlcpy(file1, filename, sizeof(file1));
1198     p = strrchr(file1, '.');
1199     if (p)
1200         *p = '\0';
1201     for(stream = first_stream; stream != NULL; stream = stream->next) {
1202         av_strlcpy(file2, stream->filename, sizeof(file2));
1203         p = strrchr(file2, '.');
1204         if (p)
1205             *p = '\0';
1206         if (!strcmp(file1, file2)) {
1207             av_strlcpy(filename, stream->filename, max_size);
1208             break;
1209         }
1210     }
1211 }
1212
1213 enum RedirType {
1214     REDIR_NONE,
1215     REDIR_ASX,
1216     REDIR_RAM,
1217     REDIR_ASF,
1218     REDIR_RTSP,
1219     REDIR_SDP,
1220 };
1221
1222 /* parse http request and prepare header */
1223 static int http_parse_request(HTTPContext *c)
1224 {
1225     char *p;
1226     enum RedirType redir_type;
1227     char cmd[32];
1228     char info[1024], filename[1024];
1229     char url[1024], *q;
1230     char protocol[32];
1231     char msg[1024];
1232     const char *mime_type;
1233     FFStream *stream;
1234     int i;
1235     char ratebuf[32];
1236     char *useragent = 0;
1237
1238     p = c->buffer;
1239     get_word(cmd, sizeof(cmd), (const char **)&p);
1240     av_strlcpy(c->method, cmd, sizeof(c->method));
1241
1242     if (!strcmp(cmd, "GET"))
1243         c->post = 0;
1244     else if (!strcmp(cmd, "POST"))
1245         c->post = 1;
1246     else
1247         return -1;
1248
1249     get_word(url, sizeof(url), (const char **)&p);
1250     av_strlcpy(c->url, url, sizeof(c->url));
1251
1252     get_word(protocol, sizeof(protocol), (const char **)&p);
1253     if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1254         return -1;
1255
1256     av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1257
1258     if (ffserver_debug)
1259         http_log("New connection: %s %s\n", cmd, url);
1260
1261     /* find the filename and the optional info string in the request */
1262     p = strchr(url, '?');
1263     if (p) {
1264         av_strlcpy(info, p, sizeof(info));
1265         *p = '\0';
1266     } else
1267         info[0] = '\0';
1268
1269     av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1270
1271     for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1272         if (strncasecmp(p, "User-Agent:", 11) == 0) {
1273             useragent = p + 11;
1274             if (*useragent && *useragent != '\n' && isspace(*useragent))
1275                 useragent++;
1276             break;
1277         }
1278         p = strchr(p, '\n');
1279         if (!p)
1280             break;
1281
1282         p++;
1283     }
1284
1285     redir_type = REDIR_NONE;
1286     if (match_ext(filename, "asx")) {
1287         redir_type = REDIR_ASX;
1288         filename[strlen(filename)-1] = 'f';
1289     } else if (match_ext(filename, "asf") &&
1290         (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1291         /* if this isn't WMP or lookalike, return the redirector file */
1292         redir_type = REDIR_ASF;
1293     } else if (match_ext(filename, "rpm,ram")) {
1294         redir_type = REDIR_RAM;
1295         strcpy(filename + strlen(filename)-2, "m");
1296     } else if (match_ext(filename, "rtsp")) {
1297         redir_type = REDIR_RTSP;
1298         compute_real_filename(filename, sizeof(filename) - 1);
1299     } else if (match_ext(filename, "sdp")) {
1300         redir_type = REDIR_SDP;
1301         compute_real_filename(filename, sizeof(filename) - 1);
1302     }
1303
1304     // "redirect" / request to index.html
1305     if (!strlen(filename))
1306         av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1307
1308     stream = first_stream;
1309     while (stream != NULL) {
1310         if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1311             break;
1312         stream = stream->next;
1313     }
1314     if (stream == NULL) {
1315         snprintf(msg, sizeof(msg), "File '%s' not found", url);
1316         goto send_error;
1317     }
1318
1319     c->stream = stream;
1320     memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1321     memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1322
1323     if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1324         c->http_error = 301;
1325         q = c->buffer;
1326         q += snprintf(q, c->buffer_size,
1327                       "HTTP/1.0 301 Moved\r\n"
1328                       "Location: %s\r\n"
1329                       "Content-type: text/html\r\n"
1330                       "\r\n"
1331                       "<html><head><title>Moved</title></head><body>\r\n"
1332                       "You should be <a href=\"%s\">redirected</a>.\r\n"
1333                       "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1334         /* prepare output buffer */
1335         c->buffer_ptr = c->buffer;
1336         c->buffer_end = q;
1337         c->state = HTTPSTATE_SEND_HEADER;
1338         return 0;
1339     }
1340
1341     /* If this is WMP, get the rate information */
1342     if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1343         if (modify_current_stream(c, ratebuf)) {
1344             for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1345                 if (c->switch_feed_streams[i] >= 0)
1346                     do_switch_stream(c, i);
1347             }
1348         }
1349     }
1350
1351     /* If already streaming this feed, do not let start another feeder. */
1352     if (stream->feed_opened) {
1353         snprintf(msg, sizeof(msg), "This feed is already being received.");
1354         http_log("feed %s already being received\n", stream->feed_filename);
1355         goto send_error;
1356     }
1357
1358     if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1359         current_bandwidth += stream->bandwidth;
1360
1361     if (c->post == 0 && max_bandwidth < current_bandwidth) {
1362         c->http_error = 200;
1363         q = c->buffer;
1364         q += snprintf(q, c->buffer_size,
1365                       "HTTP/1.0 200 Server too busy\r\n"
1366                       "Content-type: text/html\r\n"
1367                       "\r\n"
1368                       "<html><head><title>Too busy</title></head><body>\r\n"
1369                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
1370                       "<p>The bandwidth being served (including your stream) is %lldkbit/sec, "
1371                       "and this exceeds the limit of %lldkbit/sec.</p>\r\n"
1372                       "</body></html>\r\n", current_bandwidth, max_bandwidth);
1373         /* prepare output buffer */
1374         c->buffer_ptr = c->buffer;
1375         c->buffer_end = q;
1376         c->state = HTTPSTATE_SEND_HEADER;
1377         return 0;
1378     }
1379
1380     if (redir_type != REDIR_NONE) {
1381         char *hostinfo = 0;
1382
1383         for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1384             if (strncasecmp(p, "Host:", 5) == 0) {
1385                 hostinfo = p + 5;
1386                 break;
1387             }
1388             p = strchr(p, '\n');
1389             if (!p)
1390                 break;
1391
1392             p++;
1393         }
1394
1395         if (hostinfo) {
1396             char *eoh;
1397             char hostbuf[260];
1398
1399             while (isspace(*hostinfo))
1400                 hostinfo++;
1401
1402             eoh = strchr(hostinfo, '\n');
1403             if (eoh) {
1404                 if (eoh[-1] == '\r')
1405                     eoh--;
1406
1407                 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1408                     memcpy(hostbuf, hostinfo, eoh - hostinfo);
1409                     hostbuf[eoh - hostinfo] = 0;
1410
1411                     c->http_error = 200;
1412                     q = c->buffer;
1413                     switch(redir_type) {
1414                     case REDIR_ASX:
1415                         q += snprintf(q, c->buffer_size,
1416                                       "HTTP/1.0 200 ASX Follows\r\n"
1417                                       "Content-type: video/x-ms-asf\r\n"
1418                                       "\r\n"
1419                                       "<ASX Version=\"3\">\r\n"
1420                                       //"<!-- Autogenerated by ffserver -->\r\n"
1421                                       "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1422                                       "</ASX>\r\n", hostbuf, filename, info);
1423                         break;
1424                     case REDIR_RAM:
1425                         q += snprintf(q, c->buffer_size,
1426                                       "HTTP/1.0 200 RAM Follows\r\n"
1427                                       "Content-type: audio/x-pn-realaudio\r\n"
1428                                       "\r\n"
1429                                       "# Autogenerated by ffserver\r\n"
1430                                       "http://%s/%s%s\r\n", hostbuf, filename, info);
1431                         break;
1432                     case REDIR_ASF:
1433                         q += snprintf(q, c->buffer_size,
1434                                       "HTTP/1.0 200 ASF Redirect follows\r\n"
1435                                       "Content-type: video/x-ms-asf\r\n"
1436                                       "\r\n"
1437                                       "[Reference]\r\n"
1438                                       "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1439                         break;
1440                     case REDIR_RTSP:
1441                         {
1442                             char hostname[256], *p;
1443                             /* extract only hostname */
1444                             av_strlcpy(hostname, hostbuf, sizeof(hostname));
1445                             p = strrchr(hostname, ':');
1446                             if (p)
1447                                 *p = '\0';
1448                             q += snprintf(q, c->buffer_size,
1449                                           "HTTP/1.0 200 RTSP Redirect follows\r\n"
1450                                           /* XXX: incorrect mime type ? */
1451                                           "Content-type: application/x-rtsp\r\n"
1452                                           "\r\n"
1453                                           "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1454                         }
1455                         break;
1456                     case REDIR_SDP:
1457                         {
1458                             uint8_t *sdp_data;
1459                             int sdp_data_size, len;
1460                             struct sockaddr_in my_addr;
1461
1462                             q += snprintf(q, c->buffer_size,
1463                                           "HTTP/1.0 200 OK\r\n"
1464                                           "Content-type: application/sdp\r\n"
1465                                           "\r\n");
1466
1467                             len = sizeof(my_addr);
1468                             getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1469
1470                             /* XXX: should use a dynamic buffer */
1471                             sdp_data_size = prepare_sdp_description(stream,
1472                                                                     &sdp_data,
1473                                                                     my_addr.sin_addr);
1474                             if (sdp_data_size > 0) {
1475                                 memcpy(q, sdp_data, sdp_data_size);
1476                                 q += sdp_data_size;
1477                                 *q = '\0';
1478                                 av_free(sdp_data);
1479                             }
1480                         }
1481                         break;
1482                     default:
1483                         abort();
1484                         break;
1485                     }
1486
1487                     /* prepare output buffer */
1488                     c->buffer_ptr = c->buffer;
1489                     c->buffer_end = q;
1490                     c->state = HTTPSTATE_SEND_HEADER;
1491                     return 0;
1492                 }
1493             }
1494         }
1495
1496         snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1497         goto send_error;
1498     }
1499
1500     stream->conns_served++;
1501
1502     /* XXX: add there authenticate and IP match */
1503
1504     if (c->post) {
1505         /* if post, it means a feed is being sent */
1506         if (!stream->is_feed) {
1507             /* However it might be a status report from WMP! Let us log the
1508              * data as it might come in handy one day. */
1509             char *logline = 0;
1510             int client_id = 0;
1511
1512             for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1513                 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1514                     logline = p;
1515                     break;
1516                 }
1517                 if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1518                     client_id = strtol(p + 18, 0, 10);
1519                 p = strchr(p, '\n');
1520                 if (!p)
1521                     break;
1522
1523                 p++;
1524             }
1525
1526             if (logline) {
1527                 char *eol = strchr(logline, '\n');
1528
1529                 logline += 17;
1530
1531                 if (eol) {
1532                     if (eol[-1] == '\r')
1533                         eol--;
1534                     http_log("%.*s\n", (int) (eol - logline), logline);
1535                     c->suppress_log = 1;
1536                 }
1537             }
1538
1539 #ifdef DEBUG_WMP
1540             http_log("\nGot request:\n%s\n", c->buffer);
1541 #endif
1542
1543             if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1544                 HTTPContext *wmpc;
1545
1546                 /* Now we have to find the client_id */
1547                 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1548                     if (wmpc->wmp_client_id == client_id)
1549                         break;
1550                 }
1551
1552                 if (wmpc && modify_current_stream(wmpc, ratebuf))
1553                     wmpc->switch_pending = 1;
1554             }
1555
1556             snprintf(msg, sizeof(msg), "POST command not handled");
1557             c->stream = 0;
1558             goto send_error;
1559         }
1560         if (http_start_receive_data(c) < 0) {
1561             snprintf(msg, sizeof(msg), "could not open feed");
1562             goto send_error;
1563         }
1564         c->http_error = 0;
1565         c->state = HTTPSTATE_RECEIVE_DATA;
1566         return 0;
1567     }
1568
1569 #ifdef DEBUG_WMP
1570     if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1571         http_log("\nGot request:\n%s\n", c->buffer);
1572 #endif
1573
1574     if (c->stream->stream_type == STREAM_TYPE_STATUS)
1575         goto send_status;
1576
1577     /* open input stream */
1578     if (open_input_stream(c, info) < 0) {
1579         snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1580         goto send_error;
1581     }
1582
1583     /* prepare http header */
1584     q = c->buffer;
1585     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1586     mime_type = c->stream->fmt->mime_type;
1587     if (!mime_type)
1588         mime_type = "application/x-octet-stream";
1589     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1590
1591     /* for asf, we need extra headers */
1592     if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1593         /* Need to allocate a client id */
1594
1595         c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1596
1597         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);
1598     }
1599     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1600     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1601
1602     /* prepare output buffer */
1603     c->http_error = 0;
1604     c->buffer_ptr = c->buffer;
1605     c->buffer_end = q;
1606     c->state = HTTPSTATE_SEND_HEADER;
1607     return 0;
1608  send_error:
1609     c->http_error = 404;
1610     q = c->buffer;
1611     q += snprintf(q, c->buffer_size,
1612                   "HTTP/1.0 404 Not Found\r\n"
1613                   "Content-type: text/html\r\n"
1614                   "\r\n"
1615                   "<HTML>\n"
1616                   "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
1617                   "<BODY>%s</BODY>\n"
1618                   "</HTML>\n", msg);
1619     /* prepare output buffer */
1620     c->buffer_ptr = c->buffer;
1621     c->buffer_end = q;
1622     c->state = HTTPSTATE_SEND_HEADER;
1623     return 0;
1624  send_status:
1625     compute_status(c);
1626     c->http_error = 200; /* horrible : we use this value to avoid
1627                             going to the send data state */
1628     c->state = HTTPSTATE_SEND_HEADER;
1629     return 0;
1630 }
1631
1632 static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1633 {
1634     static const char *suffix = " kMGTP";
1635     const char *s;
1636
1637     for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1638
1639     url_fprintf(pb, "%"PRId64"%c", count, *s);
1640 }
1641
1642 static void compute_status(HTTPContext *c)
1643 {
1644     HTTPContext *c1;
1645     FFStream *stream;
1646     char *p;
1647     time_t ti;
1648     int i, len;
1649     ByteIOContext *pb;
1650
1651     if (url_open_dyn_buf(&pb) < 0) {
1652         /* XXX: return an error ? */
1653         c->buffer_ptr = c->buffer;
1654         c->buffer_end = c->buffer;
1655         return;
1656     }
1657
1658     url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1659     url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1660     url_fprintf(pb, "Pragma: no-cache\r\n");
1661     url_fprintf(pb, "\r\n");
1662
1663     url_fprintf(pb, "<HTML><HEAD><TITLE>%s Status</TITLE>\n", program_name);
1664     if (c->stream->feed_filename[0])
1665         url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1666     url_fprintf(pb, "</HEAD>\n<BODY>");
1667     url_fprintf(pb, "<H1>%s Status</H1>\n", program_name);
1668     /* format status */
1669     url_fprintf(pb, "<H2>Available Streams</H2>\n");
1670     url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1671     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");
1672     stream = first_stream;
1673     while (stream != NULL) {
1674         char sfilename[1024];
1675         char *eosf;
1676
1677         if (stream->feed != stream) {
1678             av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1679             eosf = sfilename + strlen(sfilename);
1680             if (eosf - sfilename >= 4) {
1681                 if (strcmp(eosf - 4, ".asf") == 0)
1682                     strcpy(eosf - 4, ".asx");
1683                 else if (strcmp(eosf - 3, ".rm") == 0)
1684                     strcpy(eosf - 3, ".ram");
1685                 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1686                     /* generate a sample RTSP director if
1687                        unicast. Generate an SDP redirector if
1688                        multicast */
1689                     eosf = strrchr(sfilename, '.');
1690                     if (!eosf)
1691                         eosf = sfilename + strlen(sfilename);
1692                     if (stream->is_multicast)
1693                         strcpy(eosf, ".sdp");
1694                     else
1695                         strcpy(eosf, ".rtsp");
1696                 }
1697             }
1698
1699             url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1700                          sfilename, stream->filename);
1701             url_fprintf(pb, "<td align=right> %d <td align=right> ",
1702                         stream->conns_served);
1703             fmt_bytecount(pb, stream->bytes_served);
1704             switch(stream->stream_type) {
1705             case STREAM_TYPE_LIVE: {
1706                     int audio_bit_rate = 0;
1707                     int video_bit_rate = 0;
1708                     const char *audio_codec_name = "";
1709                     const char *video_codec_name = "";
1710                     const char *audio_codec_name_extra = "";
1711                     const char *video_codec_name_extra = "";
1712
1713                     for(i=0;i<stream->nb_streams;i++) {
1714                         AVStream *st = stream->streams[i];
1715                         AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1716                         switch(st->codec->codec_type) {
1717                         case CODEC_TYPE_AUDIO:
1718                             audio_bit_rate += st->codec->bit_rate;
1719                             if (codec) {
1720                                 if (*audio_codec_name)
1721                                     audio_codec_name_extra = "...";
1722                                 audio_codec_name = codec->name;
1723                             }
1724                             break;
1725                         case CODEC_TYPE_VIDEO:
1726                             video_bit_rate += st->codec->bit_rate;
1727                             if (codec) {
1728                                 if (*video_codec_name)
1729                                     video_codec_name_extra = "...";
1730                                 video_codec_name = codec->name;
1731                             }
1732                             break;
1733                         case CODEC_TYPE_DATA:
1734                             video_bit_rate += st->codec->bit_rate;
1735                             break;
1736                         default:
1737                             abort();
1738                         }
1739                     }
1740                     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",
1741                                  stream->fmt->name,
1742                                  stream->bandwidth,
1743                                  video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1744                                  audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1745                     if (stream->feed)
1746                         url_fprintf(pb, "<TD>%s", stream->feed->filename);
1747                     else
1748                         url_fprintf(pb, "<TD>%s", stream->feed_filename);
1749                     url_fprintf(pb, "\n");
1750                 }
1751                 break;
1752             default:
1753                 url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1754                 break;
1755             }
1756         }
1757         stream = stream->next;
1758     }
1759     url_fprintf(pb, "</TABLE>\n");
1760
1761     stream = first_stream;
1762     while (stream != NULL) {
1763         if (stream->feed == stream) {
1764             url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1765             if (stream->pid) {
1766                 url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1767
1768 #if defined(linux) && !defined(CONFIG_NOCUTILS)
1769                 {
1770                     FILE *pid_stat;
1771                     char ps_cmd[64];
1772
1773                     /* This is somewhat linux specific I guess */
1774                     snprintf(ps_cmd, sizeof(ps_cmd),
1775                              "ps -o \"%%cpu,cputime\" --no-headers %d",
1776                              stream->pid);
1777
1778                     pid_stat = popen(ps_cmd, "r");
1779                     if (pid_stat) {
1780                         char cpuperc[10];
1781                         char cpuused[64];
1782
1783                         if (fscanf(pid_stat, "%10s %64s", cpuperc,
1784                                    cpuused) == 2) {
1785                             url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1786                                          cpuperc, cpuused);
1787                         }
1788                         fclose(pid_stat);
1789                     }
1790                 }
1791 #endif
1792
1793                 url_fprintf(pb, "<p>");
1794             }
1795             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");
1796
1797             for (i = 0; i < stream->nb_streams; i++) {
1798                 AVStream *st = stream->streams[i];
1799                 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1800                 const char *type = "unknown";
1801                 char parameters[64];
1802
1803                 parameters[0] = 0;
1804
1805                 switch(st->codec->codec_type) {
1806                 case CODEC_TYPE_AUDIO:
1807                     type = "audio";
1808                     snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1809                     break;
1810                 case CODEC_TYPE_VIDEO:
1811                     type = "video";
1812                     snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1813                                 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1814                     break;
1815                 default:
1816                     abort();
1817                 }
1818                 url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1819                         i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1820             }
1821             url_fprintf(pb, "</table>\n");
1822
1823         }
1824         stream = stream->next;
1825     }
1826
1827 #if 0
1828     {
1829         float avg;
1830         AVCodecContext *enc;
1831         char buf[1024];
1832
1833         /* feed status */
1834         stream = first_feed;
1835         while (stream != NULL) {
1836             url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1837             url_fprintf(pb, "<TABLE>\n");
1838             url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1839             for(i=0;i<stream->nb_streams;i++) {
1840                 AVStream *st = stream->streams[i];
1841                 FeedData *fdata = st->priv_data;
1842                 enc = st->codec;
1843
1844                 avcodec_string(buf, sizeof(buf), enc);
1845                 avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1846                 if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1847                     avg /= enc->frame_size;
1848                 url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
1849                              buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1850             }
1851             url_fprintf(pb, "</TABLE>\n");
1852             stream = stream->next_feed;
1853         }
1854     }
1855 #endif
1856
1857     /* connection status */
1858     url_fprintf(pb, "<H2>Connection Status</H2>\n");
1859
1860     url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1861                  nb_connections, nb_max_connections);
1862
1863     url_fprintf(pb, "Bandwidth in use: %lldk / %lldk<BR>\n",
1864                  current_bandwidth, max_bandwidth);
1865
1866     url_fprintf(pb, "<TABLE>\n");
1867     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");
1868     c1 = first_http_ctx;
1869     i = 0;
1870     while (c1 != NULL) {
1871         int bitrate;
1872         int j;
1873
1874         bitrate = 0;
1875         if (c1->stream) {
1876             for (j = 0; j < c1->stream->nb_streams; j++) {
1877                 if (!c1->stream->feed)
1878                     bitrate += c1->stream->streams[j]->codec->bit_rate;
1879                 else if (c1->feed_streams[j] >= 0)
1880                     bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1881             }
1882         }
1883
1884         i++;
1885         p = inet_ntoa(c1->from_addr.sin_addr);
1886         url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1887                     i,
1888                     c1->stream ? c1->stream->filename : "",
1889                     c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1890                     p,
1891                     c1->protocol,
1892                     http_state[c1->state]);
1893         fmt_bytecount(pb, bitrate);
1894         url_fprintf(pb, "<td align=right>");
1895         fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1896         url_fprintf(pb, "<td align=right>");
1897         fmt_bytecount(pb, c1->data_count);
1898         url_fprintf(pb, "\n");
1899         c1 = c1->next;
1900     }
1901     url_fprintf(pb, "</TABLE>\n");
1902
1903     /* date */
1904     ti = time(NULL);
1905     p = ctime(&ti);
1906     url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1907     url_fprintf(pb, "</BODY>\n</HTML>\n");
1908
1909     len = url_close_dyn_buf(pb, &c->pb_buffer);
1910     c->buffer_ptr = c->pb_buffer;
1911     c->buffer_end = c->pb_buffer + len;
1912 }
1913
1914 /* check if the parser needs to be opened for stream i */
1915 static void open_parser(AVFormatContext *s, int i)
1916 {
1917     AVStream *st = s->streams[i];
1918     AVCodec *codec;
1919
1920     if (!st->codec->codec) {
1921         codec = avcodec_find_decoder(st->codec->codec_id);
1922         if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1923             st->codec->parse_only = 1;
1924             if (avcodec_open(st->codec, codec) < 0)
1925                 st->codec->parse_only = 0;
1926         }
1927     }
1928 }
1929
1930 static int open_input_stream(HTTPContext *c, const char *info)
1931 {
1932     char buf[128];
1933     char input_filename[1024];
1934     AVFormatContext *s;
1935     int buf_size, i, ret;
1936     int64_t stream_pos;
1937
1938     /* find file name */
1939     if (c->stream->feed) {
1940         strcpy(input_filename, c->stream->feed->feed_filename);
1941         buf_size = FFM_PACKET_SIZE;
1942         /* compute position (absolute time) */
1943         if (find_info_tag(buf, sizeof(buf), "date", info)) {
1944             stream_pos = parse_date(buf, 0);
1945             if (stream_pos == INT64_MIN)
1946                 return -1;
1947         } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1948             int prebuffer = strtol(buf, 0, 10);
1949             stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1950         } else
1951             stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1952     } else {
1953         strcpy(input_filename, c->stream->feed_filename);
1954         buf_size = 0;
1955         /* compute position (relative time) */
1956         if (find_info_tag(buf, sizeof(buf), "date", info)) {
1957             stream_pos = parse_date(buf, 1);
1958             if (stream_pos == INT64_MIN)
1959                 return -1;
1960         } else
1961             stream_pos = 0;
1962     }
1963     if (input_filename[0] == '\0')
1964         return -1;
1965
1966 #if 0
1967     { time_t when = stream_pos / 1000000;
1968     http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1969     }
1970 #endif
1971
1972     /* open stream */
1973     if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1974                                   buf_size, c->stream->ap_in)) < 0) {
1975         http_log("could not open %s: %d\n", input_filename, ret);
1976         return -1;
1977     }
1978     s->flags |= AVFMT_FLAG_GENPTS;
1979     c->fmt_in = s;
1980     av_find_stream_info(c->fmt_in);
1981
1982     /* open each parser */
1983     for(i=0;i<s->nb_streams;i++)
1984         open_parser(s, i);
1985
1986     /* choose stream as clock source (we favorize video stream if
1987        present) for packet sending */
1988     c->pts_stream_index = 0;
1989     for(i=0;i<c->stream->nb_streams;i++) {
1990         if (c->pts_stream_index == 0 &&
1991             c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
1992             c->pts_stream_index = i;
1993         }
1994     }
1995
1996 #if 1
1997     if (c->fmt_in->iformat->read_seek)
1998         av_seek_frame(c->fmt_in, -1, stream_pos, 0);
1999 #endif
2000     /* set the start time (needed for maxtime and RTP packet timing) */
2001     c->start_time = cur_time;
2002     c->first_pts = AV_NOPTS_VALUE;
2003     return 0;
2004 }
2005
2006 /* return the server clock (in us) */
2007 static int64_t get_server_clock(HTTPContext *c)
2008 {
2009     /* compute current pts value from system time */
2010     return (cur_time - c->start_time) * 1000;
2011 }
2012
2013 /* return the estimated time at which the current packet must be sent
2014    (in us) */
2015 static int64_t get_packet_send_clock(HTTPContext *c)
2016 {
2017     int bytes_left, bytes_sent, frame_bytes;
2018
2019     frame_bytes = c->cur_frame_bytes;
2020     if (frame_bytes <= 0)
2021         return c->cur_pts;
2022     else {
2023         bytes_left = c->buffer_end - c->buffer_ptr;
2024         bytes_sent = frame_bytes - bytes_left;
2025         return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2026     }
2027 }
2028
2029
2030 static int http_prepare_data(HTTPContext *c)
2031 {
2032     int i, len, ret;
2033     AVFormatContext *ctx;
2034
2035     av_freep(&c->pb_buffer);
2036     switch(c->state) {
2037     case HTTPSTATE_SEND_DATA_HEADER:
2038         memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2039         av_strlcpy(c->fmt_ctx.author, c->stream->author,
2040                    sizeof(c->fmt_ctx.author));
2041         av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
2042                    sizeof(c->fmt_ctx.comment));
2043         av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
2044                    sizeof(c->fmt_ctx.copyright));
2045         av_strlcpy(c->fmt_ctx.title, c->stream->title,
2046                    sizeof(c->fmt_ctx.title));
2047
2048         for(i=0;i<c->stream->nb_streams;i++) {
2049             AVStream *st;
2050             AVStream *src;
2051             st = av_mallocz(sizeof(AVStream));
2052             c->fmt_ctx.streams[i] = st;
2053             /* if file or feed, then just take streams from FFStream struct */
2054             if (!c->stream->feed ||
2055                 c->stream->feed == c->stream)
2056                 src = c->stream->streams[i];
2057             else
2058                 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2059
2060             *st = *src;
2061             st->priv_data = 0;
2062             st->codec->frame_number = 0; /* XXX: should be done in
2063                                            AVStream, not in codec */
2064         }
2065         /* set output format parameters */
2066         c->fmt_ctx.oformat = c->stream->fmt;
2067         c->fmt_ctx.nb_streams = c->stream->nb_streams;
2068
2069         c->got_key_frame = 0;
2070
2071         /* prepare header and save header data in a stream */
2072         if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2073             /* XXX: potential leak */
2074             return -1;
2075         }
2076         c->fmt_ctx.pb->is_streamed = 1;
2077
2078         /*
2079          * HACK to avoid mpeg ps muxer to spit many underflow errors
2080          * Default value from FFmpeg
2081          * Try to set it use configuration option
2082          */
2083         c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2084         c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2085
2086         av_set_parameters(&c->fmt_ctx, NULL);
2087         if (av_write_header(&c->fmt_ctx) < 0) {
2088             http_log("Error writing output header\n");
2089             return -1;
2090         }
2091
2092         len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2093         c->buffer_ptr = c->pb_buffer;
2094         c->buffer_end = c->pb_buffer + len;
2095
2096         c->state = HTTPSTATE_SEND_DATA;
2097         c->last_packet_sent = 0;
2098         break;
2099     case HTTPSTATE_SEND_DATA:
2100         /* find a new packet */
2101         /* read a packet from the input stream */
2102         if (c->stream->feed)
2103             ffm_set_write_index(c->fmt_in,
2104                                 c->stream->feed->feed_write_index,
2105                                 c->stream->feed->feed_size);
2106
2107         if (c->stream->max_time &&
2108             c->stream->max_time + c->start_time - cur_time < 0)
2109             /* We have timed out */
2110             c->state = HTTPSTATE_SEND_DATA_TRAILER;
2111         else {
2112             AVPacket pkt;
2113         redo:
2114             if (av_read_frame(c->fmt_in, &pkt) < 0) {
2115                 if (c->stream->feed && c->stream->feed->feed_opened) {
2116                     /* if coming from feed, it means we reached the end of the
2117                        ffm file, so must wait for more data */
2118                     c->state = HTTPSTATE_WAIT_FEED;
2119                     return 1; /* state changed */
2120                 } else {
2121                     if (c->stream->loop) {
2122                         av_close_input_file(c->fmt_in);
2123                         c->fmt_in = NULL;
2124                         if (open_input_stream(c, "") < 0)
2125                             goto no_loop;
2126                         goto redo;
2127                     } else {
2128                     no_loop:
2129                         /* must send trailer now because eof or error */
2130                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
2131                     }
2132                 }
2133             } else {
2134                 int source_index = pkt.stream_index;
2135                 /* update first pts if needed */
2136                 if (c->first_pts == AV_NOPTS_VALUE) {
2137                     c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2138                     c->start_time = cur_time;
2139                 }
2140                 /* send it to the appropriate stream */
2141                 if (c->stream->feed) {
2142                     /* if coming from a feed, select the right stream */
2143                     if (c->switch_pending) {
2144                         c->switch_pending = 0;
2145                         for(i=0;i<c->stream->nb_streams;i++) {
2146                             if (c->switch_feed_streams[i] == pkt.stream_index)
2147                                 if (pkt.flags & PKT_FLAG_KEY)
2148                                     do_switch_stream(c, i);
2149                             if (c->switch_feed_streams[i] >= 0)
2150                                 c->switch_pending = 1;
2151                         }
2152                     }
2153                     for(i=0;i<c->stream->nb_streams;i++) {
2154                         if (c->feed_streams[i] == pkt.stream_index) {
2155                             AVStream *st = c->fmt_in->streams[source_index];
2156                             pkt.stream_index = i;
2157                             if (pkt.flags & PKT_FLAG_KEY &&
2158                                 (st->codec->codec_type == CODEC_TYPE_VIDEO ||
2159                                  c->stream->nb_streams == 1))
2160                                 c->got_key_frame = 1;
2161                             if (!c->stream->send_on_key || c->got_key_frame)
2162                                 goto send_it;
2163                         }
2164                     }
2165                 } else {
2166                     AVCodecContext *codec;
2167                     AVStream *ist, *ost;
2168                 send_it:
2169                     ist = c->fmt_in->streams[source_index];
2170                     /* specific handling for RTP: we use several
2171                        output stream (one for each RTP
2172                        connection). XXX: need more abstract handling */
2173                     if (c->is_packetized) {
2174                         /* compute send time and duration */
2175                         c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2176                         if (ist->start_time != AV_NOPTS_VALUE)
2177                             c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2178                         c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2179 #if 0
2180                         printf("index=%d pts=%0.3f duration=%0.6f\n",
2181                                pkt.stream_index,
2182                                (double)c->cur_pts /
2183                                AV_TIME_BASE,
2184                                (double)c->cur_frame_duration /
2185                                AV_TIME_BASE);
2186 #endif
2187                         /* find RTP context */
2188                         c->packet_stream_index = pkt.stream_index;
2189                         ctx = c->rtp_ctx[c->packet_stream_index];
2190                         if(!ctx) {
2191                             av_free_packet(&pkt);
2192                             break;
2193                         }
2194                         codec = ctx->streams[0]->codec;
2195                         /* only one stream per RTP connection */
2196                         pkt.stream_index = 0;
2197                     } else {
2198                         ctx = &c->fmt_ctx;
2199                         /* Fudge here */
2200                         codec = ctx->streams[pkt.stream_index]->codec;
2201                     }
2202
2203                     if (c->is_packetized) {
2204                         int max_packet_size;
2205                         if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2206                             max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2207                         else
2208                             max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2209                         ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2210                     } else {
2211                         ret = url_open_dyn_buf(&ctx->pb);
2212                     }
2213                     if (ret < 0) {
2214                         /* XXX: potential leak */
2215                         return -1;
2216                     }
2217                     ost = ctx->streams[pkt.stream_index];
2218
2219                     ctx->pb->is_streamed = 1;
2220                     if (pkt.dts != AV_NOPTS_VALUE)
2221                         pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2222                     if (pkt.pts != AV_NOPTS_VALUE)
2223                         pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2224                     pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2225                     if (av_write_frame(ctx, &pkt) < 0) {
2226                         http_log("Error writing frame to output\n");
2227                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
2228                     }
2229
2230                     len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2231                     c->cur_frame_bytes = len;
2232                     c->buffer_ptr = c->pb_buffer;
2233                     c->buffer_end = c->pb_buffer + len;
2234
2235                     codec->frame_number++;
2236                     if (len == 0) {
2237                         av_free_packet(&pkt);
2238                         goto redo;
2239                     }
2240                 }
2241                 av_free_packet(&pkt);
2242             }
2243         }
2244         break;
2245     default:
2246     case HTTPSTATE_SEND_DATA_TRAILER:
2247         /* last packet test ? */
2248         if (c->last_packet_sent || c->is_packetized)
2249             return -1;
2250         ctx = &c->fmt_ctx;
2251         /* prepare header */
2252         if (url_open_dyn_buf(&ctx->pb) < 0) {
2253             /* XXX: potential leak */
2254             return -1;
2255         }
2256         c->fmt_ctx.pb->is_streamed = 1;
2257         av_write_trailer(ctx);
2258         len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2259         c->buffer_ptr = c->pb_buffer;
2260         c->buffer_end = c->pb_buffer + len;
2261
2262         c->last_packet_sent = 1;
2263         break;
2264     }
2265     return 0;
2266 }
2267
2268 /* should convert the format at the same time */
2269 /* send data starting at c->buffer_ptr to the output connection
2270    (either UDP or TCP connection) */
2271 static int http_send_data(HTTPContext *c)
2272 {
2273     int len, ret;
2274
2275     for(;;) {
2276         if (c->buffer_ptr >= c->buffer_end) {
2277             ret = http_prepare_data(c);
2278             if (ret < 0)
2279                 return -1;
2280             else if (ret != 0)
2281                 /* state change requested */
2282                 break;
2283         } else {
2284             if (c->is_packetized) {
2285                 /* RTP data output */
2286                 len = c->buffer_end - c->buffer_ptr;
2287                 if (len < 4) {
2288                     /* fail safe - should never happen */
2289                 fail1:
2290                     c->buffer_ptr = c->buffer_end;
2291                     return 0;
2292                 }
2293                 len = (c->buffer_ptr[0] << 24) |
2294                     (c->buffer_ptr[1] << 16) |
2295                     (c->buffer_ptr[2] << 8) |
2296                     (c->buffer_ptr[3]);
2297                 if (len > (c->buffer_end - c->buffer_ptr))
2298                     goto fail1;
2299                 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2300                     /* nothing to send yet: we can wait */
2301                     return 0;
2302                 }
2303
2304                 c->data_count += len;
2305                 update_datarate(&c->datarate, c->data_count);
2306                 if (c->stream)
2307                     c->stream->bytes_served += len;
2308
2309                 if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2310                     /* RTP packets are sent inside the RTSP TCP connection */
2311                     ByteIOContext *pb;
2312                     int interleaved_index, size;
2313                     uint8_t header[4];
2314                     HTTPContext *rtsp_c;
2315
2316                     rtsp_c = c->rtsp_c;
2317                     /* if no RTSP connection left, error */
2318                     if (!rtsp_c)
2319                         return -1;
2320                     /* if already sending something, then wait. */
2321                     if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2322                         break;
2323                     if (url_open_dyn_buf(&pb) < 0)
2324                         goto fail1;
2325                     interleaved_index = c->packet_stream_index * 2;
2326                     /* RTCP packets are sent at odd indexes */
2327                     if (c->buffer_ptr[1] == 200)
2328                         interleaved_index++;
2329                     /* write RTSP TCP header */
2330                     header[0] = '$';
2331                     header[1] = interleaved_index;
2332                     header[2] = len >> 8;
2333                     header[3] = len;
2334                     put_buffer(pb, header, 4);
2335                     /* write RTP packet data */
2336                     c->buffer_ptr += 4;
2337                     put_buffer(pb, c->buffer_ptr, len);
2338                     size = url_close_dyn_buf(pb, &c->packet_buffer);
2339                     /* prepare asynchronous TCP sending */
2340                     rtsp_c->packet_buffer_ptr = c->packet_buffer;
2341                     rtsp_c->packet_buffer_end = c->packet_buffer + size;
2342                     c->buffer_ptr += len;
2343
2344                     /* send everything we can NOW */
2345                     len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2346                                 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2347                     if (len > 0)
2348                         rtsp_c->packet_buffer_ptr += len;
2349                     if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2350                         /* if we could not send all the data, we will
2351                            send it later, so a new state is needed to
2352                            "lock" the RTSP TCP connection */
2353                         rtsp_c->state = RTSPSTATE_SEND_PACKET;
2354                         break;
2355                     } else
2356                         /* all data has been sent */
2357                         av_freep(&c->packet_buffer);
2358                 } else {
2359                     /* send RTP packet directly in UDP */
2360                     c->buffer_ptr += 4;
2361                     url_write(c->rtp_handles[c->packet_stream_index],
2362                               c->buffer_ptr, len);
2363                     c->buffer_ptr += len;
2364                     /* here we continue as we can send several packets per 10 ms slot */
2365                 }
2366             } else {
2367                 /* TCP data output */
2368                 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2369                 if (len < 0) {
2370                     if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2371                         ff_neterrno() != FF_NETERROR(EINTR))
2372                         /* error : close connection */
2373                         return -1;
2374                     else
2375                         return 0;
2376                 } else
2377                     c->buffer_ptr += len;
2378
2379                 c->data_count += len;
2380                 update_datarate(&c->datarate, c->data_count);
2381                 if (c->stream)
2382                     c->stream->bytes_served += len;
2383                 break;
2384             }
2385         }
2386     } /* for(;;) */
2387     return 0;
2388 }
2389
2390 static int http_start_receive_data(HTTPContext *c)
2391 {
2392     int fd;
2393
2394     if (c->stream->feed_opened)
2395         return -1;
2396
2397     /* Don't permit writing to this one */
2398     if (c->stream->readonly)
2399         return -1;
2400
2401     /* open feed */
2402     fd = open(c->stream->feed_filename, O_RDWR);
2403     if (fd < 0) {
2404         http_log("Error opening feeder file: %s\n", strerror(errno));
2405         return -1;
2406     }
2407     c->feed_fd = fd;
2408
2409     c->stream->feed_write_index = ffm_read_write_index(fd);
2410     c->stream->feed_size = lseek(fd, 0, SEEK_END);
2411     lseek(fd, 0, SEEK_SET);
2412
2413     /* init buffer input */
2414     c->buffer_ptr = c->buffer;
2415     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2416     c->stream->feed_opened = 1;
2417     return 0;
2418 }
2419
2420 static int http_receive_data(HTTPContext *c)
2421 {
2422     HTTPContext *c1;
2423
2424     if (c->buffer_end > c->buffer_ptr) {
2425         int len;
2426
2427         len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2428         if (len < 0) {
2429             if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2430                 ff_neterrno() != FF_NETERROR(EINTR))
2431                 /* error : close connection */
2432                 goto fail;
2433         } else if (len == 0)
2434             /* end of connection : close it */
2435             goto fail;
2436         else {
2437             c->buffer_ptr += len;
2438             c->data_count += len;
2439             update_datarate(&c->datarate, c->data_count);
2440         }
2441     }
2442
2443     if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2444         if (c->buffer[0] != 'f' ||
2445             c->buffer[1] != 'm') {
2446             http_log("Feed stream has become desynchronized -- disconnecting\n");
2447             goto fail;
2448         }
2449     }
2450
2451     if (c->buffer_ptr >= c->buffer_end) {
2452         FFStream *feed = c->stream;
2453         /* a packet has been received : write it in the store, except
2454            if header */
2455         if (c->data_count > FFM_PACKET_SIZE) {
2456
2457             //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2458             /* XXX: use llseek or url_seek */
2459             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2460             if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2461                 http_log("Error writing to feed file: %s\n", strerror(errno));
2462                 goto fail;
2463             }
2464
2465             feed->feed_write_index += FFM_PACKET_SIZE;
2466             /* update file size */
2467             if (feed->feed_write_index > c->stream->feed_size)
2468                 feed->feed_size = feed->feed_write_index;
2469
2470             /* handle wrap around if max file size reached */
2471             if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2472                 feed->feed_write_index = FFM_PACKET_SIZE;
2473
2474             /* write index */
2475             ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2476
2477             /* wake up any waiting connections */
2478             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2479                 if (c1->state == HTTPSTATE_WAIT_FEED &&
2480                     c1->stream->feed == c->stream->feed)
2481                     c1->state = HTTPSTATE_SEND_DATA;
2482             }
2483         } else {
2484             /* We have a header in our hands that contains useful data */
2485             AVFormatContext *s = NULL;
2486             ByteIOContext *pb;
2487             AVInputFormat *fmt_in;
2488             int i;
2489
2490             /* use feed output format name to find corresponding input format */
2491             fmt_in = av_find_input_format(feed->fmt->name);
2492             if (!fmt_in)
2493                 goto fail;
2494
2495             url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2496             pb->is_streamed = 1;
2497
2498             if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2499                 av_free(pb);
2500                 goto fail;
2501             }
2502
2503             /* Now we have the actual streams */
2504             if (s->nb_streams != feed->nb_streams) {
2505                 av_close_input_stream(s);
2506                 av_free(pb);
2507                 goto fail;
2508             }
2509
2510             for (i = 0; i < s->nb_streams; i++) {
2511                 AVStream *fst = feed->streams[i];
2512                 AVStream *st = s->streams[i];
2513                 memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2514                 if (fst->codec->extradata_size) {
2515                     fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2516                     if (!fst->codec->extradata)
2517                         goto fail;
2518                     memcpy(fst->codec->extradata, st->codec->extradata,
2519                            fst->codec->extradata_size);
2520                 }
2521             }
2522
2523             av_close_input_stream(s);
2524             av_free(pb);
2525         }
2526         c->buffer_ptr = c->buffer;
2527     }
2528
2529     return 0;
2530  fail:
2531     c->stream->feed_opened = 0;
2532     close(c->feed_fd);
2533     /* wake up any waiting connections to stop waiting for feed */
2534     for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2535         if (c1->state == HTTPSTATE_WAIT_FEED &&
2536             c1->stream->feed == c->stream->feed)
2537             c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2538     }
2539     return -1;
2540 }
2541
2542 /********************************************************************/
2543 /* RTSP handling */
2544
2545 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2546 {
2547     const char *str;
2548     time_t ti;
2549     char *p;
2550     char buf2[32];
2551
2552     switch(error_number) {
2553     case RTSP_STATUS_OK:
2554         str = "OK";
2555         break;
2556     case RTSP_STATUS_METHOD:
2557         str = "Method Not Allowed";
2558         break;
2559     case RTSP_STATUS_BANDWIDTH:
2560         str = "Not Enough Bandwidth";
2561         break;
2562     case RTSP_STATUS_SESSION:
2563         str = "Session Not Found";
2564         break;
2565     case RTSP_STATUS_STATE:
2566         str = "Method Not Valid in This State";
2567         break;
2568     case RTSP_STATUS_AGGREGATE:
2569         str = "Aggregate operation not allowed";
2570         break;
2571     case RTSP_STATUS_ONLY_AGGREGATE:
2572         str = "Only aggregate operation allowed";
2573         break;
2574     case RTSP_STATUS_TRANSPORT:
2575         str = "Unsupported transport";
2576         break;
2577     case RTSP_STATUS_INTERNAL:
2578         str = "Internal Server Error";
2579         break;
2580     case RTSP_STATUS_SERVICE:
2581         str = "Service Unavailable";
2582         break;
2583     case RTSP_STATUS_VERSION:
2584         str = "RTSP Version not supported";
2585         break;
2586     default:
2587         str = "Unknown Error";
2588         break;
2589     }
2590
2591     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2592     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2593
2594     /* output GMT time */
2595     ti = time(NULL);
2596     p = ctime(&ti);
2597     strcpy(buf2, p);
2598     p = buf2 + strlen(p) - 1;
2599     if (*p == '\n')
2600         *p = '\0';
2601     url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2602 }
2603
2604 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2605 {
2606     rtsp_reply_header(c, error_number);
2607     url_fprintf(c->pb, "\r\n");
2608 }
2609
2610 static int rtsp_parse_request(HTTPContext *c)
2611 {
2612     const char *p, *p1, *p2;
2613     char cmd[32];
2614     char url[1024];
2615     char protocol[32];
2616     char line[1024];
2617     int len;
2618     RTSPHeader header1, *header = &header1;
2619
2620     c->buffer_ptr[0] = '\0';
2621     p = c->buffer;
2622
2623     get_word(cmd, sizeof(cmd), &p);
2624     get_word(url, sizeof(url), &p);
2625     get_word(protocol, sizeof(protocol), &p);
2626
2627     av_strlcpy(c->method, cmd, sizeof(c->method));
2628     av_strlcpy(c->url, url, sizeof(c->url));
2629     av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2630
2631     if (url_open_dyn_buf(&c->pb) < 0) {
2632         /* XXX: cannot do more */
2633         c->pb = NULL; /* safety */
2634         return -1;
2635     }
2636
2637     /* check version name */
2638     if (strcmp(protocol, "RTSP/1.0") != 0) {
2639         rtsp_reply_error(c, RTSP_STATUS_VERSION);
2640         goto the_end;
2641     }
2642
2643     /* parse each header line */
2644     memset(header, 0, sizeof(RTSPHeader));
2645     /* skip to next line */
2646     while (*p != '\n' && *p != '\0')
2647         p++;
2648     if (*p == '\n')
2649         p++;
2650     while (*p != '\0') {
2651         p1 = strchr(p, '\n');
2652         if (!p1)
2653             break;
2654         p2 = p1;
2655         if (p2 > p && p2[-1] == '\r')
2656             p2--;
2657         /* skip empty line */
2658         if (p2 == p)
2659             break;
2660         len = p2 - p;
2661         if (len > sizeof(line) - 1)
2662             len = sizeof(line) - 1;
2663         memcpy(line, p, len);
2664         line[len] = '\0';
2665         rtsp_parse_line(header, line);
2666         p = p1 + 1;
2667     }
2668
2669     /* handle sequence number */
2670     c->seq = header->seq;
2671
2672     if (!strcmp(cmd, "DESCRIBE"))
2673         rtsp_cmd_describe(c, url);
2674     else if (!strcmp(cmd, "OPTIONS"))
2675         rtsp_cmd_options(c, url);
2676     else if (!strcmp(cmd, "SETUP"))
2677         rtsp_cmd_setup(c, url, header);
2678     else if (!strcmp(cmd, "PLAY"))
2679         rtsp_cmd_play(c, url, header);
2680     else if (!strcmp(cmd, "PAUSE"))
2681         rtsp_cmd_pause(c, url, header);
2682     else if (!strcmp(cmd, "TEARDOWN"))
2683         rtsp_cmd_teardown(c, url, header);
2684     else
2685         rtsp_reply_error(c, RTSP_STATUS_METHOD);
2686
2687  the_end:
2688     len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2689     c->pb = NULL; /* safety */
2690     if (len < 0) {
2691         /* XXX: cannot do more */
2692         return -1;
2693     }
2694     c->buffer_ptr = c->pb_buffer;
2695     c->buffer_end = c->pb_buffer + len;
2696     c->state = RTSPSTATE_SEND_REPLY;
2697     return 0;
2698 }
2699
2700 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2701                                    struct in_addr my_ip)
2702 {
2703     AVFormatContext *avc;
2704     AVStream avs[MAX_STREAMS];
2705     int i;
2706
2707     avc =  av_alloc_format_context();
2708     if (avc == NULL) {
2709         return -1;
2710     }
2711     if (stream->title[0] != 0) {
2712         av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2713     } else {
2714         av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2715     }
2716     avc->nb_streams = stream->nb_streams;
2717     if (stream->is_multicast) {
2718         snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2719                  inet_ntoa(stream->multicast_ip),
2720                  stream->multicast_port, stream->multicast_ttl);
2721     }
2722
2723     for(i = 0; i < stream->nb_streams; i++) {
2724         avc->streams[i] = &avs[i];
2725         avc->streams[i]->codec = stream->streams[i]->codec;
2726     }
2727     *pbuffer = av_mallocz(2048);
2728     avf_sdp_create(&avc, 1, *pbuffer, 2048);
2729     av_free(avc);
2730
2731     return strlen(*pbuffer);
2732 }
2733
2734 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2735 {
2736 //    rtsp_reply_header(c, RTSP_STATUS_OK);
2737     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2738     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2739     url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2740     url_fprintf(c->pb, "\r\n");
2741 }
2742
2743 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2744 {
2745     FFStream *stream;
2746     char path1[1024];
2747     const char *path;
2748     uint8_t *content;
2749     int content_length, len;
2750     struct sockaddr_in my_addr;
2751
2752     /* find which url is asked */
2753     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2754     path = path1;
2755     if (*path == '/')
2756         path++;
2757
2758     for(stream = first_stream; stream != NULL; stream = stream->next) {
2759         if (!stream->is_feed &&
2760             stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2761             !strcmp(path, stream->filename)) {
2762             goto found;
2763         }
2764     }
2765     /* no stream found */
2766     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2767     return;
2768
2769  found:
2770     /* prepare the media description in sdp format */
2771
2772     /* get the host IP */
2773     len = sizeof(my_addr);
2774     getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2775     content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2776     if (content_length < 0) {
2777         rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2778         return;
2779     }
2780     rtsp_reply_header(c, RTSP_STATUS_OK);
2781     url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2782     url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2783     url_fprintf(c->pb, "\r\n");
2784     put_buffer(c->pb, content, content_length);
2785 }
2786
2787 static HTTPContext *find_rtp_session(const char *session_id)
2788 {
2789     HTTPContext *c;
2790
2791     if (session_id[0] == '\0')
2792         return NULL;
2793
2794     for(c = first_http_ctx; c != NULL; c = c->next) {
2795         if (!strcmp(c->session_id, session_id))
2796             return c;
2797     }
2798     return NULL;
2799 }
2800
2801 static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2802 {
2803     RTSPTransportField *th;
2804     int i;
2805
2806     for(i=0;i<h->nb_transports;i++) {
2807         th = &h->transports[i];
2808         if (th->protocol == protocol)
2809             return th;
2810     }
2811     return NULL;
2812 }
2813
2814 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2815                            RTSPHeader *h)
2816 {
2817     FFStream *stream;
2818     int stream_index, port;
2819     char buf[1024];
2820     char path1[1024];
2821     const char *path;
2822     HTTPContext *rtp_c;
2823     RTSPTransportField *th;
2824     struct sockaddr_in dest_addr;
2825     RTSPActionServerSetup setup;
2826
2827     /* find which url is asked */
2828     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2829     path = path1;
2830     if (*path == '/')
2831         path++;
2832
2833     /* now check each stream */
2834     for(stream = first_stream; stream != NULL; stream = stream->next) {
2835         if (!stream->is_feed &&
2836             stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2837             /* accept aggregate filenames only if single stream */
2838             if (!strcmp(path, stream->filename)) {
2839                 if (stream->nb_streams != 1) {
2840                     rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2841                     return;
2842                 }
2843                 stream_index = 0;
2844                 goto found;
2845             }
2846
2847             for(stream_index = 0; stream_index < stream->nb_streams;
2848                 stream_index++) {
2849                 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2850                          stream->filename, stream_index);
2851                 if (!strcmp(path, buf))
2852                     goto found;
2853             }
2854         }
2855     }
2856     /* no stream found */
2857     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2858     return;
2859  found:
2860
2861     /* generate session id if needed */
2862     if (h->session_id[0] == '\0')
2863         snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2864                  av_random(&random_state), av_random(&random_state));
2865
2866     /* find rtp session, and create it if none found */
2867     rtp_c = find_rtp_session(h->session_id);
2868     if (!rtp_c) {
2869         /* always prefer UDP */
2870         th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2871         if (!th) {
2872             th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2873             if (!th) {
2874                 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2875                 return;
2876             }
2877         }
2878
2879         rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2880                                    th->protocol);
2881         if (!rtp_c) {
2882             rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2883             return;
2884         }
2885
2886         /* open input stream */
2887         if (open_input_stream(rtp_c, "") < 0) {
2888             rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2889             return;
2890         }
2891     }
2892
2893     /* test if stream is OK (test needed because several SETUP needs
2894        to be done for a given file) */
2895     if (rtp_c->stream != stream) {
2896         rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2897         return;
2898     }
2899
2900     /* test if stream is already set up */
2901     if (rtp_c->rtp_ctx[stream_index]) {
2902         rtsp_reply_error(c, RTSP_STATUS_STATE);
2903         return;
2904     }
2905
2906     /* check transport */
2907     th = find_transport(h, rtp_c->rtp_protocol);
2908     if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2909                 th->client_port_min <= 0)) {
2910         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2911         return;
2912     }
2913
2914     /* setup default options */
2915     setup.transport_option[0] = '\0';
2916     dest_addr = rtp_c->from_addr;
2917     dest_addr.sin_port = htons(th->client_port_min);
2918
2919     /* setup stream */
2920     if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2921         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2922         return;
2923     }
2924
2925     /* now everything is OK, so we can send the connection parameters */
2926     rtsp_reply_header(c, RTSP_STATUS_OK);
2927     /* session ID */
2928     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2929
2930     switch(rtp_c->rtp_protocol) {
2931     case RTSP_PROTOCOL_RTP_UDP:
2932         port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2933         url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2934                     "client_port=%d-%d;server_port=%d-%d",
2935                     th->client_port_min, th->client_port_min + 1,
2936                     port, port + 1);
2937         break;
2938     case RTSP_PROTOCOL_RTP_TCP:
2939         url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2940                     stream_index * 2, stream_index * 2 + 1);
2941         break;
2942     default:
2943         break;
2944     }
2945     if (setup.transport_option[0] != '\0')
2946         url_fprintf(c->pb, ";%s", setup.transport_option);
2947     url_fprintf(c->pb, "\r\n");
2948
2949
2950     url_fprintf(c->pb, "\r\n");
2951 }
2952
2953
2954 /* find an rtp connection by using the session ID. Check consistency
2955    with filename */
2956 static HTTPContext *find_rtp_session_with_url(const char *url,
2957                                               const char *session_id)
2958 {
2959     HTTPContext *rtp_c;
2960     char path1[1024];
2961     const char *path;
2962     char buf[1024];
2963     int s;
2964
2965     rtp_c = find_rtp_session(session_id);
2966     if (!rtp_c)
2967         return NULL;
2968
2969     /* find which url is asked */
2970     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2971     path = path1;
2972     if (*path == '/')
2973         path++;
2974     if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2975     for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2976       snprintf(buf, sizeof(buf), "%s/streamid=%d",
2977         rtp_c->stream->filename, s);
2978       if(!strncmp(path, buf, sizeof(buf))) {
2979     // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2980         return rtp_c;
2981       }
2982     }
2983     return NULL;
2984 }
2985
2986 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2987 {
2988     HTTPContext *rtp_c;
2989
2990     rtp_c = find_rtp_session_with_url(url, h->session_id);
2991     if (!rtp_c) {
2992         rtsp_reply_error(c, RTSP_STATUS_SESSION);
2993         return;
2994     }
2995
2996     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2997         rtp_c->state != HTTPSTATE_WAIT_FEED &&
2998         rtp_c->state != HTTPSTATE_READY) {
2999         rtsp_reply_error(c, RTSP_STATUS_STATE);
3000         return;
3001     }
3002
3003 #if 0
3004     /* XXX: seek in stream */
3005     if (h->range_start != AV_NOPTS_VALUE) {
3006         printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3007         av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3008     }
3009 #endif
3010
3011     rtp_c->state = HTTPSTATE_SEND_DATA;
3012
3013     /* now everything is OK, so we can send the connection parameters */
3014     rtsp_reply_header(c, RTSP_STATUS_OK);
3015     /* session ID */
3016     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3017     url_fprintf(c->pb, "\r\n");
3018 }
3019
3020 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3021 {
3022     HTTPContext *rtp_c;
3023
3024     rtp_c = find_rtp_session_with_url(url, h->session_id);
3025     if (!rtp_c) {
3026         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3027         return;
3028     }
3029
3030     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3031         rtp_c->state != HTTPSTATE_WAIT_FEED) {
3032         rtsp_reply_error(c, RTSP_STATUS_STATE);
3033         return;
3034     }
3035
3036     rtp_c->state = HTTPSTATE_READY;
3037     rtp_c->first_pts = AV_NOPTS_VALUE;
3038     /* now everything is OK, so we can send the connection parameters */
3039     rtsp_reply_header(c, RTSP_STATUS_OK);
3040     /* session ID */
3041     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3042     url_fprintf(c->pb, "\r\n");
3043 }
3044
3045 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3046 {
3047     HTTPContext *rtp_c;
3048     char session_id[32];
3049
3050     rtp_c = find_rtp_session_with_url(url, h->session_id);
3051     if (!rtp_c) {
3052         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3053         return;
3054     }
3055
3056     av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3057
3058     /* abort the session */
3059     close_connection(rtp_c);
3060
3061     /* now everything is OK, so we can send the connection parameters */
3062     rtsp_reply_header(c, RTSP_STATUS_OK);
3063     /* session ID */
3064     url_fprintf(c->pb, "Session: %s\r\n", session_id);
3065     url_fprintf(c->pb, "\r\n");
3066 }
3067
3068
3069 /********************************************************************/
3070 /* RTP handling */
3071
3072 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3073                                        FFStream *stream, const char *session_id,
3074                                        enum RTSPProtocol rtp_protocol)
3075 {
3076     HTTPContext *c = NULL;
3077     const char *proto_str;
3078
3079     /* XXX: should output a warning page when coming
3080        close to the connection limit */
3081     if (nb_connections >= nb_max_connections)
3082         goto fail;
3083
3084     /* add a new connection */
3085     c = av_mallocz(sizeof(HTTPContext));
3086     if (!c)
3087         goto fail;
3088
3089     c->fd = -1;
3090     c->poll_entry = NULL;
3091     c->from_addr = *from_addr;
3092     c->buffer_size = IOBUFFER_INIT_SIZE;
3093     c->buffer = av_malloc(c->buffer_size);
3094     if (!c->buffer)
3095         goto fail;
3096     nb_connections++;
3097     c->stream = stream;
3098     av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3099     c->state = HTTPSTATE_READY;
3100     c->is_packetized = 1;
3101     c->rtp_protocol = rtp_protocol;
3102
3103     /* protocol is shown in statistics */
3104     switch(c->rtp_protocol) {
3105     case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3106         proto_str = "MCAST";
3107         break;
3108     case RTSP_PROTOCOL_RTP_UDP:
3109         proto_str = "UDP";
3110         break;
3111     case RTSP_PROTOCOL_RTP_TCP:
3112         proto_str = "TCP";
3113         break;
3114     default:
3115         proto_str = "???";
3116         break;
3117     }
3118     av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3119     av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3120
3121     current_bandwidth += stream->bandwidth;
3122
3123     c->next = first_http_ctx;
3124     first_http_ctx = c;
3125     return c;
3126
3127  fail:
3128     if (c) {
3129         av_free(c->buffer);
3130         av_free(c);
3131     }
3132     return NULL;
3133 }
3134
3135 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3136    command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3137    used. */
3138 static int rtp_new_av_stream(HTTPContext *c,
3139                              int stream_index, struct sockaddr_in *dest_addr,
3140                              HTTPContext *rtsp_c)
3141 {
3142     AVFormatContext *ctx;
3143     AVStream *st;
3144     char *ipaddr;
3145     URLContext *h = NULL;
3146     uint8_t *dummy_buf;
3147     int max_packet_size;
3148
3149     /* now we can open the relevant output stream */
3150     ctx = av_alloc_format_context();
3151     if (!ctx)
3152         return -1;
3153     ctx->oformat = guess_format("rtp", NULL, NULL);
3154
3155     st = av_mallocz(sizeof(AVStream));
3156     if (!st)
3157         goto fail;
3158     st->codec= avcodec_alloc_context();
3159     ctx->nb_streams = 1;
3160     ctx->streams[0] = st;
3161
3162     if (!c->stream->feed ||
3163         c->stream->feed == c->stream)
3164         memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3165     else
3166         memcpy(st,
3167                c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3168                sizeof(AVStream));
3169     st->priv_data = NULL;
3170
3171     /* build destination RTP address */
3172     ipaddr = inet_ntoa(dest_addr->sin_addr);
3173
3174     switch(c->rtp_protocol) {
3175     case RTSP_PROTOCOL_RTP_UDP:
3176     case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3177         /* RTP/UDP case */
3178
3179         /* XXX: also pass as parameter to function ? */
3180         if (c->stream->is_multicast) {
3181             int ttl;
3182             ttl = c->stream->multicast_ttl;
3183             if (!ttl)
3184                 ttl = 16;
3185             snprintf(ctx->filename, sizeof(ctx->filename),
3186                      "rtp://%s:%d?multicast=1&ttl=%d",
3187                      ipaddr, ntohs(dest_addr->sin_port), ttl);
3188         } else {
3189             snprintf(ctx->filename, sizeof(ctx->filename),
3190                      "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3191         }
3192
3193         if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3194             goto fail;
3195         c->rtp_handles[stream_index] = h;
3196         max_packet_size = url_get_max_packet_size(h);
3197         break;
3198     case RTSP_PROTOCOL_RTP_TCP:
3199         /* RTP/TCP case */
3200         c->rtsp_c = rtsp_c;
3201         max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3202         break;
3203     default:
3204         goto fail;
3205     }
3206
3207     http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3208              ipaddr, ntohs(dest_addr->sin_port),
3209              c->stream->filename, stream_index, c->protocol);
3210
3211     /* normally, no packets should be output here, but the packet size may be checked */
3212     if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3213         /* XXX: close stream */
3214         goto fail;
3215     }
3216     av_set_parameters(ctx, NULL);
3217     if (av_write_header(ctx) < 0) {
3218     fail:
3219         if (h)
3220             url_close(h);
3221         av_free(ctx);
3222         return -1;
3223     }
3224     url_close_dyn_buf(ctx->pb, &dummy_buf);
3225     av_free(dummy_buf);
3226
3227     c->rtp_ctx[stream_index] = ctx;
3228     return 0;
3229 }
3230
3231 /********************************************************************/
3232 /* ffserver initialization */
3233
3234 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3235 {
3236     AVStream *fst;
3237
3238     fst = av_mallocz(sizeof(AVStream));
3239     if (!fst)
3240         return NULL;
3241     fst->codec= avcodec_alloc_context();
3242     fst->priv_data = av_mallocz(sizeof(FeedData));
3243     memcpy(fst->codec, codec, sizeof(AVCodecContext));
3244     fst->index = stream->nb_streams;
3245     av_set_pts_info(fst, 33, 1, 90000);
3246     stream->streams[stream->nb_streams++] = fst;
3247     return fst;
3248 }
3249
3250 /* return the stream number in the feed */
3251 static int add_av_stream(FFStream *feed, AVStream *st)
3252 {
3253     AVStream *fst;
3254     AVCodecContext *av, *av1;
3255     int i;
3256
3257     av = st->codec;
3258     for(i=0;i<feed->nb_streams;i++) {
3259         st = feed->streams[i];
3260         av1 = st->codec;
3261         if (av1->codec_id == av->codec_id &&
3262             av1->codec_type == av->codec_type &&
3263             av1->bit_rate == av->bit_rate) {
3264
3265             switch(av->codec_type) {
3266             case CODEC_TYPE_AUDIO:
3267                 if (av1->channels == av->channels &&
3268                     av1->sample_rate == av->sample_rate)
3269                     goto found;
3270                 break;
3271             case CODEC_TYPE_VIDEO:
3272                 if (av1->width == av->width &&
3273                     av1->height == av->height &&
3274                     av1->time_base.den == av->time_base.den &&
3275                     av1->time_base.num == av->time_base.num &&
3276                     av1->gop_size == av->gop_size)
3277                     goto found;
3278                 break;
3279             default:
3280                 abort();
3281             }
3282         }
3283     }
3284
3285     fst = add_av_stream1(feed, av);
3286     if (!fst)
3287         return -1;
3288     return feed->nb_streams - 1;
3289  found:
3290     return i;
3291 }
3292
3293 static void remove_stream(FFStream *stream)
3294 {
3295     FFStream **ps;
3296     ps = &first_stream;
3297     while (*ps != NULL) {
3298         if (*ps == stream)
3299             *ps = (*ps)->next;
3300         else
3301             ps = &(*ps)->next;
3302     }
3303 }
3304
3305 /* specific mpeg4 handling : we extract the raw parameters */
3306 static void extract_mpeg4_header(AVFormatContext *infile)
3307 {
3308     int mpeg4_count, i, size;
3309     AVPacket pkt;
3310     AVStream *st;
3311     const uint8_t *p;
3312
3313     mpeg4_count = 0;
3314     for(i=0;i<infile->nb_streams;i++) {
3315         st = infile->streams[i];
3316         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3317             st->codec->extradata_size == 0) {
3318             mpeg4_count++;
3319         }
3320     }
3321     if (!mpeg4_count)
3322         return;
3323
3324     printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3325     while (mpeg4_count > 0) {
3326         if (av_read_packet(infile, &pkt) < 0)
3327             break;
3328         st = infile->streams[pkt.stream_index];
3329         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3330             st->codec->extradata_size == 0) {
3331             av_freep(&st->codec->extradata);
3332             /* fill extradata with the header */
3333             /* XXX: we make hard suppositions here ! */
3334             p = pkt.data;
3335             while (p < pkt.data + pkt.size - 4) {
3336                 /* stop when vop header is found */
3337                 if (p[0] == 0x00 && p[1] == 0x00 &&
3338                     p[2] == 0x01 && p[3] == 0xb6) {
3339                     size = p - pkt.data;
3340                     //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3341                     st->codec->extradata = av_malloc(size);
3342                     st->codec->extradata_size = size;
3343                     memcpy(st->codec->extradata, pkt.data, size);
3344                     break;
3345                 }
3346                 p++;
3347             }
3348             mpeg4_count--;
3349         }
3350         av_free_packet(&pkt);
3351     }
3352 }
3353
3354 /* compute the needed AVStream for each file */
3355 static void build_file_streams(void)
3356 {
3357     FFStream *stream, *stream_next;
3358     AVFormatContext *infile;
3359     int i, ret;
3360
3361     /* gather all streams */
3362     for(stream = first_stream; stream != NULL; stream = stream_next) {
3363         stream_next = stream->next;
3364         if (stream->stream_type == STREAM_TYPE_LIVE &&
3365             !stream->feed) {
3366             /* the stream comes from a file */
3367             /* try to open the file */
3368             /* open stream */
3369             stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3370             if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3371                 /* specific case : if transport stream output to RTP,
3372                    we use a raw transport stream reader */
3373                 stream->ap_in->mpeg2ts_raw = 1;
3374                 stream->ap_in->mpeg2ts_compute_pcr = 1;
3375             }
3376
3377             if ((ret = av_open_input_file(&infile, stream->feed_filename,
3378                                           stream->ifmt, 0, stream->ap_in)) < 0) {
3379                 http_log("could not open %s: %d\n", stream->feed_filename, ret);
3380                 /* remove stream (no need to spend more time on it) */
3381             fail:
3382                 remove_stream(stream);
3383             } else {
3384                 /* find all the AVStreams inside and reference them in
3385                    'stream' */
3386                 if (av_find_stream_info(infile) < 0) {
3387                     http_log("Could not find codec parameters from '%s'\n",
3388                              stream->feed_filename);
3389                     av_close_input_file(infile);
3390                     goto fail;
3391                 }
3392                 extract_mpeg4_header(infile);
3393
3394                 for(i=0;i<infile->nb_streams;i++)
3395                     add_av_stream1(stream, infile->streams[i]->codec);
3396
3397                 av_close_input_file(infile);
3398             }
3399         }
3400     }
3401 }
3402
3403 /* compute the needed AVStream for each feed */
3404 static void build_feed_streams(void)
3405 {
3406     FFStream *stream, *feed;
3407     int i;
3408
3409     /* gather all streams */
3410     for(stream = first_stream; stream != NULL; stream = stream->next) {
3411         feed = stream->feed;
3412         if (feed) {
3413             if (!stream->is_feed) {
3414                 /* we handle a stream coming from a feed */
3415                 for(i=0;i<stream->nb_streams;i++)
3416                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3417             }
3418         }
3419     }
3420
3421     /* gather all streams */
3422     for(stream = first_stream; stream != NULL; stream = stream->next) {
3423         feed = stream->feed;
3424         if (feed) {
3425             if (stream->is_feed) {
3426                 for(i=0;i<stream->nb_streams;i++)
3427                     stream->feed_streams[i] = i;
3428             }
3429         }
3430     }
3431
3432     /* create feed files if needed */
3433     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3434         int fd;
3435
3436         if (url_exist(feed->feed_filename)) {
3437             /* See if it matches */
3438             AVFormatContext *s;
3439             int matches = 0;
3440
3441             if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3442                 /* Now see if it matches */
3443                 if (s->nb_streams == feed->nb_streams) {
3444                     matches = 1;
3445                     for(i=0;i<s->nb_streams;i++) {
3446                         AVStream *sf, *ss;
3447                         sf = feed->streams[i];
3448                         ss = s->streams[i];
3449
3450                         if (sf->index != ss->index ||
3451                             sf->id != ss->id) {
3452                             http_log("Index & Id do not match for stream %d (%s)\n",
3453                                    i, feed->feed_filename);
3454                             matches = 0;
3455                         } else {
3456                             AVCodecContext *ccf, *ccs;
3457
3458                             ccf = sf->codec;
3459                             ccs = ss->codec;
3460 #define CHECK_CODEC(x)  (ccf->x != ccs->x)
3461
3462                             if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3463                                 http_log("Codecs do not match for stream %d\n", i);
3464                                 matches = 0;
3465                             } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3466                                 http_log("Codec bitrates do not match for stream %d\n", i);
3467                                 matches = 0;
3468                             } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3469                                 if (CHECK_CODEC(time_base.den) ||
3470                                     CHECK_CODEC(time_base.num) ||
3471                                     CHECK_CODEC(width) ||
3472                                     CHECK_CODEC(height)) {
3473                                     http_log("Codec width, height and framerate do not match for stream %d\n", i);
3474                                     matches = 0;
3475                                 }
3476                             } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3477                                 if (CHECK_CODEC(sample_rate) ||
3478                                     CHECK_CODEC(channels) ||
3479                                     CHECK_CODEC(frame_size)) {
3480                                     http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3481                                     matches = 0;
3482                                 }
3483                             } else {
3484                                 http_log("Unknown codec type\n");
3485                                 matches = 0;
3486                             }
3487                         }
3488                         if (!matches)
3489                             break;
3490                     }
3491                 } else
3492                     http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3493                         feed->feed_filename, s->nb_streams, feed->nb_streams);
3494
3495                 av_close_input_file(s);
3496             } else
3497                 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3498                         feed->feed_filename);
3499
3500             if (!matches) {
3501                 if (feed->readonly) {
3502                     http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3503                         feed->feed_filename);
3504                     exit(1);
3505                 }
3506                 unlink(feed->feed_filename);
3507             }
3508         }
3509         if (!url_exist(feed->feed_filename)) {
3510             AVFormatContext s1, *s = &s1;
3511
3512             if (feed->readonly) {
3513                 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3514                     feed->feed_filename);
3515                 exit(1);
3516             }
3517
3518             /* only write the header of the ffm file */
3519             if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3520                 http_log("Could not open output feed file '%s'\n",
3521                          feed->feed_filename);
3522                 exit(1);
3523             }
3524             s->oformat = feed->fmt;
3525             s->nb_streams = feed->nb_streams;
3526             for(i=0;i<s->nb_streams;i++) {
3527                 AVStream *st;
3528                 st = feed->streams[i];
3529                 s->streams[i] = st;
3530             }
3531             av_set_parameters(s, NULL);
3532             if (av_write_header(s) < 0) {
3533                 http_log("Container doesn't supports the required parameters\n");
3534                 exit(1);
3535             }
3536             /* XXX: need better api */
3537             av_freep(&s->priv_data);
3538             url_fclose(s->pb);
3539         }
3540         /* get feed size and write index */
3541         fd = open(feed->feed_filename, O_RDONLY);
3542         if (fd < 0) {
3543             http_log("Could not open output feed file '%s'\n",
3544                     feed->feed_filename);
3545             exit(1);
3546         }
3547
3548         feed->feed_write_index = ffm_read_write_index(fd);
3549         feed->feed_size = lseek(fd, 0, SEEK_END);
3550         /* ensure that we do not wrap before the end of file */
3551         if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3552             feed->feed_max_size = feed->feed_size;
3553
3554         close(fd);
3555     }
3556 }
3557
3558 /* compute the bandwidth used by each stream */
3559 static void compute_bandwidth(void)
3560 {
3561     unsigned bandwidth;
3562     int i;
3563     FFStream *stream;
3564
3565     for(stream = first_stream; stream != NULL; stream = stream->next) {
3566         bandwidth = 0;
3567         for(i=0;i<stream->nb_streams;i++) {
3568             AVStream *st = stream->streams[i];
3569             switch(st->codec->codec_type) {
3570             case CODEC_TYPE_AUDIO:
3571             case CODEC_TYPE_VIDEO:
3572                 bandwidth += st->codec->bit_rate;
3573                 break;
3574             default:
3575                 break;
3576             }
3577         }
3578         stream->bandwidth = (bandwidth + 999) / 1000;
3579     }
3580 }
3581
3582 static void get_arg(char *buf, int buf_size, const char **pp)
3583 {
3584     const char *p;
3585     char *q;
3586     int quote;
3587
3588     p = *pp;
3589     while (isspace(*p)) p++;
3590     q = buf;
3591     quote = 0;
3592     if (*p == '\"' || *p == '\'')
3593         quote = *p++;
3594     for(;;) {
3595         if (quote) {
3596             if (*p == quote)
3597                 break;
3598         } else {
3599             if (isspace(*p))
3600                 break;
3601         }
3602         if (*p == '\0')
3603             break;
3604         if ((q - buf) < buf_size - 1)
3605             *q++ = *p;
3606         p++;
3607     }
3608     *q = '\0';
3609     if (quote && *p == quote)
3610         p++;
3611     *pp = p;
3612 }
3613
3614 /* add a codec and set the default parameters */
3615 static void add_codec(FFStream *stream, AVCodecContext *av)
3616 {
3617     AVStream *st;
3618
3619     /* compute default parameters */
3620     switch(av->codec_type) {
3621     case CODEC_TYPE_AUDIO:
3622         if (av->bit_rate == 0)
3623             av->bit_rate = 64000;
3624         if (av->sample_rate == 0)
3625             av->sample_rate = 22050;
3626         if (av->channels == 0)
3627             av->channels = 1;
3628         break;
3629     case CODEC_TYPE_VIDEO:
3630         if (av->bit_rate == 0)
3631             av->bit_rate = 64000;
3632         if (av->time_base.num == 0){
3633             av->time_base.den = 5;
3634             av->time_base.num = 1;
3635         }
3636         if (av->width == 0 || av->height == 0) {
3637             av->width = 160;
3638             av->height = 128;
3639         }
3640         /* Bitrate tolerance is less for streaming */
3641         if (av->bit_rate_tolerance == 0)
3642             av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3643                       (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3644         if (av->qmin == 0)
3645             av->qmin = 3;
3646         if (av->qmax == 0)
3647             av->qmax = 31;
3648         if (av->max_qdiff == 0)
3649             av->max_qdiff = 3;
3650         av->qcompress = 0.5;
3651         av->qblur = 0.5;
3652
3653         if (!av->nsse_weight)
3654             av->nsse_weight = 8;
3655
3656         av->frame_skip_cmp = FF_CMP_DCTMAX;
3657         av->me_method = ME_EPZS;
3658         av->rc_buffer_aggressivity = 1.0;
3659
3660         if (!av->rc_eq)
3661             av->rc_eq = "tex^qComp";
3662         if (!av->i_quant_factor)
3663             av->i_quant_factor = -0.8;
3664         if (!av->b_quant_factor)
3665             av->b_quant_factor = 1.25;
3666         if (!av->b_quant_offset)
3667             av->b_quant_offset = 1.25;
3668         if (!av->rc_max_rate)
3669             av->rc_max_rate = av->bit_rate * 2;
3670
3671         if (av->rc_max_rate && !av->rc_buffer_size) {
3672             av->rc_buffer_size = av->rc_max_rate;
3673         }
3674
3675
3676         break;
3677     default:
3678         abort();
3679     }
3680
3681     st = av_mallocz(sizeof(AVStream));
3682     if (!st)
3683         return;
3684     st->codec = avcodec_alloc_context();
3685     stream->streams[stream->nb_streams++] = st;
3686     memcpy(st->codec, av, sizeof(AVCodecContext));
3687 }
3688
3689 static int opt_audio_codec(const char *arg)
3690 {
3691     AVCodec *p= avcodec_find_encoder_by_name(arg);
3692
3693     if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3694         return CODEC_ID_NONE;
3695
3696     return p->id;
3697 }
3698
3699 static int opt_video_codec(const char *arg)
3700 {
3701     AVCodec *p= avcodec_find_encoder_by_name(arg);
3702
3703     if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3704         return CODEC_ID_NONE;
3705
3706     return p->id;
3707 }
3708
3709 /* simplistic plugin support */
3710
3711 #ifdef HAVE_DLOPEN
3712 static void load_module(const char *filename)
3713 {
3714     void *dll;
3715     void (*init_func)(void);
3716     dll = dlopen(filename, RTLD_NOW);
3717     if (!dll) {
3718         fprintf(stderr, "Could not load module '%s' - %s\n",
3719                 filename, dlerror());
3720         return;
3721     }
3722
3723     init_func = dlsym(dll, "ffserver_module_init");
3724     if (!init_func) {
3725         fprintf(stderr,
3726                 "%s: init function 'ffserver_module_init()' not found\n",
3727                 filename);
3728         dlclose(dll);
3729     }
3730
3731     init_func();
3732 }
3733 #endif
3734
3735 static int opt_default(const char *opt, const char *arg,
3736                        AVCodecContext *avctx, int type)
3737 {
3738     const AVOption *o  = NULL;
3739     const AVOption *o2 = av_find_opt(avctx, opt, NULL, type, type);
3740     if(o2)
3741         o = av_set_string2(avctx, opt, arg, 1);
3742     if(!o)
3743         return -1;
3744     return 0;
3745 }
3746
3747 static int parse_ffconfig(const char *filename)
3748 {
3749     FILE *f;
3750     char line[1024];
3751     char cmd[64];
3752     char arg[1024];
3753     const char *p;
3754     int val, errors, line_num;
3755     FFStream **last_stream, *stream, *redirect;
3756     FFStream **last_feed, *feed;
3757     AVCodecContext audio_enc, video_enc;
3758     int audio_id, video_id;
3759
3760     f = fopen(filename, "r");
3761     if (!f) {
3762         perror(filename);
3763         return -1;
3764     }
3765
3766     errors = 0;
3767     line_num = 0;
3768     first_stream = NULL;
3769     last_stream = &first_stream;
3770     first_feed = NULL;
3771     last_feed = &first_feed;
3772     stream = NULL;
3773     feed = NULL;
3774     redirect = NULL;
3775     audio_id = CODEC_ID_NONE;
3776     video_id = CODEC_ID_NONE;
3777     for(;;) {
3778         if (fgets(line, sizeof(line), f) == NULL)
3779             break;
3780         line_num++;
3781         p = line;
3782         while (isspace(*p))
3783             p++;
3784         if (*p == '\0' || *p == '#')
3785             continue;
3786
3787         get_arg(cmd, sizeof(cmd), &p);
3788
3789         if (!strcasecmp(cmd, "Port")) {
3790             get_arg(arg, sizeof(arg), &p);
3791             val = atoi(arg);
3792             if (val < 1 || val > 65536) {
3793                 fprintf(stderr, "%s:%d: Invalid port: %s\n",
3794                         filename, line_num, arg);
3795                 errors++;
3796             }
3797             my_http_addr.sin_port = htons(val);
3798         } else if (!strcasecmp(cmd, "BindAddress")) {
3799             get_arg(arg, sizeof(arg), &p);
3800             if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3801                 fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3802                         filename, line_num, arg);
3803                 errors++;
3804             }
3805         } else if (!strcasecmp(cmd, "NoDaemon")) {
3806             ffserver_daemon = 0;
3807         } else if (!strcasecmp(cmd, "RTSPPort")) {
3808             get_arg(arg, sizeof(arg), &p);
3809             val = atoi(arg);
3810             if (val < 1 || val > 65536) {
3811                 fprintf(stderr, "%s:%d: Invalid port: %s\n",
3812                         filename, line_num, arg);
3813                 errors++;
3814             }
3815             my_rtsp_addr.sin_port = htons(atoi(arg));
3816         } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3817             get_arg(arg, sizeof(arg), &p);
3818             if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3819                 fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3820                         filename, line_num, arg);
3821                 errors++;
3822             }
3823         } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
3824             get_arg(arg, sizeof(arg), &p);
3825             val = atoi(arg);
3826             if (val < 1 || val > 65536) {
3827                 fprintf(stderr, "%s:%d: Invalid MaxHTTPConnections: %s\n",
3828                         filename, line_num, arg);
3829                 errors++;
3830             }
3831             nb_max_http_connections = val;
3832         } else if (!strcasecmp(cmd, "MaxClients")) {
3833             get_arg(arg, sizeof(arg), &p);
3834             val = atoi(arg);
3835             if (val < 1 || val > nb_max_http_connections) {
3836                 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3837                         filename, line_num, arg);
3838                 errors++;
3839             } else {
3840                 nb_max_connections = val;
3841             }
3842         } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3843             int64_t llval;
3844             get_arg(arg, sizeof(arg), &p);
3845             llval = atoll(arg);
3846             if (llval < 10 || llval > 10000000) {
3847                 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3848                         filename, line_num, arg);
3849                 errors++;
3850             } else
3851                 max_bandwidth = llval;
3852         } else if (!strcasecmp(cmd, "CustomLog")) {
3853             if (!ffserver_debug)
3854                 get_arg(logfilename, sizeof(logfilename), &p);
3855         } else if (!strcasecmp(cmd, "<Feed")) {
3856             /*********************************************/
3857             /* Feed related options */
3858             char *q;
3859             if (stream || feed) {
3860                 fprintf(stderr, "%s:%d: Already in a tag\n",
3861                         filename, line_num);
3862             } else {
3863                 feed = av_mallocz(sizeof(FFStream));
3864                 /* add in stream list */
3865                 *last_stream = feed;
3866                 last_stream = &feed->next;
3867                 /* add in feed list */
3868                 *last_feed = feed;
3869                 last_feed = &feed->next_feed;
3870
3871                 get_arg(feed->filename, sizeof(feed->filename), &p);
3872                 q = strrchr(feed->filename, '>');
3873                 if (*q)
3874                     *q = '\0';
3875                 feed->fmt = guess_format("ffm", NULL, NULL);
3876                 /* defaut feed file */
3877                 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3878                          "/tmp/%s.ffm", feed->filename);
3879                 feed->feed_max_size = 5 * 1024 * 1024;
3880                 feed->is_feed = 1;
3881                 feed->feed = feed; /* self feeding :-) */
3882             }
3883         } else if (!strcasecmp(cmd, "Launch")) {
3884             if (feed) {
3885                 int i;
3886
3887                 feed->child_argv = av_mallocz(64 * sizeof(char *));
3888
3889                 for (i = 0; i < 62; i++) {
3890                     get_arg(arg, sizeof(arg), &p);
3891                     if (!arg[0])
3892                         break;
3893
3894                     feed->child_argv[i] = av_strdup(arg);
3895                 }
3896
3897                 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
3898
3899                 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3900                     "http://%s:%d/%s",
3901                         (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3902                     inet_ntoa(my_http_addr.sin_addr),
3903                     ntohs(my_http_addr.sin_port), feed->filename);
3904             }
3905         } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3906             if (feed) {
3907                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3908                 feed->readonly = 1;
3909             } else if (stream) {
3910                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3911             }
3912         } else if (!strcasecmp(cmd, "File")) {
3913             if (feed) {
3914                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3915             } else if (stream)
3916                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3917         } else if (!strcasecmp(cmd, "FileMaxSize")) {
3918             if (feed) {
3919                 char *p1;
3920                 double fsize;
3921
3922                 get_arg(arg, sizeof(arg), &p);
3923                 p1 = arg;
3924                 fsize = strtod(p1, &p1);
3925                 switch(toupper(*p1)) {
3926                 case 'K':
3927                     fsize *= 1024;
3928                     break;
3929                 case 'M':
3930                     fsize *= 1024 * 1024;
3931                     break;
3932                 case 'G':
3933                     fsize *= 1024 * 1024 * 1024;
3934                     break;
3935                 }
3936                 feed->feed_max_size = (int64_t)fsize;
3937             }
3938         } else if (!strcasecmp(cmd, "</Feed>")) {
3939             if (!feed) {
3940                 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3941                         filename, line_num);
3942                 errors++;
3943             }
3944             feed = NULL;
3945         } else if (!strcasecmp(cmd, "<Stream")) {
3946             /*********************************************/
3947             /* Stream related options */
3948             char *q;
3949             if (stream || feed) {
3950                 fprintf(stderr, "%s:%d: Already in a tag\n",
3951                         filename, line_num);
3952             } else {
3953                 const AVClass *class;
3954                 stream = av_mallocz(sizeof(FFStream));
3955                 *last_stream = stream;
3956                 last_stream = &stream->next;
3957
3958                 get_arg(stream->filename, sizeof(stream->filename), &p);
3959                 q = strrchr(stream->filename, '>');
3960                 if (*q)
3961                     *q = '\0';
3962                 stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3963                 /* fetch avclass so AVOption works
3964                  * FIXME try to use avcodec_get_context_defaults2
3965                  * without changing defaults too much */
3966                 avcodec_get_context_defaults(&video_enc);
3967                 class = video_enc.av_class;
3968                 memset(&audio_enc, 0, sizeof(AVCodecContext));
3969                 memset(&video_enc, 0, sizeof(AVCodecContext));
3970                 audio_enc.av_class = class;
3971                 video_enc.av_class = class;
3972                 audio_id = CODEC_ID_NONE;
3973                 video_id = CODEC_ID_NONE;
3974                 if (stream->fmt) {
3975                     audio_id = stream->fmt->audio_codec;
3976                     video_id = stream->fmt->video_codec;
3977                 }
3978             }
3979         } else if (!strcasecmp(cmd, "Feed")) {
3980             get_arg(arg, sizeof(arg), &p);
3981             if (stream) {
3982                 FFStream *sfeed;
3983
3984                 sfeed = first_feed;
3985                 while (sfeed != NULL) {
3986                     if (!strcmp(sfeed->filename, arg))
3987                         break;
3988                     sfeed = sfeed->next_feed;
3989                 }
3990                 if (!sfeed)
3991                     fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3992                             filename, line_num, arg);
3993                 else
3994                     stream->feed = sfeed;
3995             }
3996         } else if (!strcasecmp(cmd, "Format")) {
3997             get_arg(arg, sizeof(arg), &p);
3998             if (stream) {
3999                 if (!strcmp(arg, "status")) {
4000                     stream->stream_type = STREAM_TYPE_STATUS;
4001                     stream->fmt = NULL;
4002                 } else {
4003                     stream->stream_type = STREAM_TYPE_LIVE;
4004                     /* jpeg cannot be used here, so use single frame jpeg */
4005                     if (!strcmp(arg, "jpeg"))
4006                         strcpy(arg, "mjpeg");
4007                     stream->fmt = guess_stream_format(arg, NULL, NULL);
4008                     if (!stream->fmt) {
4009                         fprintf(stderr, "%s:%d: Unknown Format: %s\n",
4010                                 filename, line_num, arg);
4011                         errors++;
4012                     }
4013                 }
4014                 if (stream->fmt) {
4015                     audio_id = stream->fmt->audio_codec;
4016                     video_id = stream->fmt->video_codec;
4017                 }
4018             }
4019         } else if (!strcasecmp(cmd, "InputFormat")) {
4020             get_arg(arg, sizeof(arg), &p);
4021             stream->ifmt = av_find_input_format(arg);
4022             if (!stream->ifmt) {
4023                 fprintf(stderr, "%s:%d: Unknown input format: %s\n",
4024                         filename, line_num, arg);
4025             }
4026         } else if (!strcasecmp(cmd, "FaviconURL")) {
4027             if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4028                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4029             } else {
4030                 fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
4031                             filename, line_num);
4032                 errors++;
4033             }
4034         } else if (!strcasecmp(cmd, "Author")) {
4035             if (stream)
4036                 get_arg(stream->author, sizeof(stream->author), &p);
4037         } else if (!strcasecmp(cmd, "Comment")) {
4038             if (stream)
4039                 get_arg(stream->comment, sizeof(stream->comment), &p);
4040         } else if (!strcasecmp(cmd, "Copyright")) {
4041             if (stream)
4042                 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4043         } else if (!strcasecmp(cmd, "Title")) {
4044             if (stream)
4045                 get_arg(stream->title, sizeof(stream->title), &p);
4046         } else if (!strcasecmp(cmd, "Preroll")) {
4047             get_arg(arg, sizeof(arg), &p);
4048             if (stream)
4049                 stream->prebuffer = atof(arg) * 1000;
4050         } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4051             if (stream)
4052                 stream->send_on_key = 1;
4053         } else if (!strcasecmp(cmd, "AudioCodec")) {
4054             get_arg(arg, sizeof(arg), &p);
4055             audio_id = opt_audio_codec(arg);
4056             if (audio_id == CODEC_ID_NONE) {
4057                 fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4058                         filename, line_num, arg);
4059                 errors++;
4060             }
4061         } else if (!strcasecmp(cmd, "VideoCodec")) {
4062             get_arg(arg, sizeof(arg), &p);
4063             video_id = opt_video_codec(arg);
4064             if (video_id == CODEC_ID_NONE) {
4065                 fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4066                         filename, line_num, arg);
4067                 errors++;
4068             }
4069         } else if (!strcasecmp(cmd, "MaxTime")) {
4070             get_arg(arg, sizeof(arg), &p);
4071             if (stream)
4072                 stream->max_time = atof(arg) * 1000;
4073         } else if (!strcasecmp(cmd, "AudioBitRate")) {
4074             get_arg(arg, sizeof(arg), &p);
4075             if (stream)
4076                 audio_enc.bit_rate = atoi(arg) * 1000;
4077         } else if (!strcasecmp(cmd, "AudioChannels")) {
4078             get_arg(arg, sizeof(arg), &p);
4079             if (stream)
4080                 audio_enc.channels = atoi(arg);
4081         } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4082             get_arg(arg, sizeof(arg), &p);
4083             if (stream)
4084                 audio_enc.sample_rate = atoi(arg);
4085         } else if (!strcasecmp(cmd, "AudioQuality")) {
4086             get_arg(arg, sizeof(arg), &p);
4087             if (stream) {
4088 //                audio_enc.quality = atof(arg) * 1000;
4089             }
4090         } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4091             if (stream) {
4092                 int minrate, maxrate;
4093
4094                 get_arg(arg, sizeof(arg), &p);
4095
4096                 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4097                     video_enc.rc_min_rate = minrate * 1000;
4098                     video_enc.rc_max_rate = maxrate * 1000;
4099                 } else {
4100                     fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4101                             filename, line_num, arg);
4102                     errors++;
4103                 }
4104             }
4105         } else if (!strcasecmp(cmd, "Debug")) {
4106             if (stream) {
4107                 get_arg(arg, sizeof(arg), &p);
4108                 video_enc.debug = strtol(arg,0,0);
4109             }
4110         } else if (!strcasecmp(cmd, "Strict")) {
4111             if (stream) {
4112                 get_arg(arg, sizeof(arg), &p);
4113                 video_enc.strict_std_compliance = atoi(arg);
4114             }
4115         } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4116             if (stream) {
4117                 get_arg(arg, sizeof(arg), &p);
4118                 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4119             }
4120         } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4121             if (stream) {
4122                 get_arg(arg, sizeof(arg), &p);
4123                 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4124             }
4125         } else if (!strcasecmp(cmd, "VideoBitRate")) {
4126             get_arg(arg, sizeof(arg), &p);
4127             if (stream) {
4128                 video_enc.bit_rate = atoi(arg) * 1000;
4129             }
4130         } else if (!strcasecmp(cmd, "VideoSize")) {
4131             get_arg(arg, sizeof(arg), &p);
4132             if (stream) {
4133                 av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4134                 if ((video_enc.width % 16) != 0 ||
4135                     (video_enc.height % 16) != 0) {
4136                     fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4137                             filename, line_num);
4138                     errors++;
4139                 }
4140             }
4141         } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4142             get_arg(arg, sizeof(arg), &p);
4143             if (stream) {
4144                 AVRational frame_rate;
4145                 if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
4146                     fprintf(stderr, "Incorrect frame rate\n");
4147                     errors++;
4148                 } else {
4149                     video_enc.time_base.num = frame_rate.den;
4150                     video_enc.time_base.den = frame_rate.num;
4151                 }
4152             }
4153         } else if (!strcasecmp(cmd, "VideoGopSize")) {
4154             get_arg(arg, sizeof(arg), &p);
4155             if (stream)
4156                 video_enc.gop_size = atoi(arg);
4157         } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4158             if (stream)
4159                 video_enc.gop_size = 1;
4160         } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4161             if (stream)
4162                 video_enc.mb_decision = FF_MB_DECISION_BITS;
4163         } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4164             if (stream) {
4165                 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4166                 video_enc.flags |= CODEC_FLAG_4MV;
4167             }
4168         } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4169                    !strcasecmp(cmd, "AVOptionAudio")) {
4170             char arg2[1024];
4171             AVCodecContext *avctx;
4172             int type;
4173             get_arg(arg, sizeof(arg), &p);
4174             get_arg(arg2, sizeof(arg2), &p);
4175             if (!strcasecmp(cmd, "AVOptionVideo")) {
4176                 avctx = &video_enc;
4177                 type = AV_OPT_FLAG_VIDEO_PARAM;
4178             } else {
4179                 avctx = &audio_enc;
4180                 type = AV_OPT_FLAG_AUDIO_PARAM;
4181             }
4182             if (opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4183                 fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
4184                 errors++;
4185             }
4186         } else if (!strcasecmp(cmd, "VideoTag")) {
4187             get_arg(arg, sizeof(arg), &p);
4188             if ((strlen(arg) == 4) && stream)
4189                 video_enc.codec_tag = ff_get_fourcc(arg);
4190         } else if (!strcasecmp(cmd, "BitExact")) {
4191             if (stream)
4192                 video_enc.flags |= CODEC_FLAG_BITEXACT;
4193         } else if (!strcasecmp(cmd, "DctFastint")) {
4194             if (stream)
4195                 video_enc.dct_algo  = FF_DCT_FASTINT;
4196         } else if (!strcasecmp(cmd, "IdctSimple")) {
4197             if (stream)
4198                 video_enc.idct_algo = FF_IDCT_SIMPLE;
4199         } else if (!strcasecmp(cmd, "Qscale")) {
4200             get_arg(arg, sizeof(arg), &p);
4201             if (stream) {
4202                 video_enc.flags |= CODEC_FLAG_QSCALE;
4203                 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4204             }
4205         } else if (!strcasecmp(cmd, "VideoQDiff")) {
4206             get_arg(arg, sizeof(arg), &p);
4207             if (stream) {
4208                 video_enc.max_qdiff = atoi(arg);
4209                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4210                     fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4211                             filename, line_num);
4212                     errors++;
4213                 }
4214             }
4215         } else if (!strcasecmp(cmd, "VideoQMax")) {
4216             get_arg(arg, sizeof(arg), &p);
4217             if (stream) {
4218                 video_enc.qmax = atoi(arg);
4219                 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4220                     fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4221                             filename, line_num);
4222                     errors++;
4223                 }
4224             }
4225         } else if (!strcasecmp(cmd, "VideoQMin")) {
4226             get_arg(arg, sizeof(arg), &p);
4227             if (stream) {
4228                 video_enc.qmin = atoi(arg);
4229                 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4230                     fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4231                             filename, line_num);
4232                     errors++;
4233                 }
4234             }
4235         } else if (!strcasecmp(cmd, "LumaElim")) {
4236             get_arg(arg, sizeof(arg), &p);
4237             if (stream)
4238                 video_enc.luma_elim_threshold = atoi(arg);
4239         } else if (!strcasecmp(cmd, "ChromaElim")) {
4240             get_arg(arg, sizeof(arg), &p);
4241             if (stream)
4242                 video_enc.chroma_elim_threshold = atoi(arg);
4243         } else if (!strcasecmp(cmd, "LumiMask")) {
4244             get_arg(arg, sizeof(arg), &p);
4245             if (stream)
4246                 video_enc.lumi_masking = atof(arg);
4247         } else if (!strcasecmp(cmd, "DarkMask")) {
4248             get_arg(arg, sizeof(arg), &p);
4249             if (stream)
4250                 video_enc.dark_masking = atof(arg);
4251         } else if (!strcasecmp(cmd, "NoVideo")) {
4252             video_id = CODEC_ID_NONE;
4253         } else if (!strcasecmp(cmd, "NoAudio")) {
4254             audio_id = CODEC_ID_NONE;
4255         } else if (!strcasecmp(cmd, "ACL")) {
4256             IPAddressACL acl;
4257
4258             get_arg(arg, sizeof(arg), &p);
4259             if (strcasecmp(arg, "allow") == 0)
4260                 acl.action = IP_ALLOW;
4261             else if (strcasecmp(arg, "deny") == 0)
4262                 acl.action = IP_DENY;
4263             else {
4264                 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4265                         filename, line_num, arg);
4266                 errors++;
4267             }
4268
4269             get_arg(arg, sizeof(arg), &p);
4270
4271             if (resolve_host(&acl.first, arg) != 0) {
4272                 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4273                         filename, line_num, arg);
4274                 errors++;
4275             } else
4276                 acl.last = acl.first;
4277
4278             get_arg(arg, sizeof(arg), &p);
4279
4280             if (arg[0]) {
4281                 if (resolve_host(&acl.last, arg) != 0) {
4282                     fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4283                             filename, line_num, arg);
4284                     errors++;
4285                 }
4286             }
4287
4288             if (!errors) {
4289                 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4290                 IPAddressACL **naclp = 0;
4291
4292                 acl.next = 0;
4293                 *nacl = acl;
4294
4295                 if (stream)
4296                     naclp = &stream->acl;
4297                 else if (feed)
4298                     naclp = &feed->acl;
4299                 else {
4300                     fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4301                             filename, line_num);
4302                     errors++;
4303                 }
4304
4305                 if (naclp) {
4306                     while (*naclp)
4307                         naclp = &(*naclp)->next;
4308
4309                     *naclp = nacl;
4310                 }
4311             }
4312         } else if (!strcasecmp(cmd, "RTSPOption")) {
4313             get_arg(arg, sizeof(arg), &p);
4314             if (stream) {
4315                 av_freep(&stream->rtsp_option);
4316                 stream->rtsp_option = av_strdup(arg);
4317             }
4318         } else if (!strcasecmp(cmd, "MulticastAddress")) {
4319             get_arg(arg, sizeof(arg), &p);
4320             if (stream) {
4321                 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4322                     fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4323                             filename, line_num, arg);
4324                     errors++;
4325                 }
4326                 stream->is_multicast = 1;
4327                 stream->loop = 1; /* default is looping */
4328             }
4329         } else if (!strcasecmp(cmd, "MulticastPort")) {
4330             get_arg(arg, sizeof(arg), &p);
4331             if (stream)
4332                 stream->multicast_port = atoi(arg);
4333         } else if (!strcasecmp(cmd, "MulticastTTL")) {
4334             get_arg(arg, sizeof(arg), &p);
4335             if (stream)
4336                 stream->multicast_ttl = atoi(arg);
4337         } else if (!strcasecmp(cmd, "NoLoop")) {
4338             if (stream)
4339                 stream->loop = 0;
4340         } else if (!strcasecmp(cmd, "</Stream>")) {
4341             if (!stream) {
4342                 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4343                         filename, line_num);
4344                 errors++;
4345             } else {
4346                 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4347                     if (audio_id != CODEC_ID_NONE) {
4348                         audio_enc.codec_type = CODEC_TYPE_AUDIO;
4349                         audio_enc.codec_id = audio_id;
4350                         add_codec(stream, &audio_enc);
4351                     }
4352                     if (video_id != CODEC_ID_NONE) {
4353                         video_enc.codec_type = CODEC_TYPE_VIDEO;
4354                         video_enc.codec_id = video_id;
4355                         add_codec(stream, &video_enc);
4356                     }
4357                 }
4358                 stream = NULL;
4359             }
4360         } else if (!strcasecmp(cmd, "<Redirect")) {
4361             /*********************************************/
4362             char *q;
4363             if (stream || feed || redirect) {
4364                 fprintf(stderr, "%s:%d: Already in a tag\n",
4365                         filename, line_num);
4366                 errors++;
4367             } else {
4368                 redirect = av_mallocz(sizeof(FFStream));
4369                 *last_stream = redirect;
4370                 last_stream = &redirect->next;
4371
4372                 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4373                 q = strrchr(redirect->filename, '>');
4374                 if (*q)
4375                     *q = '\0';
4376                 redirect->stream_type = STREAM_TYPE_REDIRECT;
4377             }
4378         } else if (!strcasecmp(cmd, "URL")) {
4379             if (redirect)
4380                 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4381         } else if (!strcasecmp(cmd, "</Redirect>")) {
4382             if (!redirect) {
4383                 fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4384                         filename, line_num);
4385                 errors++;
4386             } else {
4387                 if (!redirect->feed_filename[0]) {
4388                     fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4389                             filename, line_num);
4390                     errors++;
4391                 }
4392                 redirect = NULL;
4393             }
4394         } else if (!strcasecmp(cmd, "LoadModule")) {
4395             get_arg(arg, sizeof(arg), &p);
4396 #ifdef HAVE_DLOPEN
4397             load_module(arg);
4398 #else
4399             fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4400                     filename, line_num, arg);
4401             errors++;
4402 #endif
4403         } else {
4404             fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4405                     filename, line_num, cmd);
4406             errors++;
4407         }
4408     }
4409
4410     fclose(f);
4411     if (errors)
4412         return -1;
4413     else
4414         return 0;
4415 }
4416
4417 static void handle_child_exit(int sig)
4418 {
4419     pid_t pid;
4420     int status;
4421
4422     while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4423         FFStream *feed;
4424
4425         for (feed = first_feed; feed; feed = feed->next) {
4426             if (feed->pid == pid) {
4427                 int uptime = time(0) - feed->pid_start;
4428
4429                 feed->pid = 0;
4430                 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4431
4432                 if (uptime < 30)
4433                     /* Turn off any more restarts */
4434                     feed->child_argv = 0;
4435             }
4436         }
4437     }
4438
4439     need_to_start_children = 1;
4440 }
4441
4442 static void opt_debug()
4443 {
4444     ffserver_debug = 1;
4445     ffserver_daemon = 0;
4446     logfilename[0] = '-';
4447 }
4448
4449 static void opt_show_help(void)
4450 {
4451     printf("usage: ffserver [options]\n"
4452            "Hyper fast multi format Audio/Video streaming server\n");
4453     printf("\n");
4454     show_help_options(options, "Main options:\n", 0, 0);
4455 }
4456
4457 static const OptionDef options[] = {
4458     { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4459     { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4460     { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4461     { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4462     { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4463     { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4464     { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4465     { NULL },
4466 };
4467
4468 int main(int argc, char **argv)
4469 {
4470     struct sigaction sigact;
4471
4472     av_register_all();
4473
4474     show_banner();
4475
4476     config_filename = "/etc/ffserver.conf";
4477
4478     my_program_name = argv[0];
4479     my_program_dir = getcwd(0, 0);
4480     ffserver_daemon = 1;
4481
4482     parse_options(argc, argv, options, NULL);
4483
4484     unsetenv("http_proxy");             /* Kill the http_proxy */
4485
4486     av_init_random(av_gettime() + (getpid() << 16), &random_state);
4487
4488     memset(&sigact, 0, sizeof(sigact));
4489     sigact.sa_handler = handle_child_exit;
4490     sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4491     sigaction(SIGCHLD, &sigact, 0);
4492
4493     if (parse_ffconfig(config_filename) < 0) {
4494         fprintf(stderr, "Incorrect config file - exiting.\n");
4495         exit(1);
4496     }
4497
4498     /* open log file if needed */
4499     if (logfilename[0] != '\0') {
4500         if (!strcmp(logfilename, "-"))
4501             logfile = stdout;
4502         else
4503             logfile = fopen(logfilename, "a");
4504         av_log_set_callback(http_av_log);
4505     }
4506
4507     build_file_streams();
4508
4509     build_feed_streams();
4510
4511     compute_bandwidth();
4512
4513     /* put the process in background and detach it from its TTY */
4514     if (ffserver_daemon) {
4515         int pid;
4516
4517         pid = fork();
4518         if (pid < 0) {
4519             perror("fork");
4520             exit(1);
4521         } else if (pid > 0) {
4522             /* parent : exit */
4523             exit(0);
4524         } else {
4525             /* child */
4526             setsid();
4527             close(0);
4528             open("/dev/null", O_RDWR);
4529             if (strcmp(logfilename, "-") != 0) {
4530                 close(1);
4531                 dup(0);
4532             }
4533             close(2);
4534             dup(0);
4535         }
4536     }
4537
4538     /* signal init */
4539     signal(SIGPIPE, SIG_IGN);
4540
4541     if (ffserver_daemon)
4542         chdir("/");
4543
4544     if (http_server() < 0) {
4545         http_log("Could not start server\n");
4546         exit(1);
4547     }
4548
4549     return 0;
4550 }