[FFmpeg-devel] [PATCH 5/8] lavf/tcp: increase range for listen and call the underlying socket operations accordingly

2015-07-20 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/tcp.c | 16 +++-
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index 6f5e175..5505945 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -45,7 +45,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 }
@@ -126,12 +126,18 @@ 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,
-  s-listen_timeout, h))  0) {
+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) {
+ret = fd;
 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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 4/8] lavf/tcp: add tcp_accept

2015-07-20 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/tcp.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index f24cad2..6f5e175 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 #include avformat.h
+#include libavutil/avassert.h
 #include libavutil/parseutils.h
 #include libavutil/opt.h
 #include libavutil/time.h
@@ -163,6 +164,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;
+av_assert0(sc-listen);
+if ((ret = ffurl_alloc(c, s-filename, s-flags  AVIO_FLAG_READ_WRITE, 
s-interrupt_callback))  0)
+return ret;
+cc = (*c)-priv_data;
+ret = ff_accept(sc-fd, sc-listen_timeout, s);
+if (ret  0)
+return ff_neterrno();
+cc-fd = ret;
+return 0;
+}
+
 static int tcp_read(URLContext *h, uint8_t *buf, int size)
 {
 TCPContext *s = h-priv_data;
@@ -223,6 +240,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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 8/8] doc/example: Add http multi-client example code

2015-07-20 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 doc/examples/Makefile   |   1 +
 doc/examples/http_multiclient.c | 139 
 2 files changed, 140 insertions(+)
 create mode 100644 doc/examples/http_multiclient.c

Changes since last version:
  - Use handshake API properly
  - Use perror() to print fork()'s error message. 

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 000..a2293b8
--- /dev/null
+++ b/doc/examples/http_multiclient.c
@@ -0,0 +1,139 @@
+/*
+ * copyright (c) 2015 Stephan Holljes
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * libavformat multi-client network API usage example.
+ *
+ * @example http_multiclient.c
+ * This example will serve a file without decoding or demuxing it over http.
+ * Multiple clients can connect and will receive the same file.
+ */
+
+#include libavformat/avformat.h
+#include unistd.h
+#include libavutil/opt.h
+
+void process_client(AVIOContext *client, const char* in_uri)
+{
+AVIOContext *input = NULL;
+uint8_t buf[1024];
+int ret, n, http_code;
+char *resource;
+for (;;) {
+if ((ret = avio_handshake(client))  0)
+goto end;
+av_opt_get(client, resource, AV_OPT_SEARCH_CHILDREN, resource);
+resource++;
+av_log(client, AV_LOG_TRACE, resource=%s\n, resource);
+if (strcmp(resource, in_uri)) {
+http_code = 404;
+} else {
+http_code = 200;
+}
+av_opt_set_int(client, http_code, http_code, AV_OPT_SEARCH_CHILDREN);
+if (ret == 0)
+break;
+}
+fprintf(stderr, Handshake performed.\n);
+if (http_code != 200)
+goto end;
+fprintf(stderr, Opening input file.\n);
+if ((ret = avio_open2(input, in_uri, AVIO_FLAG_READ, NULL, NULL))  0) {
+av_log(input, AV_LOG_ERROR, Failed to open input: %s\n, in_uri);
+goto end;
+}
+for(;;) {
+n = avio_read(input, buf, sizeof(buf));
+if (n  0) {
+if (n == AVERROR_EOF)
+break;
+av_log(input, AV_LOG_ERROR, Error reading from input: %s.\n,
+   av_err2str(n));
+ret = n;
+break;
+}
+avio_write(client, buf, n);
+avio_flush(client);
+}
+end:
+fprintf(stderr, Flushing client\n);
+avio_flush(client);
+fprintf(stderr, Closing client\n);
+avio_close(client);
+fprintf(stderr, Closing input\n);
+avio_close(input);
+}
+
+int main(int argc, char **argv)
+{
+av_log_set_level(AV_LOG_TRACE);
+AVDictionary *options = NULL;
+AVIOContext *client = NULL, *server = NULL;
+const char *in_uri, *out_uri;
+int ret, pid;
+if (argc  3) {
+printf(usage: %s input http://hostname[:port]\n;
+   API example program to serve http to multiple clients.\n
+   \n, argv[0]);
+return 1;
+}
+
+in_uri = argv[1];
+out_uri = argv[2];
+
+av_register_all();
+avformat_network_init();
+
+if ((ret = av_dict_set(options, listen, 2, 0))  0)
+goto end;
+if ((ret = avio_open2(server, out_uri, AVIO_FLAG_WRITE, NULL, options)) 
 0)
+goto end;
+fprintf(stderr, Entering main loop.\n);
+for(;;) {
+if ((ret = avio_accept(server, client))  0)
+goto end;
+fprintf(stderr, Accepted client, forking process.\n);
+// XXX: Since we don't reap our children and don't ignore signals
+//  this produces zombie processes.
+pid = fork();
+if (pid  0) {
+perror(Fork

[FFmpeg-devel] [PATCH 7/8] doc/protocols: document experimental mutli-client api

2015-07-20 Thread Stephan Holljes
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 f152f5a..905bc09 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -304,6 +304,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


Re: [FFmpeg-devel] [PATCH 4/8] lavf/tcp: add tcp_accept

2015-07-20 Thread Stephan Holljes
On Tue, Jul 21, 2015 at 5:45 AM, Stephan Holljes
klaxa1...@googlemail.com wrote:
 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/tcp.c | 18 ++
  1 file changed, 18 insertions(+)

 diff --git a/libavformat/tcp.c b/libavformat/tcp.c
 index f24cad2..6f5e175 100644
 --- a/libavformat/tcp.c
 +++ b/libavformat/tcp.c
 @@ -19,6 +19,7 @@
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
 USA
   */
  #include avformat.h
 +#include libavutil/avassert.h
  #include libavutil/parseutils.h
  #include libavutil/opt.h
  #include libavutil/time.h
 @@ -163,6 +164,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;
 +av_assert0(sc-listen);
 +if ((ret = ffurl_alloc(c, s-filename, s-flags  AVIO_FLAG_READ_WRITE, 
 s-interrupt_callback))  0)
 +return ret;
 +cc = (*c)-priv_data;
 +ret = ff_accept(sc-fd, sc-listen_timeout, s);
 +if (ret  0)
 +return ff_neterrno();
 +cc-fd = ret;
 +return 0;
 +}
 +
  static int tcp_read(URLContext *h, uint8_t *buf, int size)
  {
  TCPContext *s = h-priv_data;
 @@ -223,6 +240,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


I forgot to filter the correct flags. Attached patch is identical, but
uses s-flags  (AVIO_FLAG_READ_WRITE | AVIO_FLAG_DIRECT) in
ffurl_alloc()
From 2147606264089c7cab0b44798fa2c03d5df7547b Mon Sep 17 00:00:00 2001
From: Stephan Holljes klaxa1...@googlemail.com
Date: Fri, 3 Jul 2015 02:27:09 +0200
Subject: [PATCH 6/8] lavf/tcp: add tcp_accept

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/tcp.c | 35 ++-
 1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index f24cad2..ed9abc5 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 #include avformat.h
+#include libavutil/avassert.h
 #include libavutil/parseutils.h
 #include libavutil/opt.h
 #include libavutil/time.h
@@ -44,7 +45,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 +126,18 @@ 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,
-  s-listen_timeout, h))  0) {
+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) {
+ret = fd;
 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) {
@@ -163,6 +170,23 @@ 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;
+av_assert0(sc-listen);
+if ((ret = ffurl_alloc(c, s-filename, s-flags  (AVIO_FLAG_READ_WRITE | AVIO_FLAG_DIRECT),
+   s-interrupt_callback))  0)
+return ret;
+cc = (*c)-priv_data;
+ret = ff_accept(sc-fd, sc-listen_timeout, s);
+if (ret  0)
+return ff_neterrno();
+cc-fd = ret;
+return 0;
+}
+
 static int tcp_read(URLContext *h, uint8_t *buf, int size)
 {
 TCPContext *s = h-priv_data;
@@ -223,6 +247,7 @@ static int tcp_get_file_handle(URLContext *h)
 URLProtocol ff_tcp_protocol

Re: [FFmpeg-devel] [PATCH 4/8] lavf/tcp: add tcp_accept

2015-07-20 Thread Stephan Holljes
On Tue, Jul 21, 2015 at 5:58 AM, Stephan Holljes
klaxa1...@googlemail.com wrote:
 On Tue, Jul 21, 2015 at 5:45 AM, Stephan Holljes
 klaxa1...@googlemail.com wrote:
 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/tcp.c | 18 ++
  1 file changed, 18 insertions(+)

 diff --git a/libavformat/tcp.c b/libavformat/tcp.c
 index f24cad2..6f5e175 100644
 --- a/libavformat/tcp.c
 +++ b/libavformat/tcp.c
 @@ -19,6 +19,7 @@
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
 USA
   */
  #include avformat.h
 +#include libavutil/avassert.h
  #include libavutil/parseutils.h
  #include libavutil/opt.h
  #include libavutil/time.h
 @@ -163,6 +164,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;
 +av_assert0(sc-listen);
 +if ((ret = ffurl_alloc(c, s-filename, s-flags  AVIO_FLAG_READ_WRITE, 
 s-interrupt_callback))  0)
 +return ret;
 +cc = (*c)-priv_data;
 +ret = ff_accept(sc-fd, sc-listen_timeout, s);
 +if (ret  0)
 +return ff_neterrno();
 +cc-fd = ret;
 +return 0;
 +}
 +
  static int tcp_read(URLContext *h, uint8_t *buf, int size)
  {
  TCPContext *s = h-priv_data;
 @@ -223,6 +240,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


 I forgot to filter the correct flags. Attached patch is identical, but
 uses s-flags  (AVIO_FLAG_READ_WRITE | AVIO_FLAG_DIRECT) in
 ffurl_alloc()

Disregard the previous patch, I messed up my commits in git.
From 12d9a1e1c511615275260977941aff3067f103ea Mon Sep 17 00:00:00 2001
From: Stephan Holljes klaxa1...@googlemail.com
Date: Tue, 21 Jul 2015 06:10:25 +0200
Subject: [PATCH 4/8] lavf/tcp: add tcp_accept

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/tcp.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index f24cad2..9f8c2a0 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 #include avformat.h
+#include libavutil/avassert.h
 #include libavutil/parseutils.h
 #include libavutil/opt.h
 #include libavutil/time.h
@@ -163,6 +164,23 @@ 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;
+av_assert0(sc-listen);
+if ((ret = ffurl_alloc(c, s-filename, s-flags  (AVIO_FLAG_READ_WRITE | AVIO_FLAG_DIRECT),
+   s-interrupt_callback))  0)
+return ret;
+cc = (*c)-priv_data;
+ret = ff_accept(sc-fd, sc-listen_timeout, s);
+if (ret  0)
+return ff_neterrno();
+cc-fd = ret;
+return 0;
+}
+
 static int tcp_read(URLContext *h, uint8_t *buf, int size)
 {
 TCPContext *s = h-priv_data;
@@ -223,6 +241,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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH 6/8] lavf/http: increase range for listen, handle connection closing accordingly, add http_accept, add http_handshake and move handshake logic there

2015-07-20 Thread Stephan Holljes
On Tue, Jul 21, 2015 at 5:45 AM, Stephan Holljes
klaxa1...@googlemail.com wrote:
 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/http.c | 126 
 -
  1 file changed, 105 insertions(+), 21 deletions(-)

 Changes since last version:
   - Introduce constants for different client modes
   - Add resource and http_code to AVOptions
   - Add http_write_header()
   - Implement handshake that allows multiple roundtrips between application
 and library.

 diff --git a/libavformat/http.c b/libavformat/http.c
 index 676bfd5..2597628 100644
 --- a/libavformat/http.c
 +++ b/libavformat/http.c
 @@ -25,6 +25,7 @@
  #include zlib.h
  #endif /* CONFIG_ZLIB */

 +#include libavutil/avassert.h
  #include libavutil/avstring.h
  #include libavutil/opt.h

 @@ -44,6 +45,9 @@
   * path names). */
  #define BUFFER_SIZE   MAX_URL_SIZE
  #define MAX_REDIRECTS 8
 +#define HTTP_ONESHOT  1
 +#define HTTP_MUTLI2
 +#define HTTP_MULTI_CLIENT 4

  typedef struct HTTPContext {
  const AVClass *class;
 @@ -97,6 +101,7 @@ typedef struct HTTPContext {
  char *method;
  int reconnect;
  int listen;
 +char *resource;
  } HTTPContext;

  #define OFFSET(x) offsetof(HTTPContext, x)
 @@ -128,7 +133,9 @@ 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, 4, D | E },
 +{ resource, The resource requested by a client, OFFSET(resource), 
 AV_OPT_TYPE_STRING, { 0 }, 0, 0, E },
 +{ http_code, The http code to send to a client, OFFSET(http_code), 
 AV_OPT_TYPE_INT, { .i64 = 0}, 0, 599, E},
  { NULL }
  };

 @@ -299,32 +306,87 @@ int ff_http_averror(int status_code, int 
 default_averror)
  return default_averror;
  }

 +static int http_write_header(URLContext* h, int status_code)
 +{
 +int ret;
 +const char *message;
 +// Maybe this should be done more elegantly?
 +static const char bad_request[] = HTTP/1.1 400 Bad 
 Request\r\nContent-Type: text/plain\r\nContent-Length: 17\r\n400 Bad 
 Request\r\n;
 +static const char forbidden[] = HTTP/1.1 403 Forbidden\r\nContent-Type: 
 text/plain\r\nContent-Length: 15\r\n\r\n403 Forbidden\r\n;
 +static const char not_found[] = HTTP/1.1 404 Not Found\r\nContent-Type: 
 text/plain\r\nContent-Length: 15\r\n\r\n404 Not Found\r\n;
 +static const char internal_server_error[] = HTTP/1.1 500 Internal 
 server error\r\nContent-Type: text/plain\r\nContent-Length: 25\r\n\r\n500 
 Internal server error\r\n;
 +static const char ok[] = HTTP/1.1 200 OK\r\nContent-Type: 
 application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n;
 +av_log(h, AV_LOG_TRACE, err: %d\n, status_code);
 +if (status_code == 200) {
 +message = ok;
 +goto end;
 +}
 +switch(status_code) {
 +case AVERROR_HTTP_BAD_REQUEST:
 +message = bad_request;
 +break;
 +case AVERROR_HTTP_FORBIDDEN:
 +message = forbidden;
 +break;
 +case AVERROR_HTTP_NOT_FOUND:
 +message = not_found;
 +break;
 +default:
 +message = internal_server_error;
 +}
 +end:
 +if ((ret = ffurl_write(h, message, strlen(message)))  0)
 +return ret;
 +// Avoid returning a positive value from ffurl_write()
 +ret = ret  0 ? 0 : ret;
 +return ret;
 +}
 +
  static void handle_http_errors(URLContext *h, int error)
  {
 -static const char bad_request[] = HTTP/1.1 400 Bad 
 Request\r\nContent-Type: text/plain\r\n\r\n400 Bad Request\r\n;
 -static const char internal_server_error[] = HTTP/1.1 500 Internal 
 server error\r\nContent-Type: text/plain\r\n\r\n500 Internal server 
 error\r\n;
  HTTPContext *s = h-priv_data;
 -if (h-is_connected) {
 -switch(error) {
 -case AVERROR_HTTP_BAD_REQUEST:
 -ffurl_write(s-hd, bad_request, strlen(bad_request));
 -break;
 -default:
 -av_log(h, AV_LOG_ERROR, Unhandled HTTP error.\n);
 -ffurl_write(s-hd, internal_server_error, 
 strlen(internal_server_error));
 +URLContext *c = s-hd;
 +av_assert0(error  0);
 +http_write_header(c, error);
 +}
 +
 +static int http_handshake(URLContext *c)
 +{
 +int ret, err, new_location;
 +HTTPContext *ch = c-priv_data;
 +URLContext *cl = ch-hd;
 +for (;;) {
 +if ((ret

Re: [FFmpeg-devel] Controlling the server reply (was: 9/9] doc/example: Add http multi-client) example code

2015-07-12 Thread Stephan Holljes
On Sat, Jul 11, 2015 at 11:55 AM, Nicolas George geo...@nsup.org wrote:
 Le primidi 21 messidor, an CCXXIII, Stephan Holljes a écrit :
 Good question, I haven't thought about that myself. Adding a 404 error
 to handle_http_errors() and calling it with AVERROR_HTTP_NOT_FOUND
 could be a solution. I feel like the name handle_http_errors is not
 well chosen then, though.

 Unfortunately, that will not do, because handle_http_errors() is not public
 API.

 And this is a rather fundamental issue, we can not disregard it just by
 making handle_http_errors() public. I had hoped we could finish this patch
 series and handle this issue afterwards, but it seems it must be addressed
 sooner. Let me explain.

 Returning 404 Not found, or 401 Unauthorized, or... is performed by the
 library, but it is the decision of the application (I hope the distinction
 between application and library is clear). The library can not know if a
 particular file exists or not, because it does not even know if the
 application is getting the files from the filesystem or from a database or
 from on-the-fly computations. And the library can even less know the policy
 for authorizing files.

 I can see three rather distinct sub-issues:

 Q1. how the library communicates to the application the details of the
 request;

 Q2. how the application communicates to the library the decision it made;

 Q3. when the application can make its decision.

 Q3 is the crux of the problem: remember we had to split avio_accept() into
 avio_accept() and avio_handshake() to give the application a chance of
 forking or any other solution to handle several clients in parallel. Just
 the same, we will have to split avio_handshake() further to give the
 application a chance of making a decision.

 Furthermore, we need something that will work not only for HTTP but for any
 protocol that FFmpeg may support as a server.

 Q1 is the logical equivalent to the address parameter to the accept()
 system call. To be sure of it, think of an application that serves files
 without authentication on the local network but requires authentication
 otherwise: the client's address is part of the decision making.

 Q1 has a rather obvious and easy answer, that is the reason I hoped we could
 leave it for later: put the request parameters in the context and access
 them with the AVOption system. Thus, the application would access the
 request path with something like av_opt_get(client_ctx,
 http_request_path, AV_OPT_SEARCH_CHILDREN).

 Q2 have the same obvious answer: av_opt_set_int(client_ctx,
 http_reply_code, 404).

 Q3 is the hard part.

 I can see an answer to Q3, but since this is your internship, I think it is
 better to give you a chance to find your own answer first.

 When thinking on it, remember two situations that the API must be able to
 handle:

 * A protocol can have several round-trips with decision to make at each
   step. For example, first negotiate the authentication scheme, then
   authenticate, then request a resource. All this is part of the handshake,
   but the application needs an entry point at each step.

 * Nested protocols: in HTTP-over-TCP, there is no decision to make until we
   have the full request, but in HTTP-over-TLS, i.e. HTTPS, the application
   needs a hook during the TLS handshake to handle Server Name Indication,
   and then the normal HTTP hook to set the reply code. We do not want to add
   special code in the upper protocol to handle the lower protocol.

 Please let me know your thoughts about that.

 Regards,

 --
   Nicolas George
 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Hi,

the best thing I thought of was some kind of generic communication
function that either uses the client's AVOption system to pass around
values or just uses an AVDictionary.
Giving the application access to the results of the library could be
done in a similar way it is being done in http_read_header() by
repeatedly calling the communicate function and checking for its error
code (return  0 in case of error,  0 in case of success, but
unfinished processing and 0 on success and finished processing.) Since
we have to deal with protocol-specific decisions, each protocol should
implement its own communication function with something like a
url_comm_params() function added to the URLProtocol struct, which is
called like most (all?) other URLProtocol functions with
ffurl_comm_params() and avio_comm_params(). I'm not really sure how to
tell the application what parameters were negotiated, but maybe this
can be done in a similar fashion it has been done with unused_opts,
but instead with used_opts.

Regards,
Stephan
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH 4/9] lavf/tcp: add tcp_accept

2015-07-09 Thread Stephan Holljes
On Thu, Jul 9, 2015 at 3:31 PM, Nicolas George geo...@nsup.org wrote:
 Le decadi 20 messidor, an CCXXIII, Stephan Holljes a écrit :
 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/tcp.c | 18 ++
  1 file changed, 18 insertions(+)
 Changes since first version:
   - Add av_assert0() check for sc-listen
   - Add bitmask for s-flags in ffurl_alloc
   - Use ff_accept() instead of accept()


 diff --git a/libavformat/tcp.c b/libavformat/tcp.c
 index f24cad2..6f5e175 100644
 --- a/libavformat/tcp.c
 +++ b/libavformat/tcp.c
 @@ -19,6 +19,7 @@
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
 USA
   */
  #include avformat.h
 +#include libavutil/avassert.h
  #include libavutil/parseutils.h
  #include libavutil/opt.h
  #include libavutil/time.h
 @@ -163,6 +164,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;
 +av_assert0(sc-listen);

 +if ((ret = ffurl_alloc(c, s-filename, s-flags  AVIO_FLAG_READ_WRITE, 
 s-interrupt_callback))  0)
 +return ret;

 Any reason to remove the other flags? Since it is not possible to add flags
 on a context afterwards, setting the flags on the server to have them on the
 clients is the most obvious solution. AVIO_FLAG_NONBLOCK does not work, but
 AVIO_FLAG_DIRECT does and makes sense for network protocols.


No reason at all, I wasn't aware of that. What other flags should be
kept? Since you suggested filtering s-flags I'm assuming not all
flags from s should be kept?
Should the same filtering then be applied in http_accept() too?

 +cc = (*c)-priv_data;
 +ret = ff_accept(sc-fd, sc-listen_timeout, s);
 +if (ret  0)
 +return ff_neterrno();
 +cc-fd = ret;
 +return 0;
 +}
 +
  static int tcp_read(URLContext *h, uint8_t *buf, int size)
  {
  TCPContext *s = h-priv_data;
 @@ -223,6 +240,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,

 Regards,

 --
   Nicolas George

 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Regards,
Stephan
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH 9/9] doc/example: Add http multi-client example code

2015-07-09 Thread Stephan Holljes
On Thu, Jul 9, 2015 at 3:47 PM, Nicolas George geo...@nsup.org wrote:
 Le decadi 20 messidor, an CCXXIII, Stephan Holljes a écrit :
 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  doc/examples/Makefile   |   1 +
  doc/examples/http_multiclient.c | 120 
 
  2 files changed, 121 insertions(+)
  create mode 100644 doc/examples/http_multiclient.c
 Changes since first version:
   - Move client handling code in separate function
   - Close filedescriptors earlier

 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 000..a780321
 --- /dev/null
 +++ b/doc/examples/http_multiclient.c
 @@ -0,0 +1,120 @@
 +/*
 + * copyright (c) 2015 Stephan Holljes
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * FFmpeg is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with FFmpeg; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
 USA
 + */
 +
 +/**
 + * @file
 + * libavformat multi-client network API usage example.
 + *
 + * @example http_multiclient.c
 + * This example will serve a file without decoding or demuxing it over http.
 + * Multiple clients can connect and will receive the same file.
 + */
 +
 +#include libavformat/avformat.h
 +#include unistd.h
 +
 +void process_client(AVIOContext *client, const char* in_uri)
 +{

 +AVIOContext *input =NULL;

 Nit: space.

 +uint8_t buf[1024];
 +int ret, n;

 +avio_handshake(client);

 Check for error.

 +fprintf(stderr, Handshake performed.\n);
 +fprintf(stderr, Opening input file.\n);

 +if ((ret = avio_open2(input, in_uri, AVIO_FLAG_READ, NULL, NULL))  0) 
 {
 +av_log(input, AV_LOG_ERROR, Failed to open input: %s\n, in_uri);
 +return;
 +}

 I just realized this: how would you go about returning 404 to the client
 here?

Good question, I haven't thought about that myself. Adding a 404 error
to handle_http_errors() and calling it with AVERROR_HTTP_NOT_FOUND
could be a solution. I feel like the name handle_http_errors is not
well chosen then, though.


 +for(;;) {
 +n = avio_read(input, buf, sizeof(buf));
 +if (n  0) {
 +if (n == AVERROR_EOF)
 +break;
 +av_log(input, AV_LOG_ERROR, Error reading from input: %s.\n,
 +   av_err2str(n));
 +ret = n;
 +break;
 +}
 +avio_write(client, buf, n);
 +avio_flush(client);
 +}
 +fprintf(stderr, Flushing client\n);
 +avio_flush(client);
 +fprintf(stderr, Closing client\n);
 +avio_close(client);
 +fprintf(stderr, Closing input\n);
 +avio_close(input);
 +}
 +
 +int main(int argc, char **argv)
 +{
 +AVDictionary *options = NULL;
 +AVIOContext *client = NULL, *server = NULL;
 +const char *in_uri, *out_uri;
 +int ret, pid;
 +if (argc  3) {
 +printf(usage: %s input http://hostname[:port]\n;
 +   API example program to serve http to multiple clients.\n
 +   \n, argv[0]);
 +return 1;
 +}
 +
 +in_uri = argv[1];
 +out_uri = argv[2];
 +
 +av_register_all();
 +avformat_network_init();
 +
 +if ((ret = av_dict_set(options, listen, 2, 0))  0)
 +goto end;
 +if ((ret = avio_open2(server, out_uri, AVIO_FLAG_READ_WRITE, NULL, 
 options))  0)
 +goto end;
 +fprintf(stderr, Entering main loop.\n);
 +for(;;) {
 +if ((ret = avio_accept(server, client))  0)
 +goto end;
 +fprintf(stderr, Accepted client, forking process.\n);
 +// XXX: Since we don't reap our children and don't ignore signals
 +//  this produces zombie processes.
 +pid = fork();
 +if (pid  0

Re: [FFmpeg-devel] [PATCH 6/9] lavf/http: add http_accept

2015-07-09 Thread Stephan Holljes
On Thu, Jul 9, 2015 at 3:41 PM, Nicolas George geo...@nsup.org wrote:
 Le decadi 20 messidor, an CCXXIII, Stephan Holljes a écrit :
 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/http.c | 19 +++
  1 file changed, 19 insertions(+)

 Changes since first version:
   - Add av_assert0() check for sc-listen
   - Add bitmask for s-flags in ffurl_alloc

 Thanks.


 diff --git a/libavformat/http.c b/libavformat/http.c
 index 676bfd5..3c1ec35 100644
 --- a/libavformat/http.c
 +++ b/libavformat/http.c
 @@ -25,6 +25,7 @@
  #include zlib.h
  #endif /* CONFIG_ZLIB */

 +#include libavutil/avassert.h
  #include libavutil/avstring.h
  #include libavutil/opt.h

 @@ -382,6 +383,24 @@ 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;
 +av_assert0(sc-listen);

 +if ((ret = ffurl_alloc(c, s-filename, s-flags  AVIO_FLAG_READ_WRITE, 
 sl-interrupt_callback))  0)
 +goto fail;

 Same remark as in my previous mail.

 +cc = (*c)-priv_data;
 +if ((ret = ffurl_accept(sl, cl))  0)
 +goto fail;

 +cc-hd = cl;

 Does it make sense to set cc-listen = 1 here, to indicate that the client
 is not yet a normal client? It may make the tests for trailers simpler.

I am not sure about the implications. So far setting listen has been
exclusive to server contexts. I'll will give it some thoughts and do
some testing.


 +fail:
 +return ret;
 +}
 +
  static int http_getc(HTTPContext *s)
  {
  int len;

 Regards,

 --
   Nicolas George

 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH 7/9] lavf/http: increase range for listen, handle connection closing accordingly, add http_handshake and move handshake logic there

2015-07-09 Thread Stephan Holljes
On Thu, Jul 9, 2015 at 3:42 PM, Nicolas George geo...@nsup.org wrote:
 Le decadi 20 messidor, an CCXXIII, Stephan Holljes a écrit :
 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/http.c | 39 ---
  1 file changed, 28 insertions(+), 11 deletions(-)
 Changes since first version:
   - Return from http_handshake() if no errors occured instead of falling 
 through
 fail label
   - Add av_assert0() check for error in handle_http_errors()
   - Remove passthough if error == 0 (should never happen anymore)

 Is it possible to use tcp_accept() without tcp_handshake()? If not, you
 probably should merge patches 6 and 7.

I'm assuming you meant http_accept() and http_handshake(). On the API
level it should be possible to use them separately, for an application
it would probably not make much sense to use only http_accept()
without http_handshake(). I will merge the patches.



 diff --git a/libavformat/http.c b/libavformat/http.c
 index 3c1ec35..813870e 100644
 --- a/libavformat/http.c
 +++ b/libavformat/http.c
 @@ -129,7 +129,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 }
  };

 @@ -305,6 +305,7 @@ static void handle_http_errors(URLContext *h, int error)
  static const char bad_request[] = HTTP/1.1 400 Bad 
 Request\r\nContent-Type: text/plain\r\n\r\n400 Bad Request\r\n;
  static const char internal_server_error[] = HTTP/1.1 500 Internal 
 server error\r\nContent-Type: text/plain\r\n\r\n500 Internal server 
 error\r\n;
  HTTPContext *s = h-priv_data;
 +av_assert0(error  0);
  if (h-is_connected) {
  switch(error) {
  case AVERROR_HTTP_BAD_REQUEST:
 @@ -317,15 +318,33 @@ static void handle_http_errors(URLContext *h, int 
 error)
  }
  }


 +static int http_handshake(URLContext *c) {

 Nit: inconsistent brace placement.

Fixed locally, will be updated in next patch series.


 +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;
 +if ((ret = ffurl_handshake(cl))  0)
 +return ret;
 +if ((err = http_read_header(c, new_location))  0)
 +goto fail;
 +if ((ret = ffurl_write(cl, header, strlen(header)))  0)
 +return ret;
 +// Avoid returning a positive value from ffurl_write()
 +ret = ret  0 ? 0 : ret;
 +return ret;
 +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;
  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);
 @@ -333,18 +352,14 @@ 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);
 +if ((ret = av_dict_set_int(options, listen, s-listen, 0))  0)
 +goto fail;
  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;
  }
 @@ -1365,6 +1380,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

[FFmpeg-devel] [PATCH 4/9] lavf/tcp: add tcp_accept

2015-07-08 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/tcp.c | 18 ++
 1 file changed, 18 insertions(+)
Changes since first version:
  - Add av_assert0() check for sc-listen
  - Add bitmask for s-flags in ffurl_alloc
  - Use ff_accept() instead of accept()


diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index f24cad2..6f5e175 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 #include avformat.h
+#include libavutil/avassert.h
 #include libavutil/parseutils.h
 #include libavutil/opt.h
 #include libavutil/time.h
@@ -163,6 +164,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;
+av_assert0(sc-listen);
+if ((ret = ffurl_alloc(c, s-filename, s-flags  AVIO_FLAG_READ_WRITE, 
s-interrupt_callback))  0)
+return ret;
+cc = (*c)-priv_data;
+ret = ff_accept(sc-fd, sc-listen_timeout, s);
+if (ret  0)
+return ff_neterrno();
+cc-fd = ret;
+return 0;
+}
+
 static int tcp_read(URLContext *h, uint8_t *buf, int size)
 {
 TCPContext *s = h-priv_data;
@@ -223,6 +240,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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 5/9] lavf/tcp: increase range for listen and call the underlying socket operations accordingly

2015-07-08 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/tcp.c | 16 +++-
 1 file changed, 11 insertions(+), 5 deletions(-)
Changes since first version:
  - Set ret when ff_listen_bind() fails

diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index 6f5e175..5505945 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -45,7 +45,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 }
@@ -126,12 +126,18 @@ 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,
-  s-listen_timeout, h))  0) {
+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) {
+ret = fd;
 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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 6/9] lavf/http: add http_accept

2015-07-08 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/http.c | 19 +++
 1 file changed, 19 insertions(+)
Changes since first version:
  - Add av_assert0() check for sc-listen
  - Add bitmask for s-flags in ffurl_alloc

diff --git a/libavformat/http.c b/libavformat/http.c
index 676bfd5..3c1ec35 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -25,6 +25,7 @@
 #include zlib.h
 #endif /* CONFIG_ZLIB */
 
+#include libavutil/avassert.h
 #include libavutil/avstring.h
 #include libavutil/opt.h
 
@@ -382,6 +383,24 @@ 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;
+av_assert0(sc-listen);
+if ((ret = ffurl_alloc(c, s-filename, s-flags  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;
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 8/9] doc/protocols: document experimental mutli-client api

2015-07-08 Thread Stephan Holljes
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


[FFmpeg-devel] [PATCH 9/9] doc/example: Add http multi-client example code

2015-07-08 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 doc/examples/Makefile   |   1 +
 doc/examples/http_multiclient.c | 120 
 2 files changed, 121 insertions(+)
 create mode 100644 doc/examples/http_multiclient.c
Changes since first version:
  - Move client handling code in separate function
  - Close filedescriptors earlier

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 000..a780321
--- /dev/null
+++ b/doc/examples/http_multiclient.c
@@ -0,0 +1,120 @@
+/*
+ * copyright (c) 2015 Stephan Holljes
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * libavformat multi-client network API usage example.
+ *
+ * @example http_multiclient.c
+ * This example will serve a file without decoding or demuxing it over http.
+ * Multiple clients can connect and will receive the same file.
+ */
+
+#include libavformat/avformat.h
+#include unistd.h
+
+void process_client(AVIOContext *client, const char* in_uri)
+{
+AVIOContext *input =NULL;
+uint8_t buf[1024];
+int ret, n;
+avio_handshake(client);
+fprintf(stderr, Handshake performed.\n);
+fprintf(stderr, Opening input file.\n);
+if ((ret = avio_open2(input, in_uri, AVIO_FLAG_READ, NULL, NULL))  0) {
+av_log(input, AV_LOG_ERROR, Failed to open input: %s\n, in_uri);
+return;
+}
+for(;;) {
+n = avio_read(input, buf, sizeof(buf));
+if (n  0) {
+if (n == AVERROR_EOF)
+break;
+av_log(input, AV_LOG_ERROR, Error reading from input: %s.\n,
+   av_err2str(n));
+ret = n;
+break;
+}
+avio_write(client, buf, n);
+avio_flush(client);
+}
+fprintf(stderr, Flushing client\n);
+avio_flush(client);
+fprintf(stderr, Closing client\n);
+avio_close(client);
+fprintf(stderr, Closing input\n);
+avio_close(input);
+}
+
+int main(int argc, char **argv)
+{
+AVDictionary *options = NULL;
+AVIOContext *client = NULL, *server = NULL;
+const char *in_uri, *out_uri;
+int ret, pid;
+if (argc  3) {
+printf(usage: %s input http://hostname[:port]\n;
+   API example program to serve http to multiple clients.\n
+   \n, argv[0]);
+return 1;
+}
+
+in_uri = argv[1];
+out_uri = argv[2];
+
+av_register_all();
+avformat_network_init();
+
+if ((ret = av_dict_set(options, listen, 2, 0))  0)
+goto end;
+if ((ret = avio_open2(server, out_uri, AVIO_FLAG_READ_WRITE, NULL, 
options))  0)
+goto end;
+fprintf(stderr, Entering main loop.\n);
+for(;;) {
+if ((ret = avio_accept(server, client))  0)
+goto end;
+fprintf(stderr, Accepted client, forking process.\n);
+// XXX: Since we don't reap our children and don't ignore signals
+//  this produces zombie processes.
+pid = fork();
+if (pid  0) {
+fprintf(stderr, Fork failed.\n);
+ret = AVERROR(errno);
+goto end;
+}
+if (pid == 0) {
+fprintf(stderr, In child.\n);
+process_client(client, in_uri);
+avio_close(server);
+exit(0);
+}
+if (pid  0)
+avio_close(client);
+}
+
+end:
+avio_close(server);
+if (ret  0  ret != AVERROR_EOF) {
+fprintf(stderr, Some errors occured: );
+fprintf(stderr, %s\n, av_err2str(ret));
+return 1;
+}
+return 0;
+}
-- 
2.1.0

[FFmpeg-devel] [PATCH 2/9] lavf/avio: add ffurl_accept and ffurl_handshake

2015-07-08 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/avio.c | 19 +++
 libavformat/url.h  | 18 ++
 2 files changed, 37 insertions(+)
Changes since first version:
  - Add documentation
  - Let url_accept() allocate contexts
  - ffurl_handshake only takes one URLContext

diff --git a/libavformat/avio.c b/libavformat/avio.c
index c188adc..1182336 100644
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -211,6 +211,25 @@ int ffurl_connect(URLContext *uc, AVDictionary **options)
 return 0;
 }
 
+int ffurl_accept(URLContext *s, URLContext **c)
+{
+if (s-prot-url_accept)
+return s-prot-url_accept(s, c);
+return 0;
+}
+
+int ffurl_handshake(URLContext *c)
+{
+int ret;
+if (c-prot-url_handshake) {
+ret = c-prot-url_handshake(c);
+if (ret)
+return ret;
+}
+c-is_connected = 1;
+return 0;
+}
+
 #define URL_SCHEME_CHARS\
 abcdefghijklmnopqrstuvwxyz\
 ABCDEFGHIJKLMNOPQRSTUVWXYZ\
diff --git a/libavformat/url.h b/libavformat/url.h
index 99a3201..d010a77 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 = 0 on success, ff_neterrno() on failure.
+ */
+int ffurl_accept(URLContext *s, URLContext **c);
+
+/**
+ * Perform a protocol 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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/9] lavf/network: split ff_listen_bind into ff_listen and ff_accept

2015-07-08 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/network.c | 27 +--
 libavformat/network.h | 20 
 2 files changed, 41 insertions(+), 6 deletions(-)
Changes since first version:
  - Added documentation
  - Restore previous behaviour of not closing server socket if
accept() fails

diff --git a/libavformat/network.c b/libavformat/network.c
index 47ade8c..7a326d2 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;
+if ((ret = ff_accept(fd, timeout, h))  0)
+return ret;
+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..f83c796 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -255,6 +255,26 @@ int ff_listen_bind(int fd, const struct sockaddr *addr,
URLContext *h);
 
 /**
+ * Bind to a file descriptor to an address without accepting connections.
+ * @param fd  First argument of bind().
+ * @param addrSecond argument of bind().
+ * @param addrlen Third argument of bind().
+ * @return0 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.
+ * @returnA 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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 3/9] lavf/avio: add avio_accept and avio_handshake

2015-07-08 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/avio.h| 16 
 libavformat/aviobuf.c | 17 +
 2 files changed, 33 insertions(+)
Changes since first version:
  - Add documentation

diff --git a/libavformat/avio.h b/libavformat/avio.h
index d3d9bbd..b7a4fa8 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);
 
+/**
+ * Accept and allocate 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);
+
+/**
+ * Perform 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..ce05c5d 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)
+return ret;
+return ffio_fdopen(c, cc);
+}
+
+int avio_handshake(AVIOContext *c)
+{
+URLContext *cc = c-opaque;
+return ffurl_handshake(cc);
+}
+
 /* output in a dynamic buffer */
 
 typedef struct DynBuffer {
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] GSoC update

2015-07-08 Thread Stephan Holljes
Hi,

I have moved the client code in the sample application into a separate
function, I hope I did this correctly. I also annotated the patch
files with the changes that occurred over the past few iterations of
these exchanges. They will be sent shortly as git send-email patches.

I also tested the sample application numerous times with wget, nc and
siege. I also constantly tested that sending data as a POST client
still works (with wget).

Regards,
Stephan
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH 4/9] lavf/tcp: add tcp_accept

2015-07-06 Thread Stephan Holljes
On Mon, Jul 6, 2015 at 7:58 PM, Nicolas George geo...@nsup.org wrote:
 Le sextidi 16 messidor, an CCXXIII, Stephan Holljes a écrit :
 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/tcp.c | 18 ++
  1 file changed, 18 insertions(+)

 diff --git a/libavformat/tcp.c b/libavformat/tcp.c
 index f24cad2..71dff7a 100644
 --- a/libavformat/tcp.c
 +++ b/libavformat/tcp.c
 @@ -19,6 +19,7 @@
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
 USA
   */
  #include avformat.h
 +#include libavutil/avassert.h
  #include libavutil/parseutils.h
  #include libavutil/opt.h
  #include libavutil/time.h
 @@ -163,6 +164,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;
 +av_assert0(sc-listen);

 +if ((ret = ffurl_alloc(c, s-filename, AVIO_FLAG_READ_WRITE, 
 s-interrupt_callback))  0)
 +return ret;

 My previous comment said: Maybe c-flags instead of hardcoding
 AVIO_FLAG_READ_WRITE?, what happened to it? It is ok to not agree with it,
 but not to ignore it entirely.

Sorry, I must have missed that remark. Fixed in attached patch.


 +cc = (*c)-priv_data;
 +ret = ff_accept(sc-fd, sc-listen_timeout, s);
 +if (ret  0)
 +return ff_neterrno();
 +cc-fd = ret;
 +return 0;
 +}
 +
  static int tcp_read(URLContext *h, uint8_t *buf, int size)
  {
  TCPContext *s = h-priv_data;
 @@ -223,6 +240,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,

 Regards,

 --
   Nicolas George

Regards,
Stephan
From d796bbc8160af59995d10d17779f3909a7ee62e5 Mon Sep 17 00:00:00 2001
From: Stephan Holljes klaxa1...@googlemail.com
Date: Fri, 3 Jul 2015 02:27:09 +0200
Subject: [PATCH] lavf/tcp: add tcp_accept

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/tcp.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index f24cad2..6f5e175 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 #include avformat.h
+#include libavutil/avassert.h
 #include libavutil/parseutils.h
 #include libavutil/opt.h
 #include libavutil/time.h
@@ -163,6 +164,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;
+av_assert0(sc-listen);
+if ((ret = ffurl_alloc(c, s-filename, s-flags  AVIO_FLAG_READ_WRITE, s-interrupt_callback))  0)
+return ret;
+cc = (*c)-priv_data;
+ret = ff_accept(sc-fd, sc-listen_timeout, s);
+if (ret  0)
+return ff_neterrno();
+cc-fd = ret;
+return 0;
+}
+
 static int tcp_read(URLContext *h, uint8_t *buf, int size)
 {
 TCPContext *s = h-priv_data;
@@ -223,6 +240,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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH 7/9] lavf/http: increase range for listen, handle connection closing accordingly, add http_handshake and move handshake logic there

2015-07-05 Thread Stephan Holljes
On Sat, Jul 4, 2015 at 7:47 AM, Stephan Holljes
klaxa1...@googlemail.com wrote:
 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/http.c | 44 +++-
  1 file changed, 31 insertions(+), 13 deletions(-)

 diff --git a/libavformat/http.c b/libavformat/http.c
 index 3c1ec35..6338d80 100644
 --- a/libavformat/http.c
 +++ b/libavformat/http.c
 @@ -129,7 +129,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 }
  };

 @@ -305,8 +305,11 @@ static void handle_http_errors(URLContext *h, int error)
  static const char bad_request[] = HTTP/1.1 400 Bad 
 Request\r\nContent-Type: text/plain\r\n\r\n400 Bad Request\r\n;
  static const char internal_server_error[] = HTTP/1.1 500 Internal 
 server error\r\nContent-Type: text/plain\r\n\r\n500 Internal server 
 error\r\n;
  HTTPContext *s = h-priv_data;
 +av_assert0(error  0);
  if (h-is_connected) {
  switch(error) {
 +case 0:
 +break;
  case AVERROR_HTTP_BAD_REQUEST:
  ffurl_write(s-hd, bad_request, strlen(bad_request));
  break;
 @@ -317,15 +320,33 @@ 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;
 +if ((ret = ffurl_handshake(cl))  0)
 +return ret;
 +if ((err = http_read_header(c, new_location))  0)
 +goto fail;
 +if ((ret = ffurl_write(cl, header, strlen(header)))  0)
 +return ret;
 +// Avoid returning a positive value from ffurl_write()
 +ret = ret  0 ? 0 : ret;
 +return ret;
 +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;
  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);
 @@ -333,18 +354,14 @@ 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);
 +if ((ret = av_dict_set_int(options, listen, s-listen, 0))  0)
 +goto fail;
  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;
  }
 @@ -1262,8 +1279,7 @@ static int http_shutdown(URLContext *h, int flags)
  HTTPContext *s = h-priv_data;

  /* signal end of chunked encoding if used */
 -if (((flags  AVIO_FLAG_WRITE)  s-chunked_post) ||
 -((flags  AVIO_FLAG_READ)  s-chunked_post  s-listen)) {
 +if (((flags  AVIO_FLAG_WRITE)  s-chunked_post)) {

I just noticed that the removal of this test for s-listen introduces
a regression. Connections are not properly closed when http is used as
an input option. Attached patch is identical to this one without this
hunk.

  ret = ffurl_write(s-hd, footer, sizeof(footer) - 1);
  ret = ret  0 ? 0 : ret;
  s-end_chunked_post = 1;
 @@ -1365,6 +1381,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

Re: [FFmpeg-devel] [PATCH 7/9] lavf/http: increase range for listen, handle connection closing accordingly, add http_handshake and move handshake logic there

2015-07-03 Thread Stephan Holljes
On Fri, Jul 3, 2015 at 4:18 PM, Nicolas George geo...@nsup.org wrote:
 Le quintidi 15 messidor, an CCXXIII, Stephan Holljes a écrit :
 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/http.c | 45 -
  1 file changed, 32 insertions(+), 13 deletions(-)

 diff --git a/libavformat/http.c b/libavformat/http.c
 index d9c3624..95065f5 100644
 --- a/libavformat/http.c
 +++ b/libavformat/http.c
 @@ -129,7 +129,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 }
  };

 @@ -307,6 +307,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;
 @@ -317,15 +319,32 @@ static void handle_http_errors(URLContext *h, int 
 error)
  }
  }

 +static int http_handshake(URLContext *c) {
 +int ret, err = 0, 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;
 +if ((ret = ffurl_handshake(cl))  0)
 +return ret;
 +if ((err = http_read_header(c, new_location))  0)
 +goto fail;
 +if ((ret = ffurl_write(cl, header, strlen(header)))  0)
 +goto fail;

 +// Avoid returning a positive value from ffurl_write()
 +ret = ret  0 ? 0 : ret;
 +fail:
 +handle_http_errors(c, err);
 +return ret;

 This is a matter of taste, but I find it more readable if it avoids going
 over the fail label:

 +if ((ret = ffurl_write(cl, header, strlen(header)))  0)
 +goto fail;
 +return 0;
 +fail:
 +handle_http_errors(c, err);
 +return ret;

 That way, you also do not need to change handle_http_errors() for error=0.
 (Although av_assert0(error  0) would do no harm there.)

 +}
 +
  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);
 @@ -333,18 +352,16 @@ 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);
 +if ((ret = av_dict_set_int(options, listen, s-listen, 0))  0)
 +goto fail;
  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;
  }
 @@ -1263,7 +1280,7 @@ static int http_shutdown(URLContext *h, int flags)


  /* signal end of chunked encoding if used */
  if (((flags  AVIO_FLAG_WRITE)  s-chunked_post) ||
 -((flags  AVIO_FLAG_READ)  s-chunked_post  s-listen)) {
 +((flags  AVIO_FLAG_READ)  s-chunked_post  s-listen == 1)) {
  ret = ffurl_write(s-hd, footer, sizeof(footer) - 1);
  ret = ret  0 ? 0 : ret;
  s-end_chunked_post = 1;
 @@ -1282,7 +1299,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))

 The two tests on s-listen seem redundant. Maybe it would be better to take
 the time of renaming a few fields in the structure to make the underlying
 logic simpler.

Those tests

[FFmpeg-devel] [PATCH 1/9] lavf/network: split ff_listen_bind into ff_listen and ff_accept

2015-07-03 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/network.c | 27 +--
 libavformat/network.h | 20 
 2 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/libavformat/network.c b/libavformat/network.c
index 47ade8c..7a326d2 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;
+if ((ret = ff_accept(fd, timeout, h))  0)
+return ret;
+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..f83c796 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -255,6 +255,26 @@ int ff_listen_bind(int fd, const struct sockaddr *addr,
URLContext *h);
 
 /**
+ * Bind to a file descriptor to an address without accepting connections.
+ * @param fd  First argument of bind().
+ * @param addrSecond argument of bind().
+ * @param addrlen Third argument of bind().
+ * @return0 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.
+ * @returnA 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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 5/9] lavf/tcp: increase range for listen and call the underlying socket operations accordingly

2015-07-03 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/tcp.c | 16 +++-
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index 71dff7a..9a8e46e 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -45,7 +45,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 }
@@ -126,12 +126,18 @@ 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,
-  s-listen_timeout, h))  0) {
+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) {
+ret = fd;
 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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/9] lavf/avio: add ffurl_accept and ffurl_handshake

2015-07-03 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/avio.c | 19 +++
 libavformat/url.h  | 18 ++
 2 files changed, 37 insertions(+)

diff --git a/libavformat/avio.c b/libavformat/avio.c
index c188adc..1182336 100644
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -211,6 +211,25 @@ int ffurl_connect(URLContext *uc, AVDictionary **options)
 return 0;
 }
 
+int ffurl_accept(URLContext *s, URLContext **c)
+{
+if (s-prot-url_accept)
+return s-prot-url_accept(s, c);
+return 0;
+}
+
+int ffurl_handshake(URLContext *c)
+{
+int ret;
+if (c-prot-url_handshake) {
+ret = c-prot-url_handshake(c);
+if (ret)
+return ret;
+}
+c-is_connected = 1;
+return 0;
+}
+
 #define URL_SCHEME_CHARS\
 abcdefghijklmnopqrstuvwxyz\
 ABCDEFGHIJKLMNOPQRSTUVWXYZ\
diff --git a/libavformat/url.h b/libavformat/url.h
index 99a3201..d010a77 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 = 0 on success, ff_neterrno() on failure.
+ */
+int ffurl_accept(URLContext *s, URLContext **c);
+
+/**
+ * Perform a protocol 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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 3/9] lavf/avio: add avio_accept and avio_handshake

2015-07-03 Thread Stephan Holljes
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..b7a4fa8 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);
 
+/**
+ * Accept and allocate 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);
+
+/**
+ * Perform 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..ce05c5d 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)
+return ret;
+return ffio_fdopen(c, cc);
+}
+
+int avio_handshake(AVIOContext *c)
+{
+URLContext *cc = c-opaque;
+return ffurl_handshake(cc);
+}
+
 /* output in a dynamic buffer */
 
 typedef struct DynBuffer {
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 4/9] lavf/tcp: add tcp_accept

2015-07-03 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/tcp.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index f24cad2..71dff7a 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 #include avformat.h
+#include libavutil/avassert.h
 #include libavutil/parseutils.h
 #include libavutil/opt.h
 #include libavutil/time.h
@@ -163,6 +164,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;
+av_assert0(sc-listen);
+if ((ret = ffurl_alloc(c, s-filename, AVIO_FLAG_READ_WRITE, 
s-interrupt_callback))  0)
+return ret;
+cc = (*c)-priv_data;
+ret = ff_accept(sc-fd, sc-listen_timeout, s);
+if (ret  0)
+return ff_neterrno();
+cc-fd = ret;
+return 0;
+}
+
 static int tcp_read(URLContext *h, uint8_t *buf, int size)
 {
 TCPContext *s = h-priv_data;
@@ -223,6 +240,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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 8/9] doc/protocols: document experimental mutli-client api

2015-07-03 Thread Stephan Holljes
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


Re: [FFmpeg-devel] [PATCH 9/9] Add http multi-client example code

2015-07-03 Thread Stephan Holljes
On Fri, Jul 3, 2015 at 12:32 PM, Nicolas George geo...@nsup.org wrote:
 Le quintidi 15 messidor, an CCXXIII, Stephan Holljes a écrit :
 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  doc/examples/Makefile   |   1 +
  doc/examples/http_multiclient.c | 101 
 
  2 files changed, 102 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 000..fdecab4
 --- /dev/null
 +++ b/doc/examples/http_multiclient.c
 @@ -0,0 +1,101 @@
 +/*
 + * copyright (c) 2015 Stephan Holljes
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * FFmpeg is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with FFmpeg; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
 USA
 + */
 +
 +/**
 + * @file
 + * libavformat multi-client network API usage example.
 + *
 + * @example http_multiclient.c
 + * This example will serve a file without decoding or demuxing it over http.

 + * Multiple clients can connect and will receive the same file.

 Did you test several simultaneous clients? It should work, because fork() is
 a strong isolation, so it if works for one it works for many, but testing is
 always better.

Yes, I tested it with multiple simultaneous wget instances and with
siege (a benchmark tool for webservers).


 + */
 +
 +#include libavformat/avformat.h
 +#include unistd.h
 +
 +int main(int argc, char **argv)
 +{
 +AVDictionary *options = NULL;
 +AVIOContext *input = NULL, *client = NULL, *server = NULL;
 +const char *in_uri, *out_uri;
 +int ret, pid, n;
 +uint8_t buf[1024];
 +
 +if (argc  3) {
 +printf(usage: %s input http://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

 I suspect this sentence is outdated.

 +   \n, argv[0]);
 +return 1;
 +}
 +
 +in_uri = argv[1];
 +out_uri = argv[2];
 +
 +av_register_all();
 +avformat_network_init();
 +
 +if ((ret = av_dict_set(options, listen, 2, 0))  0)
 +goto end;
 +if ((ret = avio_open2(server, out_uri, AVIO_FLAG_READ_WRITE, NULL, 
 options))  0)
 +goto end;
 +fprintf(stderr, Entering main loop.\n);
 +for(;;) {
 +if ((ret = avio_accept(server, client))  0)
 +goto end;
 +fprintf(stderr, Accepted client, forking process.\n);

 +pid = fork();

 Zombie apocalypse ahead!

 Well, setting SIGCHLD to SIG_IGN is hardly portable, double-fork is ugly and
 proper waiting is painful, so I guess we can leave the zombies for now in a
 simple testing program, but a comment stating it would be useful.

 +if (pid == 0) {

 Maybe also:

 if (pid  0) {
 perror(Fork failed);
 err = AVERROR(errno);
 goto end;
 }

 +fprintf(stderr, Opening input file.\n);
 +if ((ret = avio_open2(input, in_uri, AVIO_FLAG_READ, NULL, 
 NULL))  0)
 +goto end;
 +fprintf(stderr, In child.\n);
 +avio_handshake(client);
 +fprintf(stderr, Handshake performed.\n);

 It would feel more natural to perform the handshake before opening the input
 file. Note that since this is your code, you are free to reject this kind of
 stylistic remark. In this particular case, it will be necessary when
 extending the code, because avio_handshake() will be responsible for getting
 the request file name from the client.

 Also: since this is fork()ing instead of pthread_create()ing, you probably
 should close the server context in the client process. And you definitely
 must close the client

[FFmpeg-devel] [PATCH 7/9] lavf/http: increase range for listen, handle connection closing accordingly, add http_handshake and move handshake logic there

2015-07-03 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/http.c | 44 +++-
 1 file changed, 31 insertions(+), 13 deletions(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index 3c1ec35..6338d80 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -129,7 +129,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 }
 };
 
@@ -305,8 +305,11 @@ static void handle_http_errors(URLContext *h, int error)
 static const char bad_request[] = HTTP/1.1 400 Bad 
Request\r\nContent-Type: text/plain\r\n\r\n400 Bad Request\r\n;
 static const char internal_server_error[] = HTTP/1.1 500 Internal server 
error\r\nContent-Type: text/plain\r\n\r\n500 Internal server error\r\n;
 HTTPContext *s = h-priv_data;
+av_assert0(error  0);
 if (h-is_connected) {
 switch(error) {
+case 0:
+break;
 case AVERROR_HTTP_BAD_REQUEST:
 ffurl_write(s-hd, bad_request, strlen(bad_request));
 break;
@@ -317,15 +320,33 @@ 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;
+if ((ret = ffurl_handshake(cl))  0)
+return ret;
+if ((err = http_read_header(c, new_location))  0)
+goto fail;
+if ((ret = ffurl_write(cl, header, strlen(header)))  0)
+return ret;
+// Avoid returning a positive value from ffurl_write()
+ret = ret  0 ? 0 : ret;
+return ret;
+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;
 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);
@@ -333,18 +354,14 @@ 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);
+if ((ret = av_dict_set_int(options, listen, s-listen, 0))  0)
+goto fail;
 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;
 }
@@ -1262,8 +1279,7 @@ static int http_shutdown(URLContext *h, int flags)
 HTTPContext *s = h-priv_data;
 
 /* signal end of chunked encoding if used */
-if (((flags  AVIO_FLAG_WRITE)  s-chunked_post) ||
-((flags  AVIO_FLAG_READ)  s-chunked_post  s-listen)) {
+if (((flags  AVIO_FLAG_WRITE)  s-chunked_post)) {
 ret = ffurl_write(s-hd, footer, sizeof(footer) - 1);
 ret = ret  0 ? 0 : ret;
 s-end_chunked_post = 1;
@@ -1365,6 +1381,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,
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 6/9] lavf/http: add http_accept

2015-07-03 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/http.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/libavformat/http.c b/libavformat/http.c
index 676bfd5..3c1ec35 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -25,6 +25,7 @@
 #include zlib.h
 #endif /* CONFIG_ZLIB */
 
+#include libavutil/avassert.h
 #include libavutil/avstring.h
 #include libavutil/opt.h
 
@@ -382,6 +383,24 @@ 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;
+av_assert0(sc-listen);
+if ((ret = ffurl_alloc(c, s-filename, s-flags  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;
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 9/9] doc/example: Add http multi-client example code

2015-07-03 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 doc/examples/Makefile   |   1 +
 doc/examples/http_multiclient.c | 111 
 2 files changed, 112 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 000..093b064
--- /dev/null
+++ b/doc/examples/http_multiclient.c
@@ -0,0 +1,111 @@
+/*
+ * copyright (c) 2015 Stephan Holljes
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * libavformat multi-client network API usage example.
+ *
+ * @example http_multiclient.c
+ * This example will serve a file without decoding or demuxing it over http.
+ * Multiple clients can connect and will receive the same file.
+ */
+
+#include libavformat/avformat.h
+#include unistd.h
+
+int main(int argc, char **argv)
+{
+AVDictionary *options = NULL;
+AVIOContext *input = NULL, *client = NULL, *server = NULL;
+const char *in_uri, *out_uri;
+int ret, pid, n;
+uint8_t buf[1024];
+
+if (argc  3) {
+printf(usage: %s input http://hostname[:port]\n;
+   API example program to serve http to multiple clients.\n
+   \n, argv[0]);
+return 1;
+}
+
+in_uri = argv[1];
+out_uri = argv[2];
+
+av_register_all();
+avformat_network_init();
+
+if ((ret = av_dict_set(options, listen, 2, 0))  0)
+goto end;
+if ((ret = avio_open2(server, out_uri, AVIO_FLAG_READ_WRITE, NULL, 
options))  0)
+goto end;
+fprintf(stderr, Entering main loop.\n);
+for(;;) {
+if ((ret = avio_accept(server, client))  0)
+goto end;
+fprintf(stderr, Accepted client, forking process.\n);
+// XXX: Since we don't reap our children and don't ignore signals
+//  this produces zombie processes.
+pid = fork();
+if (pid  0) {
+fprintf(stderr, Fork failed.\n);
+ret = AVERROR(errno);
+goto end;
+}
+if (pid == 0) {
+fprintf(stderr, In child.\n);
+avio_handshake(client);
+fprintf(stderr, Handshake performed.\n);
+fprintf(stderr, Opening input file.\n);
+if ((ret = avio_open2(input, in_uri, AVIO_FLAG_READ, NULL, NULL)) 
 0)
+goto end;
+for(;;) {
+n = avio_read(input, buf, sizeof(buf));
+if (n  0) {
+if (n == AVERROR_EOF)
+break;
+av_log(input, AV_LOG_ERROR, Error reading from input: 
%s.\n,
+   av_err2str(n));
+ret = n;
+break;
+}
+avio_write(client, buf, n);
+avio_flush(client);
+}
+fprintf(stderr, Flushing client\n);
+avio_flush(client);
+fprintf(stderr, Closing client\n);
+avio_close(client);
+break;
+}
+if (pid  0)
+avio_close(client);
+}
+
+end:
+if (ret) {
+fprintf(stderr, Some errors occured: );
+fprintf(stderr, %s\n, av_err2str(ret));
+}
+avio_close(server);
+avio_close(input);
+if (ret  0  ret != AVERROR_EOF)
+return 1;
+return 0;
+}
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/9] lavf/network: split ff_listen_bind into ff_listen and ff_accept

2015-07-02 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/network.c | 27 +--
 libavformat/network.h | 20 
 2 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/libavformat/network.c b/libavformat/network.c
index 47ade8c..7a326d2 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;
+if ((ret = ff_accept(fd, timeout, h))  0)
+return ret;
+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..f83c796 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -255,6 +255,26 @@ int ff_listen_bind(int fd, const struct sockaddr *addr,
URLContext *h);
 
 /**
+ * Bind to a file descriptor to an address without accepting connections.
+ * @param fd  First argument of bind().
+ * @param addrSecond argument of bind().
+ * @param addrlen Third argument of bind().
+ * @return0 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.
+ * @returnA 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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/9] lavf/avio: add ffurl_accept and ffurl_handshake

2015-07-02 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/avio.c | 19 +++
 libavformat/url.h  | 18 ++
 2 files changed, 37 insertions(+)

diff --git a/libavformat/avio.c b/libavformat/avio.c
index c188adc..1182336 100644
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -211,6 +211,25 @@ int ffurl_connect(URLContext *uc, AVDictionary **options)
 return 0;
 }
 
+int ffurl_accept(URLContext *s, URLContext **c)
+{
+if (s-prot-url_accept)
+return s-prot-url_accept(s, c);
+return 0;
+}
+
+int ffurl_handshake(URLContext *c)
+{
+int ret;
+if (c-prot-url_handshake) {
+ret = c-prot-url_handshake(c);
+if (ret)
+return ret;
+}
+c-is_connected = 1;
+return 0;
+}
+
 #define URL_SCHEME_CHARS\
 abcdefghijklmnopqrstuvwxyz\
 ABCDEFGHIJKLMNOPQRSTUVWXYZ\
diff --git a/libavformat/url.h b/libavformat/url.h
index 99a3201..d010a77 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 = 0 on success, ff_neterrno() on failure.
+ */
+int ffurl_accept(URLContext *s, URLContext **c);
+
+/**
+ * Perform a protocol 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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 3/9] lavf/avio: add avio_accept and avio_handshake

2015-07-02 Thread Stephan Holljes
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..b7a4fa8 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);
 
+/**
+ * Accept and allocate 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);
+
+/**
+ * Perform 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..ce05c5d 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)
+return ret;
+return ffio_fdopen(c, cc);
+}
+
+int avio_handshake(AVIOContext *c)
+{
+URLContext *cc = c-opaque;
+return ffurl_handshake(cc);
+}
+
 /* output in a dynamic buffer */
 
 typedef struct DynBuffer {
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] GSoC update

2015-07-02 Thread Stephan Holljes
On Wed, Jul 1, 2015 at 4:10 PM, Nicolas George geo...@nsup.org wrote:
 Le duodi 12 messidor, an CCXXIII, Stephan Holljes a écrit :
 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?

 You must use the avio family of function, not the OS functions directly. You
 can have a look at tools/aviocat.c, it is rather simple and does a good
 chunk of what your server needs to do per client.

 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;

 I believe you are slightly changing the behaviour here: in the old code, if
 accept() fails, the server is not closed.

 +
 +}
 +
  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 addrSecond argument of bind().
 + * @param addrlen Third argument of bind().
 + * @returnA blocking file descriptor on success
 + *or an AVERROR on failure.

 I believe the summary and @return statements are wrong: the new code always
 returns 0 for success, which is fine.

 + */
 +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.
 + * @returnA 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

[FFmpeg-devel] [PATCH 7/9] lavf/http: increase range for listen, handle connection closing accordingly, add http_handshake and move handshake logic there

2015-07-02 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/http.c | 45 -
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index d9c3624..95065f5 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -129,7 +129,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 }
 };
 
@@ -307,6 +307,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;
@@ -317,15 +319,32 @@ static void handle_http_errors(URLContext *h, int error)
 }
 }
 
+static int http_handshake(URLContext *c) {
+int ret, err = 0, 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;
+if ((ret = ffurl_handshake(cl))  0)
+return ret;
+if ((err = http_read_header(c, new_location))  0)
+goto fail;
+if ((ret = ffurl_write(cl, header, strlen(header)))  0)
+goto fail;
+// Avoid returning a positive value from ffurl_write()
+ret = ret  0 ? 0 : ret;
+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;
 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);
@@ -333,18 +352,16 @@ 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);
+if ((ret = av_dict_set_int(options, listen, s-listen, 0))  0)
+goto fail;
 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;
 }
@@ -1263,7 +1280,7 @@ static int http_shutdown(URLContext *h, int flags)
 
 /* signal end of chunked encoding if used */
 if (((flags  AVIO_FLAG_WRITE)  s-chunked_post) ||
-((flags  AVIO_FLAG_READ)  s-chunked_post  s-listen)) {
+((flags  AVIO_FLAG_READ)  s-chunked_post  s-listen == 1)) {
 ret = ffurl_write(s-hd, footer, sizeof(footer) - 1);
 ret = ret  0 ? 0 : ret;
 s-end_chunked_post = 1;
@@ -1282,7 +1299,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);
 
@@ -1365,6 +1382,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,
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 9/9] Add http multi-client example code

2015-07-02 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 doc/examples/Makefile   |   1 +
 doc/examples/http_multiclient.c | 101 
 2 files changed, 102 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 000..fdecab4
--- /dev/null
+++ b/doc/examples/http_multiclient.c
@@ -0,0 +1,101 @@
+/*
+ * copyright (c) 2015 Stephan Holljes
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * libavformat multi-client network API usage example.
+ *
+ * @example http_multiclient.c
+ * This example will serve a file without decoding or demuxing it over http.
+ * Multiple clients can connect and will receive the same file.
+ */
+
+#include libavformat/avformat.h
+#include unistd.h
+
+int main(int argc, char **argv)
+{
+AVDictionary *options = NULL;
+AVIOContext *input = NULL, *client = NULL, *server = NULL;
+const char *in_uri, *out_uri;
+int ret, pid, n;
+uint8_t buf[1024];
+
+if (argc  3) {
+printf(usage: %s input http://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_uri = argv[1];
+out_uri = argv[2];
+
+av_register_all();
+avformat_network_init();
+
+if ((ret = av_dict_set(options, listen, 2, 0))  0)
+goto end;
+if ((ret = avio_open2(server, out_uri, AVIO_FLAG_READ_WRITE, NULL, 
options))  0)
+goto end;
+fprintf(stderr, Entering main loop.\n);
+for(;;) {
+if ((ret = avio_accept(server, client))  0)
+goto end;
+fprintf(stderr, Accepted client, forking process.\n);
+pid = fork();
+if (pid == 0) {
+fprintf(stderr, Opening input file.\n);
+if ((ret = avio_open2(input, in_uri, AVIO_FLAG_READ, NULL, NULL)) 
 0)
+goto end;
+fprintf(stderr, In child.\n);
+avio_handshake(client);
+fprintf(stderr, Handshake performed.\n);
+for(;;) {
+n = avio_read(input, buf, sizeof(buf));
+fprintf(stderr, Read %d bytes from input.\n, n);
+if (n = 0) {
+fprintf(stderr, n is negative, abort.\n);
+break;
+}
+fprintf(stderr, Writing %d bytes of data.\n, n);
+avio_write(client, buf, n);
+avio_flush(client);
+}
+fprintf(stderr, Flushing client\n);
+avio_flush(client);
+fprintf(stderr, Closing client\n);
+avio_close(client);
+break;
+}
+}
+
+end:
+if (ret)
+fprintf(stderr, Some errors occured.\n);
+if (server)
+avio_close(server);
+if (input)
+avio_close(input);
+if (ret  0  ret != AVERROR_EOF)
+return 1;
+return 0;
+}
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 8/9] doc/protocols: document experimental mutli-client api

2015-07-02 Thread Stephan Holljes
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


[FFmpeg-devel] [PATCH 4/9] lavf/tcp: add tcp_accept

2015-07-02 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/tcp.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index f24cad2..875da50 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 #include avformat.h
+#include libavutil/avassert.h
 #include libavutil/parseutils.h
 #include libavutil/opt.h
 #include libavutil/time.h
@@ -163,6 +164,23 @@ 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;
+av_assert0(sc-listen);
+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 0;
+}
+
 static int tcp_read(URLContext *h, uint8_t *buf, int size)
 {
 TCPContext *s = h-priv_data;
@@ -223,6 +241,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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 5/9] lavf/tcp: increase range for listen and call the underlying socket operations accordingly

2015-07-02 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/tcp.c | 16 +++-
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index 875da50..91c70d4 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -45,7 +45,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 }
@@ -126,12 +126,18 @@ 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,
-  s-listen_timeout, h))  0) {
+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) {
+ret = fd;
 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

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] GSoC update

2015-06-27 Thread Stephan Holljes
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.
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(-)

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..44e109c 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -254,6 +254,10 @@ 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 ff_accept(int fd, int timeout, URLContext *h);
+
 /**
  * Connect to a file descriptor and poll for result.
  *
-- 
2.1.0

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(+)

diff --git a/libavformat/avio.c b/libavformat/avio.c
index aff8d10..cb8126d 100644
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -211,6 +211,21 @@ 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 *s, URLContext *c)
+{
+return s-prot-url_handshake(s, c);
+}
+
 #define URL_SCHEME_CHARS\
 abcdefghijklmnopqrstuvwxyz\
 ABCDEFGHIJKLMNOPQRSTUVWXYZ\
diff --git a/libavformat/url.h b/libavformat/url.h
index 99a3201..78613c5 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 *s, URLContext *c);
 
 /**
  * Read data from the protocol.
@@ -140,6 +142,16 @@ 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);
+
+int ffurl_handshake

Re: [FFmpeg-devel] GSoC update

2015-06-26 Thread Stephan Holljes
On Fri, Jun 26, 2015 at 10:51 AM, Nicolas George geo...@nsup.org wrote:
 Le septidi 7 messidor, an CCXXIII, Stephan Holljes a écrit :
 Thanks, I understand the datastructures and their interaction a lot
 better now. I discussed it with a friend yesterday too and there a lot
 of the things started to make more sense.
 I'm currently working on the implementation, when questions arise I
 will ask again.

 Good. Please try to pose a WIP patch today to make sure you are really in
 the right track.

 Regards,

 --
   Nicolas George

 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


I think I implemented everything necessary, but I don't know how to
test it. The old behaviour of accepting a single client is now also
broken. How do I detect which behaviour the user wants? Should I
introduce a new option for http and tcp connections or make the listen
field take more values than just 0 and 1?
Attached are patches with the changes I made so far. It compiles, but
breaks http server capabilities for now.
From 22f958ad8d0058865c94847ca8cd2488e2a61c9e Mon Sep 17 00:00:00 2001
From: Stephan Holljes klaxa1...@googlemail.com
Date: Fri, 26 Jun 2015 20:48:49 +0200
Subject: [PATCH 1/6] 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(-)

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..44e109c 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -254,6 +254,10 @@ 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 ff_accept(int fd, int timeout, URLContext *h);
+
 /**
  * Connect to a file descriptor and poll for result.
  *
-- 
2.1.0

From 4d0b5e42882f180d76a3a64da96dc87bf0ba0635 Mon Sep 17 00:00:00 2001
From: Stephan Holljes klaxa1...@googlemail.com
Date: Fri, 26 Jun 2015 20:50:35 +0200
Subject: [PATCH 2/6] lavf/avio: add ffurl_accept

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/avio.c | 5 +
 libavformat/url.h  | 9 +
 2 files changed, 14 insertions(+)

diff --git a/libavformat/avio.c b/libavformat/avio.c
index aff8d10..153230f 100644
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -211,6 +211,11 @@ int ffurl_connect(URLContext *uc, AVDictionary **options)
 return 0;
 }
 
+int ffurl_accept(URLContext *sc, URLContext *cc)
+{
+return sc-prot-url_accept(sc, cc);
+}
+
 #define URL_SCHEME_CHARS\
 abcdefghijklmnopqrstuvwxyz\
 ABCDEFGHIJKLMNOPQRSTUVWXYZ\
diff --git a/libavformat/url.h b/libavformat/url.h
index 99a3201..34fdea2 100644
--- a/libavformat/url.h
+++ b/libavformat/url.h
@@ -58,6 +58,7 @@ typedef struct URLProtocol {
  * for those nested protocols.
  */
 int (*url_open2

Re: [FFmpeg-devel] GSoC update

2015-06-23 Thread Stephan Holljes
Thank you for the detailed reply. It has helped me understand the
structures a lot better than before.
Comments inline.

On Tue, Jun 23, 2015 at 5:25 PM, Nicolas George geo...@nsup.org wrote:
 This has better go to the mailing list.

 Le quintidi 5 messidor, an CCXXIII, Stephan Holljes a écrit :
 So far I have split ff_listen_bind() into ff_listen_bind() and
 ff_accept() and added an url_accept field to URLProtocol (see attached
 patch).

 I do not believe this is the correct approach. ff_listen_bind() is an
 internal helper that works specifically for sockets.

 I read our past exchanges for a number of times and I am somewhat at a
 loss as to where to allocate my additional Client(-Contexts).
 No sourcefile I have looked at stores multiple AVIOContexts or
 AVFormatContexts (or I have not seen it).
 I also could not find out how ffmpeg would even accept multiple
 clients. The ff_listen_bind() call is blocking on accept() and it is
 only called once.
 Maybe I'm also overlooking some documentation. Maybe I am also looking
 in the wrong place. The files I have looked at the most have been:
 url.h network.c/h, avio.c/h aviobuf.c and tcp.c.

 You need to understand very well how it happens for plain Unix TCP clients.

 First, the server create and prepares the server socket s, with socket(),
 bind() and mostly listen(). There is also a list of client sockets c[i],
 initially empty.

 Then, indefinitely and in parallel:

   * call accept() on s: this returns a new c[i] added to the list;

   * perform read() / write() on each c[i], remove them from the list if they
 are finished.

 Here, in parallel means either threads, forked processes, or emulated
 parallelism with poll() and non-blocking operations. For lavf, non-blocking
 operations do not work, so you can assume parallelism between multiple
 clients is achieved with threads; although I very much would like that all
 new networking code is input-driven and therefore ready for non-blocking.

 Now, as for how to transpose it into lavf terms:

 * Creating and preparing the server socket: avio_open2() with various
   options for the address and the listen option set.

Am I correct to understand that this has to return immediately,
because if avio_open2() does not return, I have no (server)
AVIOContext to call avio_accept() with?
The HTTPContext will then not have any clients connected to it, which
is different from the current behaviour.


 * Accepting a new client: a new function that you have to design, probably
   avio_accept().

 There are a few caveats for avio_accept():

 * Creating a new AVFormatContext, like accept() creates a new socket. That
   is not really difficult, IMHO. It just means the API will look somewhat
   like that:

   int avio_accept(AVIOContext *s, AVIOContext **c, ...);

   The c parameter is just like the s parameter to avio_open2(): it allocates
   a new context if necessary and populates it.

 * Except, the current API accepts a single client by replacing the server
   context. This must still be possible after the change. Maybe just
   overwriting the server context will work, but it must be considered.

 * If you remember, a full TCP accept() requires three handshake packets: SYN
   from the client, ACK-SYN from the server and then ACK from the client. The
   kernel handles this in the background and accept() returns a new client
   only when the full handshake is done. In lavf, we do not have a kernel
   working in the background, so it must be explicit.

   We can look at how non-blocking connect() works: first call connect() on
   the socket, it returns EINPROGRESS immediately, the repeatedly call
   getsockopt(SO_ERROR) to check the status of the connection until it stops
   returning EAGAIN.

   I believe we can do the same: avio_accept(s, c) to initiate the accept,
   and then avio_accept_connect(c) or something (feel free to suggest better
   names) to finish the handshake.

   For the particular case of the HTTP server, the avio_accept() part would
   call avio_accept() on the underlying socket (or TLS context), and the
   avio_accept_connect() would call avio_accept_connect() on the underlying
   context and then perform the handshake.

   In terms of application, the code would probably look something like this
   (error checks and stuff removed):

   av_dict_set(options, listen, 1);
   avio_open2(server, http://:8080;, options);
   while (1) {
   avio_accept(server, client);
   thread_run {
   avio_accept_connect(client);
   communicate_with_the_client(client);
   avio_close(client);
   };
   }

Would this still be in http.c? If my thinking is correct, this should
be in http_open() then, but only if http_listen() returns without
accepting an initial client.


 Hope this helps.

 Regards,

 --
   Nicolas George


A lot of this I still can't wrap my head around. I am still not sure
about a lot of things, for example how and where to use threading to
serve clients in parallel

[FFmpeg-devel] [PATCH][GSoC] lavf/http: Correctly terminate session with HTTP POST client.

2015-06-09 Thread Stephan Holljes
Send a footer to correctly close client sockets.
This fixes network errors in client applications.

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/http.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index 2db2dea..676bfd5 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -325,6 +325,7 @@ static int http_listen(URLContext *h, const char *uri, int 
flags,
 char lower_url[100];
 const char *lower_proto = tcp;
 int port, new_location;
+s-chunked_post = 1;
 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), 
port,
  NULL, 0, uri);
 if (!strcmp(proto, https))
@@ -1242,7 +1243,8 @@ static int http_shutdown(URLContext *h, int flags)
 HTTPContext *s = h-priv_data;
 
 /* signal end of chunked encoding if used */
-if ((flags  AVIO_FLAG_WRITE)  s-chunked_post) {
+if (((flags  AVIO_FLAG_WRITE)  s-chunked_post) ||
+((flags  AVIO_FLAG_READ)  s-chunked_post  s-listen)) {
 ret = ffurl_write(s-hd, footer, sizeof(footer) - 1);
 ret = ret  0 ? 0 : ret;
 s-end_chunked_post = 1;
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH][GSoC] lavf/http: Add simple autodetection for client HTTP method, based on AVIO_FLAG_READ.

2015-06-06 Thread Stephan Holljes
On Sat, Jun 6, 2015 at 9:47 AM, Nicolas George geo...@nsup.org wrote:
 Le septidi 17 prairial, an CCXXIII, Stephan Holljes a écrit :
 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/http.c | 9 +
  1 file changed, 9 insertions(+)

 LGTM.

 Michael, I have pushed these to my tree, can you pull please:

 aa74401 lavf/http: Document method option.
 bbcee92 lavf/http: Process HTTP header before sending response.
 8cfaa76 lavf/http: Rudimentary error handling for HTTP requests received from 
 clients.
 a7e7c68 lavf/http: Properly process HTTP header on listen.
 290b237 lavf/http: Indent else-clause.
 44d1921 lavf/http: Add simple autodetection for client HTTP method, based on 
 AVIO_FLAG_READ.

 (fixing the empty line and brace in 8cfaa76)

 Stephan: do you have a publicly available Git clone?

No, should I? I'm still learning the ropes with git. I haven't used it
with more than 3 people at once.


 Regards,

 --
   Nicolas George
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH][GSoC] lavf/http: Add simple autodetection for client HTTP method, based on AVIO_FLAG_READ.

2015-06-04 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/http.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/libavformat/http.c b/libavformat/http.c
index 90e88ad..32fc1ce 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -563,6 +563,7 @@ static int process_line(URLContext *h, char *line, int 
line_count,
 int *new_location)
 {
 HTTPContext *s = h-priv_data;
+const char *auto_method =  h-flags  AVIO_FLAG_READ ? POST : GET;
 char *tag, *p, *end, *method, *resource, *version;
 int ret;
 
@@ -587,6 +588,14 @@ static int process_line(URLContext *h, char *line, int 
line_count,
s-method, method);
 return ff_http_averror(400, AVERROR(EIO));
 }
+} else {
+// use autodetected HTTP method to expect
+av_log(h, AV_LOG_TRACE, Autodetected %s HTTP method\n, 
auto_method);
+if (av_strcasecmp(auto_method, method)) {
+av_log(h, AV_LOG_ERROR, Received and autodetected HTTP 
method did not match 
+   (%s autodetected %s received)\n, auto_method, 
method);
+return ff_http_averror(400, AVERROR(EIO));
+}
 }
 
 // HTTP resource
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH][GSoC] lavf/http: Parse and set HTTP method when listening on HTTP(S)

2015-06-03 Thread Stephan Holljes
On Tue, Jun 2, 2015 at 10:56 AM, Nicolas George geo...@nsup.org wrote:
 Le quartidi 14 prairial, an CCXXIII, Stephan Holljes a écrit :
 I agree, I have probably thought a little bit too far ahead.

 I hope the attached patches are okay.
 I'm somewhat unsure about the first patch, because it checks ret and
 sets it explicitly if no other error occurred.
 I also added documentation for the method option in HTTPContext.

 See remarks below.

 A related issue is how to autodetect which method is to be expected
 when it is not explicitly set.
 For example, when listening for a client as an input, a POST request
 should be expected, but how do I know that inside http.c?

 I suspect you must look at AVIO_FLAG_WRITE and AVIO_FLAG_READ: if WRITE is
 set, then the user must use a request with a body.

I haven't looked at this in-depth. A quick test didn't work as
expected, but I'll keep working on it.


 From 8188b8a3b0cf21df7b80e410fd58b26f974db29e Mon Sep 17 00:00:00 2001
 From: Stephan Holljes klaxa1...@googlemail.com
 Date: Tue, 2 Jun 2015 01:35:26 +0200
 Subject: [PATCH 1/2] lavf/http: Process client HTTP request header before
  sending response and handle bad requests.

 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/http.c | 10 --
  1 file changed, 8 insertions(+), 2 deletions(-)

 diff --git a/libavformat/http.c b/libavformat/http.c
 index 4f6716a..6c18243 100644
 --- a/libavformat/http.c
 +++ b/libavformat/http.c
 @@ -304,6 +304,7 @@ static int http_listen(URLContext *h, const char *uri, 
 int flags,
  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;

 +static const char bad_request[] = HTTP/1.1 400 Bad Request\r\n\r\n;

 IIRC, a valid HTTP response should contain a minimal body, with a content
 type. Even if it is not a hard requirement, it is probably a good practice.

OK, fixed.


  char hostname[1024], proto[10];
  char lower_url[100];
  const char *lower_proto = tcp;
 @@ -318,13 +319,18 @@ static int http_listen(URLContext *h, const char *uri, 
 int flags,
  if ((ret = ffurl_open(s-hd, lower_url, AVIO_FLAG_READ_WRITE,
h-interrupt_callback, options))  0)
  goto fail;
 -if ((ret = ffurl_write(s-hd, header, strlen(header)))  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;

  fail:

 +if (ret == AVERROR_HTTP_BAD_REQUEST) {
 +if ((ret = ffurl_write(s-hd, bad_request, strlen(bad_request)))  
 0)
 +goto fail;
 +ret = AVERROR_HTTP_BAD_REQUEST;
 +}

 An error when writing the bad_request response will lead to a second attempt
 at writing, and it will probably make an error again.

 IMHO, it is ok to ignore write errors when sending error responses.

 Errors that are not handler by the code should probably return some kind of
 500 Internal server error response.

500 error added.
I also just now noticed while testing that sending a CTRL+C interrupt
results in a segmentation fault, because no client was connected and
ffurl_write() tried to send data anyway. That is (hopefully) fixed
now.


 And it would probably be a good idea to isolate that part in a separate
 function.

Can you point me to a function where I can see how this should be done
properly? I've been thinking for a long time and I couldn't come up
with a clean solution.


  av_dict_free(s-chained_options);
  return ret;
  }
 --
 2.1.0


 From 3263509fa862c944acc95fd61ba524b1c31545ca Mon Sep 17 00:00:00 2001
 From: Stephan Holljes klaxa1...@googlemail.com
 Date: Tue, 2 Jun 2015 01:37:47 +0200
 Subject: [PATCH 2/2] lavf/http: Process client HTTP methods and document
  method option.

 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  doc/protocols.texi | 10 ++
  libavformat/http.c | 16 +++-
  2 files changed, 25 insertions(+), 1 deletion(-)

 diff --git a/doc/protocols.texi b/doc/protocols.texi
 index f822d81..d5ae332 100644
 --- a/doc/protocols.texi
 +++ b/doc/protocols.texi
 @@ -278,6 +278,16 @@ Set initial byte offset.
  @item end_offset
  Try to limit the request to bytes preceding this offset.

 +@item method
 +When used as a client option it sets the HTTP method for the request.
 +

 +When used as a server option it sets the HTTP method that is going to be
 +expected by the client(s).

 Expected *from* the clients?

Fixed.


 +If the expected and the received HTTP method do not match the client will
 +be given a Bad Request response.

 +When unset the HTTP method used by the first client will be used for
 +comparison to later clients.

 Are you sure this is a good idea? When multi-client is implemented, you want
 different clients to be able to use different methods: some GET, some POST

Re: [FFmpeg-devel] [PATCH][GSoC] lavf/http: Parse and set HTTP method when listening on HTTP(S)

2015-06-03 Thread Stephan Holljes
On Wed, Jun 3, 2015 at 10:39 PM, Nicolas George geo...@nsup.org wrote:
 http_listen(), you wrote it yourself. Maybe I was not clear enough, I just
 suggested to move the code in a function for better readability (the name of
 the function is self-documentating), nothing more complicated.

I hope I understood what you meant.

 From 3af5c5867672624d45de447d11c2107b3c77742c Mon Sep 17 00:00:00 2001
 From: Stephan Holljes klaxa1...@googlemail.com
 Date: Wed, 3 Jun 2015 20:57:53 +0200
 Subject: [PATCH 5/5] lavf/http: Indent else-clause.

 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/http.c | 16 
  1 file changed, 8 insertions(+), 8 deletions(-)

 This looks ok.

 Personally, I have the habit of inserting /* TODO reindent */ in the code
 where it is needed and only make the reindent patch at the last moment, to
 reduce rebase nuisance.

The order of the patches attached was reversed, maybe that's why it
looked like the indentation was done first.


 From 90f17ce9711304228bc3b7bf8cb4cdfac6b14011 Mon Sep 17 00:00:00 2001
 From: Stephan Holljes klaxa1...@googlemail.com
 Date: Wed, 3 Jun 2015 20:57:23 +0200
 Subject: [PATCH 4/5] lavf/http: Properly process HTTP header on listen.

 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/http.c | 44 +++-
  1 file changed, 43 insertions(+), 1 deletion(-)

 diff --git a/libavformat/http.c b/libavformat/http.c
 index 6fad584..dfe2616 100644
 --- a/libavformat/http.c
 +++ b/libavformat/http.c
 @@ -558,7 +558,7 @@ static int process_line(URLContext *h, char *line, int 
 line_count,
  int *new_location)
  {
  HTTPContext *s = h-priv_data;
 -char *tag, *p, *end;
 +char *tag, *p, *end, *method, *resource, *version;
  int ret;

  /* end of header */
 @@ -569,6 +569,47 @@ static int process_line(URLContext *h, char *line, int 
 line_count,

  p = line;
  if (line_count == 0) {
 +if (s-listen) {
 +// HTTP method

 +while (av_isspace(*p))
 +p++;

 I believe spaces are not allowed before the request.

Fixed.


 +method = p;
 +while (!av_isspace(*p))
 +p++;

 +*p = '\0';

 Plain 0 is acceptable, your choice.

The rest of the function uses '\0' and I wanted to keep it consistent.


 +av_log(h, AV_LOG_TRACE, Received method: %s\n, method);
 +if (s-method) {
 +if (av_strcasecmp(s-method, method)) {
 +av_log(h, AV_LOG_ERROR, Received and expected HTTP 
 method do not match. (%s expected, %s received)\n,
 +   s-method, method);
 +return ff_http_averror(400, AVERROR(EIO));
 +}
 +}

 +p++;

 Maybe better keep it grouped with *p = 0, possibly in a single step:
 *(p++) = 0.

Fixed.


 +
 +// HTTP resource
 +while (av_isspace(*p))
 +p++;
 +resource = p;
 +while (!av_isspace(*p))
 +p++;
 +*p = '\0';
 +p++;
 +av_log(h, AV_LOG_TRACE, Requested resource: %s\n, resource);
 +
 +// HTTP version
 +while (av_isspace(*p))
 +p++;
 +version = p;
 +while (!av_isspace(*p))
 +p++;
 +*p = '\0';
 +if (av_strncasecmp(version, HTTP/, 5)) {
 +av_log(h, AV_LOG_ERROR, Malformed HTTP version string.\n);
 +return ff_http_averror(400, AVERROR(EIO));
 +}
 +av_log(h, AV_LOG_TRACE, HTTP version string: %s\n, version);
 +} else {
  while (!av_isspace(*p)  *p != '\0')
  p++;
  while (av_isspace(*p))
 @@ -579,6 +620,7 @@ static int process_line(URLContext *h, char *line, int 
 line_count,

  if ((ret = check_http_code(h, s-http_code, end))  0)
  return ret;
 +}
  } else {
  while (*p != '\0'  *p != ':')
  p++;
 --
 2.1.0


 From bbe015d20c1852e7c0c8885ca49a8ba2d926911d Mon Sep 17 00:00:00 2001
 From: Stephan Holljes klaxa1...@googlemail.com
 Date: Wed, 3 Jun 2015 20:45:08 +0200
 Subject: [PATCH 3/5] lavf/http: Rudimentary error handling for HTTP requests
  received from clients.

 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/http.c | 13 +
  1 file changed, 13 insertions(+)

 diff --git a/libavformat/http.c b/libavformat/http.c
 index e51f524..6fad584 100644
 --- a/libavformat/http.c
 +++ b/libavformat/http.c
 @@ -304,6 +304,9 @@ static int http_listen(URLContext *h, const char *uri, 
 int flags,
  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;
 +static const char bad_request[] = HTTP/1.1 400

Re: [FFmpeg-devel] [PATCH][GSoC] lavf/http: Parse and set HTTP method when listening on HTTP(S)

2015-06-01 Thread Stephan Holljes
On Sat, May 30, 2015 at 10:13 AM, Nicolas George geo...@nsup.org wrote:
 Le decadi 10 prairial, an CCXXIII, Stephan Holljes a écrit :
 Should method be reassigned or should the set value be kept? As far as
 I can tell the only way to set method is by specifying it as an option
 in the command line.
 I don't think overwriting specific values set by the user is good.
 Maybe output a warning?

 Until now, the option was used for client code only, not for server.
 Therefore, you have to decide how you want to use the option for server
 code, and document it.

 You can use it to return to the application the method the client used.
 Output-only options already exist elsewhere in the code. In that case, a
 warning if the option is already set is a good idea.

 Or you can use to let the user specify the expected request, and have the
 server code reject clients with an error if it does not match.

 Or you can find other uses I did not think of. I suspect you need to think
 ahead about the avio_accept() API, and in particular how it will return
 the address of the incoming client, since the request method is part of
 HTTP address.

After looking at the ffserver code, I'm wondering if maintaining a
list of clients as HTTPContext or custom wrapper structs would make
sense.
For the time being it would only contain the singular client context
which can be accepted right now, but in the future could contain an
arbitrary number of clients.
Before I start implementing that I would like to know if it is a good
choice to do this.


 Regards,

 --
   Nicolas George

 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH][GSoC] lavf/http: Parse and set HTTP method when listening on HTTP(S)

2015-06-01 Thread Stephan Holljes
On Mon, Jun 1, 2015 at 10:52 PM, Nicolas George geo...@nsup.org wrote:
 Le tridi 13 prairial, an CCXXIII, Stephan Holljes a écrit :
 After looking at the ffserver code, I'm wondering if maintaining a
 list of clients as HTTPContext or custom wrapper structs would make
 sense.
 For the time being it would only contain the singular client context
 which can be accepted right now, but in the future could contain an
 arbitrary number of clients.
 Before I start implementing that I would like to know if it is a good
 choice to do this.

 Have you considered the more traditional approach: when a client is
 accepted, create a new AVFormatContext for it?

 It seems simpler, and more adapted for various uses, for example if an
 application wants to handle clients in separate threads or even forks. But
 maybe there are benefits to your idea that I have not seen.

 Also, that choice seems orthogonal to the question at hand: what do you want
 to do with the method and other connection options?

I agree, I have probably thought a little bit too far ahead.

I hope the attached patches are okay.
I'm somewhat unsure about the first patch, because it checks ret and
sets it explicitly if no other error occurred.
I also added documentation for the method option in HTTPContext.

A related issue is how to autodetect which method is to be expected
when it is not explicitly set.
For example, when listening for a client as an input, a POST request
should be expected, but how do I know that inside http.c?


 Regards,

 --
   Nicolas George

 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

From 8188b8a3b0cf21df7b80e410fd58b26f974db29e Mon Sep 17 00:00:00 2001
From: Stephan Holljes klaxa1...@googlemail.com
Date: Tue, 2 Jun 2015 01:35:26 +0200
Subject: [PATCH 1/2] lavf/http: Process client HTTP request header before
 sending response and handle bad requests.

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/http.c | 10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index 4f6716a..6c18243 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -304,6 +304,7 @@ static int http_listen(URLContext *h, const char *uri, int flags,
 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;
+static const char bad_request[] = HTTP/1.1 400 Bad Request\r\n\r\n;
 char hostname[1024], proto[10];
 char lower_url[100];
 const char *lower_proto = tcp;
@@ -318,13 +319,18 @@ static int http_listen(URLContext *h, const char *uri, int flags,
 if ((ret = ffurl_open(s-hd, lower_url, AVIO_FLAG_READ_WRITE,
   h-interrupt_callback, options))  0)
 goto fail;
-if ((ret = ffurl_write(s-hd, header, strlen(header)))  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;
 
 fail:
+if (ret == AVERROR_HTTP_BAD_REQUEST) {
+if ((ret = ffurl_write(s-hd, bad_request, strlen(bad_request)))  0)
+goto fail;
+ret = AVERROR_HTTP_BAD_REQUEST;
+}
 av_dict_free(s-chained_options);
 return ret;
 }
-- 
2.1.0

From 3263509fa862c944acc95fd61ba524b1c31545ca Mon Sep 17 00:00:00 2001
From: Stephan Holljes klaxa1...@googlemail.com
Date: Tue, 2 Jun 2015 01:37:47 +0200
Subject: [PATCH 2/2] lavf/http: Process client HTTP methods and document
 method option.

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 doc/protocols.texi | 10 ++
 libavformat/http.c | 16 +++-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index f822d81..d5ae332 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -278,6 +278,16 @@ Set initial byte offset.
 @item end_offset
 Try to limit the request to bytes preceding this offset.
 
+@item method
+When used as a client option it sets the HTTP method for the request.
+
+When used as a server option it sets the HTTP method that is going to be
+expected by the client(s).
+If the expected and the received HTTP method do not match the client will
+be given a Bad Request response.
+When unset the HTTP method used by the first client will be used for
+comparison to later clients.
+
 @item listen
 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
diff --git a/libavformat/http.c b/libavformat/http.c
index 6c18243..6ef9f0c 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -126,7 +126,7 @@ static const AVOption options[] = {
 { location, The actual location of the data received, OFFSET(location

Re: [FFmpeg-devel] [PATCH][GSoC] lavf/http: Parse and set HTTP method when listening on HTTP(S)

2015-05-29 Thread Stephan Holljes
On Fri, May 29, 2015 at 4:19 PM, wm4 nfx...@googlemail.com wrote:
 On Fri, 29 May 2015 16:12:27 +0200
 Stephan Holljes klaxa1...@googlemail.com wrote:

 Hi,

 On Fri, May 29, 2015 at 11:54 AM, Michael Niedermayer michae...@gmx.at 
 wrote:
  On Fri, May 29, 2015 at 05:05:08AM +0200, Stephan Holljes wrote:
  Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
  ---
   libavformat/http.c | 8 
   1 file changed, 8 insertions(+)
 
  diff --git a/libavformat/http.c b/libavformat/http.c
  index 4f6716a..3fad43d 100644
  --- a/libavformat/http.c
  +++ b/libavformat/http.c
  @@ -556,6 +556,14 @@ static int process_line(URLContext *h, char *line, 
  int line_count,
 
   p = line;
   if (line_count == 0) {
  +if (s-listen) {
  +while (!av_isspace(*p))
  +p++;
 
  +s-method = av_malloc(p - line);
  +if (!s-method)
  +return AVERROR(ENOMEM);
  +av_strlcpy(s-method, line, p - line + 1);
 
  the allocated size and the size passed to av_strlcpy() should match

 Attached patch fixes that.


 av_strndup?

That looks a lot more suited. Will change the code accordingly.

 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH][GSoC] lavf/http: Parse and set HTTP method when listening on HTTP(S)

2015-05-29 Thread Stephan Holljes
On Fri, May 29, 2015 at 4:34 PM, Stephan Holljes
klaxa1...@googlemail.com wrote:
 On Fri, May 29, 2015 at 4:19 PM, wm4 nfx...@googlemail.com wrote:
 On Fri, 29 May 2015 16:12:27 +0200
 Stephan Holljes klaxa1...@googlemail.com wrote:

 Hi,

 On Fri, May 29, 2015 at 11:54 AM, Michael Niedermayer michae...@gmx.at 
 wrote:
  On Fri, May 29, 2015 at 05:05:08AM +0200, Stephan Holljes wrote:
  Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
  ---
   libavformat/http.c | 8 
   1 file changed, 8 insertions(+)
 
  diff --git a/libavformat/http.c b/libavformat/http.c
  index 4f6716a..3fad43d 100644
  --- a/libavformat/http.c
  +++ b/libavformat/http.c
  @@ -556,6 +556,14 @@ static int process_line(URLContext *h, char *line, 
  int line_count,
 
   p = line;
   if (line_count == 0) {
  +if (s-listen) {
  +while (!av_isspace(*p))
  +p++;
 
  +s-method = av_malloc(p - line);
  +if (!s-method)
  +return AVERROR(ENOMEM);
  +av_strlcpy(s-method, line, p - line + 1);
 
  the allocated size and the size passed to av_strlcpy() should match

 Attached patch fixes that.


 av_strndup?

 That looks a lot more suited. Will change the code accordingly.


Attached patch makes use of av_strndup.

 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
From 33a479200b9a941d0783d941c6ea68f8b85cc4de Mon Sep 17 00:00:00 2001
From: Stephan Holljes klaxa1...@googlemail.com
Date: Fri, 29 May 2015 16:47:11 +0200
Subject: [PATCH] lavf/http: Parse and set HTTP method when listening on
 HTTP(S)

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/http.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/libavformat/http.c b/libavformat/http.c
index 4f6716a..c73734f 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -556,6 +556,12 @@ static int process_line(URLContext *h, char *line, int line_count,
 
 p = line;
 if (line_count == 0) {
+if (s-listen) {
+while (!av_isspace(*p))
+p++;
+if (!(s-method = av_strndup(line, p - line)))
+return AVERROR(ENOMEM);
+}
 while (!av_isspace(*p)  *p != '\0')
 p++;
 while (av_isspace(*p))
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH][GSoC] lavf/http: Parse and set HTTP method when listening on HTTP(S)

2015-05-29 Thread Stephan Holljes
On Fri, May 29, 2015 at 7:10 PM, Nicolas George geo...@nsup.org wrote:
 Le decadi 10 prairial, an CCXXIII, Stephan Holljes a écrit :
 From 33a479200b9a941d0783d941c6ea68f8b85cc4de Mon Sep 17 00:00:00 2001
 From: Stephan Holljes klaxa1...@googlemail.com
 Date: Fri, 29 May 2015 16:47:11 +0200
 Subject: [PATCH] lavf/http: Parse and set HTTP method when listening on
  HTTP(S)

 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/http.c | 6 ++
  1 file changed, 6 insertions(+)

 diff --git a/libavformat/http.c b/libavformat/http.c
 index 4f6716a..c73734f 100644
 --- a/libavformat/http.c
 +++ b/libavformat/http.c
 @@ -556,6 +556,12 @@ static int process_line(URLContext *h, char *line, int 
 line_count,

  p = line;
  if (line_count == 0) {
 +if (s-listen) {
 +while (!av_isspace(*p))
 +p++;
 +if (!(s-method = av_strndup(line, p - line)))
 +return AVERROR(ENOMEM);

 If method is already set, it overwrites it and therefore the old value
 leaks.

Should method be reassigned or should the set value be kept? As far as
I can tell the only way to set method is by specifying it as an option
in the command line.
I don't think overwriting specific values set by the user is good.
Maybe output a warning?


 +}
  while (!av_isspace(*p)  *p != '\0')
  p++;
  while (av_isspace(*p))

 It looks like there is client code after the if clause, it should probably
 not be executed for the server side. A malicious request could even get
 check_http_code() to return an error.

Indeed, I could reproduce this by listening on http and sending a
malformed request that got parsed as an error code.


 Regards,

 --
   Nicolas George

 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH][GSoC] lavf/http: Parse and set HTTP method when listening on HTTP(S)

2015-05-28 Thread Stephan Holljes
Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/http.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/libavformat/http.c b/libavformat/http.c
index 4f6716a..3fad43d 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -556,6 +556,14 @@ static int process_line(URLContext *h, char *line, int 
line_count,
 
 p = line;
 if (line_count == 0) {
+if (s-listen) {
+while (!av_isspace(*p))
+p++;
+s-method = av_malloc(p - line);
+if (!s-method)
+return AVERROR(ENOMEM);
+av_strlcpy(s-method, line, p - line + 1);
+}
 while (!av_isspace(*p)  *p != '\0')
 p++;
 while (av_isspace(*p))
-- 
2.1.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH] libavformat/http.c: Make http-listen work as an input stream.

2015-04-06 Thread Stephan Holljes
On Mon, Apr 6, 2015 at 1:47 PM, Lukasz Marek lukasz.m.lu...@gmail.com wrote:
 On Apr 5, 2015 6:02 PM, Stephan Holljes klaxa1...@googlemail.com wrote:

 With this patch http can be used to listen for POST data to be used as an
 input stream.

 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
 ---
  libavformat/http.c | 7 +--
  1 file changed, 5 insertions(+), 2 deletions(-)

 This should be documented I guess.
I added a short description in doc/protocols.texi.
 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Now attached two patches. The first one fixes the parenthesis and the
second one adds the original patch.

Regards,
Stephan Holljes
From bbd8fc4e700968a977b30850b7be3ec39bad3531 Mon Sep 17 00:00:00 2001
From: Stephan Holljes klaxa1...@googlemail.com
Date: Mon, 6 Apr 2015 20:23:01 +0200
Subject: [PATCH 2/2] libavformat/http.c: Make http-listen work as an input
 stream.

With this patch http can be used to listen for POST data to be used as an input stream.

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 doc/protocols.texi | 4 +++-
 libavformat/http.c | 7 +--
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index 5b7b6cf..5e9173f 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -279,7 +279,9 @@ Set initial byte offset.
 Try to limit the request to bytes preceding this offset.
 
 @item listen
-If set to 1 enables experimental HTTP server.
+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.
 @end table
 
 @subsection HTTP Cookies
diff --git a/libavformat/http.c b/libavformat/http.c
index 0993546..e4acf75 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -128,13 +128,14 @@ 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, OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, 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, E },
+{ listen, listen on HTTP, OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D | E },
 { NULL }
 };
 
 static int http_connect(URLContext *h, const char *path, const char *local_path,
 const char *hoststr, const char *auth,
 const char *proxyauth, int *new_location);
+static int http_read_header(URLContext *h, int *new_location);
 
 void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
 {
@@ -305,7 +306,7 @@ static int http_listen(URLContext *h, const char *uri, int flags,
 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];
 char lower_url[100];
-int port;
+int port, new_location;
 av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), port,
  NULL, 0, uri);
 ff_url_join(lower_url, sizeof(lower_url), tcp, NULL, hostname, port,
@@ -316,6 +317,8 @@ static int http_listen(URLContext *h, const char *uri, int flags,
 goto fail;
 if ((ret = ffurl_write(s-hd, header, strlen(header)))  0)
 goto fail;
+if ((ret = http_read_header(h, new_location))  0)
+ goto fail;
 return 0;
 
 fail:
-- 
2.3.3

From 8aedd2767d825307fc0d9f6e5b461e2ef68ebe6d Mon Sep 17 00:00:00 2001
From: Stephan Holljes klaxa1...@googlemail.com
Date: Mon, 6 Apr 2015 19:26:34 +0200
Subject: [PATCH 1/2] libavformat/http.c: Fix missing parenthesis in
 http_listen()

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/http.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index 3276737..0993546 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -311,10 +311,10 @@ static int http_listen(URLContext *h, const char *uri, int flags,
 ff_url_join(lower_url, sizeof(lower_url), tcp, NULL, hostname, port,
 NULL);
 av_dict_set(options, listen, 1, 0);
-if (ret = ffurl_open(s-hd, lower_url, AVIO_FLAG_READ_WRITE,
- h-interrupt_callback, options)  0)
+if ((ret = ffurl_open(s-hd, lower_url, AVIO_FLAG_READ_WRITE,
+  h-interrupt_callback, options))  0)
 goto fail;
-if (ret = ffurl_write(s-hd, header, strlen(header))  0)
+if ((ret = ffurl_write(s-hd, header, strlen(header)))  0)
 goto fail;
 return 0;
 
-- 
2.3.3

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org

[FFmpeg-devel] [PATCH] libavformat/http.c: Make http-listen work as an input stream.

2015-04-05 Thread Stephan Holljes
With this patch http can be used to listen for POST data to be used as an input 
stream.

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 libavformat/http.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index 3276737..8961981 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -128,13 +128,14 @@ 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, OFFSET(method), 
AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, 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, E },
+{ listen, listen on HTTP, OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 
}, 0, 1, D | E },
 { NULL }
 };
 
 static int http_connect(URLContext *h, const char *path, const char 
*local_path,
 const char *hoststr, const char *auth,
 const char *proxyauth, int *new_location);
+static int http_read_header(URLContext *h, int *new_location);
 
 void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
 {
@@ -305,7 +306,7 @@ static int http_listen(URLContext *h, const char *uri, int 
flags,
 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];
 char lower_url[100];
-int port;
+int port, new_location;
 av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), port,
  NULL, 0, uri);
 ff_url_join(lower_url, sizeof(lower_url), tcp, NULL, hostname, port,
@@ -316,6 +317,8 @@ static int http_listen(URLContext *h, const char *uri, int 
flags,
 goto fail;
 if (ret = ffurl_write(s-hd, header, strlen(header))  0)
 goto fail;
+if (ret = http_read_header(h, new_location)  0)
+goto fail;
 return 0;
 
 fail:
-- 
2.3.3

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [GSoC] Proof-of-concept HTTP Server

2015-04-02 Thread Stephan Holljes
On Mon, Mar 30, 2015 at 5:19 PM, Nicolas George geo...@nsup.org wrote:
 Le nonidi 9 germinal, an CCXXIII, Stephan Holljes a écrit :
 I hope this addresses the issues mentioned.
 I added a new label in case of failure in http_open() in favor of
 duplicated code (i.e. calling av_dict_free() multiple times). I copied
 the style from the other functions.

 Signed-off-by: Stephan Holljes klaxa1...@googlemail.com

 The patch looks good to me (acronym to learn: LGTM) as is or with the code
 moved into a separate function point.

 Except one more point that was not addressed earlier: if you want to add
 comments to a Git patch email, you need to put them between the --- and
 the first diff --git lines. That is where the small stats 2 files
 changed, 28 insertions(+), 1 deletion(-) is already inserted, it is
 considered as a simple comment too.

 If you put them before the --- line, it becomes part of the commit message
 when the patch is applied from the mail. For the final version, maybe better
 attach the patch or push it to a public clone.

 At this point, I suspect you can consider this will be applied soon (better
 give it maybe two days before asking for merging) and, if you want to
 strengthen your application, make the patch even better, for example getting
 it to work for input as well as output.

How would http listening work as an input option?


 For that, I suspect it will be convenient for you to isolate the code in its
 own function, that makes handling the variables and the failure code path
 easier, so you probably better follow wm4's advice.

 Regards,

 --
   Nicolas George

 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


I moved the functionality opening the listening socket to a new function.
The patch is attached.
Sorry for the late reply, I had exams.

Regards,
Stephan Holljes
From c01ec773448a76485895171cbfb296657d56da97 Mon Sep 17 00:00:00 2001
From: Stephan Holljes klaxa1...@googlemail.com
Date: Thu, 2 Apr 2015 22:49:07 +0200
Subject: [PATCH] libavformat/http.c: Add proof-of-concept http server.

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 doc/protocols.texi |  3 +++
 libavformat/http.c | 31 +++
 2 files changed, 34 insertions(+)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index 2a19b41..5b7b6cf 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -277,6 +277,9 @@ Set initial byte offset.
 
 @item end_offset
 Try to limit the request to bytes preceding this offset.
+
+@item listen
+If set to 1 enables experimental HTTP server.
 @end table
 
 @subsection HTTP Cookies
diff --git a/libavformat/http.c b/libavformat/http.c
index 45533e4..3276737 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -96,6 +96,7 @@ typedef struct HTTPContext {
 int send_expect_100;
 char *method;
 int reconnect;
+int listen;
 } HTTPContext;
 
 #define OFFSET(x) offsetof(HTTPContext, x)
@@ -127,6 +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, OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, 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, E },
 { NULL }
 };
 
@@ -296,6 +298,31 @@ int ff_http_averror(int status_code, int default_averror)
 return default_averror;
 }
 
+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];
+char lower_url[100];
+int port;
+av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), port,
+ NULL, 0, uri);
+ff_url_join(lower_url, sizeof(lower_url), tcp, NULL, hostname, port,
+NULL);
+av_dict_set(options, listen, 1, 0);
+if (ret = ffurl_open(s-hd, lower_url, AVIO_FLAG_READ_WRITE,
+ h-interrupt_callback, options)  0)
+goto fail;
+if (ret = ffurl_write(s-hd, header, strlen(header))  0)
+goto fail;
+return 0;
+
+fail:
+av_dict_free(s-chained_options);
+return ret;
+}
+
 static int http_open(URLContext *h, const char *uri, int flags,
  AVDictionary **options)
 {
@@ -321,12 +348,16 @@ static int http_open(URLContext *h, const char *uri, int flags,
No trailing CRLF found in HTTP header.\n);
 }
 
+if (s-listen) {
+return http_listen(h, uri, flags, options);
+}
 ret = http_open_cnx(h, options);
 if (ret  0

Re: [FFmpeg-devel] [GSoC] Proof-of-concept HTTP Server

2015-03-28 Thread Stephan Holljes
I hope this addresses the issues mentioned.
I added a new label in case of failure in http_open() in favor of
duplicated code (i.e. calling av_dict_free() multiple times). I copied
the style from the other functions.

Signed-off-by: Stephan Holljes klaxa1...@googlemail.com
---
 doc/protocols.texi |  3 +++
 libavformat/http.c | 26 +-
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index 2a19b41..5b7b6cf 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -277,6 +277,9 @@ Set initial byte offset.
 
 @item end_offset
 Try to limit the request to bytes preceding this offset.
+
+@item listen
+If set to 1 enables experimental HTTP server.
 @end table
 
 @subsection HTTP Cookies
diff --git a/libavformat/http.c b/libavformat/http.c
index da3c9be..c769918 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -96,6 +96,7 @@ typedef struct HTTPContext {
 int send_expect_100;
 char *method;
 int reconnect;
+int listen;
 } HTTPContext;
 
 #define OFFSET(x) offsetof(HTTPContext, x)
@@ -127,6 +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, OFFSET(method), 
AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, 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, E },
 { NULL }
 };
 
@@ -321,9 +323,31 @@ static int http_open(URLContext *h, const char *uri, int 
flags,
No trailing CRLF found in HTTP header.\n);
 }
 
+if (s-listen) {
+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];
+char lower_url[100];
+int port;
+av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), port,
+ NULL, 0, uri);
+ff_url_join(lower_url, sizeof(lower_url), tcp, NULL, hostname, port,
+NULL);
+av_dict_set(options, listen, 1, 0);
+ret = ffurl_open(s-hd, lower_url, AVIO_FLAG_READ_WRITE,
+ h-interrupt_callback, options);
+if (ret  0)
+goto fail;
+if (ret = ffurl_write(s-hd, header, strlen(header))  0)
+goto fail;
+return 0;
+}
 ret = http_open_cnx(h, options);
 if (ret  0)
-av_dict_free(s-chained_options);
+goto fail;
+return ret;
+
+fail:
+av_dict_free(s-chained_options);
 return ret;
 }
 
-- 
2.3.3
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [GSoC] Proof-of-concept HTTP Server

2015-03-25 Thread Stephan Holljes
I hope this time the patch is formatted correctly. I also attached it
in case it is corrupted again.
I changed the indentation of the code and used ffurl_open() instead of
creating my own listening socket.

I am still having some trouble with the Content-Type header. I would
guess creating functions like http_write_header() as the counterpart
for http_read_header() would be the most appropriate approach?


---
 libavformat/http.c | 33 -
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index da3c9be..472d8dd 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -96,6 +96,8 @@ typedef struct HTTPContext {
 int send_expect_100;
 char *method;
 int reconnect;
+int listen;
+int header_sent;
 } HTTPContext;

 #define OFFSET(x) offsetof(HTTPContext, x)
@@ -127,6 +129,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, OFFSET(method),
AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, 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 },
 { NULL }
 };

@@ -300,7 +303,9 @@ static int http_open(URLContext *h, const char
*uri, int flags,
  AVDictionary **options)
 {
 HTTPContext *s = h-priv_data;
-int ret;
+int port, ret = 0;
+char hostname[1024];
+char lower_url[100];

 if( s-seekable == 1 )
 h-is_streamed = 0;
@@ -321,6 +326,20 @@ static int http_open(URLContext *h, const char
*uri, int flags,
No trailing CRLF found in HTTP header.\n);
 }

+if (s-listen) {
+av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), port,
+ NULL, 0, uri);
+ff_url_join(lower_url, sizeof(lower_url), tcp, NULL, hostname, port,
+NULL);
+av_dict_set(options, listen, 1, AV_DICT_APPEND);
+ret = ffurl_open(s-hd, lower_url, AVIO_FLAG_READ_WRITE,
+   h-interrupt_callback, options);
+if (ret  0) {
+return ret;
+}
+
+return ret;
+}
 ret = http_open_cnx(h, options);
 if (ret  0)
 av_dict_free(s-chained_options);
@@ -1100,10 +1119,22 @@ static int http_read(URLContext *h, uint8_t
*buf, int size)
 static int http_write(URLContext *h, const uint8_t *buf, int size)
 {
 char temp[11] = ;  /* 32-bit hex + CRLF + nul */
+char header[] = HTTP 200 OK\r\nContent-Type:
application/octet-stream\r\n\r\n;
 int ret;
 char crlf[] = \r\n;
 HTTPContext *s = h-priv_data;
+if (s-listen) {
+if (!s-header_sent) {
+ret = ffurl_write(s-hd, header, strlen(header));
+if (ret  0) {
+return ff_neterrno();
+}
+s-header_sent = 1;
+}

+ret = ffurl_write(s-hd, buf, size);
+return ret  0 ? ff_neterrno() : ret;
+}
 if (!s-chunked_post) {
 /* non-chunked data is sent without any special encoding */
 return ffurl_write(s-hd, buf, size);
-- 
2.3.3

On Sun, Mar 22, 2015 at 10:33 AM, Nicolas George geo...@nsup.org wrote:
 Le primidi 1er germinal, an CCXXIII, Stephan Holljes a écrit :
 Please comment.

 As Michael pointed out, the patch was mangled at sending. That happens with
 mail user agent that rely on rich text editor and do not let users control
 the formatting finely. Using git send-email or attaching the file will solve
 the problem. They also include authorship and date information.


 Regards,
 Stephan Holljes

 ---
  libavformat/http.c |  113
 ++--
  1 file changed, 83 insertions(+), 30 deletions(-)

 diff --git a/libavformat/http.c b/libavformat/http.c
 index da3c9be..d61e4e2 100644
 --- a/libavformat/http.c
 +++ b/libavformat/http.c
 @@ -96,8 +96,12 @@ typedef struct HTTPContext {
  int send_expect_100;
  char *method;
  int reconnect;
 +int listen;
 +int fd;
 +int header_sent;
  } HTTPContext;

 +
  #define OFFSET(x) offsetof(HTTPContext, x)
  #define D AV_OPT_FLAG_DECODING_PARAM
  #define E AV_OPT_FLAG_ENCODING_PARAM
 @@ -127,6 +131,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, OFFSET(method),
 AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, 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 },
  { NULL }
  };

 @@ -299,8 +304,10 @@ int ff_http_averror(int

[FFmpeg-devel] [GSoC] Proof-of-concept HTTP Server

2015-03-21 Thread Stephan Holljes
Hi,

this is a patch for a proof-of-concept for an http server.

Usage on the server side:

ffmpeg -i test.mp3 -c copy -listen 1 -f mp3 http://0.0.0.0

Usage on the client side:

ffplay http://localhost:8080

I looked at tls.c and tcp.c and copied parts of the code.
Please comment.

Regards,
Stephan Holljes

---
 libavformat/http.c |  113
++--
 1 file changed, 83 insertions(+), 30 deletions(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index da3c9be..d61e4e2 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -96,8 +96,12 @@ typedef struct HTTPContext {
 int send_expect_100;
 char *method;
 int reconnect;
+int listen;
+int fd;
+int header_sent;
 } HTTPContext;

+
 #define OFFSET(x) offsetof(HTTPContext, x)
 #define D AV_OPT_FLAG_DECODING_PARAM
 #define E AV_OPT_FLAG_ENCODING_PARAM
@@ -127,6 +131,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, OFFSET(method),
AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, 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 },
 { NULL }
 };

@@ -299,8 +304,10 @@ int ff_http_averror(int status_code, int
default_averror)
 static int http_open(URLContext *h, const char *uri, int flags,
  AVDictionary **options)
 {
+struct addrinfo hints = { 0 }, *ai;
 HTTPContext *s = h-priv_data;
-int ret;
+int ret = -1, fd;
+char portstr[] = 8080; // allow non-root users for now

 if( s-seekable == 1 )
 h-is_streamed = 0;
@@ -320,11 +327,39 @@ static int http_open(URLContext *h, const char *uri,
int flags,
 av_log(h, AV_LOG_WARNING,
No trailing CRLF found in HTTP header.\n);
 }
+if (s-listen) {
+hints.ai_family = AF_UNSPEC;
+hints.ai_socktype = SOCK_STREAM;
+hints.ai_flags |= AI_PASSIVE;
+ret = getaddrinfo(NULL, portstr, hints, ai);
+if (ret) {
+av_log(h, AV_LOG_ERROR, borked);
+return AVERROR(EIO);
+}
+fd = ff_socket(ai-ai_family,
+   ai-ai_socktype,
+   ai-ai_protocol);
+if (fd  0) {
+ret = ff_neterrno();
+freeaddrinfo(ai);
+return -1;
+}

-ret = http_open_cnx(h, options);
-if (ret  0)
-av_dict_free(s-chained_options);
-return ret;
+fd = ff_listen_bind(fd, ai-ai_addr, ai-ai_addrlen, -1, h);
+if (fd  0) {
+freeaddrinfo(ai);
+return fd;
+}
+h-is_streamed = 1;
+s-fd = fd;
+freeaddrinfo(ai);
+return 0;
+} else {
+ret = http_open_cnx(h, options);
+if (ret  0)
+av_dict_free(s-chained_options);
+return ret;
+}
 }

 static int http_getc(HTTPContext *s)
@@ -1102,25 +1137,40 @@ static int http_write(URLContext *h, const uint8_t
*buf, int size)
 char temp[11] = ;  /* 32-bit hex + CRLF + nul */
 int ret;
 char crlf[] = \r\n;
+char header[] = HTTP 200 OK\r\n\r\n;
 HTTPContext *s = h-priv_data;
+if (!s-listen) {
+if (!s-chunked_post) {
+/* non-chunked data is sent without any special encoding */
+return ffurl_write(s-hd, buf, size);
+}

-if (!s-chunked_post) {
-/* non-chunked data is sent without any special encoding */
-return ffurl_write(s-hd, buf, size);
-}
-
-/* silently ignore zero-size data since chunk encoding that would
- * signal EOF */
-if (size  0) {
-/* upload data using chunked encoding */
-snprintf(temp, sizeof(temp), %x\r\n, size);
+/* silently ignore zero-size data since chunk encoding that would
+ * signal EOF */
+if (size  0) {
+/* upload data using chunked encoding */
+snprintf(temp, sizeof(temp), %x\r\n, size);

-if ((ret = ffurl_write(s-hd, temp, strlen(temp)))  0 ||
-(ret = ffurl_write(s-hd, buf, size))  0  ||
-(ret = ffurl_write(s-hd, crlf, sizeof(crlf) - 1))  0)
-return ret;
+if ((ret = ffurl_write(s-hd, temp, strlen(temp)))  0 ||
+(ret = ffurl_write(s-hd, buf, size))  0  ||
+(ret = ffurl_write(s-hd, crlf, sizeof(crlf) - 1))  0)
+return ret;
+}
+return size;
+} else {
+if (!s-header_sent) {
+ret = send(s-fd, header, sizeof(header), MSG_NOSIGNAL);
+s-header_sent = 1;
+return ret  0 ? ff_neterrno() : ret;
+}
+if (size  0) {
+ret = send(s-fd, buf, size, MSG_NOSIGNAL);
+return

Re: [FFmpeg-devel] [GSoC] Proof-of-concept HTTP Server

2015-03-21 Thread Stephan Holljes
Hi,

what would be the correct way to create patches that won't be corrupted? I
merely tried to copy what I have seen on the mailing-list before,
apparently I didn't do a very good job ;)

Regards,
Stephan Holljes

On Sun, Mar 22, 2015 at 12:24 AM, Michael Niedermayer michae...@gmx.at
wrote:

 On Sat, Mar 21, 2015 at 11:00:09PM +0100, Stephan Holljes wrote:
  Hi,
 
  this is a patch for a proof-of-concept for an http server.
 
  Usage on the server side:
 
  ffmpeg -i test.mp3 -c copy -listen 1 -f mp3 http://0.0.0.0
 
  Usage on the client side:
 
  ffplay http://localhost:8080
 
  I looked at tls.c and tcp.c and copied parts of the code.
  Please comment.
 
  Regards,
  Stephan Holljes
 
  ---
   libavformat/http.c |  113
  ++--
   1 file changed, 83 insertions(+), 30 deletions(-)
 
  diff --git a/libavformat/http.c b/libavformat/http.c
  index da3c9be..d61e4e2 100644
  --- a/libavformat/http.c
  +++ b/libavformat/http.c
  @@ -96,8 +96,12 @@ typedef struct HTTPContext {
   int send_expect_100;
   char *method;
   int reconnect;
  +int listen;
  +int fd;
  +int header_sent;
   } HTTPContext;
 
  +
   #define OFFSET(x) offsetof(HTTPContext, x)
   #define D AV_OPT_FLAG_DECODING_PARAM
   #define E AV_OPT_FLAG_ENCODING_PARAM
  @@ -127,6 +131,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, OFFSET(method),
  AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, 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 },

 it appears this patch has been corrupted by extra newlines from
 word/line wrap

 please resend as an attachment

 [...]
 --
 Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

 Breaking DRM is a little like attempting to break through a door even
 though the window is wide open and the only thing in the house is a bunch
 of things you dont want and which you would get tomorrow for free anyway

 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


diff --git a/libavformat/http.c b/libavformat/http.c
index da3c9be..d61e4e2 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -96,8 +96,12 @@ typedef struct HTTPContext {
 int send_expect_100;
 char *method;
 int reconnect;
+int listen;
+int fd;
+int header_sent;
 } HTTPContext;
 
+
 #define OFFSET(x) offsetof(HTTPContext, x)
 #define D AV_OPT_FLAG_DECODING_PARAM
 #define E AV_OPT_FLAG_ENCODING_PARAM
@@ -127,6 +131,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, OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, 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 },
 { NULL }
 };
 
@@ -299,8 +304,10 @@ int ff_http_averror(int status_code, int default_averror)
 static int http_open(URLContext *h, const char *uri, int flags,
  AVDictionary **options)
 {
+struct addrinfo hints = { 0 }, *ai;
 HTTPContext *s = h-priv_data;
-int ret;
+int ret = -1, fd;
+char portstr[] = 8080; // allow non-root users for now
 
 if( s-seekable == 1 )
 h-is_streamed = 0;
@@ -320,11 +327,39 @@ static int http_open(URLContext *h, const char *uri, int flags,
 av_log(h, AV_LOG_WARNING,
No trailing CRLF found in HTTP header.\n);
 }
+if (s-listen) {
+hints.ai_family = AF_UNSPEC;
+hints.ai_socktype = SOCK_STREAM;
+hints.ai_flags |= AI_PASSIVE;
+ret = getaddrinfo(NULL, portstr, hints, ai);
+if (ret) {
+av_log(h, AV_LOG_ERROR, borked);
+return AVERROR(EIO);
+}
+fd = ff_socket(ai-ai_family,
+   ai-ai_socktype,
+   ai-ai_protocol);
+if (fd  0) {
+ret = ff_neterrno();
+freeaddrinfo(ai);
+return -1;
+}
 
-ret = http_open_cnx(h, options);
-if (ret  0)
-av_dict_free(s-chained_options);
-return ret;
+fd = ff_listen_bind(fd, ai-ai_addr, ai-ai_addrlen, -1, h);
+if (fd  0) {
+freeaddrinfo(ai);
+return fd;
+}
+h-is_streamed = 1;
+s-fd = fd;
+freeaddrinfo(ai);
+return 0;
+} else {
+ret = http_open_cnx(h, options

Re: [FFmpeg-devel] [GSoC] Proof-of-concept HTTP Server

2015-03-21 Thread Stephan Holljes
On Sun, Mar 22, 2015 at 2:34 AM, Michael Niedermayer michae...@gmx.at
wrote:

 On Sun, Mar 22, 2015 at 12:33:57AM +0100, Stephan Holljes wrote:
  Hi,
 
  what would be the correct way to create patches that won't be corrupted?
 I
  merely tried to copy what I have seen on the mailing-list before,
  apparently I didn't do a very good job ;)

 git send-email -1
 would send the most recent commit on the current branch, see the
 manual for exact usage

 or

 git format-patch -1
 would create the git patch that can be attached

 about the patch itself i tried it with wget and firefox it seems to
 work but firefox failed to detect it as mp3, i guess some content type
 is missing


That would be my guess, too. I will look into that.



 [...]

 --
 Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

 Why not whip the teacher when the pupil misbehaves? -- Diogenes of Sinope

 ___
 ffmpeg-devel mailing list
 ffmpeg-devel@ffmpeg.org
 http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] GSoC Introduction

2015-03-08 Thread Stephan Holljes
Hi,

my name is Stephan Holljes, my IRC nick is klaxa.
I want to work on implementing servers for network protocols within the
GSoC project.

I've been using ffmpeg for many years already and I always wanted to
contribute in a way other than providing end-user support, but I never
really found the right way to approach this. I hope GSoC will provide a
nice framework for that.

I like coding in C and I like coding network related software. I hope I
still do after the summer!

Regards,
Stephan Holljes
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


<    1   2   3