Compare commits

...

2 commits

Author SHA1 Message Date
reemo b6cf731658 Merge branch 'master' of https://patchii.net/reemo/clii
EXTREME woomy.
2023-12-18 20:53:07 -06:00
reemo 4319c22ea1 i now am a judge
and a good judge too
2023-12-18 20:51:18 -06:00
2 changed files with 149 additions and 32 deletions

View file

@ -1,5 +1,30 @@
#include "wsock.h"
/** UTILITIES **/
/*****************/
#define WS_REORDER_BUFLEN (sizeof(long double))
inline int _sys_is_net_order() {
return ((char*)(0xB00B))[0] == 0xB0;
}
void swap_order(char* in, int length) {
if(_sys_is_net_order() || length > WS_REORDER_BUFLEN)
return;
char buf[WS_REORDER_BUFLEN];
for(int i = 0; i < length; ++i)
buf[i] = in[length - i - 1];
memcpy(in, buf, length);
}
void swap_order_copy(char* in, char* out, int length) {
memcpy(out, in, length);
swap_order(out, length);
}
/** DATA BUFFER **/
/*******************/
@ -27,48 +52,67 @@ void buffer_append
(buffer_t* buf, const char* data, int length)
{
if(buf->data != NULL) {
buf->next = buffer_create();
if(buf->next == NULL)
buf->next = buffer_create();
buffer_append(buf->next, data, length);
} else {
buf->data = malloc(length);
strncpy(buf->data, data, length);
buf->length = length;
}
buf->data = malloc(length);
strncpy(buf->data, data, length);
buf->length = length;
}
void buffer_append_str(buffer_t* buf, const char* data) {
buffer_append(buf, data, strlen(data));
}
void _buffer_read(buffer_t* buf, char* out) {
int _buffer_read(buffer_t* buf, char* out, int n) {
int i = 0;
while(buf != NULL) {
strncpy(out + i, buf->data, buf->length);
i += buf->length;
while(buf != NULL && (!n || (n && i < n))) {
if(!n || buf->length <= n - i) {
strncpy(out + i, buf->data, buf->length);
i += buf->length;
buf = buf->next;
} else if(n && buf->length > n - i) {
strncpy(out + i, buf->data, n - i);
i += n - i;
}
}
return i;
}
int buffer_peek(buffer_t* buf, char* out, int length) {
return _buffer_read(buf, out, length);
}
int buffer_peek_str(buffer_t* buf, char* out, int length) {
int read = _buffer_read(buf, out, length);
out[read] = '\0';
return read;
}
int buffer_read(buffer_t* buf, char** out) {
int length = buffer_length(buf);
*out = malloc(length);
_buffer_read(buf, *out);
_buffer_read(buf, *out, 0);
return length;
}
int buffer_read_str(buffer_t* buf, char** out) {
int length = buffer_length(buf);
*out = malloc(length + 1);
out[length] = '\0';
(*out)[length] = '\0';
_buffer_read(buf, *out);
_buffer_read(buf, *out, 0);
return length;
}
int buffer_flush(buffer_t* buf, char** out) {
int length = buffer_read(buf, out);
buffer_clear(buf);
return out;
return length;
}
int buffer_flush_str(buffer_t* buf, char** out) {
@ -105,6 +149,56 @@ void buffer_free(buffer_t* buf) {
/** WEB SOCKET **/
/******************/
typedef struct {
uint8_t fin, opcode, masked, head_length;
uint8_t mask[4];
uint64_t body_length;
} _ws_head_t;
typedef enum {
WS_CONT = 0x0,
WS_TEXT = 0x1,
WS_BIN = 0x2,
WS_CLOSE = 0x8,
WS_PING = 0x9,
WS_PONG = 0xA
} _ws_opcode_t;
int _wsock_header_length(char* head) {
return 2
+ ((head[1] & 0x80) == 0 ? 0 : 4)
+ ((head[1] & 0x7F) < 0x7E ? 0
: ((head[1] & 0x7F) == 0x7E ? 2 : 8));
}
int _wsock_read_header(char* head, _ws_head_t* out) {
out->head_length = _wsock_header_length(head);
out->fin = 0x80 & head[0];
out->opcode = 0x0F & head[0];
out->masked = 0x80 & head[1];
if((head[0] & 0x70) != 0)
return -1;
if((head[0] & 0x0F) > 0x2 && (head[0] & 0x0F) < 0x8)
return -1;
if((head[0] & 0x0F) > 0xA && (head[0] & 0x0F) <= 0xF)
return -1;
int mask_start;
if((head[1] & 0x7F) < 0x7E) {
out->body_length = head[1] & 0x7F;
mask_start = 2;
} else if((head[1] & 0x7F) == 0x7E) {
swap_order_copy(head[2], (char*)out->body_length, 2);
mask_start = 4;
} else {
swap_order_copy(head[2], (char*)out->body_length, 8);
mask_start = 10;
}
if(out->masked)
memcpy(out->mask, head + mask_start, 4);
}
wsock_t* wsock_open
(const char* host, const char* path, uint16_t port)
{
@ -153,8 +247,8 @@ wsock_t* wsock_open
pfd.fd = sock;
pfd.events = POLLIN;
char* end;
int total = 0;
char* end;
while((end = strstr(s_shake, "\r\n\r\n")) == NULL) {
if(total + 1 >= sizeof(s_shake)
|| poll(&pfd, 1, 5000) <= 0)
@ -163,11 +257,14 @@ wsock_t* wsock_open
return NULL;
}
total += recv(sock, s_shake + total,
sizeof(s_shake) - total - 1, 0);
total = recv(sock, s_shake, sizeof(s_shake) - 1, MSG_PEEK);
s_shake[total] = '\0';
}
total = end - s_shake + 3;
recv(sock, s_shake, total, 0);
s_shake[total + 1] = '\0';
const char resp_check[] = "HTTP/1.1 101 Switching Protocols";
if(strncmp(s_shake, resp_check, sizeof(resp_check) - 1) != 0)
{
@ -178,11 +275,8 @@ wsock_t* wsock_open
wsock_t* wsock = malloc(sizeof(wsock_t));
wsock->sock = sock;
wsock->mode = WS_BLOCK;
wsock->buffer = buffer_create();
if(total - 1 != (end - s_shake) + 3)
buffer_append(wsock->buffer, end + 4,
total - 1 - ((end - s_shake) + 3));
wsock->recv_buf = buffer_create();
wsock->send_buf = buffer_create();
return wsock;
}
@ -194,7 +288,15 @@ int wsock_mode_get(wsock_t* ws) {
return ws->mode;
}
int wsock_recv(wsock_t* ws, char** out) {
char buffer[4096];
int got = 0;
do {
//if((ws->mode & WS_NOBLOCK) != 0)
} while((ws->mode & WS_FULL_RECV) != 0);
return got;
}
int wsock_is_open(wsock_t* ws) {
return ws->sock >= 0;
@ -203,7 +305,8 @@ int wsock_is_open(wsock_t* ws) {
void wsock_close(wsock_t* ws) {
// todo: send close frame
shutdown(ws->sock, SHUT_RDWR);
buffer_free(ws->buffer);
buffer_free(ws->recv_buf);
buffer_free(ws->send_buf);
free(ws);
}

View file

@ -1,12 +1,20 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/poll.h>
#include <netdb.h>
/** UTILITIES **/
/*****************/
void swap_order(char*, int);
void swap_order_copy(char*, char*, int);
/** DATA BUFFER **/
/*******************/
@ -24,10 +32,12 @@ int buffer_length(buffer_t*);
void buffer_append(buffer_t*, const char*, int);
void buffer_append_str(buffer_t*, const char*);
char* buffer_read(buffer_t*, int*);
char* buffer_read_str(buffer_t*, int*);
char* buffer_flush(buffer_t*, int*);
char* buffer_flush_str(buffer_t*, int*);
int buffer_peek(buffer_t*, char*, int);
int buffer_peek_str(buffer_t*, char*, int);
int buffer_read(buffer_t*, char**);
int buffer_read_str(buffer_t*, char**);
int buffer_flush(buffer_t*, char**);
int buffer_flush_str(buffer_t*, char**);
void buffer_clear(buffer_t*);
void buffer_free(buffer_t*);
@ -38,13 +48,15 @@ void buffer_free(buffer_t*);
typedef enum {
// block on system calls
WS_BLOCK = 0,
WS_BLOCK = 0,
// do not block on system calls
WS_NOBLOCK = 1,
WS_NOBLOCK = 1,
// block until a full packet is received
WS_FULL_RECV = 2,
WS_FULL_RECV = 2,
// block until a full packet is sent
WS_FULL_SEND = 4
WS_FULL_SEND = 4,
// receive text frames as binary
WS_RECV_ALL_BIN = 8
} ws_mode_t;
// mode options that are not mutually exclusive can be
// concatenated using the OR (|) operator. note that
@ -73,14 +85,16 @@ typedef enum {
typedef struct {
int sock, mode;
buffer_t* buffer;
buffer_t *recv_buf, *send_buf;
} wsock_t;
wsock_t* wsock_open(const char*, const char*, uint16_t);
void wsock_mode_set(wsock_t*, int);
int wsock_mode_get(wsock_t*);
int wsock_recv(wsock_t*,
int wsock_recv(wsock_t*, char**);
int wsock_send(wsock_t*, char*, int);
int wsock_send_str(wsock_t*, char*);
int wsock_is_open(wsock_t*);
void wsock_close(wsock_t*);