aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--builtins.c5
-rw-r--r--builtins.h11
-rw-r--r--makefile9
-rw-r--r--network.c27
-rw-r--r--network.h7
-rw-r--r--websocket.c (renamed from ws_proto.c)64
-rw-r--r--websocket.h6
-rw-r--r--websocksy.c76
-rw-r--r--websocksy.h8
10 files changed, 147 insertions, 67 deletions
diff --git a/.gitignore b/.gitignore
index 0ac4e99..23d0915 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
*.swp
websocksy
+*.o
diff --git a/builtins.c b/builtins.c
index fa73260..d5b081f 100644
--- a/builtins.c
+++ b/builtins.c
@@ -1,3 +1,8 @@
+#include <string.h>
+
+#include "websocksy.h"
+#include "builtins.h"
+
#define UTF8_BYTE(a) ((a & 0xC0) == 0x80)
/*
diff --git a/builtins.h b/builtins.h
new file mode 100644
index 0000000..926d5bb
--- /dev/null
+++ b/builtins.h
@@ -0,0 +1,11 @@
+/* The builtin `defaultpeer` backend */
+uint64_t backend_defaultpeer_init();
+uint64_t backend_defaultpeer_configure(char* key, char* value);
+ws_peer_info backend_defaultpeer_query(char* endpoint, size_t protocols, char** protocol, size_t headers, ws_http_header* header, websocket* ws);
+void backend_defaultpeer_cleanup();
+
+/* Built-in framing functions */
+int64_t framing_auto(uint8_t* data, size_t length, size_t last_read, ws_operation* opcode, void** framing_data, char* config);
+int64_t framing_binary(uint8_t* data, size_t length, size_t last_read, ws_operation* opcode, void** framing_data, char* config);
+int64_t framing_separator(uint8_t* data, size_t length, size_t last_read, ws_operation* opcode, void** framing_data, char* config);
+int64_t framing_newline(uint8_t* data, size_t length, size_t last_read, ws_operation* opcode, void** framing_data, char* config);
diff --git a/makefile b/makefile
index 0a9c4ae..4623e49 100644
--- a/makefile
+++ b/makefile
@@ -1,10 +1,13 @@
CFLAGS=-g -Wall -Wpedantic
LDLIBS=-lnettle
+OBJECTS=builtins.o network.o websocket.o
+
all: websocksy
-websocksy: websocksy.c websocksy.h ws_proto.c builtins.c
- $(CC) $(CFLAGS) $(LDLIBS) $< -o $@
+websocksy: websocksy.c websocksy.h $(OBJECTS)
+ $(CC) $(CFLAGS) $(LDLIBS) $< -o $@ $(OBJECTS)
clean:
- rm websocksy
+ $(RM) $(OBJECTS)
+ $(RM) websocksy
diff --git a/network.c b/network.c
index 9719b27..2ecee4b 100644
--- a/network.c
+++ b/network.c
@@ -1,3 +1,19 @@
+#include "network.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/*
+ * Create a file descriptor connected to a socket peer.
+ * Client sockets will be connected, listening sockets will be bound.
+ * Returns -1 in case of failure, a valid fd otherwise.
+ */
int network_socket(char* host, char* port, int socktype, int listener){
int fd = -1, status, yes = 1, flags;
struct addrinfo hints = {
@@ -81,7 +97,12 @@ int network_socket(char* host, char* port, int socktype, int listener){
return fd;
}
+/*
+ * Send arbitrary data over multiple writes if necessary.
+ * Returns 0 on success
+ */
int network_send(int fd, uint8_t* data, size_t length){
+ //TODO probably should introduce send buffering at some point
ssize_t total = 0, sent;
while(total < length){
sent = send(fd, data + total, length - total, 0);
@@ -94,6 +115,10 @@ int network_send(int fd, uint8_t* data, size_t length){
return 0;
}
+/*
+ * Send string data over multiple writes if necessary.
+ * Returns 0 on success
+ */
int network_send_str(int fd, char* data){
return network_send(fd, (uint8_t*) data, strlen(data));
-} \ No newline at end of file
+}
diff --git a/network.h b/network.h
new file mode 100644
index 0000000..50c8e18
--- /dev/null
+++ b/network.h
@@ -0,0 +1,7 @@
+#include <stdint.h>
+#include <stdlib.h>
+
+/* Socket interface convenience functions */
+int network_socket(char* host, char* port, int socktype, int listener);
+int network_send(int fd, uint8_t* data, size_t length);
+int network_send_str(int fd, char* data);
diff --git a/ws_proto.c b/websocket.c
index c75fe22..c90c71e 100644
--- a/ws_proto.c
+++ b/websocket.c
@@ -1,3 +1,14 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "websocket.h"
+#include "network.h"
+
#define RFC6455_MAGIC_KEY "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
#define WS_FRAME_HEADER_LEN 16
@@ -8,9 +19,6 @@
#define WS_GET_MASK(a) ((a & 0x80) >> 7)
#define WS_GET_LEN(a) ((a & 0x7F))
-static size_t socks = 0;
-static websocket* sock = NULL;
-
int ws_close(websocket* ws, ws_close_reason code, char* reason){
size_t p;
ws_peer_info empty_peer = {
@@ -72,37 +80,15 @@ int ws_close(websocket* ws, ws_close_reason code, char* reason){
}
int ws_accept(int listen_fd){
- size_t n = 0;
-
websocket ws = {
.ws_fd = accept(listen_fd, NULL, NULL),
.peer_fd = -1
};
- //try to find a slot to occupy
- for(n = 0; n < socks; n++){
- if(sock[n].ws_fd == -1){
- break;
- }
- }
-
- //none found, need to extend
- if(n == socks){
- sock = realloc(sock, (socks + 1) * sizeof(websocket));
- if(!sock){
- close(ws.ws_fd);
- fprintf(stderr, "Failed to allocate memory\n");
- return 1;
- }
- socks++;
- }
-
- sock[n] = ws;
-
- return 0;
+ return client_register(&ws);
}
-int ws_handle_new(websocket* ws){
+static int ws_handle_new(websocket* ws){
size_t u;
char* path, *proto;
@@ -129,13 +115,13 @@ int ws_handle_new(websocket* ws){
return 0;
}
-int ws_upgrade_http(websocket* ws){
+static int ws_upgrade_http(websocket* ws){
if(ws->websocket_version == 13
&& ws->socket_key
&& ws->want_upgrade == 3){
//find and connect peer
- if(connect_peer(ws)){
+ if(client_connect(ws)){
ws_close(ws, ws_close_http, "500 Peer connection failed");
return 0;
}
@@ -196,7 +182,7 @@ int ws_upgrade_http(websocket* ws){
return 1;
}
-int ws_handle_http(websocket* ws){
+static int ws_handle_http(websocket* ws){
char* header, *value;
ssize_t p;
@@ -275,13 +261,13 @@ int ws_handle_http(websocket* ws){
}
else{
//limit the number of stored headers to prevent abuse
- ws_close(ws, ws_close_http, "500 Header limit");
+ //ws_close(ws, ws_close_http, "500 Header limit");
}
return 0;
}
//returns bytes handled
-size_t ws_frame(websocket* ws){
+static size_t ws_frame(websocket* ws){
size_t u;
uint64_t payload_length = 0;
uint16_t* payload_len16 = (uint16_t*) (ws->read_buffer + 2);
@@ -389,6 +375,9 @@ size_t ws_frame(websocket* ws){
case ws_frame_ping:
break;
case ws_frame_pong:
+ if(ws_send_frame(ws, ws_frame_pong, payload, payload_length)){
+ ws_close(ws, ws_close_unexpected, "Failed to send ping");
+ }
break;
default:
//unknown frame type received
@@ -500,14 +489,3 @@ int ws_data(websocket* ws){
}
return rv;
}
-
-void ws_cleanup(){
- size_t n;
- for(n = 0; n < socks; n++){
- ws_close(sock + n, ws_close_shutdown, "Shutting down");
- }
-
- free(sock);
- sock = NULL;
- socks = 0;
-}
diff --git a/websocket.h b/websocket.h
new file mode 100644
index 0000000..f2a4500
--- /dev/null
+++ b/websocket.h
@@ -0,0 +1,6 @@
+#include "websocksy.h"
+
+int ws_close(websocket* ws, ws_close_reason code, char* reason);
+int ws_accept(int listen_fd);
+int ws_send_frame(websocket* ws, ws_operation opcode, uint8_t* data, size_t len);
+int ws_data(websocket* ws);
diff --git a/websocksy.c b/websocksy.c
index 6ab0f81..aa0cf77 100644
--- a/websocksy.c
+++ b/websocksy.c
@@ -10,6 +10,11 @@
#include <fcntl.h>
#include <ctype.h>
+#include "websocksy.h"
+#include "builtins.h"
+#include "network.h"
+#include "websocket.h"
+
/* TODO
* - TLS
* - config parsing
@@ -19,16 +24,14 @@
* - framing function discovery / registry
*/
-/*
- * Main loop condition, to be set from signal handler
- */
+/* Main loop condition, to be set from signal handler */
static volatile sig_atomic_t shutdown_requested = 0;
-#include "websocksy.h"
+/* Core client registry */
+static size_t socks = 0;
+static websocket* sock = NULL;
-/*
- * Lowercase input string in-place
- */
+/* Lowercase input string in-place */
char* xstr_lower(char* in){
size_t n;
for(n = 0; n < strlen(in); n++){
@@ -37,12 +40,7 @@ char* xstr_lower(char* in){
return in;
}
-#include "network.c"
-#include "builtins.c"
-
-/*
- * WebSocket interface & peer discovery configuration
- */
+/* Daemon configuration */
static struct {
char* host;
char* port;
@@ -57,7 +55,46 @@ static struct {
.backend.cleanup = backend_defaultpeer_cleanup
};
-int connect_peer(websocket* ws){
+/* Push a new client to the registry */
+int client_register(websocket* ws){
+ size_t n = 0;
+
+ //try to find a slot to occupy
+ for(n = 0; n < socks; n++){
+ if(sock[n].ws_fd == -1){
+ break;
+ }
+ }
+
+ //none found, need to extend
+ if(n == socks){
+ sock = realloc(sock, (socks + 1) * sizeof(websocket));
+ if(!sock){
+ close(ws->ws_fd);
+ fprintf(stderr, "Failed to allocate memory\n");
+ return 1;
+ }
+ socks++;
+ }
+
+ sock[n] = *ws;
+
+ return 0;
+}
+
+void client_cleanup(){
+ size_t n;
+ for(n = 0; n < socks; n++){
+ ws_close(sock + n, ws_close_shutdown, "Shutting down");
+ }
+
+ free(sock);
+ sock = NULL;
+ socks = 0;
+}
+
+/* Establish peer connection for negotiated websocket */
+int client_connect(websocket* ws){
int rv = 1;
ws->peer = config.backend.query(ws->request_path, ws->protocols, ws->protocol, ws->headers, ws->header, ws);
@@ -71,6 +108,7 @@ int connect_peer(websocket* ws){
ws->peer.framing = framing_auto;
}
+ //TODO connection establishment should be async in the future
switch(ws->peer.transport){
case peer_tcp_client:
ws->peer_fd = network_socket(ws->peer.host, ws->peer.port, SOCK_STREAM, 0);
@@ -100,19 +138,17 @@ int connect_peer(websocket* ws){
return rv;
}
-#include "ws_proto.c"
-
/*
* Signal handler, attached to SIGINT
*/
-void signal_handler(int signum){
+static void signal_handler(int signum){
shutdown_requested = 1;
}
/*
* Usage info
*/
-int usage(char* fn){
+static int usage(char* fn){
fprintf(stderr, "\nwebsocksy v%s - Proxy between websockets and 'real' sockets\n", WEBSOCKSY_VERSION);
fprintf(stderr, "Usage:\n");
fprintf(stderr, "\t%s [-p <port>] [-l <listen address>] [-b <targeting backend>]\n", fn);
@@ -124,7 +160,7 @@ int args_parse(int argc, char** argv){
return 0;
}
-int ws_peer_data(websocket* ws){
+static int ws_peer_data(websocket* ws){
ssize_t bytes_read, bytes_left = sizeof(ws->peer_buffer) - ws->peer_buffer_offset;
int64_t bytes_framed;
//default to a binary frame
@@ -268,7 +304,7 @@ int main(int argc, char** argv){
if(config.backend.cleanup){
config.backend.cleanup();
}
- ws_cleanup();
+ client_cleanup();
close(listen_fd);
return 0;
}
diff --git a/websocksy.h b/websocksy.h
index 59ec5b2..f50bb46 100644
--- a/websocksy.h
+++ b/websocksy.h
@@ -1,3 +1,5 @@
+#ifndef WEBSOCKSY_HEADER_INCLUDED
+#define WEBSOCKSY_HEADER_INCLUDED
#include <stdint.h>
#include <stdlib.h>
#include <nettle/sha1.h>
@@ -199,3 +201,9 @@ typedef struct /*_ws_backend*/ {
ws_backend_query query;
ws_backend_cleanup cleanup;
} ws_backend;
+
+/* Internal helper functions */
+char* xstr_lower(char* in);
+int client_register(websocket* ws);
+int client_connect(websocket* ws);
+#endif