#include "libavformat/rtpdec.h"
#include "libavformat/rtsp.h"
#include "libavutil/avstring.h"
-#include "libavutil/random.h"
+#include "libavutil/lfg.h"
+#include "libavutil/random_seed.h"
#include "libavutil/intreadwrite.h"
#include "libavcodec/opt.h"
#include <stdarg.h>
int feed_opened; /* true if someone is writing to the feed */
int is_feed; /* true if it is a feed */
int readonly; /* True if writing is prohibited to the file */
+ int truncate; /* True if feeder connection truncate the feed file */
int conns_served;
int64_t bytes_served;
int64_t feed_max_size; /* maximum storage size, zero means unlimited */
static int64_t cur_time; // Making this global saves on passing it around everywhere
-static AVRandomState random_state;
+static AVLFG random_state;
static FILE *logfile = NULL;
{
static int print_prefix = 1;
AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
- if (level > av_log_level)
+ if (level > av_log_get_level())
return;
if (print_prefix && avc)
http_log("[%s @ %p]", avc->item_name(ptr), ptr);
if (stream->is_multicast) {
/* open the RTP connection */
snprintf(session_id, sizeof(session_id), "%08x%08x",
- av_random(&random_state), av_random(&random_state));
+ av_lfg_get(&random_state), av_lfg_get(&random_state));
/* choose a port if none given */
if (stream->multicast_port == 0) {
}
}
+static void http_send_too_busy_reply(int fd)
+{
+ char buffer[300];
+ int len = snprintf(buffer, sizeof(buffer),
+ "HTTP/1.0 200 Server too busy\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<html><head><title>Too busy</title></head><body>\r\n"
+ "<p>The server is too busy to serve your request at this time.</p>\r\n"
+ "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
+ "</body></html>\r\n",
+ nb_connections, nb_max_connections);
+ send(fd, buffer, len, 0);
+}
+
+
static void new_connection(int server_fd, int is_rtsp)
{
struct sockaddr_in from_addr;
}
ff_socket_nonblock(fd, 1);
- /* XXX: should output a warning page when coming
- close to the connection limit */
- if (nb_connections >= nb_max_connections)
+ if (nb_connections >= nb_max_connections) {
+ http_send_too_busy_reply(fd);
goto fail;
+ }
/* add a new connection */
c = av_mallocz(sizeof(HTTPContext));
av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
if (ffserver_debug)
- http_log("New connection: %s %s\n", cmd, url);
+ http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
/* find the filename and the optional info string in the request */
p = strchr(url, '?');
}
if (stream == NULL) {
snprintf(msg, sizeof(msg), "File '%s' not found", url);
+ http_log("File '%s' not found\n", url);
goto send_error;
}
/* If already streaming this feed, do not let start another feeder. */
if (stream->feed_opened) {
snprintf(msg, sizeof(msg), "This feed is already being received.");
- http_log("feed %s already being received\n", stream->feed_filename);
+ http_log("Feed '%s' already being received\n", stream->feed_filename);
goto send_error;
}
if (!strcmp(c->stream->fmt->name,"asf_stream")) {
/* Need to allocate a client id */
- c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
+ c->wmp_client_id = av_lfg_get(&random_state);
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);
}
}
s->flags |= AVFMT_FLAG_GENPTS;
c->fmt_in = s;
- av_find_stream_info(c->fmt_in);
+ if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
+ http_log("Could not find stream info '%s'\n", input_filename);
+ av_close_input_file(s);
+ return -1;
+ }
/* open each parser */
for(i=0;i<s->nb_streams;i++)
}
c->feed_fd = fd;
- if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
- http_log("Error reading write index from feed file: %s\n", strerror(errno));
- return -1;
+ if (c->stream->truncate) {
+ /* truncate feed file */
+ ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
+ ftruncate(c->feed_fd, FFM_PACKET_SIZE);
+ http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
+ } else {
+ if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
+ http_log("Error reading write index from feed file: %s\n", strerror(errno));
+ return -1;
+ }
}
+
+ c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
c->stream->feed_size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
if (s->nb_streams != feed->nb_streams) {
av_close_input_stream(s);
av_free(pb);
+ http_log("Feed '%s' stream number does not match registered feed\n",
+ c->stream->feed_filename);
goto fail;
}
/* generate session id if needed */
if (h->session_id[0] == '\0')
snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
- av_random(&random_state), av_random(&random_state));
+ av_lfg_get(&random_state), av_lfg_get(&random_state));
/* find rtp session, and create it if none found */
rtp_c = find_rtp_session(h->session_id);
stream->ap_in->mpeg2ts_compute_pcr = 1;
}
+ http_log("Opening file '%s'\n", stream->feed_filename);
if ((ret = av_open_input_file(&infile, stream->feed_filename,
stream->ifmt, 0, stream->ap_in)) < 0) {
- http_log("could not open %s: %d\n", stream->feed_filename, ret);
+ http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
/* remove stream (no need to spend more time on it) */
fail:
remove_stream(stream);
exit(1);
}
- feed->feed_write_index = ffm_read_write_index(fd);
+ feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
feed->feed_size = lseek(fd, 0, SEEK_END);
/* ensure that we do not wrap before the end of file */
if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
const char *p;
int val, errors, line_num;
FFStream **last_stream, *stream, *redirect;
- FFStream **last_feed, *feed;
+ FFStream **last_feed, *feed, *s;
AVCodecContext audio_enc, video_enc;
enum CodecID audio_id, video_id;
filename, line_num);
} else {
feed = av_mallocz(sizeof(FFStream));
- /* add in stream list */
- *last_stream = feed;
- last_stream = &feed->next;
- /* add in feed list */
- *last_feed = feed;
- last_feed = &feed->next_feed;
-
get_arg(feed->filename, sizeof(feed->filename), &p);
q = strrchr(feed->filename, '>');
if (*q)
*q = '\0';
+
+ for (s = first_feed; s; s = s->next) {
+ if (!strcmp(feed->filename, s->filename)) {
+ fprintf(stderr, "%s:%d: Feed '%s' already registered\n",
+ filename, line_num, s->filename);
+ errors++;
+ }
+ }
+
feed->fmt = guess_format("ffm", NULL, NULL);
/* defaut feed file */
snprintf(feed->feed_filename, sizeof(feed->feed_filename),
feed->feed_max_size = 5 * 1024 * 1024;
feed->is_feed = 1;
feed->feed = feed; /* self feeding :-) */
+
+ /* add in stream list */
+ *last_stream = feed;
+ last_stream = &feed->next;
+ /* add in feed list */
+ *last_feed = feed;
+ last_feed = &feed->next_feed;
}
} else if (!strcasecmp(cmd, "Launch")) {
if (feed) {
get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
} else if (stream)
get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
+ } else if (!strcasecmp(cmd, "Truncate")) {
+ if (feed) {
+ get_arg(arg, sizeof(arg), &p);
+ feed->truncate = strtod(arg, NULL);
+ }
} else if (!strcasecmp(cmd, "FileMaxSize")) {
if (feed) {
char *p1;
break;
}
feed->feed_max_size = (int64_t)fsize;
+ if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
+ fprintf(stderr, "%s:%d: Feed max file size is too small, "
+ "must be at least %d\n", filename, line_num, FFM_PACKET_SIZE*4);
+ errors++;
+ }
}
} else if (!strcasecmp(cmd, "</Feed>")) {
if (!feed) {
fprintf(stderr, "%s:%d: Already in a tag\n",
filename, line_num);
} else {
+ FFStream *s;
const AVClass *class;
stream = av_mallocz(sizeof(FFStream));
- *last_stream = stream;
- last_stream = &stream->next;
-
get_arg(stream->filename, sizeof(stream->filename), &p);
q = strrchr(stream->filename, '>');
if (*q)
*q = '\0';
+
+ for (s = first_stream; s; s = s->next) {
+ if (!strcmp(stream->filename, s->filename)) {
+ fprintf(stderr, "%s:%d: Stream '%s' already registered\n",
+ filename, line_num, s->filename);
+ errors++;
+ }
+ }
+
stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
/* fetch avclass so AVOption works
* FIXME try to use avcodec_get_context_defaults2
audio_id = stream->fmt->audio_codec;
video_id = stream->fmt->video_codec;
}
+
+ *last_stream = stream;
+ last_stream = &stream->next;
}
} else if (!strcasecmp(cmd, "Feed")) {
get_arg(arg, sizeof(arg), &p);
unsetenv("http_proxy"); /* Kill the http_proxy */
- av_random_init(&random_state, av_gettime() + (getpid() << 16));
+ av_lfg_init(&random_state, ff_random_get_seed());
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = handle_child_exit;