soon i will be able to do things
maybe if i read the tao te ching n+1 times i will finally understand it
This commit is contained in:
parent
9e878405e3
commit
f48f399022
3 changed files with 88 additions and 42 deletions
|
@ -33,6 +33,7 @@ struct {
|
||||||
/************/
|
/************/
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
srand(time(NULL));
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
|
|
||||||
switch(argc) {
|
switch(argc) {
|
||||||
|
|
114
src/wsock.c
114
src/wsock.c
|
@ -67,6 +67,9 @@ void buffer_append_str(buffer_t* buf, const char* data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int _buffer_read(buffer_t* buf, char* out, int n) {
|
int _buffer_read(buffer_t* buf, char* out, int n) {
|
||||||
|
if(buffer_length(buf) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(buf != NULL && (!n || (n && i < n))) {
|
while(buf != NULL && (!n || (n && i < n))) {
|
||||||
if(!n || buf->length <= n - i) {
|
if(!n || buf->length <= n - i) {
|
||||||
|
@ -88,13 +91,17 @@ int buffer_peek(buffer_t* buf, char* out, int length) {
|
||||||
|
|
||||||
int buffer_peek_str(buffer_t* buf, char* out, int length) {
|
int buffer_peek_str(buffer_t* buf, char* out, int length) {
|
||||||
int read = _buffer_read(buf, out, length);
|
int read = _buffer_read(buf, out, length);
|
||||||
|
if(read)
|
||||||
out[read] = '\0';
|
out[read] = '\0';
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
int buffer_read(buffer_t* buf, char** out) {
|
int buffer_read(buffer_t* buf, char** out) {
|
||||||
int length = buffer_length(buf);
|
int length = buffer_length(buf);
|
||||||
|
if(length)
|
||||||
*out = malloc(length);
|
*out = malloc(length);
|
||||||
|
else
|
||||||
|
*out = NULL;
|
||||||
|
|
||||||
_buffer_read(buf, *out, 0);
|
_buffer_read(buf, *out, 0);
|
||||||
return length;
|
return length;
|
||||||
|
@ -102,8 +109,11 @@ int buffer_read(buffer_t* buf, char** out) {
|
||||||
|
|
||||||
int buffer_read_str(buffer_t* buf, char** out) {
|
int buffer_read_str(buffer_t* buf, char** out) {
|
||||||
int length = buffer_length(buf);
|
int length = buffer_length(buf);
|
||||||
|
if(length) {
|
||||||
*out = malloc(length + 1);
|
*out = malloc(length + 1);
|
||||||
(*out)[length] = '\0';
|
(*out)[length] = '\0';
|
||||||
|
} else
|
||||||
|
*out = NULL;
|
||||||
|
|
||||||
_buffer_read(buf, *out, 0);
|
_buffer_read(buf, *out, 0);
|
||||||
return length;
|
return length;
|
||||||
|
@ -160,19 +170,24 @@ int _wsock_read_header(char* head, _ws_head_t* out) {
|
||||||
out->head_length = _wsock_header_length(head);
|
out->head_length = _wsock_header_length(head);
|
||||||
out->fin = 0x80 & head[0];
|
out->fin = 0x80 & head[0];
|
||||||
out->opcode = 0x0F & head[0];
|
out->opcode = 0x0F & head[0];
|
||||||
if(out->opcode == WS_CONT &&
|
|
||||||
out->first->opcode == WS_OP_UNDEF)
|
|
||||||
return -1;
|
|
||||||
if(out->opcode != WS_CONT && !WS_OP_IS_CTRL(out->opcode))
|
|
||||||
out->first_opcode = out->opcode;
|
|
||||||
out->masked = 0x80 & head[1];
|
out->masked = 0x80 & head[1];
|
||||||
|
|
||||||
if((head[0] & 0x70) != 0)
|
// garbage in check
|
||||||
|
if((head[0] & 0x70) != 0
|
||||||
|
|| ((head[0] & 0x0F) > 0x2 && (head[0] & 0x0F) < 0x8)
|
||||||
|
|| ((head[0] & 0x0F) > 0xA && (head[0] & 0x0F) <= 0xF))
|
||||||
return -1;
|
return -1;
|
||||||
if((head[0] & 0x0F) > 0x2 && (head[0] & 0x0F) < 0x8)
|
// invalid parameters check
|
||||||
return -1;
|
if((out->opcode == WS_CONT &&
|
||||||
if((head[0] & 0x0F) > 0xA && (head[0] & 0x0F) <= 0xF)
|
out->first_opcode == WS_OP_UNDEF)
|
||||||
|
|| (out->opcode != WS_CONT &&
|
||||||
|
!WS_IS_OP_CTRL(out->opcode) &&
|
||||||
|
out->first_opcode != WS_OP_UNDEF)
|
||||||
|
|| (WS_IS_OP_CTRL(out->opcode) && !out->fin))
|
||||||
return -1;
|
return -1;
|
||||||
|
// cache first opcode of fragmented data set
|
||||||
|
if(out->opcode != WS_CONT && !WS_OP_IS_CTRL(out->opcode))
|
||||||
|
out->first_opcode = out->opcode;
|
||||||
|
|
||||||
int mask_start;
|
int mask_start;
|
||||||
if((head[1] & 0x7F) < 0x7E) {
|
if((head[1] & 0x7F) < 0x7E) {
|
||||||
|
@ -189,6 +204,16 @@ int _wsock_read_header(char* head, _ws_head_t* out) {
|
||||||
memcpy(out->mask, head + mask_start, 4);
|
memcpy(out->mask, head + mask_start, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _wsock_mask(char* mask, char* msg, int length) {
|
||||||
|
for(int i = 0; i < length; ++i)
|
||||||
|
msg[i] = msg[i] ^ mask[i % 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _wsock_gen_mask(char* mask) {
|
||||||
|
for(int i = 0; i < 4; ++i)
|
||||||
|
mask[i] = rand() % 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
wsock_t* wsock_open
|
wsock_t* wsock_open
|
||||||
(const char* host, const char* path, uint16_t port)
|
(const char* host, const char* path, uint16_t port)
|
||||||
{
|
{
|
||||||
|
@ -264,12 +289,11 @@ wsock_t* wsock_open
|
||||||
|
|
||||||
wsock_t* wsock = malloc(sizeof(wsock_t));
|
wsock_t* wsock = malloc(sizeof(wsock_t));
|
||||||
wsock->sock = sock;
|
wsock->sock = sock;
|
||||||
wsock->mode = WS_BLOCK;
|
wsock->mode = WS_BLOCK | WS_FULL_RECV;
|
||||||
wsock->head_buf.first_opcode = WS_OP_UNDEF;
|
wsock->head_buf.first_opcode = WS_OP_UNDEF;
|
||||||
wsock->head_buf.opcode = WS_OP_UNDEF;
|
wsock->head_buf.opcode = WS_OP_UNDEF;
|
||||||
wsock->recv_buf = buffer_create();
|
wsock->recv_buf = buffer_create();
|
||||||
wsock->frag_buf = buffer_create();
|
wsock->frag_buf = buffer_create();
|
||||||
wsock->ctrl_buf = buffer_create();
|
|
||||||
return wsock;
|
return wsock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,64 +361,85 @@ int wsock_recv(wsock_t* ws, char** out) {
|
||||||
// work provided wsock_recv is called enough times
|
// work provided wsock_recv is called enough times
|
||||||
// that the wsock buffer eventually received all
|
// that the wsock buffer eventually received all
|
||||||
// information off of the recv buffer
|
// information off of the recv buffer
|
||||||
int buflen = buffer_length(
|
int buflen = buffer_length(ws->recv_buf);
|
||||||
WS_OP_IS_CTRL(ws->head_buf.opcode)
|
|
||||||
? ws->ctrl_buf : ws->recv_buf);
|
|
||||||
flags = (ws->mode & WS_NOBLOCK) ? MSG_DONTWAIT : 0;
|
flags = (ws->mode & WS_NOBLOCK) ? MSG_DONTWAIT : 0;
|
||||||
got = _srecv(ws, tmp, __MIN(sizeof(tmp), ws->head_buf.body_length - buflen), flags);
|
got = _srecv(ws, tmp, __MIN(sizeof(tmp), ws->head_buf.body_length - buflen), flags);
|
||||||
|
|
||||||
if(got < 0)
|
if(got < 0)
|
||||||
return got;
|
return got;
|
||||||
else if(got > 0)
|
else if(got > 0)
|
||||||
buffer_append((WS_OP_IS_CTRL(ws->head_buf.opcode)
|
buffer_append(ws->recv_buf, tmp, got);
|
||||||
? ws->ctrl_buf : ws->recv_buf), tmp, got);
|
|
||||||
|
|
||||||
if(got + buflen < ws->head_buf.body_length && got >= 0) {
|
if(got + buflen < ws->head_buf.body_length) {
|
||||||
got = 0;
|
got = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* body;
|
||||||
|
int body_length = buffer_flush(ws->recv_buf, &packet);
|
||||||
|
if(body != NULL) {
|
||||||
|
if(ws->head_buf.masked)
|
||||||
|
_ws_mask(body, ws->head_buf.mask, body_length);
|
||||||
|
if(!WS_PACKET_IS_CTRL(ws->head_buf.opcode)) {
|
||||||
|
buffer_append(ws->frag_buf, body, body_length);
|
||||||
|
free(body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(ws->head_buf.opcode) {
|
switch(ws->head_buf.opcode) {
|
||||||
case WS_CONT:
|
case WS_CONT:
|
||||||
case WS_TEXT:
|
case WS_TEXT:
|
||||||
case WS_BIN:
|
case WS_BIN:
|
||||||
|
if(ws->head_buf.fin) {
|
||||||
|
if(ws->head_buf.first_opcode == WS_TEXT
|
||||||
|
&& !(ws->mode & WS_RECV_ALL_BIN))
|
||||||
|
got = buffer_flush_str(ws->frag_buf, out);
|
||||||
|
else
|
||||||
|
got = buffer_flush(ws->frag_buf, out);
|
||||||
|
ws->head_buf.first_opcode = WS_OP_UNDEF;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case WS_CLOSE:
|
case WS_CLOSE:
|
||||||
wsock_close(ws);
|
wsock_close(ws);
|
||||||
return -1;
|
return -1;
|
||||||
case WS_PING:
|
case WS_PING:
|
||||||
|
wsock_send_raw(ws, WS_PONG, body, body_length);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ws->head_buf.fin) {
|
if(WS_OP_IS_CTRL(ws->head_buf.opcode))
|
||||||
if(!WS_OP_IS_CTRL(ws->opcode)) {
|
free(body);
|
||||||
buffer_clear(ws->recv_buf);
|
|
||||||
ws->head_buf.first_opcode = WS_OP_UNDEF;
|
|
||||||
} else
|
|
||||||
buffer_clear(ws->ctrl_buf);
|
|
||||||
} else if(WS_OP_IS_CTRL(ws->opcode)) {
|
|
||||||
wsock_close(ws);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int opcode_was = ws->head_buf.opcode;
|
int opcode_was = ws->head_buf.opcode;
|
||||||
ws->head_buf.opcode = WS_OP_UNDEF;
|
ws->head_buf.opcode = WS_OP_UNDEF;
|
||||||
if(WS_OP_IS_CTRL(opcode_was) ||
|
if(WS_OP_IS_CTRL(opcode_was) || !ws->head_buf.fin) {
|
||||||
(!WS_OP_IS_CTRL(opcode_was) &&
|
got = 0;
|
||||||
ws->head_buf.body_length == 0))
|
|
||||||
continue;
|
continue;
|
||||||
else
|
} else
|
||||||
break;
|
break;
|
||||||
} while(ws->mode & WS_FULL_RECV);
|
} while(ws->mode & WS_FULL_RECV);
|
||||||
|
|
||||||
|
// catches a weird potential case where the server sends
|
||||||
|
// empty data frames which will exit the main loop with
|
||||||
|
// the same condition as a nonblocking call that would
|
||||||
|
// block. to prevent confusion and the proper functioning
|
||||||
|
// of the WS_FULL_RECV flag, call recursively in this case
|
||||||
|
if(ws->mode & WS_FULL_RECV && got == 0)
|
||||||
|
return wsock_recv(ws, out);
|
||||||
|
else
|
||||||
return got;
|
return got;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int wsock_send_raw
|
||||||
|
(wsock_t* ws, int opcode, char* body, int length)
|
||||||
|
{
|
||||||
|
if(!wsock_is_open(ws))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int wsock_is_open(wsock_t* ws) {
|
int wsock_is_open(wsock_t* ws) {
|
||||||
return ws->sock >= 0;
|
return ws->sock >= 0;
|
||||||
}
|
}
|
||||||
|
@ -413,7 +458,6 @@ void wsock_free(wsock_t* ws) {
|
||||||
wsock_close(ws);
|
wsock_close(ws);
|
||||||
buffer_free(ws->recv_buf);
|
buffer_free(ws->recv_buf);
|
||||||
buffer_free(ws->frag_buf);
|
buffer_free(ws->frag_buf);
|
||||||
buffer_free(ws->ctrl_buf);
|
|
||||||
free(ws);
|
free(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ typedef enum {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int sock, mode;
|
int sock, mode;
|
||||||
_ws_head_t head_buf;
|
_ws_head_t head_buf;
|
||||||
buffer_t *recv_buf, *frag_buf, *ctrl_buf;
|
buffer_t *recv_buf, *frag_buf;
|
||||||
} wsock_t;
|
} wsock_t;
|
||||||
|
|
||||||
wsock_t* wsock_open(const char*, const char*, uint16_t);
|
wsock_t* wsock_open(const char*, const char*, uint16_t);
|
||||||
|
@ -117,6 +117,7 @@ void wsock_mode_set(wsock_t*, int);
|
||||||
int wsock_mode_get(wsock_t*);
|
int wsock_mode_get(wsock_t*);
|
||||||
|
|
||||||
int wsock_recv(wsock_t*, char**);
|
int wsock_recv(wsock_t*, char**);
|
||||||
|
int wsock_send_raw(wsock_t*, int, char*, int);
|
||||||
int wsock_send(wsock_t*, char*, int);
|
int wsock_send(wsock_t*, char*, int);
|
||||||
int wsock_send_str(wsock_t*, char*);
|
int wsock_send_str(wsock_t*, char*);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue