• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files

ffserver.c

Go to the documentation of this file.
00001 /*
00002  * Multiple format streaming server
00003  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 #define _XOPEN_SOURCE 600
00023 
00024 #include "config.h"
00025 #if !HAVE_CLOSESOCKET
00026 #define closesocket close
00027 #endif
00028 #include <string.h>
00029 #include <strings.h>
00030 #include <stdlib.h>
00031 #include "libavformat/avformat.h"
00032 #include "libavformat/network.h"
00033 #include "libavformat/os_support.h"
00034 #include "libavformat/rtpdec.h"
00035 #include "libavformat/rtsp.h"
00036 #include "libavutil/avstring.h"
00037 #include "libavutil/lfg.h"
00038 #include "libavutil/random_seed.h"
00039 #include "libavutil/parseutils.h"
00040 #include "libavcodec/opt.h"
00041 #include <stdarg.h>
00042 #include <unistd.h>
00043 #include <fcntl.h>
00044 #include <sys/ioctl.h>
00045 #if HAVE_POLL_H
00046 #include <poll.h>
00047 #endif
00048 #include <errno.h>
00049 #include <sys/time.h>
00050 #include <time.h>
00051 #include <sys/wait.h>
00052 #include <signal.h>
00053 #if HAVE_DLFCN_H
00054 #include <dlfcn.h>
00055 #endif
00056 
00057 #include "cmdutils.h"
00058 
00059 const char program_name[] = "FFserver";
00060 const int program_birth_year = 2000;
00061 
00062 static const OptionDef options[];
00063 
00064 enum HTTPState {
00065     HTTPSTATE_WAIT_REQUEST,
00066     HTTPSTATE_SEND_HEADER,
00067     HTTPSTATE_SEND_DATA_HEADER,
00068     HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
00069     HTTPSTATE_SEND_DATA_TRAILER,
00070     HTTPSTATE_RECEIVE_DATA,
00071     HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
00072     HTTPSTATE_READY,
00073 
00074     RTSPSTATE_WAIT_REQUEST,
00075     RTSPSTATE_SEND_REPLY,
00076     RTSPSTATE_SEND_PACKET,
00077 };
00078 
00079 static const char *http_state[] = {
00080     "HTTP_WAIT_REQUEST",
00081     "HTTP_SEND_HEADER",
00082 
00083     "SEND_DATA_HEADER",
00084     "SEND_DATA",
00085     "SEND_DATA_TRAILER",
00086     "RECEIVE_DATA",
00087     "WAIT_FEED",
00088     "READY",
00089 
00090     "RTSP_WAIT_REQUEST",
00091     "RTSP_SEND_REPLY",
00092     "RTSP_SEND_PACKET",
00093 };
00094 
00095 #if !FF_API_MAX_STREAMS
00096 #define MAX_STREAMS 20
00097 #endif
00098 
00099 #define IOBUFFER_INIT_SIZE 8192
00100 
00101 /* timeouts are in ms */
00102 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
00103 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
00104 
00105 #define SYNC_TIMEOUT (10 * 1000)
00106 
00107 typedef struct RTSPActionServerSetup {
00108     uint32_t ipaddr;
00109     char transport_option[512];
00110 } RTSPActionServerSetup;
00111 
00112 typedef struct {
00113     int64_t count1, count2;
00114     int64_t time1, time2;
00115 } DataRateData;
00116 
00117 /* context associated with one connection */
00118 typedef struct HTTPContext {
00119     enum HTTPState state;
00120     int fd; /* socket file descriptor */
00121     struct sockaddr_in from_addr; /* origin */
00122     struct pollfd *poll_entry; /* used when polling */
00123     int64_t timeout;
00124     uint8_t *buffer_ptr, *buffer_end;
00125     int http_error;
00126     int post;
00127     int chunked_encoding;
00128     int chunk_size;               /* 0 if it needs to be read */
00129     struct HTTPContext *next;
00130     int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
00131     int64_t data_count;
00132     /* feed input */
00133     int feed_fd;
00134     /* input format handling */
00135     AVFormatContext *fmt_in;
00136     int64_t start_time;            /* In milliseconds - this wraps fairly often */
00137     int64_t first_pts;            /* initial pts value */
00138     int64_t cur_pts;             /* current pts value from the stream in us */
00139     int64_t cur_frame_duration;  /* duration of the current frame in us */
00140     int cur_frame_bytes;       /* output frame size, needed to compute
00141                                   the time at which we send each
00142                                   packet */
00143     int pts_stream_index;        /* stream we choose as clock reference */
00144     int64_t cur_clock;           /* current clock reference value in us */
00145     /* output format handling */
00146     struct FFStream *stream;
00147     /* -1 is invalid stream */
00148     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
00149     int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
00150     int switch_pending;
00151     AVFormatContext fmt_ctx; /* instance of FFStream for one user */
00152     int last_packet_sent; /* true if last data packet was sent */
00153     int suppress_log;
00154     DataRateData datarate;
00155     int wmp_client_id;
00156     char protocol[16];
00157     char method[16];
00158     char url[128];
00159     int buffer_size;
00160     uint8_t *buffer;
00161     int is_packetized; /* if true, the stream is packetized */
00162     int packet_stream_index; /* current stream for output in state machine */
00163 
00164     /* RTSP state specific */
00165     uint8_t *pb_buffer; /* XXX: use that in all the code */
00166     AVIOContext *pb;
00167     int seq; /* RTSP sequence number */
00168 
00169     /* RTP state specific */
00170     enum RTSPLowerTransport rtp_protocol;
00171     char session_id[32]; /* session id */
00172     AVFormatContext *rtp_ctx[MAX_STREAMS];
00173 
00174     /* RTP/UDP specific */
00175     URLContext *rtp_handles[MAX_STREAMS];
00176 
00177     /* RTP/TCP specific */
00178     struct HTTPContext *rtsp_c;
00179     uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
00180 } HTTPContext;
00181 
00182 /* each generated stream is described here */
00183 enum StreamType {
00184     STREAM_TYPE_LIVE,
00185     STREAM_TYPE_STATUS,
00186     STREAM_TYPE_REDIRECT,
00187 };
00188 
00189 enum IPAddressAction {
00190     IP_ALLOW = 1,
00191     IP_DENY,
00192 };
00193 
00194 typedef struct IPAddressACL {
00195     struct IPAddressACL *next;
00196     enum IPAddressAction action;
00197     /* These are in host order */
00198     struct in_addr first;
00199     struct in_addr last;
00200 } IPAddressACL;
00201 
00202 /* description of each stream of the ffserver.conf file */
00203 typedef struct FFStream {
00204     enum StreamType stream_type;
00205     char filename[1024];     /* stream filename */
00206     struct FFStream *feed;   /* feed we are using (can be null if
00207                                 coming from file) */
00208     AVFormatParameters *ap_in; /* input parameters */
00209     AVInputFormat *ifmt;       /* if non NULL, force input format */
00210     AVOutputFormat *fmt;
00211     IPAddressACL *acl;
00212     char dynamic_acl[1024];
00213     int nb_streams;
00214     int prebuffer;      /* Number of millseconds early to start */
00215     int64_t max_time;      /* Number of milliseconds to run */
00216     int send_on_key;
00217     AVStream *streams[MAX_STREAMS];
00218     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
00219     char feed_filename[1024]; /* file name of the feed storage, or
00220                                  input file name for a stream */
00221     char author[512];
00222     char title[512];
00223     char copyright[512];
00224     char comment[512];
00225     pid_t pid;  /* Of ffmpeg process */
00226     time_t pid_start;  /* Of ffmpeg process */
00227     char **child_argv;
00228     struct FFStream *next;
00229     unsigned bandwidth; /* bandwidth, in kbits/s */
00230     /* RTSP options */
00231     char *rtsp_option;
00232     /* multicast specific */
00233     int is_multicast;
00234     struct in_addr multicast_ip;
00235     int multicast_port; /* first port used for multicast */
00236     int multicast_ttl;
00237     int loop; /* if true, send the stream in loops (only meaningful if file) */
00238 
00239     /* feed specific */
00240     int feed_opened;     /* true if someone is writing to the feed */
00241     int is_feed;         /* true if it is a feed */
00242     int readonly;        /* True if writing is prohibited to the file */
00243     int truncate;        /* True if feeder connection truncate the feed file */
00244     int conns_served;
00245     int64_t bytes_served;
00246     int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
00247     int64_t feed_write_index;   /* current write position in feed (it wraps around) */
00248     int64_t feed_size;          /* current size of feed */
00249     struct FFStream *next_feed;
00250 } FFStream;
00251 
00252 typedef struct FeedData {
00253     long long data_count;
00254     float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
00255 } FeedData;
00256 
00257 static struct sockaddr_in my_http_addr;
00258 static struct sockaddr_in my_rtsp_addr;
00259 
00260 static char logfilename[1024];
00261 static HTTPContext *first_http_ctx;
00262 static FFStream *first_feed;   /* contains only feeds */
00263 static FFStream *first_stream; /* contains all streams, including feeds */
00264 
00265 static void new_connection(int server_fd, int is_rtsp);
00266 static void close_connection(HTTPContext *c);
00267 
00268 /* HTTP handling */
00269 static int handle_connection(HTTPContext *c);
00270 static int http_parse_request(HTTPContext *c);
00271 static int http_send_data(HTTPContext *c);
00272 static void compute_status(HTTPContext *c);
00273 static int open_input_stream(HTTPContext *c, const char *info);
00274 static int http_start_receive_data(HTTPContext *c);
00275 static int http_receive_data(HTTPContext *c);
00276 
00277 /* RTSP handling */
00278 static int rtsp_parse_request(HTTPContext *c);
00279 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
00280 static void rtsp_cmd_options(HTTPContext *c, const char *url);
00281 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
00282 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
00283 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
00284 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
00285 
00286 /* SDP handling */
00287 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
00288                                    struct in_addr my_ip);
00289 
00290 /* RTP handling */
00291 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
00292                                        FFStream *stream, const char *session_id,
00293                                        enum RTSPLowerTransport rtp_protocol);
00294 static int rtp_new_av_stream(HTTPContext *c,
00295                              int stream_index, struct sockaddr_in *dest_addr,
00296                              HTTPContext *rtsp_c);
00297 
00298 static const char *my_program_name;
00299 static const char *my_program_dir;
00300 
00301 static const char *config_filename = "/etc/ffserver.conf";
00302 
00303 static int ffserver_debug;
00304 static int ffserver_daemon;
00305 static int no_launch;
00306 static int need_to_start_children;
00307 
00308 /* maximum number of simultaneous HTTP connections */
00309 static unsigned int nb_max_http_connections = 2000;
00310 static unsigned int nb_max_connections = 5;
00311 static unsigned int nb_connections;
00312 
00313 static uint64_t max_bandwidth = 1000;
00314 static uint64_t current_bandwidth;
00315 
00316 static int64_t cur_time;           // Making this global saves on passing it around everywhere
00317 
00318 static AVLFG random_state;
00319 
00320 static FILE *logfile = NULL;
00321 
00322 /* FIXME: make ffserver work with IPv6 */
00323 /* resolve host with also IP address parsing */
00324 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
00325 {
00326 
00327     if (!ff_inet_aton(hostname, sin_addr)) {
00328 #if HAVE_GETADDRINFO
00329         struct addrinfo *ai, *cur;
00330         struct addrinfo hints;
00331         memset(&hints, 0, sizeof(hints));
00332         hints.ai_family = AF_INET;
00333         if (getaddrinfo(hostname, NULL, &hints, &ai))
00334             return -1;
00335         /* getaddrinfo returns a linked list of addrinfo structs.
00336          * Even if we set ai_family = AF_INET above, make sure
00337          * that the returned one actually is of the correct type. */
00338         for (cur = ai; cur; cur = cur->ai_next) {
00339             if (cur->ai_family == AF_INET) {
00340                 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
00341                 freeaddrinfo(ai);
00342                 return 0;
00343             }
00344         }
00345         freeaddrinfo(ai);
00346         return -1;
00347 #else
00348         struct hostent *hp;
00349         hp = gethostbyname(hostname);
00350         if (!hp)
00351             return -1;
00352         memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
00353 #endif
00354     }
00355     return 0;
00356 }
00357 
00358 static char *ctime1(char *buf2)
00359 {
00360     time_t ti;
00361     char *p;
00362 
00363     ti = time(NULL);
00364     p = ctime(&ti);
00365     strcpy(buf2, p);
00366     p = buf2 + strlen(p) - 1;
00367     if (*p == '\n')
00368         *p = '\0';
00369     return buf2;
00370 }
00371 
00372 static void http_vlog(const char *fmt, va_list vargs)
00373 {
00374     static int print_prefix = 1;
00375     if (logfile) {
00376         if (print_prefix) {
00377             char buf[32];
00378             ctime1(buf);
00379             fprintf(logfile, "%s ", buf);
00380         }
00381         print_prefix = strstr(fmt, "\n") != NULL;
00382         vfprintf(logfile, fmt, vargs);
00383         fflush(logfile);
00384     }
00385 }
00386 
00387 #ifdef __GNUC__
00388 __attribute__ ((format (printf, 1, 2)))
00389 #endif
00390 static void http_log(const char *fmt, ...)
00391 {
00392     va_list vargs;
00393     va_start(vargs, fmt);
00394     http_vlog(fmt, vargs);
00395     va_end(vargs);
00396 }
00397 
00398 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
00399 {
00400     static int print_prefix = 1;
00401     AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
00402     if (level > av_log_get_level())
00403         return;
00404     if (print_prefix && avc)
00405         http_log("[%s @ %p]", avc->item_name(ptr), ptr);
00406     print_prefix = strstr(fmt, "\n") != NULL;
00407     http_vlog(fmt, vargs);
00408 }
00409 
00410 static void log_connection(HTTPContext *c)
00411 {
00412     if (c->suppress_log)
00413         return;
00414 
00415     http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
00416              inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
00417              c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
00418 }
00419 
00420 static void update_datarate(DataRateData *drd, int64_t count)
00421 {
00422     if (!drd->time1 && !drd->count1) {
00423         drd->time1 = drd->time2 = cur_time;
00424         drd->count1 = drd->count2 = count;
00425     } else if (cur_time - drd->time2 > 5000) {
00426         drd->time1 = drd->time2;
00427         drd->count1 = drd->count2;
00428         drd->time2 = cur_time;
00429         drd->count2 = count;
00430     }
00431 }
00432 
00433 /* In bytes per second */
00434 static int compute_datarate(DataRateData *drd, int64_t count)
00435 {
00436     if (cur_time == drd->time1)
00437         return 0;
00438 
00439     return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
00440 }
00441 
00442 
00443 static void start_children(FFStream *feed)
00444 {
00445     if (no_launch)
00446         return;
00447 
00448     for (; feed; feed = feed->next) {
00449         if (feed->child_argv && !feed->pid) {
00450             feed->pid_start = time(0);
00451 
00452             feed->pid = fork();
00453 
00454             if (feed->pid < 0) {
00455                 http_log("Unable to create children\n");
00456                 exit(1);
00457             }
00458             if (!feed->pid) {
00459                 /* In child */
00460                 char pathname[1024];
00461                 char *slash;
00462                 int i;
00463 
00464                 av_strlcpy(pathname, my_program_name, sizeof(pathname));
00465 
00466                 slash = strrchr(pathname, '/');
00467                 if (!slash)
00468                     slash = pathname;
00469                 else
00470                     slash++;
00471                 strcpy(slash, "ffmpeg");
00472 
00473                 http_log("Launch commandline: ");
00474                 http_log("%s ", pathname);
00475                 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
00476                     http_log("%s ", feed->child_argv[i]);
00477                 http_log("\n");
00478 
00479                 for (i = 3; i < 256; i++)
00480                     close(i);
00481 
00482                 if (!ffserver_debug) {
00483                     i = open("/dev/null", O_RDWR);
00484                     if (i != -1) {
00485                         dup2(i, 0);
00486                         dup2(i, 1);
00487                         dup2(i, 2);
00488                         close(i);
00489                     }
00490                 }
00491 
00492                 /* This is needed to make relative pathnames work */
00493                 chdir(my_program_dir);
00494 
00495                 signal(SIGPIPE, SIG_DFL);
00496 
00497                 execvp(pathname, feed->child_argv);
00498 
00499                 _exit(1);
00500             }
00501         }
00502     }
00503 }
00504 
00505 /* open a listening socket */
00506 static int socket_open_listen(struct sockaddr_in *my_addr)
00507 {
00508     int server_fd, tmp;
00509 
00510     server_fd = socket(AF_INET,SOCK_STREAM,0);
00511     if (server_fd < 0) {
00512         perror ("socket");
00513         return -1;
00514     }
00515 
00516     tmp = 1;
00517     setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
00518 
00519     if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
00520         char bindmsg[32];
00521         snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
00522         perror (bindmsg);
00523         closesocket(server_fd);
00524         return -1;
00525     }
00526 
00527     if (listen (server_fd, 5) < 0) {
00528         perror ("listen");
00529         closesocket(server_fd);
00530         return -1;
00531     }
00532     ff_socket_nonblock(server_fd, 1);
00533 
00534     return server_fd;
00535 }
00536 
00537 /* start all multicast streams */
00538 static void start_multicast(void)
00539 {
00540     FFStream *stream;
00541     char session_id[32];
00542     HTTPContext *rtp_c;
00543     struct sockaddr_in dest_addr;
00544     int default_port, stream_index;
00545 
00546     default_port = 6000;
00547     for(stream = first_stream; stream != NULL; stream = stream->next) {
00548         if (stream->is_multicast) {
00549             /* open the RTP connection */
00550             snprintf(session_id, sizeof(session_id), "%08x%08x",
00551                      av_lfg_get(&random_state), av_lfg_get(&random_state));
00552 
00553             /* choose a port if none given */
00554             if (stream->multicast_port == 0) {
00555                 stream->multicast_port = default_port;
00556                 default_port += 100;
00557             }
00558 
00559             dest_addr.sin_family = AF_INET;
00560             dest_addr.sin_addr = stream->multicast_ip;
00561             dest_addr.sin_port = htons(stream->multicast_port);
00562 
00563             rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
00564                                        RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
00565             if (!rtp_c)
00566                 continue;
00567 
00568             if (open_input_stream(rtp_c, "") < 0) {
00569                 http_log("Could not open input stream for stream '%s'\n",
00570                          stream->filename);
00571                 continue;
00572             }
00573 
00574             /* open each RTP stream */
00575             for(stream_index = 0; stream_index < stream->nb_streams;
00576                 stream_index++) {
00577                 dest_addr.sin_port = htons(stream->multicast_port +
00578                                            2 * stream_index);
00579                 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
00580                     http_log("Could not open output stream '%s/streamid=%d'\n",
00581                              stream->filename, stream_index);
00582                     exit(1);
00583                 }
00584             }
00585 
00586             /* change state to send data */
00587             rtp_c->state = HTTPSTATE_SEND_DATA;
00588         }
00589     }
00590 }
00591 
00592 /* main loop of the http server */
00593 static int http_server(void)
00594 {
00595     int server_fd = 0, rtsp_server_fd = 0;
00596     int ret, delay, delay1;
00597     struct pollfd *poll_table, *poll_entry;
00598     HTTPContext *c, *c_next;
00599 
00600     if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
00601         http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
00602         return -1;
00603     }
00604 
00605     if (my_http_addr.sin_port) {
00606         server_fd = socket_open_listen(&my_http_addr);
00607         if (server_fd < 0)
00608             return -1;
00609     }
00610 
00611     if (my_rtsp_addr.sin_port) {
00612         rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
00613         if (rtsp_server_fd < 0)
00614             return -1;
00615     }
00616 
00617     if (!rtsp_server_fd && !server_fd) {
00618         http_log("HTTP and RTSP disabled.\n");
00619         return -1;
00620     }
00621 
00622     http_log("FFserver started.\n");
00623 
00624     start_children(first_feed);
00625 
00626     start_multicast();
00627 
00628     for(;;) {
00629         poll_entry = poll_table;
00630         if (server_fd) {
00631             poll_entry->fd = server_fd;
00632             poll_entry->events = POLLIN;
00633             poll_entry++;
00634         }
00635         if (rtsp_server_fd) {
00636             poll_entry->fd = rtsp_server_fd;
00637             poll_entry->events = POLLIN;
00638             poll_entry++;
00639         }
00640 
00641         /* wait for events on each HTTP handle */
00642         c = first_http_ctx;
00643         delay = 1000;
00644         while (c != NULL) {
00645             int fd;
00646             fd = c->fd;
00647             switch(c->state) {
00648             case HTTPSTATE_SEND_HEADER:
00649             case RTSPSTATE_SEND_REPLY:
00650             case RTSPSTATE_SEND_PACKET:
00651                 c->poll_entry = poll_entry;
00652                 poll_entry->fd = fd;
00653                 poll_entry->events = POLLOUT;
00654                 poll_entry++;
00655                 break;
00656             case HTTPSTATE_SEND_DATA_HEADER:
00657             case HTTPSTATE_SEND_DATA:
00658             case HTTPSTATE_SEND_DATA_TRAILER:
00659                 if (!c->is_packetized) {
00660                     /* for TCP, we output as much as we can (may need to put a limit) */
00661                     c->poll_entry = poll_entry;
00662                     poll_entry->fd = fd;
00663                     poll_entry->events = POLLOUT;
00664                     poll_entry++;
00665                 } else {
00666                     /* when ffserver is doing the timing, we work by
00667                        looking at which packet need to be sent every
00668                        10 ms */
00669                     delay1 = 10; /* one tick wait XXX: 10 ms assumed */
00670                     if (delay1 < delay)
00671                         delay = delay1;
00672                 }
00673                 break;
00674             case HTTPSTATE_WAIT_REQUEST:
00675             case HTTPSTATE_RECEIVE_DATA:
00676             case HTTPSTATE_WAIT_FEED:
00677             case RTSPSTATE_WAIT_REQUEST:
00678                 /* need to catch errors */
00679                 c->poll_entry = poll_entry;
00680                 poll_entry->fd = fd;
00681                 poll_entry->events = POLLIN;/* Maybe this will work */
00682                 poll_entry++;
00683                 break;
00684             default:
00685                 c->poll_entry = NULL;
00686                 break;
00687             }
00688             c = c->next;
00689         }
00690 
00691         /* wait for an event on one connection. We poll at least every
00692            second to handle timeouts */
00693         do {
00694             ret = poll(poll_table, poll_entry - poll_table, delay);
00695             if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
00696                 ff_neterrno() != AVERROR(EINTR))
00697                 return -1;
00698         } while (ret < 0);
00699 
00700         cur_time = av_gettime() / 1000;
00701 
00702         if (need_to_start_children) {
00703             need_to_start_children = 0;
00704             start_children(first_feed);
00705         }
00706 
00707         /* now handle the events */
00708         for(c = first_http_ctx; c != NULL; c = c_next) {
00709             c_next = c->next;
00710             if (handle_connection(c) < 0) {
00711                 /* close and free the connection */
00712                 log_connection(c);
00713                 close_connection(c);
00714             }
00715         }
00716 
00717         poll_entry = poll_table;
00718         if (server_fd) {
00719             /* new HTTP connection request ? */
00720             if (poll_entry->revents & POLLIN)
00721                 new_connection(server_fd, 0);
00722             poll_entry++;
00723         }
00724         if (rtsp_server_fd) {
00725             /* new RTSP connection request ? */
00726             if (poll_entry->revents & POLLIN)
00727                 new_connection(rtsp_server_fd, 1);
00728         }
00729     }
00730 }
00731 
00732 /* start waiting for a new HTTP/RTSP request */
00733 static void start_wait_request(HTTPContext *c, int is_rtsp)
00734 {
00735     c->buffer_ptr = c->buffer;
00736     c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
00737 
00738     if (is_rtsp) {
00739         c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
00740         c->state = RTSPSTATE_WAIT_REQUEST;
00741     } else {
00742         c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
00743         c->state = HTTPSTATE_WAIT_REQUEST;
00744     }
00745 }
00746 
00747 static void http_send_too_busy_reply(int fd)
00748 {
00749     char buffer[300];
00750     int len = snprintf(buffer, sizeof(buffer),
00751                        "HTTP/1.0 503 Server too busy\r\n"
00752                        "Content-type: text/html\r\n"
00753                        "\r\n"
00754                        "<html><head><title>Too busy</title></head><body>\r\n"
00755                        "<p>The server is too busy to serve your request at this time.</p>\r\n"
00756                        "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
00757                        "</body></html>\r\n",
00758                        nb_connections, nb_max_connections);
00759     send(fd, buffer, len, 0);
00760 }
00761 
00762 
00763 static void new_connection(int server_fd, int is_rtsp)
00764 {
00765     struct sockaddr_in from_addr;
00766     int fd, len;
00767     HTTPContext *c = NULL;
00768 
00769     len = sizeof(from_addr);
00770     fd = accept(server_fd, (struct sockaddr *)&from_addr,
00771                 &len);
00772     if (fd < 0) {
00773         http_log("error during accept %s\n", strerror(errno));
00774         return;
00775     }
00776     ff_socket_nonblock(fd, 1);
00777 
00778     if (nb_connections >= nb_max_connections) {
00779         http_send_too_busy_reply(fd);
00780         goto fail;
00781     }
00782 
00783     /* add a new connection */
00784     c = av_mallocz(sizeof(HTTPContext));
00785     if (!c)
00786         goto fail;
00787 
00788     c->fd = fd;
00789     c->poll_entry = NULL;
00790     c->from_addr = from_addr;
00791     c->buffer_size = IOBUFFER_INIT_SIZE;
00792     c->buffer = av_malloc(c->buffer_size);
00793     if (!c->buffer)
00794         goto fail;
00795 
00796     c->next = first_http_ctx;
00797     first_http_ctx = c;
00798     nb_connections++;
00799 
00800     start_wait_request(c, is_rtsp);
00801 
00802     return;
00803 
00804  fail:
00805     if (c) {
00806         av_free(c->buffer);
00807         av_free(c);
00808     }
00809     closesocket(fd);
00810 }
00811 
00812 static void close_connection(HTTPContext *c)
00813 {
00814     HTTPContext **cp, *c1;
00815     int i, nb_streams;
00816     AVFormatContext *ctx;
00817     URLContext *h;
00818     AVStream *st;
00819 
00820     /* remove connection from list */
00821     cp = &first_http_ctx;
00822     while ((*cp) != NULL) {
00823         c1 = *cp;
00824         if (c1 == c)
00825             *cp = c->next;
00826         else
00827             cp = &c1->next;
00828     }
00829 
00830     /* remove references, if any (XXX: do it faster) */
00831     for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
00832         if (c1->rtsp_c == c)
00833             c1->rtsp_c = NULL;
00834     }
00835 
00836     /* remove connection associated resources */
00837     if (c->fd >= 0)
00838         closesocket(c->fd);
00839     if (c->fmt_in) {
00840         /* close each frame parser */
00841         for(i=0;i<c->fmt_in->nb_streams;i++) {
00842             st = c->fmt_in->streams[i];
00843             if (st->codec->codec)
00844                 avcodec_close(st->codec);
00845         }
00846         av_close_input_file(c->fmt_in);
00847     }
00848 
00849     /* free RTP output streams if any */
00850     nb_streams = 0;
00851     if (c->stream)
00852         nb_streams = c->stream->nb_streams;
00853 
00854     for(i=0;i<nb_streams;i++) {
00855         ctx = c->rtp_ctx[i];
00856         if (ctx) {
00857             av_write_trailer(ctx);
00858             av_metadata_free(&ctx->metadata);
00859             av_free(ctx->streams[0]);
00860             av_free(ctx);
00861         }
00862         h = c->rtp_handles[i];
00863         if (h)
00864             url_close(h);
00865     }
00866 
00867     ctx = &c->fmt_ctx;
00868 
00869     if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
00870         if (ctx->oformat) {
00871             /* prepare header */
00872             if (url_open_dyn_buf(&ctx->pb) >= 0) {
00873                 av_write_trailer(ctx);
00874                 av_freep(&c->pb_buffer);
00875                 url_close_dyn_buf(ctx->pb, &c->pb_buffer);
00876             }
00877         }
00878     }
00879 
00880     for(i=0; i<ctx->nb_streams; i++)
00881         av_free(ctx->streams[i]);
00882 
00883     if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
00884         current_bandwidth -= c->stream->bandwidth;
00885 
00886     /* signal that there is no feed if we are the feeder socket */
00887     if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
00888         c->stream->feed_opened = 0;
00889         close(c->feed_fd);
00890     }
00891 
00892     av_freep(&c->pb_buffer);
00893     av_freep(&c->packet_buffer);
00894     av_free(c->buffer);
00895     av_free(c);
00896     nb_connections--;
00897 }
00898 
00899 static int handle_connection(HTTPContext *c)
00900 {
00901     int len, ret;
00902 
00903     switch(c->state) {
00904     case HTTPSTATE_WAIT_REQUEST:
00905     case RTSPSTATE_WAIT_REQUEST:
00906         /* timeout ? */
00907         if ((c->timeout - cur_time) < 0)
00908             return -1;
00909         if (c->poll_entry->revents & (POLLERR | POLLHUP))
00910             return -1;
00911 
00912         /* no need to read if no events */
00913         if (!(c->poll_entry->revents & POLLIN))
00914             return 0;
00915         /* read the data */
00916     read_loop:
00917         len = recv(c->fd, c->buffer_ptr, 1, 0);
00918         if (len < 0) {
00919             if (ff_neterrno() != AVERROR(EAGAIN) &&
00920                 ff_neterrno() != AVERROR(EINTR))
00921                 return -1;
00922         } else if (len == 0) {
00923             return -1;
00924         } else {
00925             /* search for end of request. */
00926             uint8_t *ptr;
00927             c->buffer_ptr += len;
00928             ptr = c->buffer_ptr;
00929             if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
00930                 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
00931                 /* request found : parse it and reply */
00932                 if (c->state == HTTPSTATE_WAIT_REQUEST) {
00933                     ret = http_parse_request(c);
00934                 } else {
00935                     ret = rtsp_parse_request(c);
00936                 }
00937                 if (ret < 0)
00938                     return -1;
00939             } else if (ptr >= c->buffer_end) {
00940                 /* request too long: cannot do anything */
00941                 return -1;
00942             } else goto read_loop;
00943         }
00944         break;
00945 
00946     case HTTPSTATE_SEND_HEADER:
00947         if (c->poll_entry->revents & (POLLERR | POLLHUP))
00948             return -1;
00949 
00950         /* no need to write if no events */
00951         if (!(c->poll_entry->revents & POLLOUT))
00952             return 0;
00953         len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
00954         if (len < 0) {
00955             if (ff_neterrno() != AVERROR(EAGAIN) &&
00956                 ff_neterrno() != AVERROR(EINTR)) {
00957                 /* error : close connection */
00958                 av_freep(&c->pb_buffer);
00959                 return -1;
00960             }
00961         } else {
00962             c->buffer_ptr += len;
00963             if (c->stream)
00964                 c->stream->bytes_served += len;
00965             c->data_count += len;
00966             if (c->buffer_ptr >= c->buffer_end) {
00967                 av_freep(&c->pb_buffer);
00968                 /* if error, exit */
00969                 if (c->http_error)
00970                     return -1;
00971                 /* all the buffer was sent : synchronize to the incoming stream */
00972                 c->state = HTTPSTATE_SEND_DATA_HEADER;
00973                 c->buffer_ptr = c->buffer_end = c->buffer;
00974             }
00975         }
00976         break;
00977 
00978     case HTTPSTATE_SEND_DATA:
00979     case HTTPSTATE_SEND_DATA_HEADER:
00980     case HTTPSTATE_SEND_DATA_TRAILER:
00981         /* for packetized output, we consider we can always write (the
00982            input streams sets the speed). It may be better to verify
00983            that we do not rely too much on the kernel queues */
00984         if (!c->is_packetized) {
00985             if (c->poll_entry->revents & (POLLERR | POLLHUP))
00986                 return -1;
00987 
00988             /* no need to read if no events */
00989             if (!(c->poll_entry->revents & POLLOUT))
00990                 return 0;
00991         }
00992         if (http_send_data(c) < 0)
00993             return -1;
00994         /* close connection if trailer sent */
00995         if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
00996             return -1;
00997         break;
00998     case HTTPSTATE_RECEIVE_DATA:
00999         /* no need to read if no events */
01000         if (c->poll_entry->revents & (POLLERR | POLLHUP))
01001             return -1;
01002         if (!(c->poll_entry->revents & POLLIN))
01003             return 0;
01004         if (http_receive_data(c) < 0)
01005             return -1;
01006         break;
01007     case HTTPSTATE_WAIT_FEED:
01008         /* no need to read if no events */
01009         if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
01010             return -1;
01011 
01012         /* nothing to do, we'll be waken up by incoming feed packets */
01013         break;
01014 
01015     case RTSPSTATE_SEND_REPLY:
01016         if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
01017             av_freep(&c->pb_buffer);
01018             return -1;
01019         }
01020         /* no need to write if no events */
01021         if (!(c->poll_entry->revents & POLLOUT))
01022             return 0;
01023         len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
01024         if (len < 0) {
01025             if (ff_neterrno() != AVERROR(EAGAIN) &&
01026                 ff_neterrno() != AVERROR(EINTR)) {
01027                 /* error : close connection */
01028                 av_freep(&c->pb_buffer);
01029                 return -1;
01030             }
01031         } else {
01032             c->buffer_ptr += len;
01033             c->data_count += len;
01034             if (c->buffer_ptr >= c->buffer_end) {
01035                 /* all the buffer was sent : wait for a new request */
01036                 av_freep(&c->pb_buffer);
01037                 start_wait_request(c, 1);
01038             }
01039         }
01040         break;
01041     case RTSPSTATE_SEND_PACKET:
01042         if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
01043             av_freep(&c->packet_buffer);
01044             return -1;
01045         }
01046         /* no need to write if no events */
01047         if (!(c->poll_entry->revents & POLLOUT))
01048             return 0;
01049         len = send(c->fd, c->packet_buffer_ptr,
01050                     c->packet_buffer_end - c->packet_buffer_ptr, 0);
01051         if (len < 0) {
01052             if (ff_neterrno() != AVERROR(EAGAIN) &&
01053                 ff_neterrno() != AVERROR(EINTR)) {
01054                 /* error : close connection */
01055                 av_freep(&c->packet_buffer);
01056                 return -1;
01057             }
01058         } else {
01059             c->packet_buffer_ptr += len;
01060             if (c->packet_buffer_ptr >= c->packet_buffer_end) {
01061                 /* all the buffer was sent : wait for a new request */
01062                 av_freep(&c->packet_buffer);
01063                 c->state = RTSPSTATE_WAIT_REQUEST;
01064             }
01065         }
01066         break;
01067     case HTTPSTATE_READY:
01068         /* nothing to do */
01069         break;
01070     default:
01071         return -1;
01072     }
01073     return 0;
01074 }
01075 
01076 static int extract_rates(char *rates, int ratelen, const char *request)
01077 {
01078     const char *p;
01079 
01080     for (p = request; *p && *p != '\r' && *p != '\n'; ) {
01081         if (strncasecmp(p, "Pragma:", 7) == 0) {
01082             const char *q = p + 7;
01083 
01084             while (*q && *q != '\n' && isspace(*q))
01085                 q++;
01086 
01087             if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
01088                 int stream_no;
01089                 int rate_no;
01090 
01091                 q += 20;
01092 
01093                 memset(rates, 0xff, ratelen);
01094 
01095                 while (1) {
01096                     while (*q && *q != '\n' && *q != ':')
01097                         q++;
01098 
01099                     if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
01100                         break;
01101 
01102                     stream_no--;
01103                     if (stream_no < ratelen && stream_no >= 0)
01104                         rates[stream_no] = rate_no;
01105 
01106                     while (*q && *q != '\n' && !isspace(*q))
01107                         q++;
01108                 }
01109 
01110                 return 1;
01111             }
01112         }
01113         p = strchr(p, '\n');
01114         if (!p)
01115             break;
01116 
01117         p++;
01118     }
01119 
01120     return 0;
01121 }
01122 
01123 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
01124 {
01125     int i;
01126     int best_bitrate = 100000000;
01127     int best = -1;
01128 
01129     for (i = 0; i < feed->nb_streams; i++) {
01130         AVCodecContext *feed_codec = feed->streams[i]->codec;
01131 
01132         if (feed_codec->codec_id != codec->codec_id ||
01133             feed_codec->sample_rate != codec->sample_rate ||
01134             feed_codec->width != codec->width ||
01135             feed_codec->height != codec->height)
01136             continue;
01137 
01138         /* Potential stream */
01139 
01140         /* We want the fastest stream less than bit_rate, or the slowest
01141          * faster than bit_rate
01142          */
01143 
01144         if (feed_codec->bit_rate <= bit_rate) {
01145             if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
01146                 best_bitrate = feed_codec->bit_rate;
01147                 best = i;
01148             }
01149         } else {
01150             if (feed_codec->bit_rate < best_bitrate) {
01151                 best_bitrate = feed_codec->bit_rate;
01152                 best = i;
01153             }
01154         }
01155     }
01156 
01157     return best;
01158 }
01159 
01160 static int modify_current_stream(HTTPContext *c, char *rates)
01161 {
01162     int i;
01163     FFStream *req = c->stream;
01164     int action_required = 0;
01165 
01166     /* Not much we can do for a feed */
01167     if (!req->feed)
01168         return 0;
01169 
01170     for (i = 0; i < req->nb_streams; i++) {
01171         AVCodecContext *codec = req->streams[i]->codec;
01172 
01173         switch(rates[i]) {
01174             case 0:
01175                 c->switch_feed_streams[i] = req->feed_streams[i];
01176                 break;
01177             case 1:
01178                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
01179                 break;
01180             case 2:
01181                 /* Wants off or slow */
01182                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
01183 #ifdef WANTS_OFF
01184                 /* This doesn't work well when it turns off the only stream! */
01185                 c->switch_feed_streams[i] = -2;
01186                 c->feed_streams[i] = -2;
01187 #endif
01188                 break;
01189         }
01190 
01191         if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
01192             action_required = 1;
01193     }
01194 
01195     return action_required;
01196 }
01197 
01198 /* XXX: factorize in utils.c ? */
01199 /* XXX: take care with different space meaning */
01200 static void skip_spaces(const char **pp)
01201 {
01202     const char *p;
01203     p = *pp;
01204     while (*p == ' ' || *p == '\t')
01205         p++;
01206     *pp = p;
01207 }
01208 
01209 static void get_word(char *buf, int buf_size, const char **pp)
01210 {
01211     const char *p;
01212     char *q;
01213 
01214     p = *pp;
01215     skip_spaces(&p);
01216     q = buf;
01217     while (!isspace(*p) && *p != '\0') {
01218         if ((q - buf) < buf_size - 1)
01219             *q++ = *p;
01220         p++;
01221     }
01222     if (buf_size > 0)
01223         *q = '\0';
01224     *pp = p;
01225 }
01226 
01227 static void get_arg(char *buf, int buf_size, const char **pp)
01228 {
01229     const char *p;
01230     char *q;
01231     int quote;
01232 
01233     p = *pp;
01234     while (isspace(*p)) p++;
01235     q = buf;
01236     quote = 0;
01237     if (*p == '\"' || *p == '\'')
01238         quote = *p++;
01239     for(;;) {
01240         if (quote) {
01241             if (*p == quote)
01242                 break;
01243         } else {
01244             if (isspace(*p))
01245                 break;
01246         }
01247         if (*p == '\0')
01248             break;
01249         if ((q - buf) < buf_size - 1)
01250             *q++ = *p;
01251         p++;
01252     }
01253     *q = '\0';
01254     if (quote && *p == quote)
01255         p++;
01256     *pp = p;
01257 }
01258 
01259 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
01260                          const char *p, const char *filename, int line_num)
01261 {
01262     char arg[1024];
01263     IPAddressACL acl;
01264     int errors = 0;
01265 
01266     get_arg(arg, sizeof(arg), &p);
01267     if (strcasecmp(arg, "allow") == 0)
01268         acl.action = IP_ALLOW;
01269     else if (strcasecmp(arg, "deny") == 0)
01270         acl.action = IP_DENY;
01271     else {
01272         fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
01273                 filename, line_num, arg);
01274         errors++;
01275     }
01276 
01277     get_arg(arg, sizeof(arg), &p);
01278 
01279     if (resolve_host(&acl.first, arg) != 0) {
01280         fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
01281                 filename, line_num, arg);
01282         errors++;
01283     } else
01284         acl.last = acl.first;
01285 
01286     get_arg(arg, sizeof(arg), &p);
01287 
01288     if (arg[0]) {
01289         if (resolve_host(&acl.last, arg) != 0) {
01290             fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
01291                     filename, line_num, arg);
01292             errors++;
01293         }
01294     }
01295 
01296     if (!errors) {
01297         IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
01298         IPAddressACL **naclp = 0;
01299 
01300         acl.next = 0;
01301         *nacl = acl;
01302 
01303         if (stream)
01304             naclp = &stream->acl;
01305         else if (feed)
01306             naclp = &feed->acl;
01307         else if (ext_acl)
01308             naclp = &ext_acl;
01309         else {
01310             fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
01311                     filename, line_num);
01312             errors++;
01313         }
01314 
01315         if (naclp) {
01316             while (*naclp)
01317                 naclp = &(*naclp)->next;
01318 
01319             *naclp = nacl;
01320         }
01321     }
01322 }
01323 
01324 
01325 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
01326 {
01327     FILE* f;
01328     char line[1024];
01329     char  cmd[1024];
01330     IPAddressACL *acl = NULL;
01331     int line_num = 0;
01332     const char *p;
01333 
01334     f = fopen(stream->dynamic_acl, "r");
01335     if (!f) {
01336         perror(stream->dynamic_acl);
01337         return NULL;
01338     }
01339 
01340     acl = av_mallocz(sizeof(IPAddressACL));
01341 
01342     /* Build ACL */
01343     for(;;) {
01344         if (fgets(line, sizeof(line), f) == NULL)
01345             break;
01346         line_num++;
01347         p = line;
01348         while (isspace(*p))
01349             p++;
01350         if (*p == '\0' || *p == '#')
01351             continue;
01352         get_arg(cmd, sizeof(cmd), &p);
01353 
01354         if (!strcasecmp(cmd, "ACL"))
01355             parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
01356     }
01357     fclose(f);
01358     return acl;
01359 }
01360 
01361 
01362 static void free_acl_list(IPAddressACL *in_acl)
01363 {
01364     IPAddressACL *pacl,*pacl2;
01365 
01366     pacl = in_acl;
01367     while(pacl) {
01368         pacl2 = pacl;
01369         pacl = pacl->next;
01370         av_freep(pacl2);
01371     }
01372 }
01373 
01374 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
01375 {
01376     enum IPAddressAction last_action = IP_DENY;
01377     IPAddressACL *acl;
01378     struct in_addr *src = &c->from_addr.sin_addr;
01379     unsigned long src_addr = src->s_addr;
01380 
01381     for (acl = in_acl; acl; acl = acl->next) {
01382         if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
01383             return (acl->action == IP_ALLOW) ? 1 : 0;
01384         last_action = acl->action;
01385     }
01386 
01387     /* Nothing matched, so return not the last action */
01388     return (last_action == IP_DENY) ? 1 : 0;
01389 }
01390 
01391 static int validate_acl(FFStream *stream, HTTPContext *c)
01392 {
01393     int ret = 0;
01394     IPAddressACL *acl;
01395 
01396 
01397     /* if stream->acl is null validate_acl_list will return 1 */
01398     ret = validate_acl_list(stream->acl, c);
01399 
01400     if (stream->dynamic_acl[0]) {
01401         acl = parse_dynamic_acl(stream, c);
01402 
01403         ret = validate_acl_list(acl, c);
01404 
01405         free_acl_list(acl);
01406     }
01407 
01408     return ret;
01409 }
01410 
01411 /* compute the real filename of a file by matching it without its
01412    extensions to all the stream filenames */
01413 static void compute_real_filename(char *filename, int max_size)
01414 {
01415     char file1[1024];
01416     char file2[1024];
01417     char *p;
01418     FFStream *stream;
01419 
01420     /* compute filename by matching without the file extensions */
01421     av_strlcpy(file1, filename, sizeof(file1));
01422     p = strrchr(file1, '.');
01423     if (p)
01424         *p = '\0';
01425     for(stream = first_stream; stream != NULL; stream = stream->next) {
01426         av_strlcpy(file2, stream->filename, sizeof(file2));
01427         p = strrchr(file2, '.');
01428         if (p)
01429             *p = '\0';
01430         if (!strcmp(file1, file2)) {
01431             av_strlcpy(filename, stream->filename, max_size);
01432             break;
01433         }
01434     }
01435 }
01436 
01437 enum RedirType {
01438     REDIR_NONE,
01439     REDIR_ASX,
01440     REDIR_RAM,
01441     REDIR_ASF,
01442     REDIR_RTSP,
01443     REDIR_SDP,
01444 };
01445 
01446 /* parse http request and prepare header */
01447 static int http_parse_request(HTTPContext *c)
01448 {
01449     char *p;
01450     enum RedirType redir_type;
01451     char cmd[32];
01452     char info[1024], filename[1024];
01453     char url[1024], *q;
01454     char protocol[32];
01455     char msg[1024];
01456     const char *mime_type;
01457     FFStream *stream;
01458     int i;
01459     char ratebuf[32];
01460     char *useragent = 0;
01461 
01462     p = c->buffer;
01463     get_word(cmd, sizeof(cmd), (const char **)&p);
01464     av_strlcpy(c->method, cmd, sizeof(c->method));
01465 
01466     if (!strcmp(cmd, "GET"))
01467         c->post = 0;
01468     else if (!strcmp(cmd, "POST"))
01469         c->post = 1;
01470     else
01471         return -1;
01472 
01473     get_word(url, sizeof(url), (const char **)&p);
01474     av_strlcpy(c->url, url, sizeof(c->url));
01475 
01476     get_word(protocol, sizeof(protocol), (const char **)&p);
01477     if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
01478         return -1;
01479 
01480     av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
01481 
01482     if (ffserver_debug)
01483         http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
01484 
01485     /* find the filename and the optional info string in the request */
01486     p = strchr(url, '?');
01487     if (p) {
01488         av_strlcpy(info, p, sizeof(info));
01489         *p = '\0';
01490     } else
01491         info[0] = '\0';
01492 
01493     av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
01494 
01495     for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
01496         if (strncasecmp(p, "User-Agent:", 11) == 0) {
01497             useragent = p + 11;
01498             if (*useragent && *useragent != '\n' && isspace(*useragent))
01499                 useragent++;
01500             break;
01501         }
01502         p = strchr(p, '\n');
01503         if (!p)
01504             break;
01505 
01506         p++;
01507     }
01508 
01509     redir_type = REDIR_NONE;
01510     if (av_match_ext(filename, "asx")) {
01511         redir_type = REDIR_ASX;
01512         filename[strlen(filename)-1] = 'f';
01513     } else if (av_match_ext(filename, "asf") &&
01514         (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
01515         /* if this isn't WMP or lookalike, return the redirector file */
01516         redir_type = REDIR_ASF;
01517     } else if (av_match_ext(filename, "rpm,ram")) {
01518         redir_type = REDIR_RAM;
01519         strcpy(filename + strlen(filename)-2, "m");
01520     } else if (av_match_ext(filename, "rtsp")) {
01521         redir_type = REDIR_RTSP;
01522         compute_real_filename(filename, sizeof(filename) - 1);
01523     } else if (av_match_ext(filename, "sdp")) {
01524         redir_type = REDIR_SDP;
01525         compute_real_filename(filename, sizeof(filename) - 1);
01526     }
01527 
01528     // "redirect" / request to index.html
01529     if (!strlen(filename))
01530         av_strlcpy(filename, "index.html", sizeof(filename) - 1);
01531 
01532     stream = first_stream;
01533     while (stream != NULL) {
01534         if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
01535             break;
01536         stream = stream->next;
01537     }
01538     if (stream == NULL) {
01539         snprintf(msg, sizeof(msg), "File '%s' not found", url);
01540         http_log("File '%s' not found\n", url);
01541         goto send_error;
01542     }
01543 
01544     c->stream = stream;
01545     memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
01546     memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
01547 
01548     if (stream->stream_type == STREAM_TYPE_REDIRECT) {
01549         c->http_error = 301;
01550         q = c->buffer;
01551         q += snprintf(q, c->buffer_size,
01552                       "HTTP/1.0 301 Moved\r\n"
01553                       "Location: %s\r\n"
01554                       "Content-type: text/html\r\n"
01555                       "\r\n"
01556                       "<html><head><title>Moved</title></head><body>\r\n"
01557                       "You should be <a href=\"%s\">redirected</a>.\r\n"
01558                       "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
01559         /* prepare output buffer */
01560         c->buffer_ptr = c->buffer;
01561         c->buffer_end = q;
01562         c->state = HTTPSTATE_SEND_HEADER;
01563         return 0;
01564     }
01565 
01566     /* If this is WMP, get the rate information */
01567     if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
01568         if (modify_current_stream(c, ratebuf)) {
01569             for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
01570                 if (c->switch_feed_streams[i] >= 0)
01571                     c->switch_feed_streams[i] = -1;
01572             }
01573         }
01574     }
01575 
01576     if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
01577         current_bandwidth += stream->bandwidth;
01578 
01579     /* If already streaming this feed, do not let start another feeder. */
01580     if (stream->feed_opened) {
01581         snprintf(msg, sizeof(msg), "This feed is already being received.");
01582         http_log("Feed '%s' already being received\n", stream->feed_filename);
01583         goto send_error;
01584     }
01585 
01586     if (c->post == 0 && max_bandwidth < current_bandwidth) {
01587         c->http_error = 503;
01588         q = c->buffer;
01589         q += snprintf(q, c->buffer_size,
01590                       "HTTP/1.0 503 Server too busy\r\n"
01591                       "Content-type: text/html\r\n"
01592                       "\r\n"
01593                       "<html><head><title>Too busy</title></head><body>\r\n"
01594                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
01595                       "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
01596                       "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
01597                       "</body></html>\r\n", current_bandwidth, max_bandwidth);
01598         /* prepare output buffer */
01599         c->buffer_ptr = c->buffer;
01600         c->buffer_end = q;
01601         c->state = HTTPSTATE_SEND_HEADER;
01602         return 0;
01603     }
01604 
01605     if (redir_type != REDIR_NONE) {
01606         char *hostinfo = 0;
01607 
01608         for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
01609             if (strncasecmp(p, "Host:", 5) == 0) {
01610                 hostinfo = p + 5;
01611                 break;
01612             }
01613             p = strchr(p, '\n');
01614             if (!p)
01615                 break;
01616 
01617             p++;
01618         }
01619 
01620         if (hostinfo) {
01621             char *eoh;
01622             char hostbuf[260];
01623 
01624             while (isspace(*hostinfo))
01625                 hostinfo++;
01626 
01627             eoh = strchr(hostinfo, '\n');
01628             if (eoh) {
01629                 if (eoh[-1] == '\r')
01630                     eoh--;
01631 
01632                 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
01633                     memcpy(hostbuf, hostinfo, eoh - hostinfo);
01634                     hostbuf[eoh - hostinfo] = 0;
01635 
01636                     c->http_error = 200;
01637                     q = c->buffer;
01638                     switch(redir_type) {
01639                     case REDIR_ASX:
01640                         q += snprintf(q, c->buffer_size,
01641                                       "HTTP/1.0 200 ASX Follows\r\n"
01642                                       "Content-type: video/x-ms-asf\r\n"
01643                                       "\r\n"
01644                                       "<ASX Version=\"3\">\r\n"
01645                                       //"<!-- Autogenerated by ffserver -->\r\n"
01646                                       "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
01647                                       "</ASX>\r\n", hostbuf, filename, info);
01648                         break;
01649                     case REDIR_RAM:
01650                         q += snprintf(q, c->buffer_size,
01651                                       "HTTP/1.0 200 RAM Follows\r\n"
01652                                       "Content-type: audio/x-pn-realaudio\r\n"
01653                                       "\r\n"
01654                                       "# Autogenerated by ffserver\r\n"
01655                                       "http://%s/%s%s\r\n", hostbuf, filename, info);
01656                         break;
01657                     case REDIR_ASF:
01658                         q += snprintf(q, c->buffer_size,
01659                                       "HTTP/1.0 200 ASF Redirect follows\r\n"
01660                                       "Content-type: video/x-ms-asf\r\n"
01661                                       "\r\n"
01662                                       "[Reference]\r\n"
01663                                       "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
01664                         break;
01665                     case REDIR_RTSP:
01666                         {
01667                             char hostname[256], *p;
01668                             /* extract only hostname */
01669                             av_strlcpy(hostname, hostbuf, sizeof(hostname));
01670                             p = strrchr(hostname, ':');
01671                             if (p)
01672                                 *p = '\0';
01673                             q += snprintf(q, c->buffer_size,
01674                                           "HTTP/1.0 200 RTSP Redirect follows\r\n"
01675                                           /* XXX: incorrect mime type ? */
01676                                           "Content-type: application/x-rtsp\r\n"
01677                                           "\r\n"
01678                                           "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
01679                         }
01680                         break;
01681                     case REDIR_SDP:
01682                         {
01683                             uint8_t *sdp_data;
01684                             int sdp_data_size, len;
01685                             struct sockaddr_in my_addr;
01686 
01687                             q += snprintf(q, c->buffer_size,
01688                                           "HTTP/1.0 200 OK\r\n"
01689                                           "Content-type: application/sdp\r\n"
01690                                           "\r\n");
01691 
01692                             len = sizeof(my_addr);
01693                             getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
01694 
01695                             /* XXX: should use a dynamic buffer */
01696                             sdp_data_size = prepare_sdp_description(stream,
01697                                                                     &sdp_data,
01698                                                                     my_addr.sin_addr);
01699                             if (sdp_data_size > 0) {
01700                                 memcpy(q, sdp_data, sdp_data_size);
01701                                 q += sdp_data_size;
01702                                 *q = '\0';
01703                                 av_free(sdp_data);
01704                             }
01705                         }
01706                         break;
01707                     default:
01708                         abort();
01709                         break;
01710                     }
01711 
01712                     /* prepare output buffer */
01713                     c->buffer_ptr = c->buffer;
01714                     c->buffer_end = q;
01715                     c->state = HTTPSTATE_SEND_HEADER;
01716                     return 0;
01717                 }
01718             }
01719         }
01720 
01721         snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
01722         goto send_error;
01723     }
01724 
01725     stream->conns_served++;
01726 
01727     /* XXX: add there authenticate and IP match */
01728 
01729     if (c->post) {
01730         /* if post, it means a feed is being sent */
01731         if (!stream->is_feed) {
01732             /* However it might be a status report from WMP! Let us log the
01733              * data as it might come in handy one day. */
01734             char *logline = 0;
01735             int client_id = 0;
01736 
01737             for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
01738                 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
01739                     logline = p;
01740                     break;
01741                 }
01742                 if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
01743                     client_id = strtol(p + 18, 0, 10);
01744                 p = strchr(p, '\n');
01745                 if (!p)
01746                     break;
01747 
01748                 p++;
01749             }
01750 
01751             if (logline) {
01752                 char *eol = strchr(logline, '\n');
01753 
01754                 logline += 17;
01755 
01756                 if (eol) {
01757                     if (eol[-1] == '\r')
01758                         eol--;
01759                     http_log("%.*s\n", (int) (eol - logline), logline);
01760                     c->suppress_log = 1;
01761                 }
01762             }
01763 
01764 #ifdef DEBUG_WMP
01765             http_log("\nGot request:\n%s\n", c->buffer);
01766 #endif
01767 
01768             if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
01769                 HTTPContext *wmpc;
01770 
01771                 /* Now we have to find the client_id */
01772                 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
01773                     if (wmpc->wmp_client_id == client_id)
01774                         break;
01775                 }
01776 
01777                 if (wmpc && modify_current_stream(wmpc, ratebuf))
01778                     wmpc->switch_pending = 1;
01779             }
01780 
01781             snprintf(msg, sizeof(msg), "POST command not handled");
01782             c->stream = 0;
01783             goto send_error;
01784         }
01785         if (http_start_receive_data(c) < 0) {
01786             snprintf(msg, sizeof(msg), "could not open feed");
01787             goto send_error;
01788         }
01789         c->http_error = 0;
01790         c->state = HTTPSTATE_RECEIVE_DATA;
01791         return 0;
01792     }
01793 
01794 #ifdef DEBUG_WMP
01795     if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
01796         http_log("\nGot request:\n%s\n", c->buffer);
01797 #endif
01798 
01799     if (c->stream->stream_type == STREAM_TYPE_STATUS)
01800         goto send_status;
01801 
01802     /* open input stream */
01803     if (open_input_stream(c, info) < 0) {
01804         snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
01805         goto send_error;
01806     }
01807 
01808     /* prepare http header */
01809     q = c->buffer;
01810     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
01811     mime_type = c->stream->fmt->mime_type;
01812     if (!mime_type)
01813         mime_type = "application/x-octet-stream";
01814     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
01815 
01816     /* for asf, we need extra headers */
01817     if (!strcmp(c->stream->fmt->name,"asf_stream")) {
01818         /* Need to allocate a client id */
01819 
01820         c->wmp_client_id = av_lfg_get(&random_state);
01821 
01822         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);
01823     }
01824     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
01825     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
01826 
01827     /* prepare output buffer */
01828     c->http_error = 0;
01829     c->buffer_ptr = c->buffer;
01830     c->buffer_end = q;
01831     c->state = HTTPSTATE_SEND_HEADER;
01832     return 0;
01833  send_error:
01834     c->http_error = 404;
01835     q = c->buffer;
01836     q += snprintf(q, c->buffer_size,
01837                   "HTTP/1.0 404 Not Found\r\n"
01838                   "Content-type: text/html\r\n"
01839                   "\r\n"
01840                   "<html>\n"
01841                   "<head><title>404 Not Found</title></head>\n"
01842                   "<body>%s</body>\n"
01843                   "</html>\n", msg);
01844     /* prepare output buffer */
01845     c->buffer_ptr = c->buffer;
01846     c->buffer_end = q;
01847     c->state = HTTPSTATE_SEND_HEADER;
01848     return 0;
01849  send_status:
01850     compute_status(c);
01851     c->http_error = 200; /* horrible : we use this value to avoid
01852                             going to the send data state */
01853     c->state = HTTPSTATE_SEND_HEADER;
01854     return 0;
01855 }
01856 
01857 static void fmt_bytecount(AVIOContext *pb, int64_t count)
01858 {
01859     static const char *suffix = " kMGTP";
01860     const char *s;
01861 
01862     for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
01863 
01864     avio_printf(pb, "%"PRId64"%c", count, *s);
01865 }
01866 
01867 static void compute_status(HTTPContext *c)
01868 {
01869     HTTPContext *c1;
01870     FFStream *stream;
01871     char *p;
01872     time_t ti;
01873     int i, len;
01874     AVIOContext *pb;
01875 
01876     if (url_open_dyn_buf(&pb) < 0) {
01877         /* XXX: return an error ? */
01878         c->buffer_ptr = c->buffer;
01879         c->buffer_end = c->buffer;
01880         return;
01881     }
01882 
01883     avio_printf(pb, "HTTP/1.0 200 OK\r\n");
01884     avio_printf(pb, "Content-type: %s\r\n", "text/html");
01885     avio_printf(pb, "Pragma: no-cache\r\n");
01886     avio_printf(pb, "\r\n");
01887 
01888     avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
01889     if (c->stream->feed_filename[0])
01890         avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
01891     avio_printf(pb, "</head>\n<body>");
01892     avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
01893     /* format status */
01894     avio_printf(pb, "<h2>Available Streams</h2>\n");
01895     avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
01896     avio_printf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbits/s<th align=left>Video<br>kbits/s<th><br>Codec<th align=left>Audio<br>kbits/s<th><br>Codec<th align=left valign=top>Feed\n");
01897     stream = first_stream;
01898     while (stream != NULL) {
01899         char sfilename[1024];
01900         char *eosf;
01901 
01902         if (stream->feed != stream) {
01903             av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
01904             eosf = sfilename + strlen(sfilename);
01905             if (eosf - sfilename >= 4) {
01906                 if (strcmp(eosf - 4, ".asf") == 0)
01907                     strcpy(eosf - 4, ".asx");
01908                 else if (strcmp(eosf - 3, ".rm") == 0)
01909                     strcpy(eosf - 3, ".ram");
01910                 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
01911                     /* generate a sample RTSP director if
01912                        unicast. Generate an SDP redirector if
01913                        multicast */
01914                     eosf = strrchr(sfilename, '.');
01915                     if (!eosf)
01916                         eosf = sfilename + strlen(sfilename);
01917                     if (stream->is_multicast)
01918                         strcpy(eosf, ".sdp");
01919                     else
01920                         strcpy(eosf, ".rtsp");
01921                 }
01922             }
01923 
01924             avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
01925                          sfilename, stream->filename);
01926             avio_printf(pb, "<td align=right> %d <td align=right> ",
01927                         stream->conns_served);
01928             fmt_bytecount(pb, stream->bytes_served);
01929             switch(stream->stream_type) {
01930             case STREAM_TYPE_LIVE: {
01931                     int audio_bit_rate = 0;
01932                     int video_bit_rate = 0;
01933                     const char *audio_codec_name = "";
01934                     const char *video_codec_name = "";
01935                     const char *audio_codec_name_extra = "";
01936                     const char *video_codec_name_extra = "";
01937 
01938                     for(i=0;i<stream->nb_streams;i++) {
01939                         AVStream *st = stream->streams[i];
01940                         AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
01941                         switch(st->codec->codec_type) {
01942                         case AVMEDIA_TYPE_AUDIO:
01943                             audio_bit_rate += st->codec->bit_rate;
01944                             if (codec) {
01945                                 if (*audio_codec_name)
01946                                     audio_codec_name_extra = "...";
01947                                 audio_codec_name = codec->name;
01948                             }
01949                             break;
01950                         case AVMEDIA_TYPE_VIDEO:
01951                             video_bit_rate += st->codec->bit_rate;
01952                             if (codec) {
01953                                 if (*video_codec_name)
01954                                     video_codec_name_extra = "...";
01955                                 video_codec_name = codec->name;
01956                             }
01957                             break;
01958                         case AVMEDIA_TYPE_DATA:
01959                             video_bit_rate += st->codec->bit_rate;
01960                             break;
01961                         default:
01962                             abort();
01963                         }
01964                     }
01965                     avio_printf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
01966                                  stream->fmt->name,
01967                                  stream->bandwidth,
01968                                  video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
01969                                  audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
01970                     if (stream->feed)
01971                         avio_printf(pb, "<td>%s", stream->feed->filename);
01972                     else
01973                         avio_printf(pb, "<td>%s", stream->feed_filename);
01974                     avio_printf(pb, "\n");
01975                 }
01976                 break;
01977             default:
01978                 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
01979                 break;
01980             }
01981         }
01982         stream = stream->next;
01983     }
01984     avio_printf(pb, "</table>\n");
01985 
01986     stream = first_stream;
01987     while (stream != NULL) {
01988         if (stream->feed == stream) {
01989             avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
01990             if (stream->pid) {
01991                 avio_printf(pb, "Running as pid %d.\n", stream->pid);
01992 
01993 #if defined(linux) && !defined(CONFIG_NOCUTILS)
01994                 {
01995                     FILE *pid_stat;
01996                     char ps_cmd[64];
01997 
01998                     /* This is somewhat linux specific I guess */
01999                     snprintf(ps_cmd, sizeof(ps_cmd),
02000                              "ps -o \"%%cpu,cputime\" --no-headers %d",
02001                              stream->pid);
02002 
02003                     pid_stat = popen(ps_cmd, "r");
02004                     if (pid_stat) {
02005                         char cpuperc[10];
02006                         char cpuused[64];
02007 
02008                         if (fscanf(pid_stat, "%10s %64s", cpuperc,
02009                                    cpuused) == 2) {
02010                             avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
02011                                          cpuperc, cpuused);
02012                         }
02013                         fclose(pid_stat);
02014                     }
02015                 }
02016 #endif
02017 
02018                 avio_printf(pb, "<p>");
02019             }
02020             avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
02021 
02022             for (i = 0; i < stream->nb_streams; i++) {
02023                 AVStream *st = stream->streams[i];
02024                 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
02025                 const char *type = "unknown";
02026                 char parameters[64];
02027 
02028                 parameters[0] = 0;
02029 
02030                 switch(st->codec->codec_type) {
02031                 case AVMEDIA_TYPE_AUDIO:
02032                     type = "audio";
02033                     snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
02034                     break;
02035                 case AVMEDIA_TYPE_VIDEO:
02036                     type = "video";
02037                     snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
02038                                 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
02039                     break;
02040                 default:
02041                     abort();
02042                 }
02043                 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
02044                         i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
02045             }
02046             avio_printf(pb, "</table>\n");
02047 
02048         }
02049         stream = stream->next;
02050     }
02051 
02052     /* connection status */
02053     avio_printf(pb, "<h2>Connection Status</h2>\n");
02054 
02055     avio_printf(pb, "Number of connections: %d / %d<br>\n",
02056                  nb_connections, nb_max_connections);
02057 
02058     avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
02059                  current_bandwidth, max_bandwidth);
02060 
02061     avio_printf(pb, "<table>\n");
02062     avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
02063     c1 = first_http_ctx;
02064     i = 0;
02065     while (c1 != NULL) {
02066         int bitrate;
02067         int j;
02068 
02069         bitrate = 0;
02070         if (c1->stream) {
02071             for (j = 0; j < c1->stream->nb_streams; j++) {
02072                 if (!c1->stream->feed)
02073                     bitrate += c1->stream->streams[j]->codec->bit_rate;
02074                 else if (c1->feed_streams[j] >= 0)
02075                     bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
02076             }
02077         }
02078 
02079         i++;
02080         p = inet_ntoa(c1->from_addr.sin_addr);
02081         avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
02082                     i,
02083                     c1->stream ? c1->stream->filename : "",
02084                     c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
02085                     p,
02086                     c1->protocol,
02087                     http_state[c1->state]);
02088         fmt_bytecount(pb, bitrate);
02089         avio_printf(pb, "<td align=right>");
02090         fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
02091         avio_printf(pb, "<td align=right>");
02092         fmt_bytecount(pb, c1->data_count);
02093         avio_printf(pb, "\n");
02094         c1 = c1->next;
02095     }
02096     avio_printf(pb, "</table>\n");
02097 
02098     /* date */
02099     ti = time(NULL);
02100     p = ctime(&ti);
02101     avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
02102     avio_printf(pb, "</body>\n</html>\n");
02103 
02104     len = url_close_dyn_buf(pb, &c->pb_buffer);
02105     c->buffer_ptr = c->pb_buffer;
02106     c->buffer_end = c->pb_buffer + len;
02107 }
02108 
02109 /* check if the parser needs to be opened for stream i */
02110 static void open_parser(AVFormatContext *s, int i)
02111 {
02112     AVStream *st = s->streams[i];
02113     AVCodec *codec;
02114 
02115     if (!st->codec->codec) {
02116         codec = avcodec_find_decoder(st->codec->codec_id);
02117         if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
02118             st->codec->parse_only = 1;
02119             if (avcodec_open(st->codec, codec) < 0)
02120                 st->codec->parse_only = 0;
02121         }
02122     }
02123 }
02124 
02125 static int open_input_stream(HTTPContext *c, const char *info)
02126 {
02127     char buf[128];
02128     char input_filename[1024];
02129     AVFormatContext *s;
02130     int buf_size, i, ret;
02131     int64_t stream_pos;
02132 
02133     /* find file name */
02134     if (c->stream->feed) {
02135         strcpy(input_filename, c->stream->feed->feed_filename);
02136         buf_size = FFM_PACKET_SIZE;
02137         /* compute position (absolute time) */
02138         if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
02139             if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
02140                 return ret;
02141         } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
02142             int prebuffer = strtol(buf, 0, 10);
02143             stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
02144         } else
02145             stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
02146     } else {
02147         strcpy(input_filename, c->stream->feed_filename);
02148         buf_size = 0;
02149         /* compute position (relative time) */
02150         if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
02151             if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
02152                 return ret;
02153         } else
02154             stream_pos = 0;
02155     }
02156     if (input_filename[0] == '\0')
02157         return -1;
02158 
02159     /* open stream */
02160     if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
02161                                   buf_size, c->stream->ap_in)) < 0) {
02162         http_log("could not open %s: %d\n", input_filename, ret);
02163         return -1;
02164     }
02165     s->flags |= AVFMT_FLAG_GENPTS;
02166     c->fmt_in = s;
02167     if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
02168         http_log("Could not find stream info '%s'\n", input_filename);
02169         av_close_input_file(s);
02170         return -1;
02171     }
02172 
02173     /* open each parser */
02174     for(i=0;i<s->nb_streams;i++)
02175         open_parser(s, i);
02176 
02177     /* choose stream as clock source (we favorize video stream if
02178        present) for packet sending */
02179     c->pts_stream_index = 0;
02180     for(i=0;i<c->stream->nb_streams;i++) {
02181         if (c->pts_stream_index == 0 &&
02182             c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
02183             c->pts_stream_index = i;
02184         }
02185     }
02186 
02187 #if 1
02188     if (c->fmt_in->iformat->read_seek)
02189         av_seek_frame(c->fmt_in, -1, stream_pos, 0);
02190 #endif
02191     /* set the start time (needed for maxtime and RTP packet timing) */
02192     c->start_time = cur_time;
02193     c->first_pts = AV_NOPTS_VALUE;
02194     return 0;
02195 }
02196 
02197 /* return the server clock (in us) */
02198 static int64_t get_server_clock(HTTPContext *c)
02199 {
02200     /* compute current pts value from system time */
02201     return (cur_time - c->start_time) * 1000;
02202 }
02203 
02204 /* return the estimated time at which the current packet must be sent
02205    (in us) */
02206 static int64_t get_packet_send_clock(HTTPContext *c)
02207 {
02208     int bytes_left, bytes_sent, frame_bytes;
02209 
02210     frame_bytes = c->cur_frame_bytes;
02211     if (frame_bytes <= 0)
02212         return c->cur_pts;
02213     else {
02214         bytes_left = c->buffer_end - c->buffer_ptr;
02215         bytes_sent = frame_bytes - bytes_left;
02216         return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
02217     }
02218 }
02219 
02220 
02221 static int http_prepare_data(HTTPContext *c)
02222 {
02223     int i, len, ret;
02224     AVFormatContext *ctx;
02225 
02226     av_freep(&c->pb_buffer);
02227     switch(c->state) {
02228     case HTTPSTATE_SEND_DATA_HEADER:
02229         memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
02230         av_metadata_set2(&c->fmt_ctx.metadata, "author"   , c->stream->author   , 0);
02231         av_metadata_set2(&c->fmt_ctx.metadata, "comment"  , c->stream->comment  , 0);
02232         av_metadata_set2(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
02233         av_metadata_set2(&c->fmt_ctx.metadata, "title"    , c->stream->title    , 0);
02234 
02235         for(i=0;i<c->stream->nb_streams;i++) {
02236             AVStream *st;
02237             AVStream *src;
02238             st = av_mallocz(sizeof(AVStream));
02239             c->fmt_ctx.streams[i] = st;
02240             /* if file or feed, then just take streams from FFStream struct */
02241             if (!c->stream->feed ||
02242                 c->stream->feed == c->stream)
02243                 src = c->stream->streams[i];
02244             else
02245                 src = c->stream->feed->streams[c->stream->feed_streams[i]];
02246 
02247             *st = *src;
02248             st->priv_data = 0;
02249             st->codec->frame_number = 0; /* XXX: should be done in
02250                                            AVStream, not in codec */
02251         }
02252         /* set output format parameters */
02253         c->fmt_ctx.oformat = c->stream->fmt;
02254         c->fmt_ctx.nb_streams = c->stream->nb_streams;
02255 
02256         c->got_key_frame = 0;
02257 
02258         /* prepare header and save header data in a stream */
02259         if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
02260             /* XXX: potential leak */
02261             return -1;
02262         }
02263         c->fmt_ctx.pb->is_streamed = 1;
02264 
02265         /*
02266          * HACK to avoid mpeg ps muxer to spit many underflow errors
02267          * Default value from FFmpeg
02268          * Try to set it use configuration option
02269          */
02270         c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
02271         c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
02272 
02273         av_set_parameters(&c->fmt_ctx, NULL);
02274         if (av_write_header(&c->fmt_ctx) < 0) {
02275             http_log("Error writing output header\n");
02276             return -1;
02277         }
02278         av_metadata_free(&c->fmt_ctx.metadata);
02279 
02280         len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
02281         c->buffer_ptr = c->pb_buffer;
02282         c->buffer_end = c->pb_buffer + len;
02283 
02284         c->state = HTTPSTATE_SEND_DATA;
02285         c->last_packet_sent = 0;
02286         break;
02287     case HTTPSTATE_SEND_DATA:
02288         /* find a new packet */
02289         /* read a packet from the input stream */
02290         if (c->stream->feed)
02291             ffm_set_write_index(c->fmt_in,
02292                                 c->stream->feed->feed_write_index,
02293                                 c->stream->feed->feed_size);
02294 
02295         if (c->stream->max_time &&
02296             c->stream->max_time + c->start_time - cur_time < 0)
02297             /* We have timed out */
02298             c->state = HTTPSTATE_SEND_DATA_TRAILER;
02299         else {
02300             AVPacket pkt;
02301         redo:
02302             ret = av_read_frame(c->fmt_in, &pkt);
02303             if (ret < 0) {
02304                 if (c->stream->feed) {
02305                     /* if coming from feed, it means we reached the end of the
02306                        ffm file, so must wait for more data */
02307                     c->state = HTTPSTATE_WAIT_FEED;
02308                     return 1; /* state changed */
02309                 } else if (ret == AVERROR(EAGAIN)) {
02310                     /* input not ready, come back later */
02311                     return 0;
02312                 } else {
02313                     if (c->stream->loop) {
02314                         av_close_input_file(c->fmt_in);
02315                         c->fmt_in = NULL;
02316                         if (open_input_stream(c, "") < 0)
02317                             goto no_loop;
02318                         goto redo;
02319                     } else {
02320                     no_loop:
02321                         /* must send trailer now because eof or error */
02322                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
02323                     }
02324                 }
02325             } else {
02326                 int source_index = pkt.stream_index;
02327                 /* update first pts if needed */
02328                 if (c->first_pts == AV_NOPTS_VALUE) {
02329                     c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
02330                     c->start_time = cur_time;
02331                 }
02332                 /* send it to the appropriate stream */
02333                 if (c->stream->feed) {
02334                     /* if coming from a feed, select the right stream */
02335                     if (c->switch_pending) {
02336                         c->switch_pending = 0;
02337                         for(i=0;i<c->stream->nb_streams;i++) {
02338                             if (c->switch_feed_streams[i] == pkt.stream_index)
02339                                 if (pkt.flags & AV_PKT_FLAG_KEY)
02340                                     c->switch_feed_streams[i] = -1;
02341                             if (c->switch_feed_streams[i] >= 0)
02342                                 c->switch_pending = 1;
02343                         }
02344                     }
02345                     for(i=0;i<c->stream->nb_streams;i++) {
02346                         if (c->stream->feed_streams[i] == pkt.stream_index) {
02347                             AVStream *st = c->fmt_in->streams[source_index];
02348                             pkt.stream_index = i;
02349                             if (pkt.flags & AV_PKT_FLAG_KEY &&
02350                                 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
02351                                  c->stream->nb_streams == 1))
02352                                 c->got_key_frame = 1;
02353                             if (!c->stream->send_on_key || c->got_key_frame)
02354                                 goto send_it;
02355                         }
02356                     }
02357                 } else {
02358                     AVCodecContext *codec;
02359                     AVStream *ist, *ost;
02360                 send_it:
02361                     ist = c->fmt_in->streams[source_index];
02362                     /* specific handling for RTP: we use several
02363                        output stream (one for each RTP
02364                        connection). XXX: need more abstract handling */
02365                     if (c->is_packetized) {
02366                         /* compute send time and duration */
02367                         c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
02368                         c->cur_pts -= c->first_pts;
02369                         c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
02370                         /* find RTP context */
02371                         c->packet_stream_index = pkt.stream_index;
02372                         ctx = c->rtp_ctx[c->packet_stream_index];
02373                         if(!ctx) {
02374                             av_free_packet(&pkt);
02375                             break;
02376                         }
02377                         codec = ctx->streams[0]->codec;
02378                         /* only one stream per RTP connection */
02379                         pkt.stream_index = 0;
02380                     } else {
02381                         ctx = &c->fmt_ctx;
02382                         /* Fudge here */
02383                         codec = ctx->streams[pkt.stream_index]->codec;
02384                     }
02385 
02386                     if (c->is_packetized) {
02387                         int max_packet_size;
02388                         if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
02389                             max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
02390                         else
02391                             max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
02392                         ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
02393                     } else {
02394                         ret = url_open_dyn_buf(&ctx->pb);
02395                     }
02396                     if (ret < 0) {
02397                         /* XXX: potential leak */
02398                         return -1;
02399                     }
02400                     ost = ctx->streams[pkt.stream_index];
02401 
02402                     ctx->pb->is_streamed = 1;
02403                     if (pkt.dts != AV_NOPTS_VALUE)
02404                         pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
02405                     if (pkt.pts != AV_NOPTS_VALUE)
02406                         pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
02407                     pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
02408                     if (av_write_frame(ctx, &pkt) < 0) {
02409                         http_log("Error writing frame to output\n");
02410                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
02411                     }
02412 
02413                     len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
02414                     c->cur_frame_bytes = len;
02415                     c->buffer_ptr = c->pb_buffer;
02416                     c->buffer_end = c->pb_buffer + len;
02417 
02418                     codec->frame_number++;
02419                     if (len == 0) {
02420                         av_free_packet(&pkt);
02421                         goto redo;
02422                     }
02423                 }
02424                 av_free_packet(&pkt);
02425             }
02426         }
02427         break;
02428     default:
02429     case HTTPSTATE_SEND_DATA_TRAILER:
02430         /* last packet test ? */
02431         if (c->last_packet_sent || c->is_packetized)
02432             return -1;
02433         ctx = &c->fmt_ctx;
02434         /* prepare header */
02435         if (url_open_dyn_buf(&ctx->pb) < 0) {
02436             /* XXX: potential leak */
02437             return -1;
02438         }
02439         c->fmt_ctx.pb->is_streamed = 1;
02440         av_write_trailer(ctx);
02441         len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
02442         c->buffer_ptr = c->pb_buffer;
02443         c->buffer_end = c->pb_buffer + len;
02444 
02445         c->last_packet_sent = 1;
02446         break;
02447     }
02448     return 0;
02449 }
02450 
02451 /* should convert the format at the same time */
02452 /* send data starting at c->buffer_ptr to the output connection
02453    (either UDP or TCP connection) */
02454 static int http_send_data(HTTPContext *c)
02455 {
02456     int len, ret;
02457 
02458     for(;;) {
02459         if (c->buffer_ptr >= c->buffer_end) {
02460             ret = http_prepare_data(c);
02461             if (ret < 0)
02462                 return -1;
02463             else if (ret != 0)
02464                 /* state change requested */
02465                 break;
02466         } else {
02467             if (c->is_packetized) {
02468                 /* RTP data output */
02469                 len = c->buffer_end - c->buffer_ptr;
02470                 if (len < 4) {
02471                     /* fail safe - should never happen */
02472                 fail1:
02473                     c->buffer_ptr = c->buffer_end;
02474                     return 0;
02475                 }
02476                 len = (c->buffer_ptr[0] << 24) |
02477                     (c->buffer_ptr[1] << 16) |
02478                     (c->buffer_ptr[2] << 8) |
02479                     (c->buffer_ptr[3]);
02480                 if (len > (c->buffer_end - c->buffer_ptr))
02481                     goto fail1;
02482                 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
02483                     /* nothing to send yet: we can wait */
02484                     return 0;
02485                 }
02486 
02487                 c->data_count += len;
02488                 update_datarate(&c->datarate, c->data_count);
02489                 if (c->stream)
02490                     c->stream->bytes_served += len;
02491 
02492                 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
02493                     /* RTP packets are sent inside the RTSP TCP connection */
02494                     AVIOContext *pb;
02495                     int interleaved_index, size;
02496                     uint8_t header[4];
02497                     HTTPContext *rtsp_c;
02498 
02499                     rtsp_c = c->rtsp_c;
02500                     /* if no RTSP connection left, error */
02501                     if (!rtsp_c)
02502                         return -1;
02503                     /* if already sending something, then wait. */
02504                     if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
02505                         break;
02506                     if (url_open_dyn_buf(&pb) < 0)
02507                         goto fail1;
02508                     interleaved_index = c->packet_stream_index * 2;
02509                     /* RTCP packets are sent at odd indexes */
02510                     if (c->buffer_ptr[1] == 200)
02511                         interleaved_index++;
02512                     /* write RTSP TCP header */
02513                     header[0] = '$';
02514                     header[1] = interleaved_index;
02515                     header[2] = len >> 8;
02516                     header[3] = len;
02517                     avio_write(pb, header, 4);
02518                     /* write RTP packet data */
02519                     c->buffer_ptr += 4;
02520                     avio_write(pb, c->buffer_ptr, len);
02521                     size = url_close_dyn_buf(pb, &c->packet_buffer);
02522                     /* prepare asynchronous TCP sending */
02523                     rtsp_c->packet_buffer_ptr = c->packet_buffer;
02524                     rtsp_c->packet_buffer_end = c->packet_buffer + size;
02525                     c->buffer_ptr += len;
02526 
02527                     /* send everything we can NOW */
02528                     len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
02529                                 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
02530                     if (len > 0)
02531                         rtsp_c->packet_buffer_ptr += len;
02532                     if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
02533                         /* if we could not send all the data, we will
02534                            send it later, so a new state is needed to
02535                            "lock" the RTSP TCP connection */
02536                         rtsp_c->state = RTSPSTATE_SEND_PACKET;
02537                         break;
02538                     } else
02539                         /* all data has been sent */
02540                         av_freep(&c->packet_buffer);
02541                 } else {
02542                     /* send RTP packet directly in UDP */
02543                     c->buffer_ptr += 4;
02544                     url_write(c->rtp_handles[c->packet_stream_index],
02545                               c->buffer_ptr, len);
02546                     c->buffer_ptr += len;
02547                     /* here we continue as we can send several packets per 10 ms slot */
02548                 }
02549             } else {
02550                 /* TCP data output */
02551                 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
02552                 if (len < 0) {
02553                     if (ff_neterrno() != AVERROR(EAGAIN) &&
02554                         ff_neterrno() != AVERROR(EINTR))
02555                         /* error : close connection */
02556                         return -1;
02557                     else
02558                         return 0;
02559                 } else
02560                     c->buffer_ptr += len;
02561 
02562                 c->data_count += len;
02563                 update_datarate(&c->datarate, c->data_count);
02564                 if (c->stream)
02565                     c->stream->bytes_served += len;
02566                 break;
02567             }
02568         }
02569     } /* for(;;) */
02570     return 0;
02571 }
02572 
02573 static int http_start_receive_data(HTTPContext *c)
02574 {
02575     int fd;
02576 
02577     if (c->stream->feed_opened)
02578         return -1;
02579 
02580     /* Don't permit writing to this one */
02581     if (c->stream->readonly)
02582         return -1;
02583 
02584     /* open feed */
02585     fd = open(c->stream->feed_filename, O_RDWR);
02586     if (fd < 0) {
02587         http_log("Error opening feeder file: %s\n", strerror(errno));
02588         return -1;
02589     }
02590     c->feed_fd = fd;
02591 
02592     if (c->stream->truncate) {
02593         /* truncate feed file */
02594         ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
02595         ftruncate(c->feed_fd, FFM_PACKET_SIZE);
02596         http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
02597     } else {
02598         if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
02599             http_log("Error reading write index from feed file: %s\n", strerror(errno));
02600             return -1;
02601         }
02602     }
02603 
02604     c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
02605     c->stream->feed_size = lseek(fd, 0, SEEK_END);
02606     lseek(fd, 0, SEEK_SET);
02607 
02608     /* init buffer input */
02609     c->buffer_ptr = c->buffer;
02610     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
02611     c->stream->feed_opened = 1;
02612     c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
02613     return 0;
02614 }
02615 
02616 static int http_receive_data(HTTPContext *c)
02617 {
02618     HTTPContext *c1;
02619     int len, loop_run = 0;
02620 
02621     while (c->chunked_encoding && !c->chunk_size &&
02622            c->buffer_end > c->buffer_ptr) {
02623         /* read chunk header, if present */
02624         len = recv(c->fd, c->buffer_ptr, 1, 0);
02625 
02626         if (len < 0) {
02627             if (ff_neterrno() != AVERROR(EAGAIN) &&
02628                 ff_neterrno() != AVERROR(EINTR))
02629                 /* error : close connection */
02630                 goto fail;
02631             return 0;
02632         } else if (len == 0) {
02633             /* end of connection : close it */
02634             goto fail;
02635         } else if (c->buffer_ptr - c->buffer >= 2 &&
02636                    !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
02637             c->chunk_size = strtol(c->buffer, 0, 16);
02638             if (c->chunk_size == 0) // end of stream
02639                 goto fail;
02640             c->buffer_ptr = c->buffer;
02641             break;
02642         } else if (++loop_run > 10) {
02643             /* no chunk header, abort */
02644             goto fail;
02645         } else {
02646             c->buffer_ptr++;
02647         }
02648     }
02649 
02650     if (c->buffer_end > c->buffer_ptr) {
02651         len = recv(c->fd, c->buffer_ptr,
02652                    FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
02653         if (len < 0) {
02654             if (ff_neterrno() != AVERROR(EAGAIN) &&
02655                 ff_neterrno() != AVERROR(EINTR))
02656                 /* error : close connection */
02657                 goto fail;
02658         } else if (len == 0)
02659             /* end of connection : close it */
02660             goto fail;
02661         else {
02662             c->chunk_size -= len;
02663             c->buffer_ptr += len;
02664             c->data_count += len;
02665             update_datarate(&c->datarate, c->data_count);
02666         }
02667     }
02668 
02669     if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
02670         if (c->buffer[0] != 'f' ||
02671             c->buffer[1] != 'm') {
02672             http_log("Feed stream has become desynchronized -- disconnecting\n");
02673             goto fail;
02674         }
02675     }
02676 
02677     if (c->buffer_ptr >= c->buffer_end) {
02678         FFStream *feed = c->stream;
02679         /* a packet has been received : write it in the store, except
02680            if header */
02681         if (c->data_count > FFM_PACKET_SIZE) {
02682 
02683             //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
02684             /* XXX: use llseek or url_seek */
02685             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
02686             if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
02687                 http_log("Error writing to feed file: %s\n", strerror(errno));
02688                 goto fail;
02689             }
02690 
02691             feed->feed_write_index += FFM_PACKET_SIZE;
02692             /* update file size */
02693             if (feed->feed_write_index > c->stream->feed_size)
02694                 feed->feed_size = feed->feed_write_index;
02695 
02696             /* handle wrap around if max file size reached */
02697             if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
02698                 feed->feed_write_index = FFM_PACKET_SIZE;
02699 
02700             /* write index */
02701             if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
02702                 http_log("Error writing index to feed file: %s\n", strerror(errno));
02703                 goto fail;
02704             }
02705 
02706             /* wake up any waiting connections */
02707             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
02708                 if (c1->state == HTTPSTATE_WAIT_FEED &&
02709                     c1->stream->feed == c->stream->feed)
02710                     c1->state = HTTPSTATE_SEND_DATA;
02711             }
02712         } else {
02713             /* We have a header in our hands that contains useful data */
02714             AVFormatContext *s = NULL;
02715             AVIOContext *pb;
02716             AVInputFormat *fmt_in;
02717             int i;
02718 
02719             /* use feed output format name to find corresponding input format */
02720             fmt_in = av_find_input_format(feed->fmt->name);
02721             if (!fmt_in)
02722                 goto fail;
02723 
02724             pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
02725                                     0, NULL, NULL, NULL, NULL);
02726             pb->is_streamed = 1;
02727 
02728             if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
02729                 av_free(pb);
02730                 goto fail;
02731             }
02732 
02733             /* Now we have the actual streams */
02734             if (s->nb_streams != feed->nb_streams) {
02735                 av_close_input_stream(s);
02736                 av_free(pb);
02737                 http_log("Feed '%s' stream number does not match registered feed\n",
02738                          c->stream->feed_filename);
02739                 goto fail;
02740             }
02741 
02742             for (i = 0; i < s->nb_streams; i++) {
02743                 AVStream *fst = feed->streams[i];
02744                 AVStream *st = s->streams[i];
02745                 avcodec_copy_context(fst->codec, st->codec);
02746             }
02747 
02748             av_close_input_stream(s);
02749             av_free(pb);
02750         }
02751         c->buffer_ptr = c->buffer;
02752     }
02753 
02754     return 0;
02755  fail:
02756     c->stream->feed_opened = 0;
02757     close(c->feed_fd);
02758     /* wake up any waiting connections to stop waiting for feed */
02759     for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
02760         if (c1->state == HTTPSTATE_WAIT_FEED &&
02761             c1->stream->feed == c->stream->feed)
02762             c1->state = HTTPSTATE_SEND_DATA_TRAILER;
02763     }
02764     return -1;
02765 }
02766 
02767 /********************************************************************/
02768 /* RTSP handling */
02769 
02770 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
02771 {
02772     const char *str;
02773     time_t ti;
02774     struct tm *tm;
02775     char buf2[32];
02776 
02777     switch(error_number) {
02778     case RTSP_STATUS_OK:
02779         str = "OK";
02780         break;
02781     case RTSP_STATUS_METHOD:
02782         str = "Method Not Allowed";
02783         break;
02784     case RTSP_STATUS_BANDWIDTH:
02785         str = "Not Enough Bandwidth";
02786         break;
02787     case RTSP_STATUS_SESSION:
02788         str = "Session Not Found";
02789         break;
02790     case RTSP_STATUS_STATE:
02791         str = "Method Not Valid in This State";
02792         break;
02793     case RTSP_STATUS_AGGREGATE:
02794         str = "Aggregate operation not allowed";
02795         break;
02796     case RTSP_STATUS_ONLY_AGGREGATE:
02797         str = "Only aggregate operation allowed";
02798         break;
02799     case RTSP_STATUS_TRANSPORT:
02800         str = "Unsupported transport";
02801         break;
02802     case RTSP_STATUS_INTERNAL:
02803         str = "Internal Server Error";
02804         break;
02805     case RTSP_STATUS_SERVICE:
02806         str = "Service Unavailable";
02807         break;
02808     case RTSP_STATUS_VERSION:
02809         str = "RTSP Version not supported";
02810         break;
02811     default:
02812         str = "Unknown Error";
02813         break;
02814     }
02815 
02816     avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
02817     avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
02818 
02819     /* output GMT time */
02820     ti = time(NULL);
02821     tm = gmtime(&ti);
02822     strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
02823     avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
02824 }
02825 
02826 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
02827 {
02828     rtsp_reply_header(c, error_number);
02829     avio_printf(c->pb, "\r\n");
02830 }
02831 
02832 static int rtsp_parse_request(HTTPContext *c)
02833 {
02834     const char *p, *p1, *p2;
02835     char cmd[32];
02836     char url[1024];
02837     char protocol[32];
02838     char line[1024];
02839     int len;
02840     RTSPMessageHeader header1, *header = &header1;
02841 
02842     c->buffer_ptr[0] = '\0';
02843     p = c->buffer;
02844 
02845     get_word(cmd, sizeof(cmd), &p);
02846     get_word(url, sizeof(url), &p);
02847     get_word(protocol, sizeof(protocol), &p);
02848 
02849     av_strlcpy(c->method, cmd, sizeof(c->method));
02850     av_strlcpy(c->url, url, sizeof(c->url));
02851     av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
02852 
02853     if (url_open_dyn_buf(&c->pb) < 0) {
02854         /* XXX: cannot do more */
02855         c->pb = NULL; /* safety */
02856         return -1;
02857     }
02858 
02859     /* check version name */
02860     if (strcmp(protocol, "RTSP/1.0") != 0) {
02861         rtsp_reply_error(c, RTSP_STATUS_VERSION);
02862         goto the_end;
02863     }
02864 
02865     /* parse each header line */
02866     memset(header, 0, sizeof(*header));
02867     /* skip to next line */
02868     while (*p != '\n' && *p != '\0')
02869         p++;
02870     if (*p == '\n')
02871         p++;
02872     while (*p != '\0') {
02873         p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
02874         if (!p1)
02875             break;
02876         p2 = p1;
02877         if (p2 > p && p2[-1] == '\r')
02878             p2--;
02879         /* skip empty line */
02880         if (p2 == p)
02881             break;
02882         len = p2 - p;
02883         if (len > sizeof(line) - 1)
02884             len = sizeof(line) - 1;
02885         memcpy(line, p, len);
02886         line[len] = '\0';
02887         ff_rtsp_parse_line(header, line, NULL, NULL);
02888         p = p1 + 1;
02889     }
02890 
02891     /* handle sequence number */
02892     c->seq = header->seq;
02893 
02894     if (!strcmp(cmd, "DESCRIBE"))
02895         rtsp_cmd_describe(c, url);
02896     else if (!strcmp(cmd, "OPTIONS"))
02897         rtsp_cmd_options(c, url);
02898     else if (!strcmp(cmd, "SETUP"))
02899         rtsp_cmd_setup(c, url, header);
02900     else if (!strcmp(cmd, "PLAY"))
02901         rtsp_cmd_play(c, url, header);
02902     else if (!strcmp(cmd, "PAUSE"))
02903         rtsp_cmd_pause(c, url, header);
02904     else if (!strcmp(cmd, "TEARDOWN"))
02905         rtsp_cmd_teardown(c, url, header);
02906     else
02907         rtsp_reply_error(c, RTSP_STATUS_METHOD);
02908 
02909  the_end:
02910     len = url_close_dyn_buf(c->pb, &c->pb_buffer);
02911     c->pb = NULL; /* safety */
02912     if (len < 0) {
02913         /* XXX: cannot do more */
02914         return -1;
02915     }
02916     c->buffer_ptr = c->pb_buffer;
02917     c->buffer_end = c->pb_buffer + len;
02918     c->state = RTSPSTATE_SEND_REPLY;
02919     return 0;
02920 }
02921 
02922 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
02923                                    struct in_addr my_ip)
02924 {
02925     AVFormatContext *avc;
02926     AVStream *avs = NULL;
02927     int i;
02928 
02929     avc =  avformat_alloc_context();
02930     if (avc == NULL) {
02931         return -1;
02932     }
02933     av_metadata_set2(&avc->metadata, "title",
02934                      stream->title[0] ? stream->title : "No Title", 0);
02935     avc->nb_streams = stream->nb_streams;
02936     if (stream->is_multicast) {
02937         snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
02938                  inet_ntoa(stream->multicast_ip),
02939                  stream->multicast_port, stream->multicast_ttl);
02940     } else {
02941         snprintf(avc->filename, 1024, "rtp://0.0.0.0");
02942     }
02943 
02944 #if !FF_API_MAX_STREAMS
02945     if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
02946         !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
02947         goto sdp_done;
02948 #endif
02949     if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
02950         !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
02951         goto sdp_done;
02952 
02953     for(i = 0; i < stream->nb_streams; i++) {
02954         avc->streams[i] = &avs[i];
02955         avc->streams[i]->codec = stream->streams[i]->codec;
02956     }
02957     *pbuffer = av_mallocz(2048);
02958     avf_sdp_create(&avc, 1, *pbuffer, 2048);
02959 
02960  sdp_done:
02961 #if !FF_API_MAX_STREAMS
02962     av_free(avc->streams);
02963 #endif
02964     av_metadata_free(&avc->metadata);
02965     av_free(avc);
02966     av_free(avs);
02967 
02968     return strlen(*pbuffer);
02969 }
02970 
02971 static void rtsp_cmd_options(HTTPContext *c, const char *url)
02972 {
02973 //    rtsp_reply_header(c, RTSP_STATUS_OK);
02974     avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
02975     avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
02976     avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
02977     avio_printf(c->pb, "\r\n");
02978 }
02979 
02980 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
02981 {
02982     FFStream *stream;
02983     char path1[1024];
02984     const char *path;
02985     uint8_t *content;
02986     int content_length, len;
02987     struct sockaddr_in my_addr;
02988 
02989     /* find which url is asked */
02990     av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
02991     path = path1;
02992     if (*path == '/')
02993         path++;
02994 
02995     for(stream = first_stream; stream != NULL; stream = stream->next) {
02996         if (!stream->is_feed &&
02997             stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
02998             !strcmp(path, stream->filename)) {
02999             goto found;
03000         }
03001     }
03002     /* no stream found */
03003     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
03004     return;
03005 
03006  found:
03007     /* prepare the media description in sdp format */
03008 
03009     /* get the host IP */
03010     len = sizeof(my_addr);
03011     getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
03012     content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
03013     if (content_length < 0) {
03014         rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
03015         return;
03016     }
03017     rtsp_reply_header(c, RTSP_STATUS_OK);
03018     avio_printf(c->pb, "Content-Base: %s/\r\n", url);
03019     avio_printf(c->pb, "Content-Type: application/sdp\r\n");
03020     avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
03021     avio_printf(c->pb, "\r\n");
03022     avio_write(c->pb, content, content_length);
03023     av_free(content);
03024 }
03025 
03026 static HTTPContext *find_rtp_session(const char *session_id)
03027 {
03028     HTTPContext *c;
03029 
03030     if (session_id[0] == '\0')
03031         return NULL;
03032 
03033     for(c = first_http_ctx; c != NULL; c = c->next) {
03034         if (!strcmp(c->session_id, session_id))
03035             return c;
03036     }
03037     return NULL;
03038 }
03039 
03040 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
03041 {
03042     RTSPTransportField *th;
03043     int i;
03044 
03045     for(i=0;i<h->nb_transports;i++) {
03046         th = &h->transports[i];
03047         if (th->lower_transport == lower_transport)
03048             return th;
03049     }
03050     return NULL;
03051 }
03052 
03053 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
03054                            RTSPMessageHeader *h)
03055 {
03056     FFStream *stream;
03057     int stream_index, rtp_port, rtcp_port;
03058     char buf[1024];
03059     char path1[1024];
03060     const char *path;
03061     HTTPContext *rtp_c;
03062     RTSPTransportField *th;
03063     struct sockaddr_in dest_addr;
03064     RTSPActionServerSetup setup;
03065 
03066     /* find which url is asked */
03067     av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
03068     path = path1;
03069     if (*path == '/')
03070         path++;
03071 
03072     /* now check each stream */
03073     for(stream = first_stream; stream != NULL; stream = stream->next) {
03074         if (!stream->is_feed &&
03075             stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
03076             /* accept aggregate filenames only if single stream */
03077             if (!strcmp(path, stream->filename)) {
03078                 if (stream->nb_streams != 1) {
03079                     rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
03080                     return;
03081                 }
03082                 stream_index = 0;
03083                 goto found;
03084             }
03085 
03086             for(stream_index = 0; stream_index < stream->nb_streams;
03087                 stream_index++) {
03088                 snprintf(buf, sizeof(buf), "%s/streamid=%d",
03089                          stream->filename, stream_index);
03090                 if (!strcmp(path, buf))
03091                     goto found;
03092             }
03093         }
03094     }
03095     /* no stream found */
03096     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
03097     return;
03098  found:
03099 
03100     /* generate session id if needed */
03101     if (h->session_id[0] == '\0')
03102         snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
03103                  av_lfg_get(&random_state), av_lfg_get(&random_state));
03104 
03105     /* find rtp session, and create it if none found */
03106     rtp_c = find_rtp_session(h->session_id);
03107     if (!rtp_c) {
03108         /* always prefer UDP */
03109         th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
03110         if (!th) {
03111             th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
03112             if (!th) {
03113                 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
03114                 return;
03115             }
03116         }
03117 
03118         rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
03119                                    th->lower_transport);
03120         if (!rtp_c) {
03121             rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
03122             return;
03123         }
03124 
03125         /* open input stream */
03126         if (open_input_stream(rtp_c, "") < 0) {
03127             rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
03128             return;
03129         }
03130     }
03131 
03132     /* test if stream is OK (test needed because several SETUP needs
03133        to be done for a given file) */
03134     if (rtp_c->stream != stream) {
03135         rtsp_reply_error(c, RTSP_STATUS_SERVICE);
03136         return;
03137     }
03138 
03139     /* test if stream is already set up */
03140     if (rtp_c->rtp_ctx[stream_index]) {
03141         rtsp_reply_error(c, RTSP_STATUS_STATE);
03142         return;
03143     }
03144 
03145     /* check transport */
03146     th = find_transport(h, rtp_c->rtp_protocol);
03147     if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
03148                 th->client_port_min <= 0)) {
03149         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
03150         return;
03151     }
03152 
03153     /* setup default options */
03154     setup.transport_option[0] = '\0';
03155     dest_addr = rtp_c->from_addr;
03156     dest_addr.sin_port = htons(th->client_port_min);
03157 
03158     /* setup stream */
03159     if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
03160         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
03161         return;
03162     }
03163 
03164     /* now everything is OK, so we can send the connection parameters */
03165     rtsp_reply_header(c, RTSP_STATUS_OK);
03166     /* session ID */
03167     avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
03168 
03169     switch(rtp_c->rtp_protocol) {
03170     case RTSP_LOWER_TRANSPORT_UDP:
03171         rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
03172         rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
03173         avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
03174                     "client_port=%d-%d;server_port=%d-%d",
03175                     th->client_port_min, th->client_port_max,
03176                     rtp_port, rtcp_port);
03177         break;
03178     case RTSP_LOWER_TRANSPORT_TCP:
03179         avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
03180                     stream_index * 2, stream_index * 2 + 1);
03181         break;
03182     default:
03183         break;
03184     }
03185     if (setup.transport_option[0] != '\0')
03186         avio_printf(c->pb, ";%s", setup.transport_option);
03187     avio_printf(c->pb, "\r\n");
03188 
03189 
03190     avio_printf(c->pb, "\r\n");
03191 }
03192 
03193 
03194 /* find an rtp connection by using the session ID. Check consistency
03195    with filename */
03196 static HTTPContext *find_rtp_session_with_url(const char *url,
03197                                               const char *session_id)
03198 {
03199     HTTPContext *rtp_c;
03200     char path1[1024];
03201     const char *path;
03202     char buf[1024];
03203     int s, len;
03204 
03205     rtp_c = find_rtp_session(session_id);
03206     if (!rtp_c)
03207         return NULL;
03208 
03209     /* find which url is asked */
03210     av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
03211     path = path1;
03212     if (*path == '/')
03213         path++;
03214     if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
03215     for(s=0; s<rtp_c->stream->nb_streams; ++s) {
03216       snprintf(buf, sizeof(buf), "%s/streamid=%d",
03217         rtp_c->stream->filename, s);
03218       if(!strncmp(path, buf, sizeof(buf))) {
03219     // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
03220         return rtp_c;
03221       }
03222     }
03223     len = strlen(path);
03224     if (len > 0 && path[len - 1] == '/' &&
03225         !strncmp(path, rtp_c->stream->filename, len - 1))
03226         return rtp_c;
03227     return NULL;
03228 }
03229 
03230 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
03231 {
03232     HTTPContext *rtp_c;
03233 
03234     rtp_c = find_rtp_session_with_url(url, h->session_id);
03235     if (!rtp_c) {
03236         rtsp_reply_error(c, RTSP_STATUS_SESSION);
03237         return;
03238     }
03239 
03240     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
03241         rtp_c->state != HTTPSTATE_WAIT_FEED &&
03242         rtp_c->state != HTTPSTATE_READY) {
03243         rtsp_reply_error(c, RTSP_STATUS_STATE);
03244         return;
03245     }
03246 
03247     rtp_c->state = HTTPSTATE_SEND_DATA;
03248 
03249     /* now everything is OK, so we can send the connection parameters */
03250     rtsp_reply_header(c, RTSP_STATUS_OK);
03251     /* session ID */
03252     avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
03253     avio_printf(c->pb, "\r\n");
03254 }
03255 
03256 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
03257 {
03258     HTTPContext *rtp_c;
03259 
03260     rtp_c = find_rtp_session_with_url(url, h->session_id);
03261     if (!rtp_c) {
03262         rtsp_reply_error(c, RTSP_STATUS_SESSION);
03263         return;
03264     }
03265 
03266     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
03267         rtp_c->state != HTTPSTATE_WAIT_FEED) {
03268         rtsp_reply_error(c, RTSP_STATUS_STATE);
03269         return;
03270     }
03271 
03272     rtp_c->state = HTTPSTATE_READY;
03273     rtp_c->first_pts = AV_NOPTS_VALUE;
03274     /* now everything is OK, so we can send the connection parameters */
03275     rtsp_reply_header(c, RTSP_STATUS_OK);
03276     /* session ID */
03277     avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
03278     avio_printf(c->pb, "\r\n");
03279 }
03280 
03281 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
03282 {
03283     HTTPContext *rtp_c;
03284     char session_id[32];
03285 
03286     rtp_c = find_rtp_session_with_url(url, h->session_id);
03287     if (!rtp_c) {
03288         rtsp_reply_error(c, RTSP_STATUS_SESSION);
03289         return;
03290     }
03291 
03292     av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
03293 
03294     /* abort the session */
03295     close_connection(rtp_c);
03296 
03297     /* now everything is OK, so we can send the connection parameters */
03298     rtsp_reply_header(c, RTSP_STATUS_OK);
03299     /* session ID */
03300     avio_printf(c->pb, "Session: %s\r\n", session_id);
03301     avio_printf(c->pb, "\r\n");
03302 }
03303 
03304 
03305 /********************************************************************/
03306 /* RTP handling */
03307 
03308 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
03309                                        FFStream *stream, const char *session_id,
03310                                        enum RTSPLowerTransport rtp_protocol)
03311 {
03312     HTTPContext *c = NULL;
03313     const char *proto_str;
03314 
03315     /* XXX: should output a warning page when coming
03316        close to the connection limit */
03317     if (nb_connections >= nb_max_connections)
03318         goto fail;
03319 
03320     /* add a new connection */
03321     c = av_mallocz(sizeof(HTTPContext));
03322     if (!c)
03323         goto fail;
03324 
03325     c->fd = -1;
03326     c->poll_entry = NULL;
03327     c->from_addr = *from_addr;
03328     c->buffer_size = IOBUFFER_INIT_SIZE;
03329     c->buffer = av_malloc(c->buffer_size);
03330     if (!c->buffer)
03331         goto fail;
03332     nb_connections++;
03333     c->stream = stream;
03334     av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
03335     c->state = HTTPSTATE_READY;
03336     c->is_packetized = 1;
03337     c->rtp_protocol = rtp_protocol;
03338 
03339     /* protocol is shown in statistics */
03340     switch(c->rtp_protocol) {
03341     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
03342         proto_str = "MCAST";
03343         break;
03344     case RTSP_LOWER_TRANSPORT_UDP:
03345         proto_str = "UDP";
03346         break;
03347     case RTSP_LOWER_TRANSPORT_TCP:
03348         proto_str = "TCP";
03349         break;
03350     default:
03351         proto_str = "???";
03352         break;
03353     }
03354     av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
03355     av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
03356 
03357     current_bandwidth += stream->bandwidth;
03358 
03359     c->next = first_http_ctx;
03360     first_http_ctx = c;
03361     return c;
03362 
03363  fail:
03364     if (c) {
03365         av_free(c->buffer);
03366         av_free(c);
03367     }
03368     return NULL;
03369 }
03370 
03371 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
03372    command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
03373    used. */
03374 static int rtp_new_av_stream(HTTPContext *c,
03375                              int stream_index, struct sockaddr_in *dest_addr,
03376                              HTTPContext *rtsp_c)
03377 {
03378     AVFormatContext *ctx;
03379     AVStream *st;
03380     char *ipaddr;
03381     URLContext *h = NULL;
03382     uint8_t *dummy_buf;
03383     int max_packet_size;
03384 
03385     /* now we can open the relevant output stream */
03386     ctx = avformat_alloc_context();
03387     if (!ctx)
03388         return -1;
03389     ctx->oformat = av_guess_format("rtp", NULL, NULL);
03390 
03391     st = av_mallocz(sizeof(AVStream));
03392     if (!st)
03393         goto fail;
03394     ctx->nb_streams = 1;
03395     ctx->streams[0] = st;
03396 
03397     if (!c->stream->feed ||
03398         c->stream->feed == c->stream)
03399         memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
03400     else
03401         memcpy(st,
03402                c->stream->feed->streams[c->stream->feed_streams[stream_index]],
03403                sizeof(AVStream));
03404     st->priv_data = NULL;
03405 
03406     /* build destination RTP address */
03407     ipaddr = inet_ntoa(dest_addr->sin_addr);
03408 
03409     switch(c->rtp_protocol) {
03410     case RTSP_LOWER_TRANSPORT_UDP:
03411     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
03412         /* RTP/UDP case */
03413 
03414         /* XXX: also pass as parameter to function ? */
03415         if (c->stream->is_multicast) {
03416             int ttl;
03417             ttl = c->stream->multicast_ttl;
03418             if (!ttl)
03419                 ttl = 16;
03420             snprintf(ctx->filename, sizeof(ctx->filename),
03421                      "rtp://%s:%d?multicast=1&ttl=%d",
03422                      ipaddr, ntohs(dest_addr->sin_port), ttl);
03423         } else {
03424             snprintf(ctx->filename, sizeof(ctx->filename),
03425                      "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
03426         }
03427 
03428         if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
03429             goto fail;
03430         c->rtp_handles[stream_index] = h;
03431         max_packet_size = url_get_max_packet_size(h);
03432         break;
03433     case RTSP_LOWER_TRANSPORT_TCP:
03434         /* RTP/TCP case */
03435         c->rtsp_c = rtsp_c;
03436         max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
03437         break;
03438     default:
03439         goto fail;
03440     }
03441 
03442     http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
03443              ipaddr, ntohs(dest_addr->sin_port),
03444              c->stream->filename, stream_index, c->protocol);
03445 
03446     /* normally, no packets should be output here, but the packet size may be checked */
03447     if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
03448         /* XXX: close stream */
03449         goto fail;
03450     }
03451     av_set_parameters(ctx, NULL);
03452     if (av_write_header(ctx) < 0) {
03453     fail:
03454         if (h)
03455             url_close(h);
03456         av_free(ctx);
03457         return -1;
03458     }
03459     url_close_dyn_buf(ctx->pb, &dummy_buf);
03460     av_free(dummy_buf);
03461 
03462     c->rtp_ctx[stream_index] = ctx;
03463     return 0;
03464 }
03465 
03466 /********************************************************************/
03467 /* ffserver initialization */
03468 
03469 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
03470 {
03471     AVStream *fst;
03472 
03473     fst = av_mallocz(sizeof(AVStream));
03474     if (!fst)
03475         return NULL;
03476     if (copy) {
03477         fst->codec= avcodec_alloc_context();
03478         memcpy(fst->codec, codec, sizeof(AVCodecContext));
03479         if (codec->extradata_size) {
03480             fst->codec->extradata = av_malloc(codec->extradata_size);
03481             memcpy(fst->codec->extradata, codec->extradata,
03482                 codec->extradata_size);
03483         }
03484     } else {
03485         /* live streams must use the actual feed's codec since it may be
03486          * updated later to carry extradata needed by the streams.
03487          */
03488         fst->codec = codec;
03489     }
03490     fst->priv_data = av_mallocz(sizeof(FeedData));
03491     fst->index = stream->nb_streams;
03492     av_set_pts_info(fst, 33, 1, 90000);
03493     fst->sample_aspect_ratio = codec->sample_aspect_ratio;
03494     stream->streams[stream->nb_streams++] = fst;
03495     return fst;
03496 }
03497 
03498 /* return the stream number in the feed */
03499 static int add_av_stream(FFStream *feed, AVStream *st)
03500 {
03501     AVStream *fst;
03502     AVCodecContext *av, *av1;
03503     int i;
03504 
03505     av = st->codec;
03506     for(i=0;i<feed->nb_streams;i++) {
03507         st = feed->streams[i];
03508         av1 = st->codec;
03509         if (av1->codec_id == av->codec_id &&
03510             av1->codec_type == av->codec_type &&
03511             av1->bit_rate == av->bit_rate) {
03512 
03513             switch(av->codec_type) {
03514             case AVMEDIA_TYPE_AUDIO:
03515                 if (av1->channels == av->channels &&
03516                     av1->sample_rate == av->sample_rate)
03517                     goto found;
03518                 break;
03519             case AVMEDIA_TYPE_VIDEO:
03520                 if (av1->width == av->width &&
03521                     av1->height == av->height &&
03522                     av1->time_base.den == av->time_base.den &&
03523                     av1->time_base.num == av->time_base.num &&
03524                     av1->