Commit 1d384b96 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

http: add opaque data pointer to connection structures

This is to pass a VLC object (so far for logging only).
parent 5c83aea8
......@@ -54,11 +54,15 @@ static inline void vlc_http_conn_release(struct vlc_http_conn *conn)
conn->cbs->release(conn);
}
void vlc_http_err(void *, const char *msg, ...) VLC_FORMAT(2, 3);
void vlc_http_dbg(void *, const char *msg, ...) VLC_FORMAT(2, 3);
/**
* \defgroup http1 HTTP/1.x
* @{
*/
struct vlc_http_conn *vlc_h1_conn_create(struct vlc_tls *, bool proxy);
struct vlc_http_conn *vlc_h1_conn_create(void *ctx, struct vlc_tls *,
bool proxy);
struct vlc_http_stream *vlc_chunked_open(struct vlc_http_stream *,
struct vlc_tls *);
......@@ -68,7 +72,7 @@ struct vlc_http_stream *vlc_chunked_open(struct vlc_http_stream *,
* \defgroup h2 HTTP/2.0
* @{
*/
struct vlc_http_conn *vlc_h2_conn_create(struct vlc_tls *);
struct vlc_http_conn *vlc_h2_conn_create(void *ctx, struct vlc_tls *);
/** @} */
......
......@@ -34,6 +34,24 @@
#pragma GCC visibility push(default)
void vlc_http_err(void *ctx, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
msg_GenericVa((vlc_object_t *)ctx, VLC_MSG_ERR, fmt, ap);
va_end(ap);
}
void vlc_http_dbg(void *ctx, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
msg_GenericVa((vlc_object_t *)ctx, VLC_MSG_DBG, fmt, ap);
va_end(ap);
}
static char *vlc_http_proxy_find(const char *hostname, unsigned port,
bool secure)
{
......@@ -62,7 +80,8 @@ static vlc_tls_t *vlc_https_connect_i11e(vlc_tls_creds_t *creds,
char *proxy = vlc_http_proxy_find(host, port, true);
if (proxy != NULL)
{
tls = vlc_https_connect_proxy(creds, host, port, http_two, proxy);
tls = vlc_https_connect_proxy(creds->obj.parent, creds, host, port,
http_two, proxy);
free(proxy);
}
else
......@@ -186,9 +205,9 @@ static struct vlc_http_msg *vlc_https_request(struct vlc_http_mgr *mgr,
* NOTE: We do not enforce TLS version 1.2 for HTTP 2.0 explicitly.
*/
if (http2)
conn = vlc_h2_conn_create(tls);
conn = vlc_h2_conn_create(mgr->obj, tls);
else
conn = vlc_h1_conn_create(tls, false);
conn = vlc_h1_conn_create(mgr->obj, tls, false);
if (unlikely(conn == NULL))
{
......@@ -220,9 +239,9 @@ static struct vlc_http_msg *vlc_http_request(struct vlc_http_mgr *mgr,
struct vlc_http_conn *conn;
if (mgr->use_h2c)
conn = vlc_h2_conn_create(tls);
conn = vlc_h2_conn_create(mgr->obj, tls);
else
conn = vlc_h1_conn_create(tls, proxy);
conn = vlc_h1_conn_create(mgr->obj, tls, proxy);
if (unlikely(conn == NULL))
{
......
......@@ -116,9 +116,10 @@ struct vlc_h1_conn
bool active;
bool released;
bool proxy;
void *opaque;
};
#define CO(conn) ((conn)->conn.tls->obj)
#define CO(conn) ((conn)->opaque)
static void vlc_h1_conn_destroy(struct vlc_h1_conn *conn);
......@@ -126,7 +127,7 @@ static void *vlc_h1_stream_fatal(struct vlc_h1_conn *conn)
{
if (conn->conn.tls != NULL)
{
msg_Dbg(CO(conn), "connection failed");
vlc_http_dbg(CO(conn), "connection failed");
vlc_tls_Shutdown(conn->conn.tls, true);
vlc_tls_Close(conn->conn.tls);
conn->conn.tls = NULL;
......@@ -155,7 +156,7 @@ static struct vlc_http_stream *vlc_h1_stream_open(struct vlc_http_conn *c,
if (unlikely(payload == NULL))
return NULL;
msg_Dbg(CO(conn), "outgoing request:\n%.*s", (int)len, payload);
vlc_http_dbg(CO(conn), "outgoing request:\n%.*s", (int)len, payload);
val = vlc_tls_Write(conn->conn.tls, payload, len);
free(payload);
......@@ -185,7 +186,7 @@ static struct vlc_http_msg *vlc_h1_stream_wait(struct vlc_http_stream *stream)
if (payload == NULL)
return vlc_h1_stream_fatal(conn);
msg_Dbg(CO(conn), "incoming response:\n%.*s", (int)len, payload);
vlc_http_dbg(CO(conn), "incoming response:\n%.*s", (int)len, payload);
resp = vlc_http_msg_headers(payload);
minor = vlc_http_minor(payload);
......@@ -321,7 +322,7 @@ static const struct vlc_http_conn_cbs vlc_h1_conn_callbacks =
vlc_h1_conn_release,
};
struct vlc_http_conn *vlc_h1_conn_create(vlc_tls_t *tls, bool proxy)
struct vlc_http_conn *vlc_h1_conn_create(void *ctx, vlc_tls_t *tls, bool proxy)
{
struct vlc_h1_conn *conn = malloc(sizeof (*conn));
if (unlikely(conn == NULL))
......@@ -333,6 +334,7 @@ struct vlc_http_conn *vlc_h1_conn_create(vlc_tls_t *tls, bool proxy)
conn->active = false;
conn->released = false;
conn->proxy = proxy;
conn->opaque = ctx;
return &conn->conn;
}
......@@ -25,7 +25,7 @@
#undef NDEBUG
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
......@@ -52,7 +52,7 @@ static void conn_create(void)
external_fd = fds[0];
conn = vlc_h1_conn_create(tls, false);
conn = vlc_h1_conn_create(NULL, tls, false);
assert(conn != NULL);
}
......
......@@ -39,7 +39,7 @@
#include "conn.h"
#include "message.h"
#define CO(c) ((c)->conn.tls->obj)
#define CO(c) ((c)->opaque)
#define SO(s) CO((s)->conn)
/** HTTP/2 connection */
......@@ -47,6 +47,7 @@ struct vlc_h2_conn
{
struct vlc_http_conn conn;
struct vlc_h2_output *out; /**< Send thread */
void *opaque;
struct vlc_h2_stream *streams; /**< List of open streams */
uint32_t next_id; /**< Next free stream identifier */
......@@ -80,6 +81,20 @@ struct vlc_h2_stream
vlc_cond_t recv_wait;
};
static int vlc_h2_conn_queue(struct vlc_h2_conn *conn, struct vlc_h2_frame *f)
{
vlc_h2_frame_dump(conn->opaque, f, "out");
return vlc_h2_output_send(conn->out, f);
}
static int vlc_h2_conn_queue_prio(struct vlc_h2_conn *conn,
struct vlc_h2_frame *f)
{
vlc_h2_frame_dump(conn->opaque, f, "out (priority)");
return vlc_h2_output_send_prio(conn->out, f);
}
/* Stream callbacks */
/** Looks a stream up by ID. */
......@@ -100,11 +115,11 @@ static int vlc_h2_stream_error(void *ctx, uint_fast32_t id, uint_fast32_t code)
/* NOTE: This function is used both w/ and w/o conn->lock. Care. */
if (code != VLC_H2_NO_ERROR)
msg_Err(CO(conn), "local stream %"PRIuFAST32" error: "
"%s (0x%"PRIXFAST32")", id, vlc_h2_strerror(code), code);
vlc_http_err(CO(conn), "local stream %"PRIuFAST32" error: "
"%s (0x%"PRIXFAST32")", id, vlc_h2_strerror(code), code);
else
msg_Dbg(CO(conn), "local stream %"PRIuFAST32" shut down", id);
return vlc_h2_output_send(conn->out, vlc_h2_frame_rst_stream(id, code));
vlc_http_dbg(CO(conn), "local stream %"PRIuFAST32" shut down", id);
return vlc_h2_conn_queue(conn, vlc_h2_frame_rst_stream(id, code));
}
static int vlc_h2_stream_fatal(struct vlc_h2_stream *s, uint_fast32_t code)
......@@ -125,15 +140,15 @@ static void vlc_h2_stream_headers(void *ctx, unsigned count,
* Then it is safe to discard the existing header. */
if (s->recv_hdr != NULL)
{
msg_Dbg(SO(s), "stream %"PRIu32" discarding old headers", s->id);
vlc_http_dbg(SO(s), "stream %"PRIu32" discarding old headers", s->id);
vlc_http_msg_destroy(s->recv_hdr);
s->recv_hdr = NULL;
}
msg_Dbg(SO(s), "stream %"PRIu32" %u headers:", s->id, count);
vlc_http_dbg(SO(s), "stream %"PRIu32" %u headers:", s->id, count);
for (unsigned i = 0; i < count; i++)
msg_Dbg(SO(s), " %s: \"%s\"", hdrs[i][0], hdrs[i][1]);
vlc_http_dbg(SO(s), " %s: \"%s\"", hdrs[i][0], hdrs[i][1]);
s->recv_hdr = vlc_http_msg_h2_headers(count, hdrs);
if (unlikely(s->recv_hdr == NULL))
......@@ -173,7 +188,7 @@ static void vlc_h2_stream_end(void *ctx)
{
struct vlc_h2_stream *s = ctx;
msg_Dbg(SO(s), "stream %"PRIu32" closed by peer", s->id);
vlc_http_dbg(SO(s), "stream %"PRIu32" closed by peer", s->id);
s->recv_end = true;
vlc_cond_broadcast(&s->recv_wait);
......@@ -184,8 +199,8 @@ static int vlc_h2_stream_reset(void *ctx, uint_fast32_t code)
{
struct vlc_h2_stream *s = ctx;
msg_Err(SO(s), "peer stream %"PRIu32" error: %s (0x%"PRIXFAST32")",
s->id, vlc_h2_strerror(code), code);
vlc_http_err(SO(s), "peer stream %"PRIu32" error: %s (0x%"PRIXFAST32")",
s->id, vlc_h2_strerror(code), code);
s->recv_end = true;
s->recv_err = ECONNRESET;
......@@ -289,8 +304,7 @@ static block_t *vlc_h2_stream_read(struct vlc_http_stream *stream)
/* Credit the receive window if missing credit exceeds 50%. */
uint_fast32_t credit = VLC_H2_INIT_WINDOW - s->recv_cwnd;
if (credit >= (VLC_H2_INIT_WINDOW / 2)
&& !vlc_h2_output_send(conn->out,
vlc_h2_frame_window_update(s->id, credit)))
&& !vlc_h2_conn_queue(conn, vlc_h2_frame_window_update(s->id, credit)))
s->recv_cwnd += credit;
vlc_h2_stream_unlock(s);
......@@ -405,7 +419,7 @@ static struct vlc_http_stream *vlc_h2_stream_open(struct vlc_http_conn *c,
if (conn->next_id > 0x7ffffff)
{ /* Out of stream identifiers */
msg_Dbg(CO(conn), "no more stream identifiers");
vlc_http_dbg(CO(conn), "no more stream identifiers");
goto error;
}
......@@ -416,7 +430,7 @@ static struct vlc_http_stream *vlc_h2_stream_open(struct vlc_http_conn *c,
if (f == NULL)
goto error;
vlc_h2_output_send(conn->out, f);
vlc_h2_conn_queue(conn, f);
s->older = conn->streams;
if (s->older != NULL)
......@@ -439,8 +453,8 @@ static void vlc_h2_setting(void *ctx, uint_fast16_t id, uint_fast32_t value)
{
struct vlc_h2_conn *conn = ctx;
msg_Dbg(CO(conn), "setting: %s (0x%04"PRIxFAST16"): %"PRIuFAST32,
vlc_h2_setting_name(id), id, value);
vlc_http_dbg(CO(conn), "setting: %s (0x%04"PRIxFAST16"): %"PRIuFAST32,
vlc_h2_setting_name(id), id, value);
}
/** Reports end of HTTP/2 peer settings */
......@@ -448,7 +462,7 @@ static int vlc_h2_settings_done(void *ctx)
{
struct vlc_h2_conn *conn = ctx;
return vlc_h2_output_send(conn->out, vlc_h2_frame_settings_ack());
return vlc_h2_conn_queue(conn, vlc_h2_frame_settings_ack());
}
/** Reports a ping received from HTTP/2 peer */
......@@ -456,7 +470,7 @@ static int vlc_h2_ping(void *ctx, uint_fast64_t opaque)
{
struct vlc_h2_conn *conn = ctx;
return vlc_h2_output_send_prio(conn->out, vlc_h2_frame_pong(opaque));
return vlc_h2_conn_queue_prio(conn, vlc_h2_frame_pong(opaque));
}
/** Reports a local HTTP/2 connection failure */
......@@ -466,12 +480,12 @@ static void vlc_h2_error(void *ctx, uint_fast32_t code)
/* NOTE: This function is used both w/ and w/o conn->lock. Care. */
if (code != VLC_H2_NO_ERROR)
msg_Err(CO(conn), "local error: %s (0x%"PRIxFAST32")",
vlc_h2_strerror(code), code);
vlc_http_err(CO(conn), "local error: %s (0x%"PRIxFAST32")",
vlc_h2_strerror(code), code);
else
msg_Dbg(CO(conn), "local shutdown");
vlc_http_dbg(CO(conn), "local shutdown");
/* NOTE: currently, the peer cannot create a stream, so ID=0 */
vlc_h2_output_send(conn->out, vlc_h2_frame_goaway(0, code));
vlc_h2_conn_queue(conn, vlc_h2_frame_goaway(0, code));
}
/** Reports a remote HTTP/2 connection error */
......@@ -479,12 +493,12 @@ static int vlc_h2_reset(void *ctx, uint_fast32_t last_seq, uint_fast32_t code)
{
struct vlc_h2_conn *conn = ctx;
msg_Err(CO(conn), "peer error: %s (0x%"PRIxFAST32")",
vlc_h2_strerror(code), code);
msg_Dbg(CO(conn), "last stream: %"PRIuFAST32, last_seq);
vlc_http_err(CO(conn), "peer error: %s (0x%"PRIxFAST32")",
vlc_h2_strerror(code), code);
vlc_http_dbg(CO(conn), "last stream: %"PRIuFAST32, last_seq);
/* NOTE: currently, the peer cannot create a stream, so ID=0 */
vlc_h2_output_send(conn->out, vlc_h2_frame_goaway(0, VLC_H2_NO_ERROR));
vlc_h2_conn_queue(conn, vlc_h2_frame_goaway(0, VLC_H2_NO_ERROR));
/* Prevent adding new streams on this end. */
conn->next_id = 0x80000000;
......@@ -504,8 +518,8 @@ static void vlc_h2_window_status(void *ctx, uint32_t *restrict rcwd)
/* Maintain connection receive window to insanely large values.
* Congestion control is done per stream instead. */
if (*rcwd < (1 << 30)
&& vlc_h2_output_send_prio(conn->out,
vlc_h2_frame_window_update(0, 1 << 30)) == 0)
&& vlc_h2_conn_queue_prio(conn,
vlc_h2_frame_window_update(0, 1 << 30)) == 0)
*rcwd += 1 << 30;
}
......@@ -641,7 +655,7 @@ static void *vlc_h2_recv_thread(void *data)
if (frame == NULL)
{
msg_Dbg(CO(conn), "connection shutdown");
vlc_http_dbg(CO(conn), "connection shutdown");
break;
}
......@@ -700,7 +714,7 @@ static const struct vlc_http_conn_cbs vlc_h2_conn_callbacks =
vlc_h2_conn_release,
};
struct vlc_http_conn *vlc_h2_conn_create(struct vlc_tls *tls)
struct vlc_http_conn *vlc_h2_conn_create(void *ctx, struct vlc_tls *tls)
{
struct vlc_h2_conn *conn = malloc(sizeof (*conn));
if (unlikely(conn == NULL))
......@@ -709,6 +723,7 @@ struct vlc_http_conn *vlc_h2_conn_create(struct vlc_tls *tls)
conn->conn.cbs = &vlc_h2_conn_callbacks;
conn->conn.tls = tls;
conn->out = vlc_h2_output_create(tls, true);
conn->opaque = ctx;
conn->streams = NULL;
conn->next_id = 1; /* TODO: server side */
conn->released = false;
......@@ -718,7 +733,7 @@ struct vlc_http_conn *vlc_h2_conn_create(struct vlc_tls *tls)
vlc_mutex_init(&conn->lock);
if (vlc_h2_output_send(conn->out, vlc_h2_frame_settings())
if (vlc_h2_conn_queue(conn, vlc_h2_frame_settings())
|| vlc_clone(&conn->thread, vlc_h2_recv_thread, conn,
VLC_THREAD_PRIORITY_INPUT))
{
......
......@@ -98,7 +98,7 @@ static void conn_create(void)
external_fd = fds[0];
conn = vlc_h2_conn_create(tls);
conn = vlc_h2_conn_create(NULL, tls);
assert(conn != NULL);
conn_send(vlc_h2_frame_settings());
......
......@@ -31,6 +31,7 @@
#include <vlc_common.h>
#include "conn.h"
#include "hpack.h"
#include "h2frame.h"
......@@ -403,8 +404,8 @@ const char *vlc_h2_strerror(uint_fast32_t code)
return names[code];
}
void (vlc_h2_frame_dump)(vlc_object_t *obj, const struct vlc_h2_frame *f,
const char *msg)
void vlc_h2_frame_dump(void *opaque, const struct vlc_h2_frame *f,
const char *msg)
{
size_t len = vlc_h2_frame_length(f);
uint_fast8_t type = vlc_h2_frame_type(f);
......@@ -412,13 +413,13 @@ void (vlc_h2_frame_dump)(vlc_object_t *obj, const struct vlc_h2_frame *f,
uint_fast32_t sid = vlc_h2_frame_id(f);
if (sid != 0)
msg_Dbg(obj, "%s %s (0x%02"PRIxFAST8") frame of %zu bytes, "
"flags 0x%02"PRIxFAST8", stream %"PRIuFAST32, msg,
vlc_h2_type_name(type), type, len, flags, sid);
vlc_http_dbg(opaque, "%s %s (0x%02"PRIxFAST8") frame of %zu bytes, "
"flags 0x%02"PRIxFAST8", stream %"PRIuFAST32, msg,
vlc_h2_type_name(type), type, len, flags, sid);
else
msg_Dbg(obj, "%s %s (0x%02"PRIxFAST8") frame of %zu bytes, "
"flags 0x%02"PRIxFAST8", global", msg,
vlc_h2_type_name(type), type, len, flags);
vlc_http_dbg(opaque, "%s %s (0x%02"PRIxFAST8") frame of %zu bytes, "
"flags 0x%02"PRIxFAST8", global", msg,
vlc_h2_type_name(type), type, len, flags);
}
const uint8_t *(vlc_h2_frame_data_get)(const struct vlc_h2_frame *f,
......
......@@ -52,11 +52,7 @@ vlc_h2_frame_goaway(uint_fast32_t last_stream_id, uint_fast32_t error_code);
struct vlc_h2_frame *
vlc_h2_frame_window_update(uint_fast32_t stream_id, uint_fast32_t credit);
struct vlc_object_t;
void vlc_h2_frame_dump(struct vlc_object_t *, const struct vlc_h2_frame *,
const char *);
#define vlc_h2_frame_dump(o, f, m) vlc_h2_frame_dump(VLC_OBJECT(o), f, m)
void vlc_h2_frame_dump(void *, const struct vlc_h2_frame *, const char *);
enum vlc_h2_error {
VLC_H2_NO_ERROR,
......
......@@ -32,12 +32,23 @@
#include <string.h>
#include "h2frame.h"
#include <vlc_common.h>
#include "conn.h"
#define CTX ((void *)(uintptr_t)0x44556677)
static unsigned settings;
/* Callbacks */
void vlc_http_dbg(void *stream, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stream, fmt, ap);
va_end(ap);
}
static void vlc_h2_setting(void *ctx, uint_fast16_t id, uint_fast32_t value)
{
assert(ctx == CTX);
......
......@@ -258,8 +258,6 @@ static void *vlc_h2_output_thread(void *data)
while ((frame = vlc_h2_output_dequeue(out)) != NULL)
{
vlc_h2_frame_dump(out->tls->obj, frame, "out");
if (vlc_h2_frame_send(out->tls, frame))
{ /* The connection failed asynchronously. The caller will be
* notified at the next attempt to queue (as with TCP sockets). */
......
......@@ -30,7 +30,7 @@ struct vlc_tls_creds;
struct vlc_tls *vlc_https_connect(struct vlc_tls_creds *creds,
const char *name, unsigned port,
bool *restrict two);
struct vlc_tls *vlc_https_connect_proxy(struct vlc_tls_creds *creds,
struct vlc_tls *vlc_https_connect_proxy(void *ctx, struct vlc_tls_creds *creds,
const char *name, unsigned port,
bool *restrict two, const char *proxy);
#endif
......@@ -123,7 +123,7 @@ static void vlc_tls_ProxyClose(vlc_tls_t *tls)
(void) tls;
}
vlc_tls_t *vlc_https_connect_proxy(vlc_tls_creds_t *creds,
vlc_tls_t *vlc_https_connect_proxy(void *ctx, vlc_tls_creds_t *creds,
const char *hostname, unsigned port,
bool *restrict two, const char *proxy)
{
......@@ -180,8 +180,8 @@ vlc_tls_t *vlc_https_connect_proxy(vlc_tls_creds_t *creds,
psock->close = vlc_tls_ProxyClose;
psock->p = NULL;
struct vlc_http_conn *conn = /*ptwo ? vlc_h2_conn_create(psock)
:*/ vlc_h1_conn_create(psock, false);
struct vlc_http_conn *conn = /*ptwo ? vlc_h2_conn_create(ctx, psock)
:*/ vlc_h1_conn_create(ctx, psock, false);
if (unlikely(conn == NULL))
{
vlc_tls_Close(psock);
......
......@@ -138,9 +138,9 @@ int main(void)
bool two = false;
/* Test bad URLs */
vlc_https_connect_proxy(NULL, "www.example.com", 0, &two,
vlc_https_connect_proxy(NULL, NULL, "www.example.com", 0, &two,
"/test");
vlc_https_connect_proxy(NULL, "www.example.com", 0, &two,
vlc_https_connect_proxy(NULL, NULL, "www.example.com", 0, &two,
"ftp://proxy.example.com/");
int lfd = server_socket(&port);
......@@ -153,7 +153,7 @@ int main(void)
assert(url != NULL);
/* Test connection failure */
vlc_https_connect_proxy(NULL, "www.example.com", 0, &two, url);
vlc_https_connect_proxy(NULL, NULL, "www.example.com", 0, &two, url);
if (listen(lfd, 255))
{
......@@ -167,7 +167,7 @@ int main(void)
assert(!"Thread error");
/* Test proxy error */
vlc_https_connect_proxy(NULL, "www.example.com", 0, &two, url);
vlc_https_connect_proxy(NULL, NULL, "www.example.com", 0, &two, url);
vlc_cancel(th);
vlc_join(th, NULL);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment