Commit e1a9ad7f authored by Marko Mikulicic's avatar Marko Mikulicic Committed by Cesanta Bot

Overload `mg_bind` to bind to tunnel

PUBLISHED_FROM=f554cc63dfea12455fe5e428c6ce5f3152774f8e
parent 296affc6
...@@ -10,11 +10,14 @@ signature: | ...@@ -10,11 +10,14 @@ signature: |
struct mg_iface *iface; /* Interface instance */ struct mg_iface *iface; /* Interface instance */
#if MG_ENABLE_SSL #if MG_ENABLE_SSL
/* SSL settings. */ /* SSL settings. */
const char *ssl_cert; /* Server certificate to present to clients */ const char *ssl_cert; /* Server certificate to present to clients
* Or client certificate to present to tunnel
* dispatcher. */
const char *ssl_key; /* Private key corresponding to the certificate. const char *ssl_key; /* Private key corresponding to the certificate.
If ssl_cert is set but ssl_key is not, ssl_cert If ssl_cert is set but ssl_key is not, ssl_cert
is used. */ is used. */
const char *ssl_ca_cert; /* Verify client certificates with this CA bundle */ const char *ssl_ca_cert; /* CA bundle used to verify client certificates or
* tunnel dispatchers. */
#endif #endif
}; };
--- ---
......
#include "mongoose.h" #include "mongoose.h"
static const char *s_local_port = ":8001"; static const char *s_local_port = ":8001";
static const char *s_dispatcher = "ws://localhost:8000"; static const char *s_dispatcher = "ws://foo:bar@localhost:8000";
static const char *s_user = "foo";
static const char *s_pass = "bar";
void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct http_message *hm = (struct http_message *) ev_data; struct http_message *hm = (struct http_message *) ev_data;
...@@ -41,15 +39,10 @@ int main(int argc, char **argv) { ...@@ -41,15 +39,10 @@ int main(int argc, char **argv) {
s_local_port = argv[++i]; s_local_port = argv[++i];
} else if (strcmp(argv[i], "-d") == 0) { } else if (strcmp(argv[i], "-d") == 0) {
s_dispatcher = argv[++i]; s_dispatcher = argv[++i];
} else if (strcmp(argv[i], "-u") == 0) {
s_user = argv[++i];
} else if (strcmp(argv[i], "-p") == 0) {
s_pass = argv[++i];
} }
} }
if ((nc = mg_tuna_bind(&mgr, ev_handler, s_dispatcher, s_user, s_pass)) == if ((nc = mg_bind(&mgr, s_dispatcher, ev_handler)) == NULL) {
NULL) {
fprintf(stderr, "Cannot create tunneled listening socket on [%s]\n", fprintf(stderr, "Cannot create tunneled listening socket on [%s]\n",
s_dispatcher); s_dispatcher);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
......
...@@ -1796,6 +1796,87 @@ int64_t cs_to64(const char *s) { ...@@ -1796,6 +1796,87 @@ int64_t cs_to64(const char *s) {
#endif /* EXCLUDE_COMMON */ #endif /* EXCLUDE_COMMON */
#ifdef MG_MODULE_LINES #ifdef MG_MODULE_LINES
#line 1 "mongoose/src/tun.h"
#endif
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_MONGOOSE_SRC_TUN_H_
#define CS_MONGOOSE_SRC_TUN_H_
#if MG_ENABLE_TUN
/* Amalgamated: #include "mongoose/src/net.h" */
/* Amalgamated: #include "common/mg_str.h" */
#ifndef MG_TUN_RECONNECT_INTERVAL
#define MG_TUN_RECONNECT_INTERVAL 1
#endif
#define MG_TUN_DATA_FRAME 0x0
#define MG_TUN_F_END_STREAM 0x1
/*
* MG TUN frame format is loosely based on HTTP/2.
* However since the communication happens via WebSocket
* there is no need to encode the frame length, since that's
* solved by WebSocket framing.
*
* TODO(mkm): Detailed description of the protocol.
*/
struct mg_tun_frame {
uint8_t type;
uint8_t flags;
uint32_t stream_id; /* opaque stream identifier */
struct mg_str body;
};
struct mg_tun_ssl_opts {
#if MG_ENABLE_SSL
const char *ssl_cert;
const char *ssl_key;
const char *ssl_ca_cert;
#else
int dummy; /* some compilers don't like empty structs */
#endif
};
struct mg_tun_client {
struct mg_mgr *mgr;
struct mg_iface *iface;
const char *disp_url;
struct mg_tun_ssl_opts ssl;
uint32_t last_stream_id; /* stream id of most recently accepted connection */
struct mg_connection *disp;
struct mg_connection *listener;
};
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct mg_connection *mg_tun_bind_opt(struct mg_mgr *mgr,
const char *dispatcher,
mg_event_handler_t handler,
struct mg_bind_opts opts);
int mg_tun_parse_frame(void *data, size_t len, struct mg_tun_frame *frame);
void mg_tun_send_frame(struct mg_connection *ws, uint32_t stream_id,
uint8_t type, uint8_t flags, struct mg_str msg);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* MG_ENABLE_TUN */
#endif /* CS_MONGOOSE_SRC_TUN_H_ */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/net.c" #line 1 "mongoose/src/net.c"
#endif #endif
/* /*
...@@ -1821,6 +1902,7 @@ int64_t cs_to64(const char *s) { ...@@ -1821,6 +1902,7 @@ int64_t cs_to64(const char *s) {
/* Amalgamated: #include "mongoose/src/internal.h" */ /* Amalgamated: #include "mongoose/src/internal.h" */
/* Amalgamated: #include "mongoose/src/resolv.h" */ /* Amalgamated: #include "mongoose/src/resolv.h" */
/* Amalgamated: #include "mongoose/src/util.h" */ /* Amalgamated: #include "mongoose/src/util.h" */
/* Amalgamated: #include "mongoose/src/tun.h" */
#define MG_MAX_HOST_LEN 200 #define MG_MAX_HOST_LEN 200
...@@ -2797,6 +2879,13 @@ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, ...@@ -2797,6 +2879,13 @@ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address,
MG_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts); MG_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts);
#if MG_ENABLE_TUN
if (mg_strncmp(mg_mk_str(address), mg_mk_str("ws://"), 5) == 0 ||
mg_strncmp(mg_mk_str(address), mg_mk_str("wss://"), 6) == 0) {
return mg_tun_bind_opt(mgr, address, callback, opts);
}
#endif
if (mg_parse_address(address, &sa, &proto, host, sizeof(host)) <= 0) { if (mg_parse_address(address, &sa, &proto, host, sizeof(host)) <= 0) {
MG_SET_PTRPTR(opts.error_string, "cannot parse address"); MG_SET_PTRPTR(opts.error_string, "cannot parse address");
return NULL; return NULL;
...@@ -10676,13 +10765,12 @@ static void mg_tun_reconnect(struct mg_tun_client *client); ...@@ -10676,13 +10765,12 @@ static void mg_tun_reconnect(struct mg_tun_client *client);
static void mg_tun_init_client(struct mg_tun_client *client, struct mg_mgr *mgr, static void mg_tun_init_client(struct mg_tun_client *client, struct mg_mgr *mgr,
struct mg_iface *iface, const char *dispatcher, struct mg_iface *iface, const char *dispatcher,
const char *user, const char *pass) { struct mg_tun_ssl_opts ssl) {
client->mgr = mgr; client->mgr = mgr;
client->iface = iface; client->iface = iface;
client->disp_url = dispatcher; client->disp_url = dispatcher;
client->user = user;
client->pass = pass;
client->last_stream_id = 0; client->last_stream_id = 0;
client->ssl = ssl;
client->disp = NULL; /* will be set by mg_tun_reconnect */ client->disp = NULL; /* will be set by mg_tun_reconnect */
client->listener = NULL; /* will be set by mg_do_bind */ client->listener = NULL; /* will be set by mg_do_bind */
...@@ -10787,24 +10875,23 @@ static void mg_tun_client_handler(struct mg_connection *nc, int ev, ...@@ -10787,24 +10875,23 @@ static void mg_tun_client_handler(struct mg_connection *nc, int ev,
static void mg_tun_do_reconnect(struct mg_tun_client *client) { static void mg_tun_do_reconnect(struct mg_tun_client *client) {
struct mg_connection *dc; struct mg_connection *dc;
struct mbuf headers; struct mg_connect_opts opts;
mbuf_init(&headers, 0); memset(&opts, 0, sizeof(opts));
#if MG_ENABLE_SSL
opts.ssl_cert = client->ssl.ssl_cert;
opts.ssl_key = client->ssl.ssl_key;
opts.ssl_ca_cert = client->ssl.ssl_ca_cert;
#endif
/* HTTP/Websocket listener */ /* HTTP/Websocket listener */
mg_basic_auth_header(client->user, client->pass, &headers); if ((dc = mg_connect_ws_opt(client->mgr, mg_tun_client_handler, opts,
mbuf_append(&headers, "", 1); /* nul terminate */ client->disp_url, "mg_tun", NULL)) == NULL) {
if ((dc = mg_connect_ws(client->mgr, mg_tun_client_handler, client->disp_url,
"mg_tun", headers.buf)) == NULL) {
LOG(LL_ERROR, LOG(LL_ERROR,
("Cannot connect to WS server on addr [%s]\n", client->disp_url)); ("Cannot connect to WS server on addr [%s]\n", client->disp_url));
goto clean; return;
} }
client->disp = dc; client->disp = dc;
dc->user_data = client; dc->user_data = client;
clean:
mbuf_free(&headers);
} }
void mg_tun_reconnect_ev_handler(struct mg_connection *nc, int ev, void mg_tun_reconnect_ev_handler(struct mg_connection *nc, int ev,
...@@ -10829,8 +10916,7 @@ static void mg_tun_reconnect(struct mg_tun_client *client) { ...@@ -10829,8 +10916,7 @@ static void mg_tun_reconnect(struct mg_tun_client *client) {
static struct mg_tun_client *mg_tun_create_client(struct mg_mgr *mgr, static struct mg_tun_client *mg_tun_create_client(struct mg_mgr *mgr,
const char *dispatcher, const char *dispatcher,
const char *user, struct mg_tun_ssl_opts ssl) {
const char *pass) {
struct mg_tun_client *client = NULL; struct mg_tun_client *client = NULL;
struct mg_iface *iface = mg_find_iface(mgr, &mg_tun_iface_vtable, NULL); struct mg_iface *iface = mg_find_iface(mgr, &mg_tun_iface_vtable, NULL);
if (iface == NULL) { if (iface == NULL) {
...@@ -10840,39 +10926,43 @@ static struct mg_tun_client *mg_tun_create_client(struct mg_mgr *mgr, ...@@ -10840,39 +10926,43 @@ static struct mg_tun_client *mg_tun_create_client(struct mg_mgr *mgr,
} }
client = (struct mg_tun_client *) MG_MALLOC(sizeof(*client)); client = (struct mg_tun_client *) MG_MALLOC(sizeof(*client));
mg_tun_init_client(client, mgr, iface, dispatcher, user, pass); mg_tun_init_client(client, mgr, iface, dispatcher, ssl);
iface->data = client; iface->data = client;
mg_tun_do_reconnect(client); mg_tun_do_reconnect(client);
return client; return client;
} }
static struct mg_connection *mg_tuna_do_bind(struct mg_tun_client *client, static struct mg_connection *mg_tun_do_bind(struct mg_tun_client *client,
mg_event_handler_t handler) { mg_event_handler_t handler,
struct mg_bind_opts opts) {
struct mg_connection *lc; struct mg_connection *lc;
struct mg_bind_opts opts;
const char *err;
memset(&opts, 0, sizeof(opts));
opts.iface = client->iface; opts.iface = client->iface;
opts.error_string = &err;
lc = mg_bind_opt(client->mgr, ":1234" /* dummy port */, handler, opts); lc = mg_bind_opt(client->mgr, ":1234" /* dummy port */, handler, opts);
if (lc == NULL) {
LOG(LL_ERROR, ("Cannot bind: %s", err));
}
client->listener = lc; client->listener = lc;
return lc; return lc;
} }
struct mg_connection *mg_tuna_bind(struct mg_mgr *mgr, struct mg_connection *mg_tun_bind_opt(struct mg_mgr *mgr,
mg_event_handler_t handler, const char *dispatcher,
const char *dispatcher, const char *user, mg_event_handler_t handler,
const char *pass) { struct mg_bind_opts opts) {
struct mg_tun_client *client = #if MG_ENABLE_SSL
mg_tun_create_client(mgr, dispatcher, user, pass); struct mg_tun_ssl_opts ssl = {opts.ssl_cert, opts.ssl_key, opts.ssl_ca_cert};
#else
struct mg_tun_ssl_opts ssl = {0};
#endif
struct mg_tun_client *client = mg_tun_create_client(mgr, dispatcher, ssl);
if (client == NULL) { if (client == NULL) {
return NULL; return NULL;
} }
return mg_tuna_do_bind(client, handler); #if MG_ENABLE_SSL
/* these options don't make sense in the local mouth of the tunnel */
opts.ssl_cert = NULL;
opts.ssl_key = NULL;
opts.ssl_ca_cert = NULL;
#endif
return mg_tun_do_bind(client, handler, opts);
} }
int mg_tun_parse_frame(void *data, size_t len, struct mg_tun_frame *frame) { int mg_tun_parse_frame(void *data, size_t len, struct mg_tun_frame *frame) {
......
...@@ -3221,11 +3221,14 @@ struct mg_bind_opts { ...@@ -3221,11 +3221,14 @@ struct mg_bind_opts {
struct mg_iface *iface; /* Interface instance */ struct mg_iface *iface; /* Interface instance */
#if MG_ENABLE_SSL #if MG_ENABLE_SSL
/* SSL settings. */ /* SSL settings. */
const char *ssl_cert; /* Server certificate to present to clients */ const char *ssl_cert; /* Server certificate to present to clients
* Or client certificate to present to tunnel
* dispatcher. */
const char *ssl_key; /* Private key corresponding to the certificate. const char *ssl_key; /* Private key corresponding to the certificate.
If ssl_cert is set but ssl_key is not, ssl_cert If ssl_cert is set but ssl_key is not, ssl_cert
is used. */ is used. */
const char *ssl_ca_cert; /* Verify client certificates with this CA bundle */ const char *ssl_ca_cert; /* CA bundle used to verify client certificates or
* tunnel dispatchers. */
#endif #endif
}; };
...@@ -5540,75 +5543,3 @@ uint32_t mg_coap_compose(struct mg_coap_message *cm, struct mbuf *io); ...@@ -5540,75 +5543,3 @@ uint32_t mg_coap_compose(struct mg_coap_message *cm, struct mbuf *io);
#endif /* MG_ENABLE_COAP */ #endif /* MG_ENABLE_COAP */
#endif /* CS_MONGOOSE_SRC_COAP_H_ */ #endif /* CS_MONGOOSE_SRC_COAP_H_ */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/tun.h"
#endif
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_MONGOOSE_SRC_TUN_H_
#define CS_MONGOOSE_SRC_TUN_H_
#if MG_ENABLE_TUN
/* Amalgamated: #include "mongoose/src/net.h" */
/* Amalgamated: #include "common/mg_str.h" */
#ifndef MG_TUN_RECONNECT_INTERVAL
#define MG_TUN_RECONNECT_INTERVAL 1
#endif
#define MG_TUN_DATA_FRAME 0x0
#define MG_TUN_F_END_STREAM 0x1
/*
* MG TUN frame format is loosely based on HTTP/2.
* However since the communication happens via WebSocket
* there is no need to encode the frame length, since that's
* solved by WebSocket framing.
*
* TODO(mkm): Detailed description of the protocol.
*/
struct mg_tun_frame {
uint8_t type;
uint8_t flags;
uint32_t stream_id; /* opaque stream identifier */
struct mg_str body;
};
struct mg_tun_client {
struct mg_mgr *mgr;
struct mg_iface *iface;
const char *disp_url;
const char *user;
const char *pass;
uint32_t last_stream_id; /* stream id of most recently accepted connection */
struct mg_connection *disp;
struct mg_connection *listener;
};
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct mg_connection *mg_tuna_bind(struct mg_mgr *mgr,
mg_event_handler_t handler,
const char *dispatcher, const char *user,
const char *pass);
int mg_tun_parse_frame(void *data, size_t len, struct mg_tun_frame *frame);
void mg_tun_send_frame(struct mg_connection *ws, uint32_t stream_id,
uint8_t type, uint8_t flags, struct mg_str msg);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* MG_ENABLE_TUN */
#endif /* CS_MONGOOSE_SRC_TUN_H_ */
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