aboutsummaryrefslogtreecommitdiff
path: root/src/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/net.c')
-rw-r--r--src/net.c308
1 files changed, 198 insertions, 110 deletions
diff --git a/src/net.c b/src/net.c
index 49eabd7..abab731 100644
--- a/src/net.c
+++ b/src/net.c
@@ -8,10 +8,11 @@
#include <netdb.h>
#include <netinet/tcp.h>
+#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
-#include <netinet/in.h>
-#include <netdb.h>
+#include <sys/poll.h>
+#include <sys/eventfd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
@@ -91,7 +92,7 @@ int chunked_encoding_round(char* input, int length, struct chunked_encoding_stat
for(int i = 0; i < length; i++){
//printf("%i/%i\n", i, length);
if(state->reading_length){
- str_pushl(state->buffer, input + i, 1);
+ str_pushl(state->buffer, input + i, 1);
if(state->buffer->len >= 2 && memmem(state->buffer->c + state->buffer->len - 2, 2, "\r\n", 2)){
@@ -121,9 +122,9 @@ int chunked_encoding_round(char* input, int length, struct chunked_encoding_stat
struct url {
str* proto,
- * domain,
- * port,
- * path;
+ * domain,
+ * port,
+ * path;
};
struct url parse_url(char* url, int len){
@@ -202,7 +203,7 @@ int i_ws_read(lua_State* L){
}
if(len < 0) luaI_error(L, len, "SSL_read error");
-
+
uint64_t payload = 0;
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,
@@ -223,8 +224,8 @@ int i_ws_read(lua_State* L){
payload = (buffer[0] & 0xff) << 8 | (buffer[1] & 0xff);
} else {
for(; (len = SSL_read(data->ssl, buffer + total_len, 8 - total_len)) > 0;){
- total_len += len;
- if(total_len >= 8) break;
+ total_len += len;
+ if(total_len >= 8) break;
}
if(len < 0) luaI_error(L, -1, "SSL_read error");
@@ -246,7 +247,7 @@ int i_ws_read(lua_State* L){
str_free(message);
luaI_error(L, len, "SSL_read error");
}
-
+
lua_newtable(L);
int idx = lua_gettop(L);
luaI_tsetsl(L, idx, "content", message->c, message->len);
@@ -373,7 +374,7 @@ int l_wss(lua_State* L){
luaI_tsetcf(L, idx, "read", i_ws_read);
luaI_tsetcf(L, idx, "write", i_ws_write);
luaI_tsetcf(L, idx, "close", i_ws_close);
-
+
lua_newtable(L);
int meta_idx = lua_gettop(L);
@@ -383,11 +384,11 @@ int l_wss(lua_State* L){
lua_setmetatable(L, idx);
lua_pushvalue(L, idx);
-
+
//verify stuff here
//parray_t* owo = NULL;
//parse_header(a->c, header_eof - a->c, &owo);
-
+
return 1;
}
@@ -519,7 +520,7 @@ int _request(lua_State* L, struct request_state* state){
state->ssl = ssl_connect(state->ctx, state->sock, host);
if(state->ssl == NULL) luaI_error(L, -1, "ssl_connect error");
}
-
+
char* cont = "";
size_t cont_len = 0;
if(params >= 2){
@@ -539,7 +540,9 @@ int _request(lua_State* L, struct request_state* state){
luaI_tsets(L, header_idx, "User-Agent", "lullaby/"MAJOR_VERSION);
if(params >= 3){
- luaI_jointable(L, header_idx, 3);
+ lua_pushvalue(L, header_idx);
+ lua_pushvalue(L, 3);
+ luaI_jointable(L);
}
str* header = str_init("");
@@ -552,7 +555,7 @@ int _request(lua_State* L, struct request_state* state){
str_push(header, lua_tostring(L, -1));
lua_pop(L, 1);
}
-
+
char* action = "GET";
if(params >= 4){
action = (char*)lua_tostring(L, 4);
@@ -561,7 +564,12 @@ int _request(lua_State* L, struct request_state* state){
//char* req = "GET / HTTP/1.1\nHost: amyy.cc\nConnection: Close\n\n";
char* request = calloc(cont_len + header->len + strlen(host) + strlen(path) + 512, sizeof * request);
- sprintf(request, "%s %s HTTP/1.1\r\nHost: %s\r\nConnection: Close%s\r\n\r\n%s", action, path, host, header->c, cont);
+ sprintf(request, "%s %s HTTP/1.1\r\nHost: %s\r\nConnection: Close%s\r\n\r\n%s", action, path, host, header->c, cont);
+
+ if(awa.path != NULL) str_free(awa.path);
+ if(awa.domain != NULL) str_free(awa.domain);
+ if(awa.proto != NULL) str_free(awa.proto);
+ if(awa.port != NULL) str_free(awa.port);
str_free(header);
@@ -595,7 +603,7 @@ int _request(lua_State* L, struct request_state* state){
parray_t* owo = NULL;
//handle errors
- int err = parse_header(a->c, header_eof - a->c, &owo);
+ int err = parse_header(a->c, header_eof - a->c + 2, &owo);
assert(err == 0);
for(int i = 0; i != owo->len; i++){
@@ -610,7 +618,7 @@ int _request(lua_State* L, struct request_state* state){
lua_gettable(L, idx);
int code = atoi(lua_tostring(L, -1));
luaI_tseti(L, idx, "code", code);
-
+
void* encoding = parray_get(owo, "Transfer-Encoding");
//struct _srequest_state *read_state = calloc(sizeof * read_state, 1);
@@ -626,7 +634,7 @@ int _request(lua_State* L, struct request_state* state){
chunked_encoding_round(header_eof + 4, extra_len - 4, chunk_state);
memset(buffer, 0, BUFFER_LEN);
-
+
state->buffer = str_init("");
state->state = chunk_state;
}
@@ -645,11 +653,11 @@ int _request(lua_State* L, struct request_state* state){
str_free(a);
/*SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN | SSL_SENT_SHUTDOWN);
- SSL_shutdown(ssl);
- SSL_free(ssl);
- SSL_CTX_free(ctx);
+ SSL_shutdown(ssl);
+ SSL_free(ssl);
+ SSL_CTX_free(ctx);
- close(sock);*/
+ close(sock);*/
return 1;
}
@@ -667,7 +675,7 @@ void path_parse(struct net_path_t* path, str* raw){
str** reading = &path->path;
- for(int i = 0; i <= raw->len; i++){
+ for(int i = 0; i <= raw->len - 1; i++){
if(raw->len - i > 1){
switch(raw->c[i]){
case '&':
@@ -713,12 +721,12 @@ void* handle_client(void *_arg){
int64_t bite = recv_header(client_fd, &buffer, &header);
header_eof = header - buffer;
-
+
if(bite > 0){
parray_t* table;
//checks for a valid header
- int val = parse_header(buffer, header_eof, &table);
+ int val = parse_header(buffer, header_eof + 2, &table);
if(val == -2) net_error(client_fd, 414);
@@ -746,14 +754,14 @@ void* handle_client(void *_arg){
larray_t* params = NULL;
parray_t* v = NULL;
- if(decoded_err == 1 || paths == NULL){
+ if(decoded_err == 1 || args->paths == NULL){
net_error(client_fd, 400);
} else {
str_push(aa, decoded_path->c);
params = larray_init();
- v = route_match(paths, aa->c, &params);
-
+ v = route_match(args->paths, aa->c, &params);
+
if(sT != NULL)
rolling_file_parse(L, &files_idx, &body_idx, header + 4, sT, bite - header_eof - 4, file_cont);
}
@@ -765,7 +773,7 @@ void* handle_client(void *_arg){
int req_idx = lua_gettop(L);
lua_newtable(L);
int res_idx = lua_gettop(L);
-
+
//handle cookies
if(sC != NULL){
lua_newtable(L);
@@ -815,7 +823,7 @@ void* handle_client(void *_arg){
luaI_tseti(L, req_idx, "_bytes", bite - header_eof - 4);
luaI_tseti(L, req_idx, "client_fd", client_fd);
luaI_tsetcf(L, req_idx, "roll", l_roll);
-
+
//functions
luaI_tsetcf(L, res_idx, "send", l_send);
luaI_tsetcf(L, res_idx, "sendfile", l_sendfile);
@@ -832,7 +840,7 @@ void* handle_client(void *_arg){
lua_newtable(L);
int header_idx = lua_gettop(L);
luaI_tseti(L, header_idx, "Code", 200);
-
+
luaI_tsetv(L, res_idx, "header", header_idx);
//get all function that kinda match
@@ -860,29 +868,29 @@ void* handle_client(void *_arg){
//if request is HEAD, it is valid for GET and HEAD listeners
if(strcmp(wowa->req, "all") == 0 || strcmp(wowa->req, sR->c) == 0 ||
(strcmp(sR->c, "HEAD") == 0 && strcmp(wowa->req, "GET") == 0)){
-
- luaL_loadbuffer(L, wowa->c, wowa->len, "fun");
- int func = lua_gettop(L);
- lua_assign_upvalues(L, func);
-
- lua_pushvalue(L, res_idx); //push methods related to dealing with the request
- lua_pushvalue(L, req_idx); //push info about the request
-
- //call the function
- if(lua_pcall(L, 2, 0, 0) != 0){
- printf("(net thread) %s\n", lua_tostring(L, -1));
- //send an error message if send has not been called
- if(client_fd >= 0) net_error(client_fd, 500);
-
- goto net_end;
- }
-
- //check if res:stop() was called
- lua_pushstring(L, "_stop");
- lua_gettable(L, res_idx);
- if(!lua_isnil(L, -1))
- goto net_end;
-
+
+ luaL_loadbuffer(L, wowa->c, wowa->len, "fun");
+ int func = lua_gettop(L);
+ lua_assign_upvalues(L, func);
+
+ lua_pushvalue(L, res_idx); //push methods related to dealing with the request
+ lua_pushvalue(L, req_idx); //push info about the request
+
+ //call the function
+ if(lua_pcall(L, 2, 0, 0) != 0){
+ fprintf(stderr, "(net thread) %s\n", lua_tostring(L, -1));
+ //send an error message if send has not been called
+ if(client_fd >= 0) net_error(client_fd, 500);
+
+ goto net_end;
+ }
+
+ //check if res:stop() was called
+ lua_pushstring(L, "_stop");
+ lua_gettable(L, res_idx);
+ if(!lua_isnil(L, -1))
+ goto net_end;
+
}
}
}
@@ -923,13 +931,10 @@ net_end:
}
int clean_lullaby_net(lua_State* L){
- if(mime_type != NULL){
- map_clear(mime_type, FREE);
- }
return 0;
}
-int start_serv(lua_State* L, int port){
+int start_serv(lua_State* L, int port, parray_t* paths, struct net_server_state* state){
parse_mimetypes();
//need these on windows for sockets (stupid)
#ifdef _WIN32
@@ -939,10 +944,11 @@ int start_serv(lua_State* L, int port){
int server_fd;
struct sockaddr_in server_addr;
+ struct pollfd fds[2];
//open the socket
if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- p_fatal("error opening socket\n");
+ luaI_error(L, -2, "error opening socket\n");
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
@@ -950,60 +956,120 @@ int start_serv(lua_State* L, int port){
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&(int){1}, sizeof(int)) < 0)
- p_fatal("SO_REUSEADDR refused\n");
+ luaI_error(L, -3, "SO_REUSEADDR refused\n");
//bind to port
if(bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
- p_fatal("failed to bind to port\n");
+ luaI_error(L, -4, "failed to bind to port\n");
if(listen(server_fd, max_con) < 0)
- p_fatal("failed to listen\n");
+ luaI_error(L, -5, "failed to listen\n");
+
+ int efd = eventfd(NETEV_DEFAULT, 0);
+ state->event_fd = efd;
+
+ memset(fds, 0, sizeof(fds));
+ fds[0].fd = server_fd;
+ fds[0].events = POLLIN;
+
+ fds[1].fd = efd;
+ fds[1].events = POLLIN;
for(;;){
- struct sockaddr_in client_addr;
- socklen_t client_addr_len = sizeof(client_addr);
- int* client_fd = malloc(sizeof(int));
+ int rc = poll(fds, 2, -1);
- if((*client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_addr_len)) < 0)
- p_fatal("failed to accept\n");
+ if(rc <= 0)
+ p_fatal("poll() <= 0\n");
- if(threads >= max_con){
- //deny request
- net_error(*client_fd, 503);
- close(*client_fd);
- free(client_fd);
+ if(fds[1].revents == POLLIN){
+ uint64_t v;
+ read(efd, &v, sizeof(uint64_t));
- continue;
- }
+ switch(v){
+ case NETEV_DEFAULT:
+ break;
+ case NETEV_CLOSE_EVENT:
+ goto net_end;
+ }
+ }
+
+ if(fds[0].revents == POLLIN){
+ struct sockaddr_in client_addr;
+ socklen_t client_addr_len = sizeof(client_addr);
+ int* client_fd = malloc(sizeof(int));
+
+ if((*client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_addr_len)) < 0)
+ p_fatal("failed to accept\n");
- thread_arg_struct* args = malloc(sizeof * args);
+ if(threads >= max_con){
+ //deny request
+ net_error(*client_fd, 503);
+ close(*client_fd);
+ free(client_fd);
- args->fd = *client_fd;
- args->port = port;
- args->cli = client_addr;
- args->L = luaL_newstate();
+ continue;
+ }
+
+ thread_arg_struct* args = malloc(sizeof * args);
+
+ args->fd = *client_fd;
+ args->port = port;
+ args->cli = client_addr;
+ args->L = luaL_newstate();
+ args->paths = paths;
+
+ int old_top = lua_gettop(L);
+ lua_getglobal(L, "_G");
+
+ luaL_openlibs(args->L);
+ luaI_copyvars(L, args->L);
+ luaL_openlibs(args->L);
+ lua_settop(L, old_top);
+ lua_set_global_table(args->L);
- int old_top = lua_gettop(L);
- lua_getglobal(L, "_G");
+ threads++;
- luaI_copyvars(L, args->L);
- lua_settop(L, old_top);
- lua_set_global_table(args->L);
+ //send request to handle_client()
+ pthread_t thread_id;
+ pthread_create(&thread_id, NULL, handle_client, (void*)args);
+ pthread_detach(thread_id);
+
+ //handle_client((void*)args);
+ free(client_fd);
+ }
+ }
- threads++;
+net_end:
+ if(mime_type != NULL) map_clear(mime_type, FREE);
+ mime_type = NULL;
+ close(server_fd);
+ close(efd);
+ free(state);
- //send request to handle_client()
- pthread_t thread_id;
- pthread_create(&thread_id, NULL, handle_client, (void*)args);
- pthread_detach(thread_id);
-
- //handle_client((void*)args);
- free(client_fd);
+ for(int i = 0; i != paths->len; i++){
+ struct sarray_t* path = paths->P[i].value;
+ for(int z = 0; z != path->len; z++){
+ free(path->cs[z]->c);
+ free(path->cs[z]);
+ }
+ free(path->cs);
+ free(path);
+ str_free(paths->P[i].key);
}
+ parray_lclear(paths);
+ lua_pushnil(L);
+ return 1;
}
+//TODO reformat all of this code and the structs (use more common/generic ones)
+//
+//this may have a memory leak (net-nested.lua) when called inside of a net thread. look into fixing when rewritten
int l_req_com(lua_State* L, char* req){
+ lua_pushstring(L, "paths");
+ lua_gettable(L, 1);
+ parray_t* paths = lua_touserdata(L, -1);
+
lua_pushstring(L, "port");
lua_gettable(L, 1);
int port = luaL_checkinteger(L, -1);
@@ -1017,16 +1083,13 @@ int l_req_com(lua_State* L, char* req){
str* uwu = str_init("");
lua_pushvalue(L, 3);
lua_dump(L, writer, (void*)uwu, 0);
-
+
awa = malloc(sizeof * awa);
awa->c = uwu->c;
awa->len = uwu->len;
strcpy(awa->req, req);
free(uwu); //yes this *should* be str_free but awa kinda owns it now:p
- if(paths == NULL)
- paths = parray_init();
-
//please free this
void* v_old_paths = parray_get(paths, portss->c);
struct sarray_t* old_paths;
@@ -1046,10 +1109,10 @@ int l_req_com(lua_State* L, char* req){
}
#define gen_reqs(T)\
-int l_##T##q (lua_State* L){\
- l_req_com(L, #T);\
- return 1;\
-}
+ int l_##T##q (lua_State* L){\
+ l_req_com(L, #T);\
+ return 1;\
+ }
gen_reqs(GET);
gen_reqs(HEAD);
gen_reqs(POST);
@@ -1061,6 +1124,23 @@ gen_reqs(TRACE);
gen_reqs(PATCH);
gen_reqs(all); //non standard lol, like expressjs 'use' keyword :3
+//https://stackoverflow.com/questions/12050072/how-to-wake-up-a-thread-being-blocked-by-select-poll-poll-function-from-anothe
+//something like this would make closeing safer
+int l_net_close(lua_State* L){
+ lua_pushstring(L, "_");
+ lua_gettable(L, 1);
+ struct net_server_state* state = lua_touserdata(L, -1);
+
+ if(state->event_fd == -1){
+ state->event_fd = -2;
+ } else {
+ uint64_t v = NETEV_CLOSE_EVENT;
+ write(state->event_fd, &v, sizeof(uint64_t));
+ }
+
+ return 0;
+}
+
int l_listen(lua_State* L){
if(lua_gettop(L) != 2) {
@@ -1070,8 +1150,11 @@ int l_listen(lua_State* L){
p_fatal("(arg:1) expected a function");
}
+ struct net_server_state *state = malloc(sizeof * state);
+ state->event_fd = -1;
+
int port = luaL_checkinteger(L, 2);
-
+
lua_newtable(L);
int mt = lua_gettop(L);
luaI_tsetcf(L, mt, "GET", l_GETq);
@@ -1084,16 +1167,21 @@ int l_listen(lua_State* L){
luaI_tsetcf(L, mt, "TRACE", l_TRACEq);
luaI_tsetcf(L, mt, "PATCH", l_PATCHq);
luaI_tsetcf(L, mt, "all", l_allq);
-
- lua_pushstring(L, "port");
- lua_pushvalue(L, 2);
- lua_settable(L, -3);
+
+ luaI_tsetcf(L, mt, "close", l_net_close);
+ luaI_tsetv(L, mt, "port", 2);
+
+ parray_t* paths = parray_init();
+ luaI_tsetlud(L, mt, "paths", paths);
+ luaI_tsetlud(L, mt, "_", state);
lua_pushvalue(L, 1); //the function
- lua_pushvalue(L, -2); //the server table
+ lua_pushvalue(L, mt); //the server table
lua_pcall(L, 1, 0, 0);
- start_serv(L, port);
- return 0;
+ if(state->event_fd == -2) luaI_error(L, -2, "closed");
+
+ return start_serv(L, port, paths, state);
+ ;
}