X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffserver.c;h=8525f7be79db2cc1fd7afaf14dc784f5460e0522;hb=af0f371246b40236253617d3924647adea979d63;hp=29b785b3e9c549ac88cef8a3e1c3096314d10141;hpb=087fa475072e9148efbfa86289abdf87e54e45b2;p=ffmpeg diff --git a/ffserver.c b/ffserver.c index 29b785b3e9c..8525f7be79d 100644 --- a/ffserver.c +++ b/ffserver.c @@ -18,7 +18,13 @@ * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#define HAVE_AV_CONFIG_H + +#include "config.h" +#if HAVE_CLOSESOCKET != 1 +#define closesocket close +#endif +#include +#include #include "avformat.h" #include @@ -32,20 +38,17 @@ #include #undef time //needed because HAVE_AV_CONFIG_H is defined on top #include -#include -#include #include -#include -#include -#include #include #ifdef HAVE_DLFCN_H #include #endif +#include "network.h" #include "version.h" #include "ffserver.h" #include "random.h" +#include "avstring.h" #undef exit @@ -234,8 +237,8 @@ typedef struct FeedData { float avg_frame_size; /* frame size averraged over last frames with exponential mean */ } FeedData; -struct sockaddr_in my_http_addr; -struct sockaddr_in my_rtsp_addr; +static struct sockaddr_in my_http_addr; +static struct sockaddr_in my_rtsp_addr; static char logfilename[1024]; static HTTPContext *first_http_ctx; @@ -394,7 +397,7 @@ static void start_children(FFStream *feed) close(i); } - pstrcpy(pathname, sizeof(pathname), my_program_name); + av_strlcpy(pathname, my_program_name, sizeof(pathname)); slash = strrchr(pathname, '/'); if (!slash) { @@ -444,7 +447,7 @@ static int socket_open_listen(struct sockaddr_in *my_addr) closesocket(server_fd); return -1; } - fcntl(server_fd, F_SETFL, O_NONBLOCK); + ff_socket_nonblock(server_fd, 1); return server_fd; } @@ -592,9 +595,10 @@ static int http_server(void) second to handle timeouts */ do { ret = poll(poll_table, poll_entry - poll_table, delay); - if (ret < 0 && errno != EAGAIN && errno != EINTR) + if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) && + ff_neterrno() != FF_NETERROR(EINTR)) return -1; - } while (ret <= 0); + } while (ret < 0); cur_time = av_gettime() / 1000; @@ -652,7 +656,7 @@ static void new_connection(int server_fd, int is_rtsp) &len); if (fd < 0) return; - fcntl(fd, F_SETFL, O_NONBLOCK); + ff_socket_nonblock(fd, 1); /* XXX: should output a warning page when coming close to the connection limit */ @@ -795,7 +799,8 @@ static int handle_connection(HTTPContext *c) read_loop: len = recv(c->fd, c->buffer_ptr, 1, 0); if (len < 0) { - if (errno != EAGAIN && errno != EINTR) + if (ff_neterrno() != FF_NETERROR(EAGAIN) && + ff_neterrno() != FF_NETERROR(EINTR)) return -1; } else if (len == 0) { return -1; @@ -830,7 +835,8 @@ static int handle_connection(HTTPContext *c) return 0; len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0); if (len < 0) { - if (errno != EAGAIN && errno != EINTR) { + if (ff_neterrno() != FF_NETERROR(EAGAIN) && + ff_neterrno() != FF_NETERROR(EINTR)) { /* error : close connection */ av_freep(&c->pb_buffer); return -1; @@ -900,7 +906,8 @@ static int handle_connection(HTTPContext *c) return 0; len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0); if (len < 0) { - if (errno != EAGAIN && errno != EINTR) { + if (ff_neterrno() != FF_NETERROR(EAGAIN) && + ff_neterrno() != FF_NETERROR(EINTR)) { /* error : close connection */ av_freep(&c->pb_buffer); return -1; @@ -926,7 +933,8 @@ static int handle_connection(HTTPContext *c) len = send(c->fd, c->packet_buffer_ptr, c->packet_buffer_end - c->packet_buffer_ptr, 0); if (len < 0) { - if (errno != EAGAIN && errno != EINTR) { + if (ff_neterrno() != FF_NETERROR(EAGAIN) && + ff_neterrno() != FF_NETERROR(EINTR)) { /* error : close connection */ av_freep(&c->packet_buffer); return -1; @@ -1120,7 +1128,7 @@ static int validate_acl(FFStream *stream, HTTPContext *c) enum IPAddressAction last_action = IP_DENY; IPAddressACL *acl; struct in_addr *src = &c->from_addr.sin_addr; - unsigned long src_addr = ntohl(src->s_addr); + unsigned long src_addr = src->s_addr; for (acl = stream->acl; acl; acl = acl->next) { if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr) { @@ -1143,17 +1151,17 @@ static void compute_real_filename(char *filename, int max_size) FFStream *stream; /* compute filename by matching without the file extensions */ - pstrcpy(file1, sizeof(file1), filename); + av_strlcpy(file1, filename, sizeof(file1)); p = strrchr(file1, '.'); if (p) *p = '\0'; for(stream = first_stream; stream != NULL; stream = stream->next) { - pstrcpy(file2, sizeof(file2), stream->filename); + av_strlcpy(file2, stream->filename, sizeof(file2)); p = strrchr(file2, '.'); if (p) *p = '\0'; if (!strcmp(file1, file2)) { - pstrcpy(filename, max_size, stream->filename); + av_strlcpy(filename, stream->filename, max_size); break; } } @@ -1186,7 +1194,7 @@ static int http_parse_request(HTTPContext *c) p = c->buffer; get_word(cmd, sizeof(cmd), (const char **)&p); - pstrcpy(c->method, sizeof(c->method), cmd); + av_strlcpy(c->method, cmd, sizeof(c->method)); if (!strcmp(cmd, "GET")) c->post = 0; @@ -1196,13 +1204,13 @@ static int http_parse_request(HTTPContext *c) return -1; get_word(url, sizeof(url), (const char **)&p); - pstrcpy(c->url, sizeof(c->url), url); + av_strlcpy(c->url, url, sizeof(c->url)); get_word(protocol, sizeof(protocol), (const char **)&p); if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1")) return -1; - pstrcpy(c->protocol, sizeof(c->protocol), protocol); + av_strlcpy(c->protocol, protocol, sizeof(c->protocol)); if (ffserver_debug) http_log("New connection: %s %s\n", cmd, url); @@ -1210,13 +1218,13 @@ static int http_parse_request(HTTPContext *c) /* find the filename and the optional info string in the request */ p = strchr(url, '?'); if (p) { - pstrcpy(info, sizeof(info), p); + av_strlcpy(info, p, sizeof(info)); *p = '\0'; } else { info[0] = '\0'; } - pstrcpy(filename, sizeof(filename)-1, url + ((*url == '/') ? 1 : 0)); + av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1); for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) { if (strncasecmp(p, "User-Agent:", 11) == 0) { @@ -1253,7 +1261,7 @@ static int http_parse_request(HTTPContext *c) // "redirect" / request to index.html if (!strlen(filename)) - pstrcpy(filename, sizeof(filename) - 1, "index.html"); + av_strlcpy(filename, "index.html", sizeof(filename) - 1); stream = first_stream; while (stream != NULL) { @@ -1298,7 +1306,7 @@ static int http_parse_request(HTTPContext *c) } } - /* If already streaming this feed, dont let start an another feeder */ + /* 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."); goto send_error; @@ -1391,7 +1399,7 @@ static int http_parse_request(HTTPContext *c) { char hostname[256], *p; /* extract only hostname */ - pstrcpy(hostname, sizeof(hostname), hostbuf); + av_strlcpy(hostname, hostbuf, sizeof(hostname)); p = strrchr(hostname, ':'); if (p) *p = '\0'; @@ -1430,7 +1438,7 @@ static int http_parse_request(HTTPContext *c) } break; default: - av_abort(); + abort(); break; } @@ -1633,7 +1641,7 @@ static void compute_stats(HTTPContext *c) char *eosf; if (stream->feed != stream) { - pstrcpy(sfilename, sizeof(sfilename) - 10, stream->filename); + av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10); eosf = sfilename + strlen(sfilename); if (eosf - sfilename >= 4) { if (strcmp(eosf - 4, ".asf") == 0) { @@ -1693,7 +1701,7 @@ static void compute_stats(HTTPContext *c) video_bit_rate += st->codec->bit_rate; break; default: - av_abort(); + abort(); } } url_fprintf(pb, " %s %d %d %s %s %d %s %s", @@ -1773,7 +1781,7 @@ static void compute_stats(HTTPContext *c) st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num); break; default: - av_abort(); + abort(); } url_fprintf(pb, "%d%s%d%s%s\n", i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters); @@ -1997,14 +2005,14 @@ static int http_prepare_data(HTTPContext *c) switch(c->state) { case HTTPSTATE_SEND_DATA_HEADER: memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx)); - pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author), - c->stream->author); - pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment), - c->stream->comment); - pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright), - c->stream->copyright); - pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title), - c->stream->title); + av_strlcpy(c->fmt_ctx.author, c->stream->author, + sizeof(c->fmt_ctx.author)); + av_strlcpy(c->fmt_ctx.comment, c->stream->comment, + sizeof(c->fmt_ctx.comment)); + av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright, + sizeof(c->fmt_ctx.copyright)); + av_strlcpy(c->fmt_ctx.title, c->stream->title, + sizeof(c->fmt_ctx.title)); /* open output stream by using specified codecs */ c->fmt_ctx.oformat = c->stream->fmt; @@ -2337,7 +2345,8 @@ static int http_send_data(HTTPContext *c) /* TCP data output */ len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0); if (len < 0) { - if (errno != EAGAIN && errno != EINTR) { + if (ff_neterrno() != FF_NETERROR(EAGAIN) && + ff_neterrno() != FF_NETERROR(EINTR)) { /* error : close connection */ return -1; } else { @@ -2394,7 +2403,8 @@ static int http_receive_data(HTTPContext *c) len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0); if (len < 0) { - if (errno != EAGAIN && errno != EINTR) { + if (ff_neterrno() != FF_NETERROR(EAGAIN) && + ff_neterrno() != FF_NETERROR(EINTR)) { /* error : close connection */ goto fail; } @@ -2508,9 +2518,39 @@ static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number) char buf2[32]; switch(error_number) { -#define DEF(n, c, s) case c: str = s; break; -#include "rtspcodes.h" -#undef DEF + case RTSP_STATUS_OK: + str = "OK"; + break; + case RTSP_STATUS_METHOD: + str = "Method Not Allowed"; + break; + case RTSP_STATUS_BANDWIDTH: + str = "Not Enough Bandwidth"; + break; + case RTSP_STATUS_SESSION: + str = "Session Not Found"; + break; + case RTSP_STATUS_STATE: + str = "Method Not Valid in This State"; + break; + case RTSP_STATUS_AGGREGATE: + str = "Aggregate operation not allowed"; + break; + case RTSP_STATUS_ONLY_AGGREGATE: + str = "Only aggregate operation allowed"; + break; + case RTSP_STATUS_TRANSPORT: + str = "Unsupported transport"; + break; + case RTSP_STATUS_INTERNAL: + str = "Internal Server Error"; + break; + case RTSP_STATUS_SERVICE: + str = "Service Unavailable"; + break; + case RTSP_STATUS_VERSION: + str = "RTSP Version not supported"; + break; default: str = "Unknown Error"; break; @@ -2553,9 +2593,9 @@ static int rtsp_parse_request(HTTPContext *c) get_word(url, sizeof(url), &p); get_word(protocol, sizeof(protocol), &p); - pstrcpy(c->method, sizeof(c->method), cmd); - pstrcpy(c->url, sizeof(c->url), url); - pstrcpy(c->protocol, sizeof(c->protocol), protocol); + av_strlcpy(c->method, cmd, sizeof(c->method)); + av_strlcpy(c->url, url, sizeof(c->url)); + av_strlcpy(c->protocol, protocol, sizeof(c->protocol)); c->pb = &pb1; if (url_open_dyn_buf(c->pb) < 0) { @@ -2902,18 +2942,6 @@ static void rtsp_cmd_setup(HTTPContext *c, const char *url, dest_addr = rtp_c->from_addr; dest_addr.sin_port = htons(th->client_port_min); - /* add transport option if needed */ - if (ff_rtsp_callback) { - setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr); - if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id, - (char *)&setup, sizeof(setup), - stream->rtsp_option) < 0) { - rtsp_reply_error(c, RTSP_STATUS_TRANSPORT); - return; - } - dest_addr.sin_addr.s_addr = htonl(setup.ipaddr); - } - /* setup stream */ if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) { rtsp_reply_error(c, RTSP_STATUS_TRANSPORT); @@ -3044,6 +3072,7 @@ static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h) static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h) { HTTPContext *rtp_c; + char session_id[32]; rtp_c = find_rtp_session_with_url(url, h->session_id); if (!rtp_c) { @@ -3051,19 +3080,15 @@ static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h) return; } + av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id)); + /* abort the session */ close_connection(rtp_c); - if (ff_rtsp_callback) { - ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id, - NULL, 0, - rtp_c->stream->rtsp_option); - } - /* now everything is OK, so we can send the connection parameters */ rtsp_reply_header(c, RTSP_STATUS_OK); /* session ID */ - url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id); + url_fprintf(c->pb, "Session: %s\r\n", session_id); url_fprintf(c->pb, "\r\n"); } @@ -3097,7 +3122,7 @@ static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, goto fail; nb_connections++; c->stream = stream; - pstrcpy(c->session_id, sizeof(c->session_id), session_id); + av_strlcpy(c->session_id, session_id, sizeof(c->session_id)); c->state = HTTPSTATE_READY; c->is_packetized = 1; c->rtp_protocol = rtp_protocol; @@ -3117,8 +3142,8 @@ static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, proto_str = "???"; break; } - pstrcpy(c->protocol, sizeof(c->protocol), "RTP/"); - pstrcat(c->protocol, sizeof(c->protocol), proto_str); + av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol)); + av_strlcat(c->protocol, proto_str, sizeof(c->protocol)); current_bandwidth += stream->bandwidth; @@ -3170,6 +3195,7 @@ static int rtp_new_av_stream(HTTPContext *c, c->stream->feed->streams[c->stream->feed_streams[stream_index]], sizeof(AVStream)); } + st->priv_data = NULL; /* build destination RTP address */ ipaddr = inet_ntoa(dest_addr->sin_addr); @@ -3282,7 +3308,7 @@ static int add_av_stream(FFStream *feed, AVStream *st) goto found; break; default: - av_abort(); + abort(); } } } @@ -3683,7 +3709,7 @@ static void add_codec(FFStream *stream, AVCodecContext *av) break; default: - av_abort(); + abort(); } st = av_mallocz(sizeof(AVStream)); @@ -3798,11 +3824,17 @@ static int parse_ffconfig(const char *filename) if (!strcasecmp(cmd, "Port")) { get_arg(arg, sizeof(arg), &p); - my_http_addr.sin_port = htons (atoi(arg)); + val = atoi(arg); + if (val < 1 || val > 65536) { + fprintf(stderr, "%s:%d: Invalid port: %s\n", + filename, line_num, arg); + errors++; + } + my_http_addr.sin_port = htons(val); } else if (!strcasecmp(cmd, "BindAddress")) { get_arg(arg, sizeof(arg), &p); - if (!inet_aton(arg, &my_http_addr.sin_addr)) { - fprintf(stderr, "%s:%d: Invalid IP address: %s\n", + if (resolve_host(&my_http_addr.sin_addr, arg) != 0) { + fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n", filename, line_num, arg); errors++; } @@ -3810,11 +3842,17 @@ static int parse_ffconfig(const char *filename) ffserver_daemon = 0; } else if (!strcasecmp(cmd, "RTSPPort")) { get_arg(arg, sizeof(arg), &p); - my_rtsp_addr.sin_port = htons (atoi(arg)); + val = atoi(arg); + if (val < 1 || val > 65536) { + fprintf(stderr, "%s:%d: Invalid port: %s\n", + filename, line_num, arg); + errors++; + } + my_rtsp_addr.sin_port = htons(atoi(arg)); } else if (!strcasecmp(cmd, "RTSPBindAddress")) { get_arg(arg, sizeof(arg), &p); - if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) { - fprintf(stderr, "%s:%d: Invalid IP address: %s\n", + if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) { + fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n", filename, line_num, arg); errors++; } @@ -3875,14 +3913,11 @@ static int parse_ffconfig(const char *filename) feed->child_argv = (char **) av_mallocz(64 * sizeof(char *)); for (i = 0; i < 62; i++) { - char argbuf[256]; - - get_arg(argbuf, sizeof(argbuf), &p); - if (!argbuf[0]) + get_arg(arg, sizeof(arg), &p); + if (!arg[0]) break; - feed->child_argv[i] = av_malloc(strlen(argbuf) + 1); - strcpy(feed->child_argv[i], argbuf); + feed->child_argv[i] = av_strdup(arg); } feed->child_argv[i] = av_malloc(30 + strlen(feed->filename)); @@ -3941,16 +3976,6 @@ static int parse_ffconfig(const char *filename) fprintf(stderr, "%s:%d: No corresponding for \n", filename, line_num); errors++; -#if 0 - } else { - /* Make sure that we start out clean */ - if (unlink(feed->feed_filename) < 0 - && errno != ENOENT) { - fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n", - filename, line_num, feed->feed_filename, strerror(errno)); - errors++; - } -#endif } feed = NULL; } else if (!strcasecmp(cmd, "fmt->video_codec; } } else if (!strcasecmp(cmd, "InputFormat")) { + get_arg(arg, sizeof(arg), &p); stream->ifmt = av_find_input_format(arg); if (!stream->ifmt) { fprintf(stderr, "%s:%d: Unknown input format: %s\n", @@ -4141,7 +4167,7 @@ static int parse_ffconfig(const char *filename) } else if (!strcasecmp(cmd, "VideoSize")) { get_arg(arg, sizeof(arg), &p); if (stream) { - parse_image_size(&video_enc.width, &video_enc.height, arg); + av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg); if ((video_enc.width % 16) != 0 || (video_enc.height % 16) != 0) { fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n", @@ -4252,7 +4278,6 @@ static int parse_ffconfig(const char *filename) audio_id = CODEC_ID_NONE; } else if (!strcasecmp(cmd, "ACL")) { IPAddressACL acl; - struct hostent *he; get_arg(arg, sizeof(arg), &p); if (strcasecmp(arg, "allow") == 0) { @@ -4267,28 +4292,21 @@ static int parse_ffconfig(const char *filename) get_arg(arg, sizeof(arg), &p); - he = gethostbyname(arg); - if (!he) { + if (resolve_host(&acl.first, arg) != 0) { fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n", filename, line_num, arg); errors++; } else { - /* Only take the first */ - acl.first.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr); acl.last = acl.first; } get_arg(arg, sizeof(arg), &p); if (arg[0]) { - he = gethostbyname(arg); - if (!he) { + if (resolve_host(&acl.last, arg) != 0) { fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n", filename, line_num, arg); errors++; - } else { - /* Only take the first */ - acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr); } } @@ -4296,8 +4314,8 @@ static int parse_ffconfig(const char *filename) IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl)); IPAddressACL **naclp = 0; + acl.next = 0; *nacl = acl; - nacl->next = 0; if (stream) { naclp = &stream->acl; @@ -4325,8 +4343,8 @@ static int parse_ffconfig(const char *filename) } else if (!strcasecmp(cmd, "MulticastAddress")) { get_arg(arg, sizeof(arg), &p); if (stream) { - if (!inet_aton(arg, &stream->multicast_ip)) { - fprintf(stderr, "%s:%d: Invalid IP address: %s\n", + if (resolve_host(&stream->multicast_ip, arg) != 0) { + fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n", filename, line_num, arg); errors++; } @@ -4456,7 +4474,7 @@ static void show_license(void) "\n" "You should have received a copy of the GNU Lesser General Public\n" "License along with FFmpeg; if not, write to the Free Software\n" - "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n" + "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" ); }