Skip to content

Instantly share code, notes, and snippets.

@jsaak
Created October 18, 2016 10:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsaak/433380daaf72a789cbd3794a25b4bf56 to your computer and use it in GitHub Desktop.
Save jsaak/433380daaf72a789cbd3794a25b4bf56 to your computer and use it in GitHub Desktop.
buggy implementation of websocket to tcp gateway, do not use it unless you correct the errors
#include <uv.h>
#include "libwebsockets.h"
struct lws_context *context;
uv_loop_t loop;
static int callback_gateway(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
#define MAX_BUFFER_COUNT 16
struct per_session_data_gateway {
uv_tcp_t socket;
uv_connect_t req_connect;
uv_write_t req_write;
struct lws *wsi;
uv_buf_t buffers[MAX_BUFFER_COUNT];
int buffer_nread[MAX_BUFFER_COUNT];
int buffer_counter;
};
struct per_session_data__http {
int dummy;
};
static struct lws_protocols protocols[] = {
{
"http-only",
callback_http,
sizeof (struct per_session_data__http),
0,
},
{
"binary",
callback_gateway,
sizeof(struct per_session_data_gateway),
4096,
},
{ NULL, NULL, 0, 0 }
};
//set gateway as the default protocol
static const struct lws_protocol_vhost_options pvo_opt = {
NULL,
NULL,
"default",
"1"
};
static const struct lws_protocol_vhost_options pvo = {
NULL,
&pvo_opt,
"gateway",
""
};
int main() {
//init libuv
uv_loop_init(&loop);
//init libwebsockets
struct lws_context_creation_info info;
memset(&info, 0, sizeof info);
info.port = 3344;
info.protocols = protocols;
info.options = LWS_SERVER_OPTION_LIBUV;
info.timeout_secs = 5;
info.gid = -1;
info.uid = -1;
info.pvo = &pvo;
context = lws_create_context(&info);
if (context == NULL) {
lwsl_err("libwebsocket init failed\n");
return -1;
}
lws_uv_initloop(context, &loop, 0);
uv_run(&loop, UV_RUN_DEFAULT);
uv_loop_close(&loop);
lws_context_destroy(context);
}
static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
//buf->base = malloc(suggested_size+LWS_PRE);
//buf->base += LWS_PRE;
//buf->len = suggested_size;
buf->base = malloc(4096);
buf->base += LWS_PRE;
buf->len = 4096-LWS_PRE;
}
static void on_close(uv_handle_t* handle) {
printf("on_close\n");
}
static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
printf("on_read %d\n",nread);
if (nread >= 0) {
if (nread > 0) {
struct per_session_data_gateway *psd = stream->data;
psd->buffers[psd->buffer_counter] = *buf; //store buf
psd->buffer_nread[psd->buffer_counter] = nread;
psd->buffer_counter++;
lws_callback_on_writable(psd->wsi);
}
} else {
printf("on_read error: %s\n", uv_strerror(nread));
uv_close((uv_handle_t*)stream, on_close); //TODO
}
}
static void on_connect(uv_connect_t* connection, int status) {
printf("on_connect %d\n",status);
if (status) {
//printf("-\n");
} else {
connection->handle->data = connection->data;
int ret = uv_read_start(connection->handle, alloc_cb, on_read);
//printf("%d\n",ret);
}
}
void on_write(uv_write_t* req, int status) {
printf("on_write %d\n",status);
if (status) {
printf("uv_write error: %s\n", uv_strerror(status));
return;
}
}
static void my_write(struct per_session_data_gateway *psd, void* data, size_t len) {
printf("my_write %d\n",len);
uv_buf_t buffer;
buffer.base = data;
buffer.len = len;
uv_write(&psd->req_write, (uv_stream_t*)&psd->socket, &buffer, 1, on_write);
}
static int callback_gateway(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
struct per_session_data_gateway *psd = (struct per_session_data_gateway *)user;
switch(reason) {
case LWS_CALLBACK_ESTABLISHED:
uv_tcp_init(&loop, &psd->socket);
struct sockaddr_in dest;
uv_ip4_addr("127.0.0.1", 3333, &dest);
psd->req_connect.data = psd; //store psd
psd->wsi = wsi;
psd->buffer_counter = 0;
uv_tcp_connect(&psd->req_connect, &psd->socket, (const struct sockaddr*)&dest, on_connect);
break;
case LWS_CALLBACK_CLOSED:
uv_close((uv_handle_t*)&psd->socket, on_close);
printf("uv_close\n");
break;
case LWS_CALLBACK_RECEIVE:
my_write(psd,in,len);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
printf("on_callback_writeable buffer_counter:%d\n",psd->buffer_counter);
if (psd->buffer_counter > 0) {
uv_buf_t* buf = &psd->buffers[(psd->buffer_counter)-1];
lws_write(wsi,buf->base,psd->buffer_nread[psd->buffer_counter-1],LWS_WRITE_BINARY);
//free buffer and set it to 0
//TODO lehet már ilyenkor?
free(buf->base-LWS_PRE);
//(buf->base)-LWS_PRE = 0;
//buf->base = 0;
psd->buffer_counter--;
if (psd->buffer_counter > 0) {
lws_callback_on_writable(wsi);
}
}
break;
default:
break;
}
return 0;
}
static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
int ret;
switch(reason) {
case LWS_CALLBACK_HTTP:
ret = lws_serve_http_file(wsi, "./my_websockify.c", "text/plain", NULL, 0);
//return 1;
break;
default:
break;
}
return 0;
}
void stop_gateway() {
if (context) {
lws_libuv_stop(context);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment