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