Hi, On Sun, Jun 28, 2015 at 10:06 PM, Nicolas George <geo...@nsup.org> wrote: > Le decadi 10 messidor, an CCXXIII, Stephan Holljes a écrit : >> Hi, >> attached patches are the current state of work. >> It's probably still a bit rough around the edges, but I think I made >> some progress. >> The sample code in doc/examples does not write any data as of yet, but >> the HTTP handshake works. > > A few quick remarks, without entering into the fine details since the patch > series will likely evolve still quite a bit. > >> From b43aeaa27f6ca7df476aa194b2f78aa1b49516d0 Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Sun, 28 Jun 2015 06:06:16 +0200 >> Subject: [PATCH 01/10] lavf/network: split ff_listen_bind into ff_listen and >> ff_accept >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> libavformat/network.c | 27 +++++++++++++++++++++------ >> libavformat/network.h | 4 ++++ >> 2 files changed, 25 insertions(+), 6 deletions(-) > > This one looks good to me, except a small doxy would be nice for the two new > functions. > >> From 39faa1ea315bb51452446e291fd5d93d7eb3a988 Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Sun, 28 Jun 2015 06:12:37 +0200 >> Subject: [PATCH 02/10] lavf/avio: add ffurl_accept and ffurl_handshake >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> libavformat/avio.c | 15 +++++++++++++++ >> libavformat/url.h | 12 ++++++++++++ >> 2 files changed, 27 insertions(+) > > ffurl_accept() requires two arguments, but I suspect ffurl_handshake() only > requires one, the client. A doxy would be nice for ffurl_handshake(). > > Also, the client argument of ffurl_accept() and url_accept() should probably > a pointer to pointer, like ffurl_alloc(), so that it can allocate the > context itself.
Fixed here and in all instances. This took me a lot longer than I want to admit. > >> From 8b473ba9acffecf98f8252eeccb413bcfbbf38c5 Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Sun, 28 Jun 2015 06:13:36 +0200 >> Subject: [PATCH 03/10] lavf/avio: add avio_accept and avio_handshake >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> libavformat/avio.h | 2 ++ >> libavformat/aviobuf.c | 21 +++++++++++++++++++++ >> 2 files changed, 23 insertions(+) > > That part looks mostly good. > >> From 8ba3d1ef528cdd9209764b0f696b8df81ea46870 Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Sun, 28 Jun 2015 06:16:02 +0200 >> Subject: [PATCH 04/10] lavf/http: add http_accept and http_handshake >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> libavformat/http.c | 38 ++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 38 insertions(+) > > I believe this patch can not come before the one for TCP. > >> >> diff --git a/libavformat/http.c b/libavformat/http.c >> index 676bfd5..7219f08 100644 >> --- a/libavformat/http.c >> +++ b/libavformat/http.c >> @@ -382,6 +382,38 @@ static int http_open(URLContext *h, const char *uri, >> int flags, >> return ret; >> } >> >> +static int http_accept(URLContext *s, URLContext *c) >> +{ >> + int ret; >> + HTTPContext *sh = s->priv_data; >> + HTTPContext *ch = c->priv_data; >> + URLContext *sl = sh->hd; >> + URLContext *cl; > >> + if ((ret = ffurl_alloc(&cl, sl->filename, AVIO_FLAG_READ_WRITE, >> &sl->interrupt_callback)) < 0) >> + goto fail; >> + if ((ret = ffurl_accept(sl, cl)) < 0) >> + goto fail; >> + ch->hd = cl; >> +fail: >> + return ret; >> +} > > This looks mostly correct, but I suspect it would be more convenient to make > url_accept() responsible for allocating the client context. Otherwise, the > application is responsible for allocating a client context with the correct > protocol and settings, this is fragile. > >> + >> +static int http_handshake(URLContext *s, URLContext *c) { >> + int ret, err, new_location; >> + HTTPContext *sh = s->priv_data; >> + HTTPContext *ch = c->priv_data; >> + URLContext *sl = sh->hd; >> + URLContext *cl = ch->hd; >> + static const char header[] = "HTTP/1.1 200 OK\r\nContent-Type: >> application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n"; >> + if ((err = http_read_header(c, &new_location)) < 0) >> + goto fail; >> + if ((ret = ffurl_write(cl, header, strlen(header))) < 0) >> + goto fail; >> +fail: >> + handle_http_errors(c, err); >> + return ret; >> +} > > As you can see, the s argument is never used. > > Also, it should probably call ffurl_handshake() on the underlying socket: > for TCP it is a nop, but for TLS, for example, it is blocking. > >> + >> static int http_getc(HTTPContext *s) >> { >> int len; >> @@ -1346,6 +1378,8 @@ HTTP_CLASS(http); >> URLProtocol ff_http_protocol = { >> .name = "http", >> .url_open2 = http_open, >> + .url_accept = http_accept, >> + .url_handshake = http_handshake, >> .url_read = http_read, >> .url_write = http_write, >> .url_seek = http_seek, >> @@ -1364,6 +1398,8 @@ HTTP_CLASS(https); >> URLProtocol ff_https_protocol = { >> .name = "https", >> .url_open2 = http_open, >> + .url_accept = http_accept, >> + .url_handshake = http_handshake, >> .url_read = http_read, >> .url_write = http_write, >> .url_seek = http_seek, >> @@ -1477,6 +1513,8 @@ static int http_proxy_write(URLContext *h, const >> uint8_t *buf, int size) >> URLProtocol ff_httpproxy_protocol = { >> .name = "httpproxy", >> .url_open = http_proxy_open, >> + .url_accept = http_accept, >> + .url_handshake = http_handshake, >> .url_read = http_buf_read, >> .url_write = http_proxy_write, >> .url_close = http_proxy_close, >> -- >> 2.1.0 >> > >> From cfd27b21cf9fae39d881608a3ba379e6fb75848c Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Sun, 28 Jun 2015 06:17:12 +0200 >> Subject: [PATCH 05/10] lavf/tcp: make tcp_open return with a listening socket >> without calling accept() >> >> --- >> libavformat/tcp.c | 4 +--- >> 1 file changed, 1 insertion(+), 3 deletions(-) > > This would break existing code. You suggested using a different value for > listen, what happened to that idea? This is implemented now, rather elegantly I think even. > >> From dd197651d205b2dece97798e933974ecef3a2b7f Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Sun, 28 Jun 2015 06:20:17 +0200 >> Subject: [PATCH 06/10] lavf/tcp: add tcp_accept >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> libavformat/tcp.c | 14 ++++++++++++++ >> 1 file changed, 14 insertions(+) > > No extra remark for that patch, but the suggestion of having url_accept() > responsible for allocating the client context applies here too. > >> From 5ab3661637c1ba571bc7f7bf365e3f3c8bc4ae89 Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Sun, 28 Jun 2015 06:25:35 +0200 >> Subject: [PATCH 07/10] lavf/http: remove connection logic from http_listen() >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> libavformat/http.c | 10 +--------- >> 1 file changed, 1 insertion(+), 9 deletions(-) > > No remark for this for now. > >> From b835a248bba5004ad8f8a598992fa959881b2376 Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Sun, 28 Jun 2015 06:26:43 +0200 >> Subject: [PATCH 08/10] lavf/http: ignore 0 in handle_http_errors() >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> libavformat/http.c | 2 ++ >> 1 file changed, 2 insertions(+) > > It should probably be merged with the patch that makes it necessary. > >> From 127b0ef456d203bc295ef017737019c0f8329515 Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Sun, 28 Jun 2015 06:39:13 +0200 >> Subject: [PATCH 09/10] lavf/http: only shut down the connection when it's a >> client. >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> libavformat/http.c | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) > > Ditto. > >> From df4b466693b8d8627cca59a17d9e7ab5fd5e843e Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Sun, 28 Jun 2015 06:39:56 +0200 >> Subject: [PATCH 10/10] doc/examples: WIP: add http_multiclient example code. >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> doc/examples/Makefile | 1 + >> doc/examples/http_multiclient.c | 60 >> +++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 61 insertions(+) >> create mode 100644 doc/examples/http_multiclient.c >> >> diff --git a/doc/examples/Makefile b/doc/examples/Makefile >> index 9699f11..8c9501b 100644 >> --- a/doc/examples/Makefile >> +++ b/doc/examples/Makefile >> @@ -18,6 +18,7 @@ EXAMPLES= avio_list_dir \ >> extract_mvs \ >> filtering_video \ >> filtering_audio \ >> + http_multiclient \ >> metadata \ >> muxing \ >> remuxing \ >> diff --git a/doc/examples/http_multiclient.c >> b/doc/examples/http_multiclient.c >> new file mode 100644 >> index 0000000..215a8bb >> --- /dev/null >> +++ b/doc/examples/http_multiclient.c >> @@ -0,0 +1,60 @@ >> +#include <libavformat/avformat.h> >> + >> +int main(int argc, char **argv) >> +{ > >> + AVOutputFormat *ofmt = NULL; >> + AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL; > > You could probably dispense with the muxers and demuxers and work directly > with bytes. That would make the code much simpler. This might be a stupid question, but how would I go about that? Just use open() and read() from stdio.h or are there structs that allow me to do that even more easily? > >> + AVDictionary *options = NULL; >> + AVPacket pkt; >> + AVIOContext *c = NULL; >> + const char *in_filename, *out_uri; >> + int ret; >> + >> + if (argc < 3) { >> + printf("usage: %s input http[s]://hostname[:port]\n" >> + "API example program to serve http to multiple clients.\n" >> + "The output format is guessed according to the input file >> extension.\n" >> + "\n", argv[0]); >> + return 1; >> + } >> + >> + in_filename = argv[1]; >> + out_uri = argv[2]; >> + >> + av_register_all(); >> + avformat_network_init(); >> + >> + if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) { >> + fprintf(stderr, "Could not open input file '%s'", in_filename); >> + goto end; >> + } >> + >> + if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) { >> + fprintf(stderr, "Failed to retrieve input stream information"); >> + goto end; >> + } >> + >> + avformat_alloc_output_context2(&ofmt_ctx, NULL, >> ifmt_ctx->iformat->name, out_uri); >> + if (!ofmt_ctx) { >> + fprintf(stderr, "Could not create output context\n"); >> + ret = AVERROR_UNKNOWN; >> + goto end; >> + } >> + >> + ofmt = ofmt_ctx->oformat; >> + av_dict_set(&options, "listen", "1", 0); >> + ret = avio_open2(&ofmt_ctx->pb, out_uri, AVIO_FLAG_READ_WRITE, NULL, >> &options); > >> + avio_accept(ofmt_ctx->pb, &c); >> + avio_handshake(ofmt_ctx->pb, c); >> + avio_close(c); > > To test the multi-client API, you need to accept several clients. You can > probably just put that in a while(1) loop, but it would be better to fork a > thread for each client. > >> + >> +end: >> + avformat_close_input(&ifmt_ctx); >> + >> + if (ofmt_ctx) >> + avio_closep(&ofmt_ctx->pb); >> + avformat_free_context(ofmt_ctx); >> + if (ret < 0 && ret != AVERROR_EOF) >> + return 1; >> + return 0; >> +} > > Regards, > > -- > Nicolas George > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel > Thanks again for the detailed review! Regards, Stephan
From b0f0caa700b8cbd0352304de703d8191bf0ac922 Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Tue, 30 Jun 2015 07:42:14 +0200 Subject: [PATCH 1/8] lavf/network: split ff_listen_bind into ff_listen and ff_accept Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- libavformat/network.c | 27 +++++++++++++++++++++------ libavformat/network.h | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/libavformat/network.c b/libavformat/network.c index 47ade8c..8d61746 100644 --- a/libavformat/network.c +++ b/libavformat/network.c @@ -187,12 +187,11 @@ int ff_socket(int af, int type, int proto) return fd; } -int ff_listen_bind(int fd, const struct sockaddr *addr, - socklen_t addrlen, int timeout, URLContext *h) +int ff_listen(int fd, const struct sockaddr *addr, + socklen_t addrlen) { int ret; int reuse = 1; - struct pollfd lp = { fd, POLLIN, 0 }; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) { av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n"); } @@ -203,6 +202,13 @@ int ff_listen_bind(int fd, const struct sockaddr *addr, ret = listen(fd, 1); if (ret) return ff_neterrno(); + return ret; +} + +int ff_accept(int fd, int timeout, URLContext *h) +{ + int ret; + struct pollfd lp = { fd, POLLIN, 0 }; ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback); if (ret < 0) @@ -211,15 +217,24 @@ int ff_listen_bind(int fd, const struct sockaddr *addr, ret = accept(fd, NULL, NULL); if (ret < 0) return ff_neterrno(); - - closesocket(fd); - if (ff_socket_nonblock(ret, 1) < 0) av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n"); return ret; } +int ff_listen_bind(int fd, const struct sockaddr *addr, + socklen_t addrlen, int timeout, URLContext *h) +{ + int ret; + if ((ret = ff_listen(fd, addr, addrlen)) < 0) + return ret; + ret = ff_accept(fd, timeout, h); + closesocket(fd); + return ret; + +} + int ff_listen_connect(int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h, int will_try_next) diff --git a/libavformat/network.h b/libavformat/network.h index 86fb656..e684787 100644 --- a/libavformat/network.h +++ b/libavformat/network.h @@ -255,6 +255,27 @@ int ff_listen_bind(int fd, const struct sockaddr *addr, URLContext *h); /** + * Bind to a file descriptor and return a listening socket without accepting connections. + * @param fd First argument of bind(). + * @param addr Second argument of bind(). + * @param addrlen Third argument of bind(). + * @return A blocking file descriptor on success + * or an AVERROR on failure. + */ +int ff_listen(int fd, const struct sockaddr *addr, socklen_t addrlen); + +/** + * Poll for a single connection on the passed file descriptor. + * @param fd The listening socket file descriptor. + * @param timeout Polling timeout in milliseconds. + * @param h URLContext providing interrupt check + * callback and logging context. + * @return A non-blocking file descriptor on success + * or an AVERROR on failure. + */ +int ff_accept(int fd, int timeout, URLContext *h); + +/** * Connect to a file descriptor and poll for result. * * @param fd First argument of connect(), -- 2.1.0
From 330c0eedaede961e52a4a4d93b2211156bc15a69 Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Tue, 30 Jun 2015 08:16:37 +0200 Subject: [PATCH 2/8] lavf/avio: add ffurl_accept and ffurl_handshake Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- libavformat/avio.c | 17 +++++++++++++++++ libavformat/url.h | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/libavformat/avio.c b/libavformat/avio.c index c188adc..63c8b75 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -211,6 +211,23 @@ int ffurl_connect(URLContext *uc, AVDictionary **options) return 0; } +int ffurl_accept(URLContext *s, URLContext **c) +{ + int ret; + if ((ret = s->prot->url_accept(s, c)) < 0) + return ret; + (*c)->is_connected = 1; + return ret; + +} + +int ffurl_handshake(URLContext *c) +{ + if (c->prot->url_handshake) + return c->prot->url_handshake(c); + return 0; +} + #define URL_SCHEME_CHARS \ "abcdefghijklmnopqrstuvwxyz" \ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ diff --git a/libavformat/url.h b/libavformat/url.h index 99a3201..4cf6892 100644 --- a/libavformat/url.h +++ b/libavformat/url.h @@ -58,6 +58,8 @@ typedef struct URLProtocol { * for those nested protocols. */ int (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options); + int (*url_accept)(URLContext *s, URLContext **c); + int (*url_handshake)(URLContext *c); /** * Read data from the protocol. @@ -140,6 +142,22 @@ int ffurl_open(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options); /** + * Accept an URLContext c on an URLContext s + * @param s server context + * @param c client context + * @return the accepted filedescriptor on success, ff_neterrno() on failure. + */ +int ffurl_accept(URLContext *s, URLContext **c); + +/** + * Performs a protocl handshake on the passed client context. + * @param c the client context + * @return >= 0 on success or a negative value corresponding + * to an AVERROR code on failure + */ +int ffurl_handshake(URLContext *c); + +/** * Read up to size bytes from the resource accessed by h, and store * the read bytes in buf. * -- 2.1.0
From 8d8cb5e32a12aedb489a36cf9a26d961244d36a0 Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Tue, 30 Jun 2015 08:24:09 +0200 Subject: [PATCH 3/8] lavf/avio: add avio_accept and avio_handshake Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- libavformat/avio.h | 16 ++++++++++++++++ libavformat/aviobuf.c | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/libavformat/avio.h b/libavformat/avio.h index d3d9bbd..667e3c5 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -648,4 +648,20 @@ struct AVBPrint; */ int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size); +/** + * Accepts and allocates a client context on a server context. + * @param s the server context + * @param c the client context + * @return >= 0 on success or a negative value corresponding + * to an AVERROR on failure + */ +int avio_accept(AVIOContext *s, AVIOContext **c); + +/** + * Performs a protocol dependent handshake + * @param c the client context to perform the handshake on + * @return >= 0 on success or a negative value corresponding + * to an AVERROR on failure + */ +int avio_handshake(AVIOContext *c); #endif /* AVFORMAT_AVIO_H */ diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index ff85081..0591ba5 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -1021,6 +1021,23 @@ int avio_read_to_bprint(AVIOContext *h, AVBPrint *pb, size_t max_size) return 0; } +int avio_accept(AVIOContext *s, AVIOContext **c) +{ + int ret; + URLContext *sc = s->opaque; + URLContext *cc; + ret = ffurl_accept(sc, &cc); + if (ret > 0) + ret = ffio_fdopen(c, cc); + return ret; +} + +int avio_handshake(AVIOContext *c) +{ + URLContext *cc = c->opaque; + return ffurl_handshake(cc); +} + /* output in a dynamic buffer */ typedef struct DynBuffer { -- 2.1.0
From b8071e7b6416c37fb05cfae29dd4a29ea71bc41e Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Tue, 30 Jun 2015 09:28:48 +0200 Subject: [PATCH 4/8] lavf/tcp: add tcp_accept Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- libavformat/tcp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/libavformat/tcp.c b/libavformat/tcp.c index f24cad2..ddaecc9 100644 --- a/libavformat/tcp.c +++ b/libavformat/tcp.c @@ -163,6 +163,22 @@ static int tcp_open(URLContext *h, const char *uri, int flags) return ret; } +static int tcp_accept(URLContext *s, URLContext **c) +{ + TCPContext *sc = s->priv_data; + TCPContext *cc; + int ret; + if ((ret = ffurl_alloc(c, s->filename, AVIO_FLAG_READ_WRITE, &s->interrupt_callback)) < 0) + return ret; + cc = (*c)->priv_data; + ret = accept(sc->fd, NULL, NULL); + if (ret < 0) { + return ff_neterrno(); + } + cc->fd = ret; + return ret; +} + static int tcp_read(URLContext *h, uint8_t *buf, int size) { TCPContext *s = h->priv_data; @@ -223,6 +239,7 @@ static int tcp_get_file_handle(URLContext *h) URLProtocol ff_tcp_protocol = { .name = "tcp", .url_open = tcp_open, + .url_accept = tcp_accept, .url_read = tcp_read, .url_write = tcp_write, .url_close = tcp_close, -- 2.1.0
From e493cad7d123025a27f04721ba236593ea44738b Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Tue, 30 Jun 2015 09:29:16 +0200 Subject: [PATCH 5/8] lavf/tcp: increase range for listen and call the underlying socket operations accordingly Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- libavformat/tcp.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libavformat/tcp.c b/libavformat/tcp.c index ddaecc9..a7a5d74 100644 --- a/libavformat/tcp.c +++ b/libavformat/tcp.c @@ -44,7 +44,7 @@ typedef struct TCPContext { #define D AV_OPT_FLAG_DECODING_PARAM #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E }, + { "listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, .flags = D|E }, { "timeout", "set timeout (in microseconds) of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "listen_timeout", "Connection awaiting timeout (in milliseconds)", OFFSET(listen_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { NULL } @@ -125,12 +125,17 @@ static int tcp_open(URLContext *h, const char *uri, int flags) goto fail; } - if (s->listen) { - if ((ret = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, + if (s->listen == 2) { + // multi-client + if ((ret = ff_listen(fd, cur_ai->ai_addr, cur_ai->ai_addrlen)) < 0) { + goto fail1; + } + } else if (s->listen == 1) { + // single client + if ((fd = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, s->listen_timeout, h)) < 0) { goto fail1; } - fd = ret; } else { if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, s->open_timeout / 1000, h, !!cur_ai->ai_next)) < 0) { -- 2.1.0
From c8622b35795ea52dc0b25ce1d5d196d1d561e250 Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Tue, 30 Jun 2015 09:58:09 +0200 Subject: [PATCH 6/8] lavf/http: add http_accept and http_handshake Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- libavformat/http.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/libavformat/http.c b/libavformat/http.c index 676bfd5..9b67b0b 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -316,6 +316,21 @@ static void handle_http_errors(URLContext *h, int error) } } +static int http_handshake(URLContext *c) { + int ret, err, new_location; + HTTPContext *ch = c->priv_data; + URLContext *cl = ch->hd; + static const char header[] = "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n"; + ffurl_handshake(cl); + if ((err = http_read_header(c, &new_location)) < 0) + goto fail; + if ((ret = ffurl_write(cl, header, strlen(header))) < 0) + goto fail; +fail: + handle_http_errors(c, err); + return ret; +} + static int http_listen(URLContext *h, const char *uri, int flags, AVDictionary **options) { HTTPContext *s = h->priv_data; @@ -382,6 +397,23 @@ static int http_open(URLContext *h, const char *uri, int flags, return ret; } +static int http_accept(URLContext *s, URLContext **c) +{ + int ret; + HTTPContext *sc = s->priv_data; + HTTPContext *cc; + URLContext *sl = sc->hd; + URLContext *cl; + if ((ret = ffurl_alloc(c, s->filename, AVIO_FLAG_READ_WRITE, &sl->interrupt_callback)) < 0) + goto fail; + cc = (*c)->priv_data; + if ((ret = ffurl_accept(sl, &cl)) < 0) + goto fail; + cc->hd = cl; +fail: + return ret; +} + static int http_getc(HTTPContext *s) { int len; @@ -1346,6 +1378,8 @@ HTTP_CLASS(http); URLProtocol ff_http_protocol = { .name = "http", .url_open2 = http_open, + .url_accept = http_accept, + .url_handshake = http_handshake, .url_read = http_read, .url_write = http_write, .url_seek = http_seek, @@ -1364,6 +1398,8 @@ HTTP_CLASS(https); URLProtocol ff_https_protocol = { .name = "https", .url_open2 = http_open, + .url_accept = http_accept, + .url_handshake = http_handshake, .url_read = http_read, .url_write = http_write, .url_seek = http_seek, @@ -1477,6 +1513,8 @@ static int http_proxy_write(URLContext *h, const uint8_t *buf, int size) URLProtocol ff_httpproxy_protocol = { .name = "httpproxy", .url_open = http_proxy_open, + .url_accept = http_accept, + .url_handshake = http_handshake, .url_read = http_buf_read, .url_write = http_proxy_write, .url_close = http_proxy_close, -- 2.1.0
From b183b01c2bd1978d922f9516f59b200415285823 Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Tue, 30 Jun 2015 11:12:15 +0200 Subject: [PATCH 7/8] lavf/http: increase range for listen, add http_handshake and move handshake logic there Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- libavformat/http.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 9b67b0b..f6a6620 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -128,7 +128,7 @@ static const AVOption options[] = { { "end_offset", "try to limit the request to bytes preceding this offset", OFFSET(end_off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D }, { "method", "Override the HTTP method or set the expected HTTP method from a client", OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E }, { "reconnect", "auto reconnect after disconnect before EOF", OFFSET(reconnect), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D }, - { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D | E }, + { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, D | E }, { NULL } }; @@ -306,6 +306,8 @@ static void handle_http_errors(URLContext *h, int error) HTTPContext *s = h->priv_data; if (h->is_connected) { switch(error) { + case 0: + break; case AVERROR_HTTP_BAD_REQUEST: ffurl_write(s->hd, bad_request, strlen(bad_request)); break; @@ -335,11 +337,10 @@ static int http_listen(URLContext *h, const char *uri, int flags, AVDictionary **options) { HTTPContext *s = h->priv_data; int ret; - static const char header[] = "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n"; char hostname[1024], proto[10]; char lower_url[100]; const char *lower_proto = "tcp"; - int port, new_location; + int port; s->chunked_post = 1; av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); @@ -347,20 +348,17 @@ static int http_listen(URLContext *h, const char *uri, int flags, lower_proto = "tls"; ff_url_join(lower_url, sizeof(lower_url), lower_proto, NULL, hostname, port, NULL); - av_dict_set(options, "listen", "1", 0); + av_dict_set_int(options, "listen", s->listen, 0); if ((ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE, &h->interrupt_callback, options)) < 0) goto fail; - if ((ret = http_read_header(h, &new_location)) < 0) - goto fail; - if ((ret = ffurl_write(s->hd, header, strlen(header))) < 0) - goto fail; - return 0; - + if (s->listen == 1) { + // single client + ret = http_handshake(h); + } fail: - handle_http_errors(h, ret); av_dict_free(&s->chained_options); - return ret; + return 0; } static int http_open(URLContext *h, const char *uri, int flags, @@ -1295,7 +1293,7 @@ static int http_close(URLContext *h) av_freep(&s->inflate_buffer); #endif /* CONFIG_ZLIB */ - if (!s->end_chunked_post) + if ((s->listen != 2 && !s->end_chunked_post)) /* Close the write direction by sending the end of chunked encoding. */ ret = http_shutdown(h, h->flags); -- 2.1.0
From 803a41609cf37ee44763ada91ae31142873a845a Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Tue, 30 Jun 2015 11:12:58 +0200 Subject: [PATCH 8/8] doc/protocols: document experimental mutli-client api Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- doc/protocols.texi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/protocols.texi b/doc/protocols.texi index 453dbcf..39a132a 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -292,6 +292,8 @@ autodetection in the future. If set to 1 enables experimental HTTP server. This can be used to send data when used as an output option, or read data from a client with HTTP POST when used as an input option. +If set to 2 enables experimental mutli-client HTTP server. This is not yet implemented +in ffmpeg.c or ffserver.c and thus must not be used as a command line option. @example # Server side (sending): ffmpeg -i somefile.ogg -c copy -listen 1 -f ogg http://@var{server}:@var{port} -- 2.1.0
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel