From db2611fcad18f73572dd1b344e4197536086be53 Mon Sep 17 00:00:00 2001 From: ame Date: Sun, 15 Feb 2026 04:08:16 -0600 Subject: ssl server support, websocket upgrades, and net changes --- src/net/common.h | 14 +++- src/net/lua.c | 109 +++++++++++++++---------- src/net/lua.h | 1 + src/net/luai.c | 4 +- src/net/ssl.h | 2 + src/net/util.c | 98 +++++++---------------- src/net/util.h | 7 +- src/net/websocket.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/net/websocket.h | 16 ++++ 9 files changed, 357 insertions(+), 119 deletions(-) create mode 100644 src/net/ssl.h create mode 100644 src/net/websocket.c create mode 100644 src/net/websocket.h (limited to 'src/net') 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 +#include 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 -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 +#include + +//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); -- cgit v1.2.3