aboutsummaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/net')
-rw-r--r--src/net/common.h14
-rw-r--r--src/net/lua.c109
-rw-r--r--src/net/lua.h1
-rw-r--r--src/net/luai.c4
-rw-r--r--src/net/ssl.h2
-rw-r--r--src/net/util.c98
-rw-r--r--src/net/util.h7
-rw-r--r--src/net/websocket.c225
-rw-r--r--src/net/websocket.h16
9 files changed, 357 insertions, 119 deletions
diff --git a/src/net/common.h b/src/net/common.h
index 6bb161c..6d2f625 100644
--- a/src/net/common.h
+++ b/src/net/common.h
@@ -17,6 +17,7 @@
#include "../types/str.h"
#include "../types/parray.h"
#include "../types/map.h"
+#include "ssl.h"
#define max_con 200
//2^42
@@ -35,8 +36,16 @@ struct file_parse {
int dash_count, table_idx;
};
+struct net_data {
+ SSL* ssl;
+ SSL_CTX* ctx;
+ int sock;
+ str* buffer;
+};
+
typedef struct {
- int fd, ser;
+ struct net_data* ctx;
+ int ser;
int port;
lua_State* L;
struct sockaddr_in cli;
@@ -51,6 +60,9 @@ struct lchar {
struct net_server_state {
int event_fd;
+ int ssl;
+ str* ssl_key;
+ str* ssl_crt;
};
struct sarray_t {
diff --git a/src/net/lua.c b/src/net/lua.c
index f005185..d2b0d35 100644
--- a/src/net/lua.c
+++ b/src/net/lua.c
@@ -1,6 +1,9 @@
#include "lua.h"
#include "luai.h"
+#include "util.h"
#include "common.h"
+#include "../hash/fnv.h"
+#include "websocket.h"
int l_write(lua_State* L){
int res_idx = 1;
@@ -12,11 +15,12 @@ int l_write(lua_State* L){
int head = strcmp(luaL_checkstring(L, -1), "HEAD") == 0;
lua_pushvalue(L, res_idx);
- lua_pushstring(L, "client_fd");
+ lua_pushstring(L, "_");
lua_gettable(L, res_idx);
- int client_fd = luaL_checkinteger(L, -1);
+ struct net_data* ctx = lua_touserdata(L, -1);
+
- client_fd_errors(client_fd);
+ client_fd_errors(ctx->sock);
size_t len;
char* content = (char*)luaL_checklstring(L, 2, &len);
@@ -42,7 +46,7 @@ int l_write(lua_State* L){
resp = str_init(content);
}
- send(client_fd, resp->c, resp->len, MSG_NOSIGNAL);
+ net_ctx_write(ctx, resp->c, resp->len);
str_free(resp);
return 0;
@@ -51,11 +55,11 @@ int l_write(lua_State* L){
int l_send(lua_State* L){
int res_idx = 1;
lua_pushvalue(L, res_idx);
- lua_pushstring(L, "client_fd");
+ lua_pushstring(L, "_");
lua_gettable(L, res_idx);
- int client_fd = luaL_checkinteger(L, -1);
+ struct net_data* ctx = lua_touserdata(L, -1);
- client_fd_errors(client_fd);
+ client_fd_errors(ctx->sock);
size_t len;
char* content = (char*)luaL_checklstring(L, 2, &len);
@@ -75,13 +79,12 @@ int l_send(lua_State* L){
} else
i_write_header(L, header, &resp, content, len);
- send(client_fd, resp->c, resp->len, MSG_NOSIGNAL);
+ net_ctx_write(ctx, resp->c, resp->len);
+
+ if(ctx->ssl != NULL) SSL_shutdown(ctx->ssl);
+ else closesocket(ctx->sock);
+ ctx->sock = -1;
- //
- lua_pushstring(L, "client_fd");
- lua_pushinteger(L, -1);
- lua_settable(L, res_idx);
- closesocket(client_fd);
//printf("%i | %i\n'%s'\n%i\n",client_fd,a,resp->c,resp->len);
str_free(resp);
return 0;
@@ -91,15 +94,14 @@ int l_close(lua_State* L){
int res_idx = 1;
lua_pushvalue(L, res_idx);
- lua_pushstring(L, "client_fd");
+ lua_pushstring(L, "_");
lua_gettable(L, res_idx);
- int client_fd = luaL_checkinteger(L, -1);
- client_fd_errors(client_fd);
+ struct net_data* ctx = lua_touserdata(L, -1);
+ client_fd_errors(ctx->sock);
- lua_pushstring(L, "client_fd");
- lua_pushinteger(L, -1);
- lua_settable(L, res_idx);
- closesocket(client_fd);
+ if(ctx->ssl != NULL) SSL_shutdown(ctx->ssl);
+ else closesocket(ctx->sock);
+ ctx->sock = -1;
return 0;
}
@@ -127,7 +129,7 @@ int l_roll(lua_State* L){
lua_gettable(L, 1);
int64_t bytes = luaL_checkinteger(L, -1);
- lua_pushstring(L, "Content-Length");
+ lua_pushstring(L, "content-length");
lua_gettable(L, 1);
if(lua_type(L, -1) == LUA_TNIL) {
lua_pushinteger(L, -1);
@@ -139,30 +141,31 @@ int l_roll(lua_State* L){
struct file_parse* data = (void*)lua_topointer(L, -1);
lua_pushvalue(L, 1);
- lua_pushstring(L, "client_fd");
+ lua_pushstring(L, "_");
lua_gettable(L, 1);
- int client_fd = luaL_checkinteger(L, -1);
- client_fd_errors(client_fd);
+ struct net_data* ctx = lua_touserdata(L, -1);
+
+ client_fd_errors(ctx->sock);
- fd_set rfd;
- FD_ZERO(&rfd);
- FD_SET(client_fd, &rfd);
+ //fd_set rfd;
+ //FD_ZERO(&rfd);
+ //FD_SET(client_fd, &rfd);
//printf("* %li / %li\n", bytes, content_length);
if(bytes >= content_length){
lua_pushinteger(L, -1);
return 1;
}
- if(select(client_fd+1, &rfd, NULL, NULL, &((struct timeval){.tv_sec = 0, .tv_usec = 0})) == 0){
+ /*if(select(client_fd+1, &rfd, NULL, NULL, &((struct timeval){.tv_sec = 0, .tv_usec = 0})) == 0){
lua_pushinteger(L, 0);
return 1;
- }
+ }*/
//time_start(recv)
if(alen == -1) alen = content_length - bytes;
char* buffer = malloc(alen * sizeof * buffer);
- int r = recv(client_fd, buffer, alen, 0);
+ int r = net_ctx_read(ctx, buffer, alen);
if(r <= 0){
lua_pushinteger(L, r - 1);
return 1;
@@ -173,7 +176,7 @@ int l_roll(lua_State* L){
lua_pushinteger(L, bytes + r);
lua_settable(L, 1);
- lua_pushstring(L, "Body");
+ lua_pushstring(L, "body");
lua_gettable(L, 1);
int body_idx = lua_gettop(L);
@@ -183,7 +186,7 @@ int l_roll(lua_State* L){
//time_start(parse)
rolling_file_parse(L, &files_idx, &body_idx, buffer, NULL, r, data);
//time_end("parse", parse)
- luaI_tsetv(L, 1, "Body", body_idx);
+ luaI_tsetv(L, 1, "body", body_idx);
luaI_tsetv(L, 1, "files", files_idx);
free(buffer);
@@ -214,17 +217,17 @@ int l_sendfile(lua_State* L){
luaI_assert(L, !access(path, R_OK) /*missing permissions*/);
lua_pushvalue(L, res_idx);
- lua_pushstring(L, "client_fd");
+ lua_pushstring(L, "_");
lua_gettable(L, res_idx);
- int client_fd = luaL_checkinteger(L, -1);
- client_fd_errors(client_fd);
+ struct net_data* ctx = lua_touserdata(L, -1);
+ client_fd_errors(ctx->sock);
lua_pushvalue(L, res_idx);
lua_pushstring(L, "header");
lua_gettable(L, -2);
int header = lua_gettop(L);
- lua_pushstring(L, "Content-Type");
+ lua_pushstring(L, "content-type");
lua_gettable(L, header);
char* ext = strrchr(path, '.');
@@ -232,7 +235,7 @@ int l_sendfile(lua_State* L){
char* content_type = map_get(mime_type, ext + 1);
if(content_type)
- {luaI_tsets(L, header, "Content-Type", content_type);}
+ {luaI_tsets(L, header, "content-type", content_type);}
}
char* buffer = calloc(sizeof* buffer, bsize + 1);
@@ -243,24 +246,24 @@ int l_sendfile(lua_State* L){
char size[256];
sprintf(size, "%li", sz);
- luaI_tsets(L, header, "Content-Length", size);
+ luaI_tsets(L, header, "content-length", size);
if(attachment) {
char disp[256];
sprintf(disp, "attachment; filename=\"%s\"", filename);
- luaI_tsets(L, header, "Content-Disposition", disp);
+ luaI_tsets(L, header, "content-disposition", disp);
} else {
- luaI_tsets(L, header, "Content-Disposition", "inline;");
+ luaI_tsets(L, header, "content-disposition", "inline;");
}
str* r;
i_write_header(L, header, &r, "", 0);
- send(client_fd, r->c, r->len, MSG_NOSIGNAL);
+ net_ctx_write(ctx, r->c, r->len);
str_free(r);
for(size_t i = 0; i < sz; i += bsize){
fread(buffer, sizeof * buffer, bsize, fp);
- if(send(client_fd, buffer, bsize > sz - i ? sz - i : bsize, MSG_NOSIGNAL) == -1)
+ if(net_ctx_write(ctx, buffer, bsize > sz - i ? sz - i : bsize) == -1)
break;
}
@@ -269,3 +272,25 @@ int l_sendfile(lua_State* L){
return 0;
}
+
+int l_connection_upgrade(lua_State* L){
+ int res_idx = 1;
+ lua_getfield(L, res_idx, "req");
+ int req_idx = 2;
+
+ lua_getfield(L, req_idx, "upgrade");
+ uint64_t hash, len;
+ uint8_t* s = (uint8_t*)luaL_checklstring(L, -1, &len);
+ hash = fnv_1(s, len, v_1);
+
+ switch(hash){
+ case 0xf042f81495060e72: //websocket
+ l_websocket_upgrade(L);
+ break;
+ default:
+ luaI_error(L, -1, "can't upgrade");
+ break;
+ }
+
+ return 0;
+}
diff --git a/src/net/lua.h b/src/net/lua.h
index b1e96fc..492a999 100644
--- a/src/net/lua.h
+++ b/src/net/lua.h
@@ -6,3 +6,4 @@ int l_close(lua_State* L);
int l_stop(lua_State* L);
int l_roll(lua_State* L);
int l_sendfile(lua_State* L);
+int l_connection_upgrade(lua_State* L);
diff --git a/src/net/luai.c b/src/net/luai.c
index 0b63d18..dc39720 100644
--- a/src/net/luai.c
+++ b/src/net/luai.c
@@ -11,7 +11,7 @@ void i_write_header(lua_State* L, int header_top, str** _resp, char* content, si
for(;lua_next(L, header_top) != 0;){
char* key = (char*)luaL_checklstring(L, -2, NULL);
- if(strcmp(key, "Code") != 0){
+ if(strcmp(key, "code") != 0){
str_push(header_vs, key);
str_push(header_vs, ": ");
str_push(header_vs, (char*)luaL_checklstring(L, -1, NULL));
@@ -21,7 +21,7 @@ void i_write_header(lua_State* L, int header_top, str** _resp, char* content, si
}
lua_pushvalue(L, header_top);
- lua_pushstring(L, "Code");
+ lua_pushstring(L, "code");
lua_gettable(L, header_top);
int code = luaL_checkinteger(L, -1);
diff --git a/src/net/ssl.h b/src/net/ssl.h
new file mode 100644
index 0000000..4473ced
--- /dev/null
+++ b/src/net/ssl.h
@@ -0,0 +1,2 @@
+#include <openssl/ssl.h>
+#include <openssl/err.h>
diff --git a/src/net/util.c b/src/net/util.c
index 62b394c..cc478e4 100644
--- a/src/net/util.c
+++ b/src/net/util.c
@@ -1,7 +1,8 @@
#include "common.h"
#include "util.h"
+#include <ctype.h>
-int64_t recv_header(int client_fd, char** _buffer, char** header_eof){
+int64_t recv_header(struct net_data* data, char** _buffer, char** header_eof){
char* buffer = calloc(sizeof* buffer, BUFFER_SIZE);
*_buffer = buffer;
int64_t len = 0;
@@ -9,7 +10,7 @@ int64_t recv_header(int client_fd, char** _buffer, char** header_eof){
*header_eof = 0;
for(;;){
- n = recv(client_fd, buffer + len, BUFFER_SIZE, 0);
+ n = net_ctx_read(data, buffer + len, BUFFER_SIZE);
if(n <= 0){
//printf("%s %i\n", strerror(errno), errno);
@@ -34,70 +35,9 @@ int64_t recv_header(int client_fd, char** _buffer, char** header_eof){
}
}
-/**
- * @brief calls recv into buffer until everything is read
- *
- */
-// deprecated!! replaced by recv_header (above)
-int64_t recv_full_buffer(int client_fd, char** _buffer, int* header_eof, int* state){
- char* header, *buffer = malloc(BUFFER_SIZE * sizeof * buffer);
- memset(buffer, 0, BUFFER_SIZE);
- int64_t len = 0;
- *header_eof = -1;
- int n, content_len = -1;
- uint64_t con_len_full = 0;
- //printf("&_\n");
- for(;;){
- n = recv(client_fd, buffer + len, BUFFER_SIZE, 0);
- if(n < 0){
- *_buffer = buffer;
- printf("%s %i\n",strerror(errno),errno);
- if(*header_eof == -1) return -2; //dont even try w/ request, no header to read
- return -1; //well the header is fine atleast
-
- };
- if(*header_eof == -1 && (header = strstr(buffer, "\r\n\r\n")) != NULL){
- *header_eof = header - buffer;
- char* cont_len_raw = strstr(buffer, "Content-Length: ");
-
- if(cont_len_raw == NULL) {
- len += n;
- *_buffer = buffer;
- return len;
- }
-
- str* cont_len_str = str_init("");
- if(cont_len_raw == NULL) abort();
- //i is length of 'Content-Length: '
- for(int i = 16; cont_len_raw[i] != '\r'; i++) str_pushl(cont_len_str, cont_len_raw + i, 1);
- con_len_full = strtol(cont_len_str->c, NULL, 10);
- //if(content_len < 0) p_fatal("idk");
- str_free(cont_len_str);
- if(con_len_full > max_content_length) {
- *_buffer = buffer;
- *state = (len + n != con_len_full + *header_eof + 4);
- return len + n;
- }
- content_len = 1;
- buffer = realloc(buffer, con_len_full + *header_eof + 4 + BUFFER_SIZE);
- if(buffer == NULL) p_fatal("unable to allocate");
- }
-
- len += n;
- if(len >= MAX_HEADER_SIZE){
- *_buffer = buffer;
- return -2;//p_fatal("too large");
- }
- if(*header_eof == -1){
- buffer = realloc(buffer, len + BUFFER_SIZE + 1);
- memset(buffer + len, 0, n + 1);
- }
-
-
- if(content_len != -1 && len - *header_eof - 4 >= con_len_full) break;
- }
- *_buffer = buffer;
- return len;
+void lowercase(char* c, uint64_t len){
+ for(int i = 0; i != len; i++)
+ c[i] = tolower(c[i]);
}
#define max_uri_len 4096
@@ -116,8 +56,8 @@ int parse_header(char* buffer, int header_eof, parray_t** _table){
for(; oi != header_eof; oi++){
if(buffer[oi] == ' ' || buffer[oi] == '\n'){
if(buffer[oi] == '\n') current->c[current->len - 1] = 0;
- if(item < 3) parray_set(table, item == 0 ? "Request" :
- item == 1 ? "Path" : "Version", (void*)str_init(current->c));
+ if(item < 3) parray_set(table, item == 0 ? "request" :
+ item == 1 ? "path" : "version", (void*)str_init(current->c));
str_clear(current);
item++;
if(buffer[oi] == '\n') break;
@@ -152,6 +92,7 @@ int parse_header(char* buffer, int header_eof, parray_t** _table){
//todo: figure out system to handle this
str* id = (str*)parray_get(table, sw->c);
if(id != NULL) str_free(id);
+ lowercase(sw->c, sw->len);
parray_set(table, sw->c, (void*)str_init(current->c));
str_clear(current);
str_free(sw);
@@ -159,7 +100,7 @@ int parse_header(char* buffer, int header_eof, parray_t** _table){
key = 1;
}
continue;
- } else str_pushl(current, buffer + i, 1);
+ } else str_pushc(current, buffer[i]);
}
if(sw != NULL){
parray_set(table, sw->c, (void*)str_init(current->c));
@@ -299,6 +240,7 @@ int content_disposition(str* src, parray_t** _dest){
return 1;
}
+#warning "leak, last calloc"
int match_param(char* path, char* match, parray_t* arr){
int pi, index, imatch, start, mi;
mi = pi = imatch = start = 0;
@@ -523,10 +465,10 @@ void _parse_mimetypes(){
}
-int net_error(int fd, int code){
+int net_error(struct net_data* ctx, int code){
char out[512] = {0};
sprintf(out, "HTTP/1.1 %i %s\n\n", code, http_code(code));
- send(fd, out, strlen(out), MSG_NOSIGNAL);
+ net_ctx_write(ctx, out, strlen(out));
return 0;
}
@@ -557,3 +499,17 @@ int percent_decode(str* input, str** _output){
*_output = output;
return 0;
}
+
+int net_ctx_read(struct net_data* data, void* buffer, size_t c){
+ if(data->ssl == NULL){
+ return read(data->sock, buffer, c);
+ }
+ return SSL_read(data->ssl, buffer, c);
+}
+
+int net_ctx_write(struct net_data* data, void* buffer, size_t c){
+ if(data->ssl == NULL){
+ return write(data->sock, buffer, c);
+ }
+ return SSL_write(data->ssl, buffer, c);
+}
diff --git a/src/net/util.h b/src/net/util.h
index a54ac95..8b11e85 100644
--- a/src/net/util.h
+++ b/src/net/util.h
@@ -12,8 +12,7 @@
* @param {int*} pointer to an int, will be where the header ends
* @return {int64_t} bytes read, -1 if the body was damaged, -2 if the header was
*/
-int64_t recv_full_buffer(int client_fd, char** _buffer, int* header_eof, int* state);
-int64_t recv_header(int client_fd, char** _buffer, char** header_eof);
+int64_t recv_header(struct net_data* ctx, char** _buffer, char** header_eof);
/**
* @brief converts the request buffer into a parray_t
@@ -55,7 +54,9 @@ int match_param(char* path, char* match, parray_t* arr);
void parse_mimetypes();
-int net_error(int fd, int code);
+int net_error(struct net_data* data, int code);
int percent_decode(str* input, str** _output);
+int net_ctx_read(struct net_data* data, void* buffer, size_t c);
+int net_ctx_write(struct net_data* data, void* buffer, size_t c);
diff --git a/src/net/websocket.c b/src/net/websocket.c
new file mode 100644
index 0000000..af37f32
--- /dev/null
+++ b/src/net/websocket.c
@@ -0,0 +1,225 @@
+#include "websocket.h"
+#include "common.h"
+#include "util.h"
+#include "../lua.h"
+#include "../hash/sha01.h"
+#include "../encode/base64.h"
+#include <limits.h>
+#include <ctype.h>
+
+//why?????
+const char* magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+
+//calloc or zero {out}
+void hex_decode(char* in, char* out, uint64_t* outlen){
+ uint64_t len = 0;
+ for(int i = 0; in[i] != '\0'; i++, len++){
+ int value = 0;
+ char c = in[i];
+ if(c >= '0' && c <= '9')
+ value = c - '0';
+ else if(c >= 'A' && c <= 'F')
+ value = 10 + (c - 'A');
+ else if(c >= 'a' && c <= 'f')
+ value = 10 + (c - 'a');
+
+ out[(i/2)] += value << (((i + 1) % 2) * 4);
+ //out[i/2] += strtoul((char[]){in[i], in[i+1]}, 0, 16);
+ }
+
+ *outlen = len/2;
+}
+
+struct ws_frame_info ws_frame_decode(char* buffer){
+ struct ws_frame_info frame_info = {.fin = (buffer[0] >> 7) & 1, .rsv1 = (buffer[0] >> 6) & 1,
+ .rsv2 = (buffer[0] >> 5) & 1, .rsv3 = (buffer[0] >> 4) & 1, .opcode = buffer[0] & 0b1111,
+ .mask = (buffer[1] >> 7) & 1, .payload = buffer[1] & 0b1111111};
+ return frame_info;
+}
+
+void ws_frame_build(struct ws_frame_info frame, uint64_t extended, char* mkey, str* out){
+ uint8_t d = (frame.fin << 7) | (frame.rsv1 << 6) | (frame.rsv2 << 5) | (frame.rsv3 << 4) | frame.opcode;
+ str_pushc(out, d);
+ frame.payload = extended;
+ if(extended > 125) frame.payload = 126;
+ if(extended > UINT16_MAX) frame.payload = 127;
+ d = (frame.mask << 7) | frame.payload;
+ str_pushc(out, d);
+
+ if(frame.payload == 126){
+ uint16_t sh = extended;
+ for(int i = 2; i != 0; i--)
+ str_pushc(out, ((uint8_t*)&sh)[i - 1]);
+ } else if(frame.payload == 127){
+ for(int i = 8; i != 0; i--)
+ str_pushc(out, ((uint8_t*)&extended)[i - 1]);
+ }
+
+ if(frame.mask){
+ str_pushl(out, mkey, 4);
+ }
+}
+
+#define BUFFER_LEN 4096
+
+int ws_read(struct net_data* data, struct ws_frame_info* frame_info){
+ char buffer[BUFFER_LEN] = {0};
+ int total_len = 0;
+ int len;
+
+ for(; (len = net_ctx_read(data, buffer + total_len, 2 - total_len)) > 0;){
+ total_len += len;
+ if(total_len >= 2) break;
+ }
+
+ if(len < 0 || total_len <= 0) return -1;
+
+ uint64_t payload = 0;
+ *frame_info = ws_frame_decode(buffer);
+ memset(buffer, 0, total_len);
+ total_len = 0;
+
+ if(frame_info->payload <= 125) payload = frame_info->payload;
+ else if(frame_info->payload == 126) {
+ for(; (len = net_ctx_read(data, buffer + total_len, 2 - total_len)) > 0;){
+ total_len += len;
+ if(total_len >= 2) break;
+ }
+
+ if(len < 0) return -1;
+
+ payload = (buffer[0] & 0xff) << 8 | (buffer[1] & 0xff);
+ } else {
+ for(; (len = net_ctx_read(data, buffer + total_len, 8 - total_len)) > 0;){
+ total_len += len;
+ if(total_len >= 8) break;
+ }
+
+ if(len < 0) return -1;
+
+ payload = ((uint64_t)buffer[0] & 0xff) << 56 | ((uint64_t)buffer[1] & 0xff) << 48 | ((uint64_t)buffer[2] & 0xff) << 40 |
+ ((uint64_t)buffer[3] & 0xff) << 32 | (buffer[4] & 0xff) << 24 | (buffer[5] & 0xff) << 16 | (buffer[6] & 0xff) << 8 | (buffer[7] & 0xff);
+ }
+
+ total_len = 0;
+ uint8_t mask[4] = {0};
+ if(frame_info->mask){
+ for(; (len = net_ctx_read(data, buffer + total_len, 4 - total_len)) > 0;){
+ total_len += len;
+ if(total_len >= 4) break;
+ }
+ mask[0] = buffer[0];
+ mask[1] = buffer[1];
+ mask[2] = buffer[2];
+ mask[3] = buffer[3];
+ }
+
+ uint64_t i = 0;
+ memset(buffer, 0, BUFFER_LEN);
+ for(; data->buffer->len != payload && (len = net_ctx_read(data, buffer, lesser(payload - data->buffer->len, BUFFER_LEN))) > 0;){
+ if(frame_info->mask){
+ for(int z = 0; z != len; z++,i++)
+ buffer[z] ^= mask[i % 4];
+ }
+ str_pushl(data->buffer, buffer, len);
+ memset(buffer, 0, len);
+ }
+
+ if(len < 0) return -1;
+
+ return 1;
+}
+
+int l_ws_read(lua_State* L){
+ lua_getfield(L, 1, "_ws");
+ struct net_data* data = lua_touserdata(L, -1);
+ struct ws_frame_info frame = {};
+ int c = ws_read(data, &frame);
+ if(c == -1){
+ luaI_error(L, -1, "SSL_read error");
+ str_clear(data->buffer);
+ }
+
+ lua_newtable(L);
+ int idx = lua_gettop(L);
+ luaI_tsetsl(L, idx, "content", data->buffer->c, data->buffer->len);
+ luaI_tseti(L, idx, "opcode", frame.opcode);
+
+ str_clear(data->buffer);
+ return 1;
+}
+
+int l_ws_write(lua_State* L){
+ lua_getfield(L, 1, "_ws");
+ struct net_data* data = lua_touserdata(L, -1);
+ struct ws_frame_info frame = {};
+ frame.rsv1 = 0;
+ frame.fin = 1;
+ frame.mask = 0;
+ frame.opcode = 0b0001;
+
+ uint64_t len;
+ const char* s = lua_tolstring(L, 2, &len);
+
+ str* f = str_init("");
+ ws_frame_build(frame, len, NULL, f);
+ str_pushl(f, s, len);
+ write(data->sock, f->c, f->len);
+ str_free(f);
+
+ return 0;
+}
+
+int l_websocket_upgrade(lua_State* L){
+ int res_idx = 1;
+ int req_idx = 2;
+
+ lua_getfield(L, res_idx, "_");
+ struct net_data* ctx = lua_touserdata(L, -1);
+
+ lua_getfield(L, req_idx, "sec-websocket-key");
+ const char* wskey = luaL_checklstring(L, -1, NULL);
+ str* newkey = str_init(wskey);
+ str_push(newkey, magic);
+ char* sha = calloc(1512, sizeof * sha);
+ printf("%s\n", newkey->c);
+ sha1((uint8_t*)newkey->c, newkey->len, sha);
+ printf("%s\n", sha);
+ char* bin = calloc(512, sizeof * bin);
+ uint64_t len;
+ hex_decode(sha, bin, &len);
+ char* b64 = calloc(512 * 3, sizeof * b64);
+ en_base64(bin, len, b64);
+
+ char* upgrade = calloc(8192, sizeof * upgrade);
+ sprintf(upgrade, "HTTP/1.1 101 Switching Protocols\r\n"
+ "upgrade: websocket\r\n"
+ "connection: upgrade\r\n"
+ "sec-websocket-accept: %s\r\n"
+ "\r\n", b64);
+
+ printf("%s\n", upgrade);
+ net_ctx_write(ctx, upgrade, strlen(upgrade));
+ free(upgrade);
+ free(sha);
+ free(bin);
+ free(b64);
+ str_free(newkey);
+
+ struct net_data *data = calloc(1, sizeof * data);
+ data->sock = ctx->sock;
+ data->ssl = ctx->ssl;
+ data->ctx = ctx->ctx;
+ data->buffer = str_init("");
+
+ luaI_tsetnil(L, req_idx, "roll");
+ luaI_tsetlud(L, res_idx, "_ws", data);
+#warning "missing ws commands"
+ luaI_tsetcf(L, res_idx, "send", l_ws_write);
+ //luaI_tsetcf(L, res_idx, "write", );
+ //luaI_tsetcf(L, res_idx, "sendfile", );
+ luaI_tsetcf(L, res_idx, "read", l_ws_read);
+ //luaI_tsetcf(L, res_idx, "close", );
+
+ return 1;
+}
diff --git a/src/net/websocket.h b/src/net/websocket.h
new file mode 100644
index 0000000..98ae1ae
--- /dev/null
+++ b/src/net/websocket.h
@@ -0,0 +1,16 @@
+#include "../lua.h"
+#include "common.h"
+
+struct ws_frame_info {
+ int fin;
+ int rsv1;
+ int rsv2;
+ int rsv3;
+ int opcode;
+ int mask;
+ int payload;
+};
+
+int ws_read(struct net_data* data, struct ws_frame_info* frame_info);
+struct ws_frame_info ws_frame_decode(char* buffer);
+int l_websocket_upgrade(lua_State* L);