mirror of
https://github.com/cesanta/mongoose.git
synced 2025-06-10 11:22:54 +08:00
Remove tunneling from mongoose
CL: Mongoose Web Server: Remove tunneling functionality which was used by nobody PUBLISHED_FROM=38b9e8ae7b0a5a1dbba5cff4074843dc681267d3
This commit is contained in:
parent
8742fac5d8
commit
f29457e967
@ -48,12 +48,11 @@ signature: |
|
|||||||
#define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */
|
#define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */
|
||||||
|
|
||||||
/* Flags that are settable by user */
|
/* Flags that are settable by user */
|
||||||
#define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */
|
#define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */
|
||||||
#define MG_F_CLOSE_IMMEDIATELY (1 << 11) /* Disconnect */
|
#define MG_F_CLOSE_IMMEDIATELY (1 << 11) /* Disconnect */
|
||||||
#define MG_F_WEBSOCKET_NO_DEFRAG (1 << 12) /* Websocket specific */
|
#define MG_F_WEBSOCKET_NO_DEFRAG (1 << 12) /* Websocket specific */
|
||||||
#define MG_F_DELETE_CHUNK (1 << 13) /* HTTP specific */
|
#define MG_F_DELETE_CHUNK (1 << 13) /* HTTP specific */
|
||||||
#define MG_F_ENABLE_BROADCAST (1 << 14) /* Allow broadcast address usage */
|
#define MG_F_ENABLE_BROADCAST (1 << 14) /* Allow broadcast address usage */
|
||||||
#define MG_F_TUN_DO_NOT_RECONNECT (1 << 15) /* Don't reconnect tunnel */
|
|
||||||
|
|
||||||
#define MG_F_USER_1 (1 << 20) /* Flags left for application */
|
#define MG_F_USER_1 (1 << 20) /* Flags left for application */
|
||||||
#define MG_F_USER_2 (1 << 21)
|
#define MG_F_USER_2 (1 << 21)
|
||||||
|
624
mongoose.c
624
mongoose.c
@ -2146,93 +2146,6 @@ size_t mg_match_prefix(const char *pattern, int pattern_len, const char *str) {
|
|||||||
|
|
||||||
#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_PROTO_NAME "mg_tun"
|
|
||||||
|
|
||||||
#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;
|
|
||||||
struct mg_connection *reconnect;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
struct mg_connection *mg_tun_bind_opt(struct mg_mgr *mgr,
|
|
||||||
const char *dispatcher,
|
|
||||||
MG_CB(mg_event_handler_t handler,
|
|
||||||
void *user_data),
|
|
||||||
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);
|
|
||||||
|
|
||||||
void mg_tun_destroy_client(struct mg_tun_client *client);
|
|
||||||
|
|
||||||
#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
|
||||||
/*
|
/*
|
||||||
@ -2257,7 +2170,6 @@ void mg_tun_destroy_client(struct mg_tun_client *client);
|
|||||||
/* Amalgamated: #include "mongoose/src/dns.h" */
|
/* Amalgamated: #include "mongoose/src/dns.h" */
|
||||||
/* 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/tun.h" */
|
|
||||||
/* Amalgamated: #include "mongoose/src/util.h" */
|
/* Amalgamated: #include "mongoose/src/util.h" */
|
||||||
|
|
||||||
#define MG_MAX_HOST_LEN 200
|
#define MG_MAX_HOST_LEN 200
|
||||||
@ -3053,13 +2965,6 @@ 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, MG_CB(callback, user_data), 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;
|
||||||
@ -3280,39 +3185,6 @@ extern const struct mg_iface_vtable mg_socket_iface_vtable;
|
|||||||
|
|
||||||
#endif /* CS_MONGOOSE_SRC_NET_IF_SOCKET_H_ */
|
#endif /* CS_MONGOOSE_SRC_NET_IF_SOCKET_H_ */
|
||||||
#ifdef MG_MODULE_LINES
|
#ifdef MG_MODULE_LINES
|
||||||
#line 1 "mongoose/src/net_if_tun.h"
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
|
||||||
* All rights reserved
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CS_MONGOOSE_SRC_NET_IF_TUN_H_
|
|
||||||
#define CS_MONGOOSE_SRC_NET_IF_TUN_H_
|
|
||||||
|
|
||||||
#if MG_ENABLE_TUN
|
|
||||||
|
|
||||||
/* Amalgamated: #include "mongoose/src/net_if.h" */
|
|
||||||
|
|
||||||
struct mg_tun_client;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
extern const struct mg_iface_vtable mg_tun_iface_vtable;
|
|
||||||
|
|
||||||
struct mg_connection *mg_tun_if_find_conn(struct mg_tun_client *client,
|
|
||||||
uint32_t stream_id);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#endif /* MG_ENABLE_TUN */
|
|
||||||
|
|
||||||
#endif /* CS_MONGOOSE_SRC_NET_IF_TUN_H_ */
|
|
||||||
#ifdef MG_MODULE_LINES
|
|
||||||
#line 1 "mongoose/src/net_if_socks.h"
|
#line 1 "mongoose/src/net_if_socks.h"
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
@ -3343,15 +3215,11 @@ extern const struct mg_iface_vtable mg_socks_iface_vtable;
|
|||||||
/* Amalgamated: #include "mongoose/src/net_if.h" */
|
/* Amalgamated: #include "mongoose/src/net_if.h" */
|
||||||
/* Amalgamated: #include "mongoose/src/internal.h" */
|
/* Amalgamated: #include "mongoose/src/internal.h" */
|
||||||
/* Amalgamated: #include "mongoose/src/net_if_socket.h" */
|
/* Amalgamated: #include "mongoose/src/net_if_socket.h" */
|
||||||
/* Amalgamated: #include "mongoose/src/net_if_tun.h" */
|
|
||||||
|
|
||||||
extern const struct mg_iface_vtable mg_default_iface_vtable;
|
extern const struct mg_iface_vtable mg_default_iface_vtable;
|
||||||
|
|
||||||
const struct mg_iface_vtable *mg_ifaces[] = {
|
const struct mg_iface_vtable *mg_ifaces[] = {
|
||||||
&mg_default_iface_vtable,
|
&mg_default_iface_vtable,
|
||||||
#if MG_ENABLE_TUN
|
|
||||||
&mg_tun_iface_vtable,
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int mg_num_ifaces = (int) (sizeof(mg_ifaces) / sizeof(mg_ifaces[0]));
|
int mg_num_ifaces = (int) (sizeof(mg_ifaces) / sizeof(mg_ifaces[0]));
|
||||||
@ -4350,180 +4218,6 @@ struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef MG_MODULE_LINES
|
#ifdef MG_MODULE_LINES
|
||||||
#line 1 "mongoose/src/net_if_tun.c"
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
|
||||||
* All rights reserved
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if MG_ENABLE_TUN
|
|
||||||
|
|
||||||
/* Amalgamated: #include "common/cs_dbg.h" */
|
|
||||||
/* Amalgamated: #include "common/cs_time.h" */
|
|
||||||
/* Amalgamated: #include "mongoose/src/internal.h" */
|
|
||||||
/* Amalgamated: #include "mongoose/src/net_if_tun.h" */
|
|
||||||
/* Amalgamated: #include "mongoose/src/tun.h" */
|
|
||||||
/* Amalgamated: #include "mongoose/src/util.h" */
|
|
||||||
|
|
||||||
#define MG_TCP_RECV_BUFFER_SIZE 1024
|
|
||||||
#define MG_UDP_RECV_BUFFER_SIZE 1500
|
|
||||||
|
|
||||||
void mg_tun_if_connect_tcp(struct mg_connection *nc,
|
|
||||||
const union socket_address *sa) {
|
|
||||||
(void) nc;
|
|
||||||
(void) sa;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_connect_udp(struct mg_connection *nc) {
|
|
||||||
(void) nc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mg_tun_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) {
|
|
||||||
(void) nc;
|
|
||||||
(void) sa;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mg_tun_if_listen_udp(struct mg_connection *nc, union socket_address *sa) {
|
|
||||||
(void) nc;
|
|
||||||
(void) sa;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) {
|
|
||||||
struct mg_tun_client *client = (struct mg_tun_client *) nc->iface->data;
|
|
||||||
uint32_t stream_id = (uint32_t)(uintptr_t) nc->mgr_data;
|
|
||||||
struct mg_str msg = {(char *) buf, len};
|
|
||||||
#if MG_ENABLE_HEXDUMP
|
|
||||||
char hex[512];
|
|
||||||
mg_hexdump(buf, len, hex, sizeof(hex));
|
|
||||||
LOG(LL_DEBUG, ("sending to stream 0x%x:\n%s", (unsigned int) stream_id, hex));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mg_tun_send_frame(client->disp, stream_id, MG_TUN_DATA_FRAME, 0, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_udp_send(struct mg_connection *nc, const void *buf, size_t len) {
|
|
||||||
(void) nc;
|
|
||||||
(void) buf;
|
|
||||||
(void) len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_recved(struct mg_connection *nc, size_t len) {
|
|
||||||
(void) nc;
|
|
||||||
(void) len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mg_tun_if_create_conn(struct mg_connection *nc) {
|
|
||||||
(void) nc;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_destroy_conn(struct mg_connection *nc) {
|
|
||||||
struct mg_tun_client *client = (struct mg_tun_client *) nc->iface->data;
|
|
||||||
|
|
||||||
if (nc->flags & MG_F_LISTENING) {
|
|
||||||
mg_tun_destroy_client(client);
|
|
||||||
} else if (client->disp) {
|
|
||||||
uint32_t stream_id = (uint32_t)(uintptr_t) nc->mgr_data;
|
|
||||||
struct mg_str msg = {NULL, 0};
|
|
||||||
|
|
||||||
LOG(LL_DEBUG, ("closing 0x%x:", (unsigned int) stream_id));
|
|
||||||
mg_tun_send_frame(client->disp, stream_id, MG_TUN_DATA_FRAME,
|
|
||||||
MG_TUN_F_END_STREAM, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Associate a socket to a connection. */
|
|
||||||
void mg_tun_if_sock_set(struct mg_connection *nc, sock_t sock) {
|
|
||||||
(void) nc;
|
|
||||||
(void) sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_init(struct mg_iface *iface) {
|
|
||||||
(void) iface;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_free(struct mg_iface *iface) {
|
|
||||||
(void) iface;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_add_conn(struct mg_connection *nc) {
|
|
||||||
nc->sock = INVALID_SOCKET;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_remove_conn(struct mg_connection *nc) {
|
|
||||||
(void) nc;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t mg_tun_if_poll(struct mg_iface *iface, int timeout_ms) {
|
|
||||||
(void) iface;
|
|
||||||
(void) timeout_ms;
|
|
||||||
return (time_t) cs_time();
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_get_conn_addr(struct mg_connection *nc, int remote,
|
|
||||||
union socket_address *sa) {
|
|
||||||
(void) nc;
|
|
||||||
(void) remote;
|
|
||||||
(void) sa;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mg_connection *mg_tun_if_find_conn(struct mg_tun_client *client,
|
|
||||||
uint32_t stream_id) {
|
|
||||||
struct mg_connection *nc = NULL;
|
|
||||||
|
|
||||||
for (nc = client->mgr->active_connections; nc != NULL; nc = nc->next) {
|
|
||||||
if (nc->iface != client->iface || (nc->flags & MG_F_LISTENING)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (stream_id == (uint32_t)(uintptr_t) nc->mgr_data) {
|
|
||||||
return nc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream_id > client->last_stream_id) {
|
|
||||||
/* create a new connection */
|
|
||||||
LOG(LL_DEBUG, ("new stream 0x%x, accepting", (unsigned int) stream_id));
|
|
||||||
nc = mg_if_accept_new_conn(client->listener);
|
|
||||||
nc->mgr_data = (void *) (uintptr_t) stream_id;
|
|
||||||
client->last_stream_id = stream_id;
|
|
||||||
} else {
|
|
||||||
LOG(LL_DEBUG,
|
|
||||||
("Ignoring stream 0x%x (last_stream_id 0x%x)", (unsigned int) stream_id,
|
|
||||||
(unsigned int) client->last_stream_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return nc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clang-format off */
|
|
||||||
#define MG_TUN_IFACE_VTABLE \
|
|
||||||
{ \
|
|
||||||
mg_tun_if_init, \
|
|
||||||
mg_tun_if_free, \
|
|
||||||
mg_tun_if_add_conn, \
|
|
||||||
mg_tun_if_remove_conn, \
|
|
||||||
mg_tun_if_poll, \
|
|
||||||
mg_tun_if_listen_tcp, \
|
|
||||||
mg_tun_if_listen_udp, \
|
|
||||||
mg_tun_if_connect_tcp, \
|
|
||||||
mg_tun_if_connect_udp, \
|
|
||||||
mg_tun_if_tcp_send, \
|
|
||||||
mg_tun_if_udp_send, \
|
|
||||||
mg_tun_if_recved, \
|
|
||||||
mg_tun_if_create_conn, \
|
|
||||||
mg_tun_if_destroy_conn, \
|
|
||||||
mg_tun_if_sock_set, \
|
|
||||||
mg_tun_if_get_conn_addr, \
|
|
||||||
}
|
|
||||||
/* clang-format on */
|
|
||||||
|
|
||||||
const struct mg_iface_vtable mg_tun_iface_vtable = MG_TUN_IFACE_VTABLE;
|
|
||||||
|
|
||||||
#endif /* MG_ENABLE_TUN */
|
|
||||||
#ifdef MG_MODULE_LINES
|
|
||||||
#line 1 "mongoose/src/ssl_if_openssl.c"
|
#line 1 "mongoose/src/ssl_if_openssl.c"
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
@ -12439,324 +12133,6 @@ int mg_set_protocol_coap(struct mg_connection *nc) {
|
|||||||
|
|
||||||
#endif /* MG_ENABLE_COAP */
|
#endif /* MG_ENABLE_COAP */
|
||||||
#ifdef MG_MODULE_LINES
|
#ifdef MG_MODULE_LINES
|
||||||
#line 1 "mongoose/src/tun.c"
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2014 Cesanta Software Limited
|
|
||||||
* All rights reserved
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if MG_ENABLE_TUN
|
|
||||||
|
|
||||||
/* Amalgamated: #include "common/cs_dbg.h" */
|
|
||||||
/* Amalgamated: #include "mongoose/src/http.h" */
|
|
||||||
/* Amalgamated: #include "mongoose/src/internal.h" */
|
|
||||||
/* Amalgamated: #include "mongoose/src/net.h" */
|
|
||||||
/* Amalgamated: #include "mongoose/src/net_if_tun.h" */
|
|
||||||
/* Amalgamated: #include "mongoose/src/tun.h" */
|
|
||||||
/* Amalgamated: #include "mongoose/src/util.h" */
|
|
||||||
|
|
||||||
static void mg_tun_reconnect(struct mg_tun_client *client, int timeout);
|
|
||||||
|
|
||||||
static void mg_tun_init_client(struct mg_tun_client *client, struct mg_mgr *mgr,
|
|
||||||
struct mg_iface *iface, const char *dispatcher,
|
|
||||||
struct mg_tun_ssl_opts ssl) {
|
|
||||||
client->mgr = mgr;
|
|
||||||
client->iface = iface;
|
|
||||||
client->disp_url = dispatcher;
|
|
||||||
client->last_stream_id = 0;
|
|
||||||
client->ssl = ssl;
|
|
||||||
|
|
||||||
client->disp = NULL; /* will be set by mg_tun_reconnect */
|
|
||||||
client->listener = NULL; /* will be set by mg_do_bind */
|
|
||||||
client->reconnect = NULL; /* will be set by mg_tun_reconnect */
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_log_frame(struct mg_tun_frame *frame) {
|
|
||||||
LOG(LL_DEBUG, ("Got TUN frame: type=0x%x, flags=0x%x stream_id=0x%x, "
|
|
||||||
"len=%d",
|
|
||||||
frame->type, frame->flags, (unsigned int) frame->stream_id,
|
|
||||||
(int) frame->body.len));
|
|
||||||
#if MG_ENABLE_HEXDUMP
|
|
||||||
{
|
|
||||||
char hex[512];
|
|
||||||
mg_hexdump(frame->body.p, frame->body.len, hex, sizeof(hex) - 1);
|
|
||||||
hex[sizeof(hex) - 1] = '\0';
|
|
||||||
LOG(LL_DEBUG, ("body:\n%s", hex));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
LOG(LL_DEBUG, ("body: '%.*s'", (int) frame->body.len, frame->body.p));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mg_tun_close_all(struct mg_tun_client *client) {
|
|
||||||
struct mg_connection *nc;
|
|
||||||
for (nc = client->mgr->active_connections; nc != NULL; nc = nc->next) {
|
|
||||||
if (nc->iface == client->iface && !(nc->flags & MG_F_LISTENING)) {
|
|
||||||
LOG(LL_DEBUG, ("Closing tunneled connection %p", nc));
|
|
||||||
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
|
||||||
/* mg_close_conn(nc); */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mg_tun_client_handler(struct mg_connection *nc, int ev,
|
|
||||||
void *ev_data MG_UD_ARG(void *user_data)) {
|
|
||||||
#if !MG_ENABLE_CALLBACK_USERDATA
|
|
||||||
void *user_data = nc->user_data;
|
|
||||||
#else
|
|
||||||
(void) nc;
|
|
||||||
#endif
|
|
||||||
struct mg_tun_client *client = (struct mg_tun_client *) user_data;
|
|
||||||
|
|
||||||
switch (ev) {
|
|
||||||
case MG_EV_CONNECT: {
|
|
||||||
int err = *(int *) ev_data;
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
LOG(LL_ERROR, ("Cannot connect to the tunnel dispatcher: %d", err));
|
|
||||||
} else {
|
|
||||||
LOG(LL_INFO, ("Connected to the tunnel dispatcher"));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MG_EV_HTTP_REPLY: {
|
|
||||||
struct http_message *hm = (struct http_message *) ev_data;
|
|
||||||
|
|
||||||
if (hm->resp_code != 200) {
|
|
||||||
LOG(LL_ERROR,
|
|
||||||
("Tunnel dispatcher reply non-OK status code %d", hm->resp_code));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
|
|
||||||
LOG(LL_INFO, ("Tunnel dispatcher handshake done"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MG_EV_WEBSOCKET_FRAME: {
|
|
||||||
struct websocket_message *wm = (struct websocket_message *) ev_data;
|
|
||||||
struct mg_connection *tc;
|
|
||||||
struct mg_tun_frame frame;
|
|
||||||
|
|
||||||
if (mg_tun_parse_frame(wm->data, wm->size, &frame) == -1) {
|
|
||||||
LOG(LL_ERROR, ("Got invalid tun frame dropping"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mg_tun_log_frame(&frame);
|
|
||||||
|
|
||||||
tc = mg_tun_if_find_conn(client, frame.stream_id);
|
|
||||||
if (tc == NULL) {
|
|
||||||
if (frame.body.len > 0) {
|
|
||||||
LOG(LL_DEBUG, ("Got frame after receiving end has been closed"));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (frame.body.len > 0) {
|
|
||||||
mg_if_recv_tcp_cb(tc, (void *) frame.body.p, frame.body.len,
|
|
||||||
0 /* own */);
|
|
||||||
}
|
|
||||||
if (frame.flags & MG_TUN_F_END_STREAM) {
|
|
||||||
LOG(LL_DEBUG, ("Closing tunneled connection because got end of stream "
|
|
||||||
"from other end"));
|
|
||||||
tc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
|
||||||
mg_close_conn(tc);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MG_EV_CLOSE: {
|
|
||||||
LOG(LL_DEBUG, ("Closing all tunneled connections"));
|
|
||||||
/*
|
|
||||||
* The client might have been already freed when the listening socket is
|
|
||||||
* closed.
|
|
||||||
*/
|
|
||||||
if (client != NULL) {
|
|
||||||
mg_tun_close_all(client);
|
|
||||||
client->disp = NULL;
|
|
||||||
LOG(LL_INFO, ("Dispatcher connection is no more, reconnecting"));
|
|
||||||
/* TODO(mkm): implement exp back off */
|
|
||||||
mg_tun_reconnect(client, MG_TUN_RECONNECT_INTERVAL);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mg_tun_do_reconnect(struct mg_tun_client *client) {
|
|
||||||
struct mg_connection *dc;
|
|
||||||
struct mg_connect_opts opts;
|
|
||||||
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 */
|
|
||||||
if ((dc = mg_connect_ws_opt(client->mgr, MG_CB(mg_tun_client_handler, client),
|
|
||||||
opts, client->disp_url, MG_TUN_PROTO_NAME,
|
|
||||||
NULL)) == NULL) {
|
|
||||||
LOG(LL_ERROR,
|
|
||||||
("Cannot connect to WS server on addr [%s]\n", client->disp_url));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
client->disp = dc;
|
|
||||||
#if !MG_ENABLE_CALLBACK_USERDATA
|
|
||||||
dc->user_data = client;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_reconnect_ev_handler(struct mg_connection *nc, int ev,
|
|
||||||
void *ev_data MG_UD_ARG(void *user_data)) {
|
|
||||||
#if !MG_ENABLE_CALLBACK_USERDATA
|
|
||||||
void *user_data = nc->user_data;
|
|
||||||
#else
|
|
||||||
(void) nc;
|
|
||||||
#endif
|
|
||||||
struct mg_tun_client *client = (struct mg_tun_client *) user_data;
|
|
||||||
(void) ev_data;
|
|
||||||
|
|
||||||
switch (ev) {
|
|
||||||
case MG_EV_TIMER:
|
|
||||||
if (!(client->listener->flags & MG_F_TUN_DO_NOT_RECONNECT)) {
|
|
||||||
mg_tun_do_reconnect(client);
|
|
||||||
} else {
|
|
||||||
/* Reconnecting is suppressed, we'll check again at the next poll */
|
|
||||||
mg_tun_reconnect(client, 0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mg_tun_reconnect(struct mg_tun_client *client, int timeout) {
|
|
||||||
if (client->reconnect == NULL) {
|
|
||||||
client->reconnect = mg_add_sock(client->mgr, INVALID_SOCKET,
|
|
||||||
MG_CB(mg_tun_reconnect_ev_handler, client));
|
|
||||||
#if !MG_ENABLE_CALLBACK_USERDATA
|
|
||||||
client->reconnect->user_data = client;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
client->reconnect->ev_timer_time = mg_time() + timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct mg_tun_client *mg_tun_create_client(struct mg_mgr *mgr,
|
|
||||||
const char *dispatcher,
|
|
||||||
struct mg_tun_ssl_opts ssl) {
|
|
||||||
struct mg_tun_client *client = NULL;
|
|
||||||
struct mg_iface *iface = mg_find_iface(mgr, &mg_tun_iface_vtable, NULL);
|
|
||||||
if (iface == NULL) {
|
|
||||||
LOG(LL_ERROR, ("The tun feature requires the manager to have a tun "
|
|
||||||
"interface enabled"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = (struct mg_tun_client *) MG_MALLOC(sizeof(*client));
|
|
||||||
mg_tun_init_client(client, mgr, iface, dispatcher, ssl);
|
|
||||||
iface->data = client;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We need to give application a chance to set MG_F_TUN_DO_NOT_RECONNECT on a
|
|
||||||
* listening connection right after mg_tun_bind_opt() returned it, so we
|
|
||||||
* should use mg_tun_reconnect() here, instead of mg_tun_do_reconnect()
|
|
||||||
*/
|
|
||||||
mg_tun_reconnect(client, 0);
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_destroy_client(struct mg_tun_client *client) {
|
|
||||||
/*
|
|
||||||
* NOTE:
|
|
||||||
* `client` is NULL in case of OOM
|
|
||||||
* `client->disp` is NULL if connection failed
|
|
||||||
* `client->iface is NULL is `mg_find_iface` failed
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (client != NULL && client->disp != NULL) {
|
|
||||||
/* the dispatcher connection handler will in turn close all tunnels */
|
|
||||||
client->disp->flags |= MG_F_CLOSE_IMMEDIATELY;
|
|
||||||
/* this is used as a signal to other tun handlers that the party is over */
|
|
||||||
client->disp->user_data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client != NULL && client->reconnect != NULL) {
|
|
||||||
client->reconnect->flags |= MG_F_CLOSE_IMMEDIATELY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client != NULL && client->iface != NULL) {
|
|
||||||
client->iface->data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
MG_FREE(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct mg_connection *mg_tun_do_bind(struct mg_tun_client *client,
|
|
||||||
MG_CB(mg_event_handler_t handler,
|
|
||||||
void *user_data),
|
|
||||||
struct mg_bind_opts opts) {
|
|
||||||
struct mg_connection *lc;
|
|
||||||
opts.iface = client->iface;
|
|
||||||
lc = mg_bind_opt(client->mgr, ":1234" /* dummy port */,
|
|
||||||
MG_CB(handler, user_data), opts);
|
|
||||||
client->listener = lc;
|
|
||||||
return lc;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mg_connection *mg_tun_bind_opt(struct mg_mgr *mgr,
|
|
||||||
const char *dispatcher,
|
|
||||||
MG_CB(mg_event_handler_t handler,
|
|
||||||
void *user_data),
|
|
||||||
struct mg_bind_opts opts) {
|
|
||||||
#if MG_ENABLE_SSL
|
|
||||||
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) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#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, MG_CB(handler, user_data), opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
int mg_tun_parse_frame(void *data, size_t len, struct mg_tun_frame *frame) {
|
|
||||||
const size_t header_size = sizeof(uint32_t) + sizeof(uint8_t) * 2;
|
|
||||||
if (len < header_size) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
frame->type = *(uint8_t *) (data);
|
|
||||||
frame->flags = *(uint8_t *) ((char *) data + 1);
|
|
||||||
memcpy(&frame->stream_id, (char *) data + 2, sizeof(uint32_t));
|
|
||||||
frame->stream_id = ntohl(frame->stream_id);
|
|
||||||
frame->body.p = (char *) data + header_size;
|
|
||||||
frame->body.len = len - header_size;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_send_frame(struct mg_connection *ws, uint32_t stream_id,
|
|
||||||
uint8_t type, uint8_t flags, struct mg_str msg) {
|
|
||||||
stream_id = htonl(stream_id);
|
|
||||||
{
|
|
||||||
struct mg_str parts[] = {
|
|
||||||
{(char *) &type, sizeof(type)},
|
|
||||||
{(char *) &flags, sizeof(flags)},
|
|
||||||
{(char *) &stream_id, sizeof(stream_id)},
|
|
||||||
{msg.p, msg.len} /* vc6 doesn't like just `msg` here */};
|
|
||||||
mg_send_websocket_framev(ws, WEBSOCKET_OP_BINARY, parts,
|
|
||||||
sizeof(parts) / sizeof(parts[0]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* MG_ENABLE_TUN */
|
|
||||||
#ifdef MG_MODULE_LINES
|
|
||||||
#line 1 "mongoose/src/sntp.c"
|
#line 1 "mongoose/src/sntp.c"
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
|
15
mongoose.h
15
mongoose.h
@ -3157,10 +3157,6 @@ struct { \
|
|||||||
(CS_PLATFORM == CS_P_WINDOWS || CS_PLATFORM == CS_P_UNIX)
|
(CS_PLATFORM == CS_P_WINDOWS || CS_PLATFORM == CS_P_UNIX)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MG_ENABLE_TUN
|
|
||||||
#define MG_ENABLE_TUN MG_ENABLE_HTTP_WEBSOCKET
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MG_ENABLE_SNTP
|
#ifndef MG_ENABLE_SNTP
|
||||||
#define MG_ENABLE_SNTP 0
|
#define MG_ENABLE_SNTP 0
|
||||||
#endif
|
#endif
|
||||||
@ -3519,12 +3515,11 @@ struct mg_connection {
|
|||||||
#define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */
|
#define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */
|
||||||
|
|
||||||
/* Flags that are settable by user */
|
/* Flags that are settable by user */
|
||||||
#define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */
|
#define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */
|
||||||
#define MG_F_CLOSE_IMMEDIATELY (1 << 11) /* Disconnect */
|
#define MG_F_CLOSE_IMMEDIATELY (1 << 11) /* Disconnect */
|
||||||
#define MG_F_WEBSOCKET_NO_DEFRAG (1 << 12) /* Websocket specific */
|
#define MG_F_WEBSOCKET_NO_DEFRAG (1 << 12) /* Websocket specific */
|
||||||
#define MG_F_DELETE_CHUNK (1 << 13) /* HTTP specific */
|
#define MG_F_DELETE_CHUNK (1 << 13) /* HTTP specific */
|
||||||
#define MG_F_ENABLE_BROADCAST (1 << 14) /* Allow broadcast address usage */
|
#define MG_F_ENABLE_BROADCAST (1 << 14) /* Allow broadcast address usage */
|
||||||
#define MG_F_TUN_DO_NOT_RECONNECT (1 << 15) /* Don't reconnect tunnel */
|
|
||||||
|
|
||||||
#define MG_F_USER_1 (1 << 20) /* Flags left for application */
|
#define MG_F_USER_1 (1 << 20) /* Flags left for application */
|
||||||
#define MG_F_USER_2 (1 << 21)
|
#define MG_F_USER_2 (1 << 21)
|
||||||
|
@ -153,10 +153,6 @@
|
|||||||
(CS_PLATFORM == CS_P_WINDOWS || CS_PLATFORM == CS_P_UNIX)
|
(CS_PLATFORM == CS_P_WINDOWS || CS_PLATFORM == CS_P_UNIX)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MG_ENABLE_TUN
|
|
||||||
#define MG_ENABLE_TUN MG_ENABLE_HTTP_WEBSOCKET
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MG_ENABLE_SNTP
|
#ifndef MG_ENABLE_SNTP
|
||||||
#define MG_ENABLE_SNTP 0
|
#define MG_ENABLE_SNTP 0
|
||||||
#endif
|
#endif
|
||||||
|
@ -59,15 +59,12 @@ SOURCES = $(COMMON)/mg_mem.h \
|
|||||||
$(COMMON)/mbuf.c \
|
$(COMMON)/mbuf.c \
|
||||||
$(COMMON)/mg_str.c \
|
$(COMMON)/mg_str.c \
|
||||||
$(COMMON)/str_util.c \
|
$(COMMON)/str_util.c \
|
||||||
tun.h \
|
|
||||||
net.c \
|
net.c \
|
||||||
net_if_socket.h \
|
net_if_socket.h \
|
||||||
net_if_tun.h \
|
|
||||||
net_if_socks.h \
|
net_if_socks.h \
|
||||||
net_if.c \
|
net_if.c \
|
||||||
net_if_socket.c \
|
net_if_socket.c \
|
||||||
net_if_socks.c \
|
net_if_socks.c \
|
||||||
net_if_tun.c \
|
|
||||||
ssl_if_openssl.c \
|
ssl_if_openssl.c \
|
||||||
ssl_if_mbedtls.c \
|
ssl_if_mbedtls.c \
|
||||||
uri.c \
|
uri.c \
|
||||||
@ -83,7 +80,6 @@ SOURCES = $(COMMON)/mg_mem.h \
|
|||||||
dns_server.c \
|
dns_server.c \
|
||||||
resolv.c \
|
resolv.c \
|
||||||
coap.c \
|
coap.c \
|
||||||
tun.c \
|
|
||||||
sntp.c \
|
sntp.c \
|
||||||
socks.c \
|
socks.c \
|
||||||
$(COMMON)/platforms/cc3200/cc3200_libc.c \
|
$(COMMON)/platforms/cc3200/cc3200_libc.c \
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "mongoose/src/dns.h"
|
#include "mongoose/src/dns.h"
|
||||||
#include "mongoose/src/internal.h"
|
#include "mongoose/src/internal.h"
|
||||||
#include "mongoose/src/resolv.h"
|
#include "mongoose/src/resolv.h"
|
||||||
#include "mongoose/src/tun.h"
|
|
||||||
#include "mongoose/src/util.h"
|
#include "mongoose/src/util.h"
|
||||||
|
|
||||||
#define MG_MAX_HOST_LEN 200
|
#define MG_MAX_HOST_LEN 200
|
||||||
@ -816,13 +815,6 @@ 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, MG_CB(callback, user_data), 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;
|
||||||
|
11
src/net.h
11
src/net.h
@ -141,12 +141,11 @@ struct mg_connection {
|
|||||||
#define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */
|
#define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */
|
||||||
|
|
||||||
/* Flags that are settable by user */
|
/* Flags that are settable by user */
|
||||||
#define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */
|
#define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */
|
||||||
#define MG_F_CLOSE_IMMEDIATELY (1 << 11) /* Disconnect */
|
#define MG_F_CLOSE_IMMEDIATELY (1 << 11) /* Disconnect */
|
||||||
#define MG_F_WEBSOCKET_NO_DEFRAG (1 << 12) /* Websocket specific */
|
#define MG_F_WEBSOCKET_NO_DEFRAG (1 << 12) /* Websocket specific */
|
||||||
#define MG_F_DELETE_CHUNK (1 << 13) /* HTTP specific */
|
#define MG_F_DELETE_CHUNK (1 << 13) /* HTTP specific */
|
||||||
#define MG_F_ENABLE_BROADCAST (1 << 14) /* Allow broadcast address usage */
|
#define MG_F_ENABLE_BROADCAST (1 << 14) /* Allow broadcast address usage */
|
||||||
#define MG_F_TUN_DO_NOT_RECONNECT (1 << 15) /* Don't reconnect tunnel */
|
|
||||||
|
|
||||||
#define MG_F_USER_1 (1 << 20) /* Flags left for application */
|
#define MG_F_USER_1 (1 << 20) /* Flags left for application */
|
||||||
#define MG_F_USER_2 (1 << 21)
|
#define MG_F_USER_2 (1 << 21)
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
#include "mongoose/src/net_if.h"
|
#include "mongoose/src/net_if.h"
|
||||||
#include "mongoose/src/internal.h"
|
#include "mongoose/src/internal.h"
|
||||||
#include "mongoose/src/net_if_socket.h"
|
#include "mongoose/src/net_if_socket.h"
|
||||||
#include "mongoose/src/net_if_tun.h"
|
|
||||||
|
|
||||||
extern const struct mg_iface_vtable mg_default_iface_vtable;
|
extern const struct mg_iface_vtable mg_default_iface_vtable;
|
||||||
|
|
||||||
const struct mg_iface_vtable *mg_ifaces[] = {
|
const struct mg_iface_vtable *mg_ifaces[] = {
|
||||||
&mg_default_iface_vtable,
|
&mg_default_iface_vtable,
|
||||||
#if MG_ENABLE_TUN
|
|
||||||
&mg_tun_iface_vtable,
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int mg_num_ifaces = (int) (sizeof(mg_ifaces) / sizeof(mg_ifaces[0]));
|
int mg_num_ifaces = (int) (sizeof(mg_ifaces) / sizeof(mg_ifaces[0]));
|
||||||
|
171
src/net_if_tun.c
171
src/net_if_tun.c
@ -1,171 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
|
||||||
* All rights reserved
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if MG_ENABLE_TUN
|
|
||||||
|
|
||||||
#include "common/cs_dbg.h"
|
|
||||||
#include "common/cs_time.h"
|
|
||||||
#include "mongoose/src/internal.h"
|
|
||||||
#include "mongoose/src/net_if_tun.h"
|
|
||||||
#include "mongoose/src/tun.h"
|
|
||||||
#include "mongoose/src/util.h"
|
|
||||||
|
|
||||||
#define MG_TCP_RECV_BUFFER_SIZE 1024
|
|
||||||
#define MG_UDP_RECV_BUFFER_SIZE 1500
|
|
||||||
|
|
||||||
void mg_tun_if_connect_tcp(struct mg_connection *nc,
|
|
||||||
const union socket_address *sa) {
|
|
||||||
(void) nc;
|
|
||||||
(void) sa;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_connect_udp(struct mg_connection *nc) {
|
|
||||||
(void) nc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mg_tun_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) {
|
|
||||||
(void) nc;
|
|
||||||
(void) sa;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mg_tun_if_listen_udp(struct mg_connection *nc, union socket_address *sa) {
|
|
||||||
(void) nc;
|
|
||||||
(void) sa;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) {
|
|
||||||
struct mg_tun_client *client = (struct mg_tun_client *) nc->iface->data;
|
|
||||||
uint32_t stream_id = (uint32_t)(uintptr_t) nc->mgr_data;
|
|
||||||
struct mg_str msg = {(char *) buf, len};
|
|
||||||
#if MG_ENABLE_HEXDUMP
|
|
||||||
char hex[512];
|
|
||||||
mg_hexdump(buf, len, hex, sizeof(hex));
|
|
||||||
LOG(LL_DEBUG, ("sending to stream 0x%x:\n%s", (unsigned int) stream_id, hex));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mg_tun_send_frame(client->disp, stream_id, MG_TUN_DATA_FRAME, 0, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_udp_send(struct mg_connection *nc, const void *buf, size_t len) {
|
|
||||||
(void) nc;
|
|
||||||
(void) buf;
|
|
||||||
(void) len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_recved(struct mg_connection *nc, size_t len) {
|
|
||||||
(void) nc;
|
|
||||||
(void) len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mg_tun_if_create_conn(struct mg_connection *nc) {
|
|
||||||
(void) nc;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_destroy_conn(struct mg_connection *nc) {
|
|
||||||
struct mg_tun_client *client = (struct mg_tun_client *) nc->iface->data;
|
|
||||||
|
|
||||||
if (nc->flags & MG_F_LISTENING) {
|
|
||||||
mg_tun_destroy_client(client);
|
|
||||||
} else if (client->disp) {
|
|
||||||
uint32_t stream_id = (uint32_t)(uintptr_t) nc->mgr_data;
|
|
||||||
struct mg_str msg = {NULL, 0};
|
|
||||||
|
|
||||||
LOG(LL_DEBUG, ("closing 0x%x:", (unsigned int) stream_id));
|
|
||||||
mg_tun_send_frame(client->disp, stream_id, MG_TUN_DATA_FRAME,
|
|
||||||
MG_TUN_F_END_STREAM, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Associate a socket to a connection. */
|
|
||||||
void mg_tun_if_sock_set(struct mg_connection *nc, sock_t sock) {
|
|
||||||
(void) nc;
|
|
||||||
(void) sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_init(struct mg_iface *iface) {
|
|
||||||
(void) iface;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_free(struct mg_iface *iface) {
|
|
||||||
(void) iface;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_add_conn(struct mg_connection *nc) {
|
|
||||||
nc->sock = INVALID_SOCKET;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_remove_conn(struct mg_connection *nc) {
|
|
||||||
(void) nc;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t mg_tun_if_poll(struct mg_iface *iface, int timeout_ms) {
|
|
||||||
(void) iface;
|
|
||||||
(void) timeout_ms;
|
|
||||||
return (time_t) cs_time();
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_if_get_conn_addr(struct mg_connection *nc, int remote,
|
|
||||||
union socket_address *sa) {
|
|
||||||
(void) nc;
|
|
||||||
(void) remote;
|
|
||||||
(void) sa;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mg_connection *mg_tun_if_find_conn(struct mg_tun_client *client,
|
|
||||||
uint32_t stream_id) {
|
|
||||||
struct mg_connection *nc = NULL;
|
|
||||||
|
|
||||||
for (nc = client->mgr->active_connections; nc != NULL; nc = nc->next) {
|
|
||||||
if (nc->iface != client->iface || (nc->flags & MG_F_LISTENING)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (stream_id == (uint32_t)(uintptr_t) nc->mgr_data) {
|
|
||||||
return nc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream_id > client->last_stream_id) {
|
|
||||||
/* create a new connection */
|
|
||||||
LOG(LL_DEBUG, ("new stream 0x%x, accepting", (unsigned int) stream_id));
|
|
||||||
nc = mg_if_accept_new_conn(client->listener);
|
|
||||||
nc->mgr_data = (void *) (uintptr_t) stream_id;
|
|
||||||
client->last_stream_id = stream_id;
|
|
||||||
} else {
|
|
||||||
LOG(LL_DEBUG,
|
|
||||||
("Ignoring stream 0x%x (last_stream_id 0x%x)", (unsigned int) stream_id,
|
|
||||||
(unsigned int) client->last_stream_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return nc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clang-format off */
|
|
||||||
#define MG_TUN_IFACE_VTABLE \
|
|
||||||
{ \
|
|
||||||
mg_tun_if_init, \
|
|
||||||
mg_tun_if_free, \
|
|
||||||
mg_tun_if_add_conn, \
|
|
||||||
mg_tun_if_remove_conn, \
|
|
||||||
mg_tun_if_poll, \
|
|
||||||
mg_tun_if_listen_tcp, \
|
|
||||||
mg_tun_if_listen_udp, \
|
|
||||||
mg_tun_if_connect_tcp, \
|
|
||||||
mg_tun_if_connect_udp, \
|
|
||||||
mg_tun_if_tcp_send, \
|
|
||||||
mg_tun_if_udp_send, \
|
|
||||||
mg_tun_if_recved, \
|
|
||||||
mg_tun_if_create_conn, \
|
|
||||||
mg_tun_if_destroy_conn, \
|
|
||||||
mg_tun_if_sock_set, \
|
|
||||||
mg_tun_if_get_conn_addr, \
|
|
||||||
}
|
|
||||||
/* clang-format on */
|
|
||||||
|
|
||||||
const struct mg_iface_vtable mg_tun_iface_vtable = MG_TUN_IFACE_VTABLE;
|
|
||||||
|
|
||||||
#endif /* MG_ENABLE_TUN */
|
|
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
|
||||||
* All rights reserved
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CS_MONGOOSE_SRC_NET_IF_TUN_H_
|
|
||||||
#define CS_MONGOOSE_SRC_NET_IF_TUN_H_
|
|
||||||
|
|
||||||
#if MG_ENABLE_TUN
|
|
||||||
|
|
||||||
#include "mongoose/src/net_if.h"
|
|
||||||
|
|
||||||
struct mg_tun_client;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
extern const struct mg_iface_vtable mg_tun_iface_vtable;
|
|
||||||
|
|
||||||
struct mg_connection *mg_tun_if_find_conn(struct mg_tun_client *client,
|
|
||||||
uint32_t stream_id);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#endif /* MG_ENABLE_TUN */
|
|
||||||
|
|
||||||
#endif /* CS_MONGOOSE_SRC_NET_IF_TUN_H_ */
|
|
315
src/tun.c
315
src/tun.c
@ -1,315 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014 Cesanta Software Limited
|
|
||||||
* All rights reserved
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if MG_ENABLE_TUN
|
|
||||||
|
|
||||||
#include "common/cs_dbg.h"
|
|
||||||
#include "mongoose/src/http.h"
|
|
||||||
#include "mongoose/src/internal.h"
|
|
||||||
#include "mongoose/src/net.h"
|
|
||||||
#include "mongoose/src/net_if_tun.h"
|
|
||||||
#include "mongoose/src/tun.h"
|
|
||||||
#include "mongoose/src/util.h"
|
|
||||||
|
|
||||||
static void mg_tun_reconnect(struct mg_tun_client *client, int timeout);
|
|
||||||
|
|
||||||
static void mg_tun_init_client(struct mg_tun_client *client, struct mg_mgr *mgr,
|
|
||||||
struct mg_iface *iface, const char *dispatcher,
|
|
||||||
struct mg_tun_ssl_opts ssl) {
|
|
||||||
client->mgr = mgr;
|
|
||||||
client->iface = iface;
|
|
||||||
client->disp_url = dispatcher;
|
|
||||||
client->last_stream_id = 0;
|
|
||||||
client->ssl = ssl;
|
|
||||||
|
|
||||||
client->disp = NULL; /* will be set by mg_tun_reconnect */
|
|
||||||
client->listener = NULL; /* will be set by mg_do_bind */
|
|
||||||
client->reconnect = NULL; /* will be set by mg_tun_reconnect */
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_log_frame(struct mg_tun_frame *frame) {
|
|
||||||
LOG(LL_DEBUG, ("Got TUN frame: type=0x%x, flags=0x%x stream_id=0x%x, "
|
|
||||||
"len=%d",
|
|
||||||
frame->type, frame->flags, (unsigned int) frame->stream_id,
|
|
||||||
(int) frame->body.len));
|
|
||||||
#if MG_ENABLE_HEXDUMP
|
|
||||||
{
|
|
||||||
char hex[512];
|
|
||||||
mg_hexdump(frame->body.p, frame->body.len, hex, sizeof(hex) - 1);
|
|
||||||
hex[sizeof(hex) - 1] = '\0';
|
|
||||||
LOG(LL_DEBUG, ("body:\n%s", hex));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
LOG(LL_DEBUG, ("body: '%.*s'", (int) frame->body.len, frame->body.p));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mg_tun_close_all(struct mg_tun_client *client) {
|
|
||||||
struct mg_connection *nc;
|
|
||||||
for (nc = client->mgr->active_connections; nc != NULL; nc = nc->next) {
|
|
||||||
if (nc->iface == client->iface && !(nc->flags & MG_F_LISTENING)) {
|
|
||||||
LOG(LL_DEBUG, ("Closing tunneled connection %p", nc));
|
|
||||||
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
|
||||||
/* mg_close_conn(nc); */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mg_tun_client_handler(struct mg_connection *nc, int ev,
|
|
||||||
void *ev_data MG_UD_ARG(void *user_data)) {
|
|
||||||
#if !MG_ENABLE_CALLBACK_USERDATA
|
|
||||||
void *user_data = nc->user_data;
|
|
||||||
#else
|
|
||||||
(void) nc;
|
|
||||||
#endif
|
|
||||||
struct mg_tun_client *client = (struct mg_tun_client *) user_data;
|
|
||||||
|
|
||||||
switch (ev) {
|
|
||||||
case MG_EV_CONNECT: {
|
|
||||||
int err = *(int *) ev_data;
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
LOG(LL_ERROR, ("Cannot connect to the tunnel dispatcher: %d", err));
|
|
||||||
} else {
|
|
||||||
LOG(LL_INFO, ("Connected to the tunnel dispatcher"));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MG_EV_HTTP_REPLY: {
|
|
||||||
struct http_message *hm = (struct http_message *) ev_data;
|
|
||||||
|
|
||||||
if (hm->resp_code != 200) {
|
|
||||||
LOG(LL_ERROR,
|
|
||||||
("Tunnel dispatcher reply non-OK status code %d", hm->resp_code));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
|
|
||||||
LOG(LL_INFO, ("Tunnel dispatcher handshake done"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MG_EV_WEBSOCKET_FRAME: {
|
|
||||||
struct websocket_message *wm = (struct websocket_message *) ev_data;
|
|
||||||
struct mg_connection *tc;
|
|
||||||
struct mg_tun_frame frame;
|
|
||||||
|
|
||||||
if (mg_tun_parse_frame(wm->data, wm->size, &frame) == -1) {
|
|
||||||
LOG(LL_ERROR, ("Got invalid tun frame dropping"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mg_tun_log_frame(&frame);
|
|
||||||
|
|
||||||
tc = mg_tun_if_find_conn(client, frame.stream_id);
|
|
||||||
if (tc == NULL) {
|
|
||||||
if (frame.body.len > 0) {
|
|
||||||
LOG(LL_DEBUG, ("Got frame after receiving end has been closed"));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (frame.body.len > 0) {
|
|
||||||
mg_if_recv_tcp_cb(tc, (void *) frame.body.p, frame.body.len,
|
|
||||||
0 /* own */);
|
|
||||||
}
|
|
||||||
if (frame.flags & MG_TUN_F_END_STREAM) {
|
|
||||||
LOG(LL_DEBUG, ("Closing tunneled connection because got end of stream "
|
|
||||||
"from other end"));
|
|
||||||
tc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
|
||||||
mg_close_conn(tc);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MG_EV_CLOSE: {
|
|
||||||
LOG(LL_DEBUG, ("Closing all tunneled connections"));
|
|
||||||
/*
|
|
||||||
* The client might have been already freed when the listening socket is
|
|
||||||
* closed.
|
|
||||||
*/
|
|
||||||
if (client != NULL) {
|
|
||||||
mg_tun_close_all(client);
|
|
||||||
client->disp = NULL;
|
|
||||||
LOG(LL_INFO, ("Dispatcher connection is no more, reconnecting"));
|
|
||||||
/* TODO(mkm): implement exp back off */
|
|
||||||
mg_tun_reconnect(client, MG_TUN_RECONNECT_INTERVAL);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mg_tun_do_reconnect(struct mg_tun_client *client) {
|
|
||||||
struct mg_connection *dc;
|
|
||||||
struct mg_connect_opts opts;
|
|
||||||
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 */
|
|
||||||
if ((dc = mg_connect_ws_opt(client->mgr, MG_CB(mg_tun_client_handler, client),
|
|
||||||
opts, client->disp_url, MG_TUN_PROTO_NAME,
|
|
||||||
NULL)) == NULL) {
|
|
||||||
LOG(LL_ERROR,
|
|
||||||
("Cannot connect to WS server on addr [%s]\n", client->disp_url));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
client->disp = dc;
|
|
||||||
#if !MG_ENABLE_CALLBACK_USERDATA
|
|
||||||
dc->user_data = client;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_reconnect_ev_handler(struct mg_connection *nc, int ev,
|
|
||||||
void *ev_data MG_UD_ARG(void *user_data)) {
|
|
||||||
#if !MG_ENABLE_CALLBACK_USERDATA
|
|
||||||
void *user_data = nc->user_data;
|
|
||||||
#else
|
|
||||||
(void) nc;
|
|
||||||
#endif
|
|
||||||
struct mg_tun_client *client = (struct mg_tun_client *) user_data;
|
|
||||||
(void) ev_data;
|
|
||||||
|
|
||||||
switch (ev) {
|
|
||||||
case MG_EV_TIMER:
|
|
||||||
if (!(client->listener->flags & MG_F_TUN_DO_NOT_RECONNECT)) {
|
|
||||||
mg_tun_do_reconnect(client);
|
|
||||||
} else {
|
|
||||||
/* Reconnecting is suppressed, we'll check again at the next poll */
|
|
||||||
mg_tun_reconnect(client, 0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mg_tun_reconnect(struct mg_tun_client *client, int timeout) {
|
|
||||||
if (client->reconnect == NULL) {
|
|
||||||
client->reconnect = mg_add_sock(client->mgr, INVALID_SOCKET,
|
|
||||||
MG_CB(mg_tun_reconnect_ev_handler, client));
|
|
||||||
#if !MG_ENABLE_CALLBACK_USERDATA
|
|
||||||
client->reconnect->user_data = client;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
client->reconnect->ev_timer_time = mg_time() + timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct mg_tun_client *mg_tun_create_client(struct mg_mgr *mgr,
|
|
||||||
const char *dispatcher,
|
|
||||||
struct mg_tun_ssl_opts ssl) {
|
|
||||||
struct mg_tun_client *client = NULL;
|
|
||||||
struct mg_iface *iface = mg_find_iface(mgr, &mg_tun_iface_vtable, NULL);
|
|
||||||
if (iface == NULL) {
|
|
||||||
LOG(LL_ERROR, ("The tun feature requires the manager to have a tun "
|
|
||||||
"interface enabled"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = (struct mg_tun_client *) MG_MALLOC(sizeof(*client));
|
|
||||||
mg_tun_init_client(client, mgr, iface, dispatcher, ssl);
|
|
||||||
iface->data = client;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We need to give application a chance to set MG_F_TUN_DO_NOT_RECONNECT on a
|
|
||||||
* listening connection right after mg_tun_bind_opt() returned it, so we
|
|
||||||
* should use mg_tun_reconnect() here, instead of mg_tun_do_reconnect()
|
|
||||||
*/
|
|
||||||
mg_tun_reconnect(client, 0);
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_destroy_client(struct mg_tun_client *client) {
|
|
||||||
/*
|
|
||||||
* NOTE:
|
|
||||||
* `client` is NULL in case of OOM
|
|
||||||
* `client->disp` is NULL if connection failed
|
|
||||||
* `client->iface is NULL is `mg_find_iface` failed
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (client != NULL && client->disp != NULL) {
|
|
||||||
/* the dispatcher connection handler will in turn close all tunnels */
|
|
||||||
client->disp->flags |= MG_F_CLOSE_IMMEDIATELY;
|
|
||||||
/* this is used as a signal to other tun handlers that the party is over */
|
|
||||||
client->disp->user_data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client != NULL && client->reconnect != NULL) {
|
|
||||||
client->reconnect->flags |= MG_F_CLOSE_IMMEDIATELY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client != NULL && client->iface != NULL) {
|
|
||||||
client->iface->data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
MG_FREE(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct mg_connection *mg_tun_do_bind(struct mg_tun_client *client,
|
|
||||||
MG_CB(mg_event_handler_t handler,
|
|
||||||
void *user_data),
|
|
||||||
struct mg_bind_opts opts) {
|
|
||||||
struct mg_connection *lc;
|
|
||||||
opts.iface = client->iface;
|
|
||||||
lc = mg_bind_opt(client->mgr, ":1234" /* dummy port */,
|
|
||||||
MG_CB(handler, user_data), opts);
|
|
||||||
client->listener = lc;
|
|
||||||
return lc;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mg_connection *mg_tun_bind_opt(struct mg_mgr *mgr,
|
|
||||||
const char *dispatcher,
|
|
||||||
MG_CB(mg_event_handler_t handler,
|
|
||||||
void *user_data),
|
|
||||||
struct mg_bind_opts opts) {
|
|
||||||
#if MG_ENABLE_SSL
|
|
||||||
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) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#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, MG_CB(handler, user_data), opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
int mg_tun_parse_frame(void *data, size_t len, struct mg_tun_frame *frame) {
|
|
||||||
const size_t header_size = sizeof(uint32_t) + sizeof(uint8_t) * 2;
|
|
||||||
if (len < header_size) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
frame->type = *(uint8_t *) (data);
|
|
||||||
frame->flags = *(uint8_t *) ((char *) data + 1);
|
|
||||||
memcpy(&frame->stream_id, (char *) data + 2, sizeof(uint32_t));
|
|
||||||
frame->stream_id = ntohl(frame->stream_id);
|
|
||||||
frame->body.p = (char *) data + header_size;
|
|
||||||
frame->body.len = len - header_size;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_tun_send_frame(struct mg_connection *ws, uint32_t stream_id,
|
|
||||||
uint8_t type, uint8_t flags, struct mg_str msg) {
|
|
||||||
stream_id = htonl(stream_id);
|
|
||||||
{
|
|
||||||
struct mg_str parts[] = {
|
|
||||||
{(char *) &type, sizeof(type)},
|
|
||||||
{(char *) &flags, sizeof(flags)},
|
|
||||||
{(char *) &stream_id, sizeof(stream_id)},
|
|
||||||
{msg.p, msg.len} /* vc6 doesn't like just `msg` here */};
|
|
||||||
mg_send_websocket_framev(ws, WEBSOCKET_OP_BINARY, parts,
|
|
||||||
sizeof(parts) / sizeof(parts[0]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* MG_ENABLE_TUN */
|
|
84
src/tun.h
84
src/tun.h
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
#include "mongoose/src/net.h"
|
|
||||||
#include "common/mg_str.h"
|
|
||||||
|
|
||||||
#ifndef MG_TUN_RECONNECT_INTERVAL
|
|
||||||
#define MG_TUN_RECONNECT_INTERVAL 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MG_TUN_PROTO_NAME "mg_tun"
|
|
||||||
|
|
||||||
#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;
|
|
||||||
struct mg_connection *reconnect;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
struct mg_connection *mg_tun_bind_opt(struct mg_mgr *mgr,
|
|
||||||
const char *dispatcher,
|
|
||||||
MG_CB(mg_event_handler_t handler,
|
|
||||||
void *user_data),
|
|
||||||
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);
|
|
||||||
|
|
||||||
void mg_tun_destroy_client(struct mg_tun_client *client);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#endif /* MG_ENABLE_TUN */
|
|
||||||
|
|
||||||
#endif /* CS_MONGOOSE_SRC_TUN_H_ */
|
|
@ -3,7 +3,7 @@
|
|||||||
PROG = unit_test
|
PROG = unit_test
|
||||||
REPO_ROOT ?= ../../
|
REPO_ROOT ?= ../../
|
||||||
SRC_DIR = ../src
|
SRC_DIR = ../src
|
||||||
TEST_SOURCES = unit_test.c $(REPO_ROOT)/common/test_util.c $(REPO_ROOT)/tuna/dispatcher.c
|
TEST_SOURCES = unit_test.c $(REPO_ROOT)/common/test_util.c
|
||||||
AMALGAMATED_SOURCES = ../mongoose.c
|
AMALGAMATED_SOURCES = ../mongoose.c
|
||||||
KRYPTON_PATH = $(REPO_ROOT)/krypton
|
KRYPTON_PATH = $(REPO_ROOT)/krypton
|
||||||
# or Krypton, or mbedTLS
|
# or Krypton, or mbedTLS
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "unit_test.h"
|
#include "unit_test.h"
|
||||||
#include "common/test_util.h"
|
#include "common/test_util.h"
|
||||||
#include "common/cs_md5.h"
|
#include "common/cs_md5.h"
|
||||||
#include "tuna/dispatcher.h"
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||||
#include <crtdbg.h>
|
#include <crtdbg.h>
|
||||||
@ -3816,44 +3815,6 @@ void tunnel_client_test_handler(struct mg_connection *nc, int ev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE(mkm): this test requires compiling the unit_test.c file with
|
|
||||||
* //tuna/dispatcher.c .
|
|
||||||
* Windows test runner doesn't use a makefile that's checked in
|
|
||||||
* and I can't shave this yak now.
|
|
||||||
* This doesn't mean the tunnel is not supposed to work on windows; there
|
|
||||||
* is no fundamental reason it shouldn't, but obviously we should shave
|
|
||||||
* the yak and make it testable there as well.
|
|
||||||
*/
|
|
||||||
#ifndef _WIN32
|
|
||||||
static const char *test_tunnel(void) {
|
|
||||||
struct mg_connection *client, *server;
|
|
||||||
struct mg_mgr mgr;
|
|
||||||
int sentinel = 0;
|
|
||||||
mg_mgr_init(&mgr, NULL);
|
|
||||||
|
|
||||||
mg_tund_bind(&mgr, "localhost:4321");
|
|
||||||
|
|
||||||
server = mg_bind(&mgr, "ws://localhost:4321", tunnel_server_test_handler);
|
|
||||||
mg_set_protocol_http_websocket(server);
|
|
||||||
/*
|
|
||||||
* Connection happens only at the next poll (because we need to give the app
|
|
||||||
* a chance to set MG_F_TUN_DO_NOT_RECONNECT), so let's poll once
|
|
||||||
*/
|
|
||||||
mg_mgr_poll(&mgr, 1);
|
|
||||||
mg_mgr_poll(&mgr, 1);
|
|
||||||
client = mg_connect_http(&mgr, tunnel_client_test_handler,
|
|
||||||
"http://localhost:4321/foo", NULL, NULL);
|
|
||||||
client->user_data = (void *) &sentinel;
|
|
||||||
|
|
||||||
poll_until(&mgr, 1, c_int_eq, &sentinel, (void *) 1);
|
|
||||||
ASSERT_EQ(sentinel, 1);
|
|
||||||
|
|
||||||
mg_mgr_free(&mgr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const char *test_http_chunk(void) {
|
static const char *test_http_chunk(void) {
|
||||||
struct mg_connection nc;
|
struct mg_connection nc;
|
||||||
init_test_connection(&nc);
|
init_test_connection(&nc);
|
||||||
@ -5544,9 +5505,6 @@ static const char *run_tests(const char *filter, double *total_elapsed) {
|
|||||||
RUN_TEST(test_hexdump_file);
|
RUN_TEST(test_hexdump_file);
|
||||||
RUN_TEST(test_basic_auth_helpers);
|
RUN_TEST(test_basic_auth_helpers);
|
||||||
RUN_TEST(test_http_auth);
|
RUN_TEST(test_http_auth);
|
||||||
#ifndef _WIN32
|
|
||||||
RUN_TEST(test_tunnel);
|
|
||||||
#endif
|
|
||||||
#if MG_ENABLE_SSL
|
#if MG_ENABLE_SSL
|
||||||
RUN_TEST(test_ssl);
|
RUN_TEST(test_ssl);
|
||||||
#ifdef OPENSSL_VERSION_NUMBER
|
#ifdef OPENSSL_VERSION_NUMBER
|
||||||
|
Loading…
Reference in New Issue
Block a user