* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#define _XOPEN_SOURCE 600
+
#include "config.h"
#ifndef HAVE_CLOSESOCKET
#define closesocket close
#endif
#include <string.h>
+#include <strings.h>
#include <stdlib.h>
#include "libavutil/random.h"
#include "libavutil/avstring.h"
static const OptionDef options[];
-/* maximum number of simultaneous HTTP connections */
-#define HTTP_MAX_CONNECTIONS 2000
-
enum HTTPState {
HTTPSTATE_WAIT_REQUEST,
HTTPSTATE_SEND_HEADER,
static int no_launch;
static int need_to_start_children;
-static int nb_max_connections = 5;
-static int nb_connections;
+/* maximum number of simultaneous HTTP connections */
+static unsigned int nb_max_http_connections = 2000;
+static unsigned int nb_max_connections = 5;
+static unsigned int nb_connections;
static uint64_t max_bandwidth = 1000;
static uint64_t current_bandwidth;
if (level > av_log_level)
return;
if (print_prefix && avc)
- http_log("[%s @ %p]", avc->item_name(ptr), avc);
+ http_log("[%s @ %p]", avc->item_name(ptr), ptr);
print_prefix = strstr(fmt, "\n") != NULL;
http_vlog(fmt, vargs);
}
{
int server_fd = 0, rtsp_server_fd = 0;
int ret, delay, delay1;
- struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
+ struct pollfd *poll_table, *poll_entry;
HTTPContext *c, *c_next;
+ if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
+ http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
+ return -1;
+ }
+
if (my_http_addr.sin_port) {
server_fd = socket_open_listen(&my_http_addr);
if (server_fd < 0)
ctx = &c->fmt_ctx;
- if (!c->last_packet_sent) {
+ if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
if (ctx->oformat) {
/* prepare header */
if (url_open_dyn_buf(&ctx->pb) >= 0) {
if (stream->stream_type == STREAM_TYPE_REDIRECT) {
c->http_error = 301;
q = c->buffer;
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 301 Moved\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Location: %s\r\n", stream->feed_filename);
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Moved</title></head><body>\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
-
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 301 Moved\r\n"
+ "Location: %s\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<html><head><title>Moved</title></head><body>\r\n"
+ "You should be <a href=\"%s\">redirected</a>.\r\n"
+ "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
/* prepare output buffer */
c->buffer_ptr = c->buffer;
c->buffer_end = q;
if (c->post == 0 && max_bandwidth < current_bandwidth) {
c->http_error = 200;
q = c->buffer;
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The server is too busy to serve your request at this time.</p>\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %lldkbit/sec, and this exceeds the limit of %lldkbit/sec.</p>\r\n",
- current_bandwidth, max_bandwidth);
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
-
+ q += snprintf(q, c->buffer_size,
+ "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 bandwidth being served (including your stream) is %" PRIu64 "kbit/sec, "
+ "and this exceeds the limit of %" PRIu64 "kbit/sec.</p>\r\n"
+ "</body></html>\r\n", current_bandwidth, max_bandwidth);
/* prepare output buffer */
c->buffer_ptr = c->buffer;
c->buffer_end = q;
q = c->buffer;
switch(redir_type) {
case REDIR_ASX:
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 ASX Follows\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: video/x-ms-asf\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<ASX Version=\"3\">\r\n");
- //q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<!-- Autogenerated by ffserver -->\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n",
- hostbuf, filename, info);
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</ASX>\r\n");
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 ASX Follows\r\n"
+ "Content-type: video/x-ms-asf\r\n"
+ "\r\n"
+ "<ASX Version=\"3\">\r\n"
+ //"<!-- Autogenerated by ffserver -->\r\n"
+ "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
+ "</ASX>\r\n", hostbuf, filename, info);
break;
case REDIR_RAM:
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 RAM Follows\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: audio/x-pn-realaudio\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "# Autogenerated by ffserver\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "http://%s/%s%s\r\n",
- hostbuf, filename, info);
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 RAM Follows\r\n"
+ "Content-type: audio/x-pn-realaudio\r\n"
+ "\r\n"
+ "# Autogenerated by ffserver\r\n"
+ "http://%s/%s%s\r\n", hostbuf, filename, info);
break;
case REDIR_ASF:
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 ASF Redirect follows\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: video/x-ms-asf\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "[Reference]\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Ref1=http://%s/%s%s\r\n",
- hostbuf, filename, info);
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 ASF Redirect follows\r\n"
+ "Content-type: video/x-ms-asf\r\n"
+ "\r\n"
+ "[Reference]\r\n"
+ "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
break;
case REDIR_RTSP:
{
p = strrchr(hostname, ':');
if (p)
*p = '\0';
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 RTSP Redirect follows\r\n");
- /* XXX: incorrect mime type ? */
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/x-rtsp\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "rtsp://%s:%d/%s\r\n",
- hostname, ntohs(my_rtsp_addr.sin_port),
- filename);
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 RTSP Redirect follows\r\n"
+ /* XXX: incorrect mime type ? */
+ "Content-type: application/x-rtsp\r\n"
+ "\r\n"
+ "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
}
break;
case REDIR_SDP:
int sdp_data_size, len;
struct sockaddr_in my_addr;
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 OK\r\n"
+ "Content-type: application/sdp\r\n"
+ "\r\n");
len = sizeof(my_addr);
getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
if (c->post) {
/* if post, it means a feed is being sent */
if (!stream->is_feed) {
- /* However it might be a status report from WMP! Lets log the data
- * as it might come in handy one day
- */
+ /* However it might be a status report from WMP! Let us log the
+ * data as it might come in handy one day. */
char *logline = 0;
int client_id = 0;
send_error:
c->http_error = 404;
q = c->buffer;
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 404 Not Found\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: %s\r\n", "text/html");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HTML>\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<BODY>%s</BODY>\n", msg);
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</HTML>\n");
-
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 404 Not Found\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<HTML>\n"
+ "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
+ "<BODY>%s</BODY>\n"
+ "</HTML>\n", msg);
/* prepare output buffer */
c->buffer_ptr = c->buffer;
c->buffer_end = q;
url_fprintf(pb, "Pragma: no-cache\r\n");
url_fprintf(pb, "\r\n");
- url_fprintf(pb, "<HEAD><TITLE>%s Status</TITLE>\n", program_name);
+ url_fprintf(pb, "<HTML><HEAD><TITLE>%s Status</TITLE>\n", program_name);
if (c->stream->feed_filename[0])
url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
url_fprintf(pb, "</HEAD>\n<BODY>");
url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
nb_connections, nb_max_connections);
- url_fprintf(pb, "Bandwidth in use: %lldk / %lldk<BR>\n",
+ url_fprintf(pb, "Bandwidth in use: %" PRIu64 "k / %" PRIu64 "k<BR>\n",
current_bandwidth, max_bandwidth);
url_fprintf(pb, "<TABLE>\n");
}
#endif
-static int opt_default(const char *opt, const char *arg,
+static int ffserver_opt_default(const char *opt, const char *arg,
AVCodecContext *avctx, int type)
{
const AVOption *o = NULL;
const AVOption *o2 = av_find_opt(avctx, opt, NULL, type, type);
if(o2)
- o = av_set_string(avctx, opt, arg);
+ o = av_set_string2(avctx, opt, arg, 1);
if(!o)
return -1;
return 0;
filename, line_num, arg);
errors++;
}
+ } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
+ get_arg(arg, sizeof(arg), &p);
+ val = atoi(arg);
+ if (val < 1 || val > 65536) {
+ fprintf(stderr, "%s:%d: Invalid MaxHTTPConnections: %s\n",
+ filename, line_num, arg);
+ errors++;
+ }
+ nb_max_http_connections = val;
} else if (!strcasecmp(cmd, "MaxClients")) {
get_arg(arg, sizeof(arg), &p);
val = atoi(arg);
- if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
+ if (val < 1 || val > nb_max_http_connections) {
fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
filename, line_num, arg);
errors++;
avctx = &audio_enc;
type = AV_OPT_FLAG_AUDIO_PARAM;
}
- if (opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
+ if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
errors++;
}