Compare commits
2 commits
6cf4ef1bef
...
b6cf731658
Author | SHA1 | Date | |
---|---|---|---|
b6cf731658 | |||
4319c22ea1 |
2 changed files with 149 additions and 32 deletions
137
src/wsock.c
137
src/wsock.c
|
@ -1,5 +1,30 @@
|
||||||
#include "wsock.h"
|
#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 **/
|
/** DATA BUFFER **/
|
||||||
/*******************/
|
/*******************/
|
||||||
|
|
||||||
|
@ -27,48 +52,67 @@ void buffer_append
|
||||||
(buffer_t* buf, const char* data, int length)
|
(buffer_t* buf, const char* data, int length)
|
||||||
{
|
{
|
||||||
if(buf->data != NULL) {
|
if(buf->data != NULL) {
|
||||||
|
if(buf->next == NULL)
|
||||||
buf->next = buffer_create();
|
buf->next = buffer_create();
|
||||||
buffer_append(buf->next, data, length);
|
buffer_append(buf->next, data, length);
|
||||||
}
|
} else {
|
||||||
|
|
||||||
buf->data = malloc(length);
|
buf->data = malloc(length);
|
||||||
strncpy(buf->data, data, length);
|
strncpy(buf->data, data, length);
|
||||||
buf->length = length;
|
buf->length = length;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void buffer_append_str(buffer_t* buf, const char* data) {
|
void buffer_append_str(buffer_t* buf, const char* data) {
|
||||||
buffer_append(buf, data, strlen(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;
|
int i = 0;
|
||||||
while(buf != NULL) {
|
while(buf != NULL && (!n || (n && i < n))) {
|
||||||
|
if(!n || buf->length <= n - i) {
|
||||||
strncpy(out + i, buf->data, buf->length);
|
strncpy(out + i, buf->data, buf->length);
|
||||||
i += 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 buffer_read(buffer_t* buf, char** out) {
|
||||||
int length = buffer_length(buf);
|
int length = buffer_length(buf);
|
||||||
*out = malloc(length);
|
*out = malloc(length);
|
||||||
|
|
||||||
_buffer_read(buf, *out);
|
_buffer_read(buf, *out, 0);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
*out = malloc(length + 1);
|
*out = malloc(length + 1);
|
||||||
out[length] = '\0';
|
(*out)[length] = '\0';
|
||||||
|
|
||||||
_buffer_read(buf, *out);
|
_buffer_read(buf, *out, 0);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int buffer_flush(buffer_t* buf, char** out) {
|
int buffer_flush(buffer_t* buf, char** out) {
|
||||||
int length = buffer_read(buf, out);
|
int length = buffer_read(buf, out);
|
||||||
buffer_clear(buf);
|
buffer_clear(buf);
|
||||||
return out;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int buffer_flush_str(buffer_t* buf, char** out) {
|
int buffer_flush_str(buffer_t* buf, char** out) {
|
||||||
|
@ -105,6 +149,56 @@ void buffer_free(buffer_t* buf) {
|
||||||
/** WEB SOCKET **/
|
/** 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
|
wsock_t* wsock_open
|
||||||
(const char* host, const char* path, uint16_t port)
|
(const char* host, const char* path, uint16_t port)
|
||||||
{
|
{
|
||||||
|
@ -153,8 +247,8 @@ wsock_t* wsock_open
|
||||||
pfd.fd = sock;
|
pfd.fd = sock;
|
||||||
pfd.events = POLLIN;
|
pfd.events = POLLIN;
|
||||||
|
|
||||||
char* end;
|
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
char* end;
|
||||||
while((end = strstr(s_shake, "\r\n\r\n")) == NULL) {
|
while((end = strstr(s_shake, "\r\n\r\n")) == NULL) {
|
||||||
if(total + 1 >= sizeof(s_shake)
|
if(total + 1 >= sizeof(s_shake)
|
||||||
|| poll(&pfd, 1, 5000) <= 0)
|
|| poll(&pfd, 1, 5000) <= 0)
|
||||||
|
@ -163,11 +257,14 @@ wsock_t* wsock_open
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
total += recv(sock, s_shake + total,
|
total = recv(sock, s_shake, sizeof(s_shake) - 1, MSG_PEEK);
|
||||||
sizeof(s_shake) - total - 1, 0);
|
|
||||||
s_shake[total] = '\0';
|
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";
|
const char resp_check[] = "HTTP/1.1 101 Switching Protocols";
|
||||||
if(strncmp(s_shake, resp_check, sizeof(resp_check) - 1) != 0)
|
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_t* wsock = malloc(sizeof(wsock_t));
|
||||||
wsock->sock = sock;
|
wsock->sock = sock;
|
||||||
wsock->mode = WS_BLOCK;
|
wsock->mode = WS_BLOCK;
|
||||||
wsock->buffer = buffer_create();
|
wsock->recv_buf = buffer_create();
|
||||||
if(total - 1 != (end - s_shake) + 3)
|
wsock->send_buf = buffer_create();
|
||||||
buffer_append(wsock->buffer, end + 4,
|
|
||||||
total - 1 - ((end - s_shake) + 3));
|
|
||||||
|
|
||||||
return wsock;
|
return wsock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +288,15 @@ int wsock_mode_get(wsock_t* ws) {
|
||||||
return ws->mode;
|
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) {
|
int wsock_is_open(wsock_t* ws) {
|
||||||
return ws->sock >= 0;
|
return ws->sock >= 0;
|
||||||
|
@ -203,7 +305,8 @@ int wsock_is_open(wsock_t* ws) {
|
||||||
void wsock_close(wsock_t* ws) {
|
void wsock_close(wsock_t* ws) {
|
||||||
// todo: send close frame
|
// todo: send close frame
|
||||||
shutdown(ws->sock, SHUT_RDWR);
|
shutdown(ws->sock, SHUT_RDWR);
|
||||||
buffer_free(ws->buffer);
|
buffer_free(ws->recv_buf);
|
||||||
|
buffer_free(ws->send_buf);
|
||||||
free(ws);
|
free(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
28
src/wsock.h
28
src/wsock.h
|
@ -1,12 +1,20 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
||||||
|
/** UTILITIES **/
|
||||||
|
/*****************/
|
||||||
|
|
||||||
|
void swap_order(char*, int);
|
||||||
|
void swap_order_copy(char*, char*, int);
|
||||||
|
|
||||||
|
|
||||||
/** DATA BUFFER **/
|
/** DATA BUFFER **/
|
||||||
/*******************/
|
/*******************/
|
||||||
|
|
||||||
|
@ -24,10 +32,12 @@ int buffer_length(buffer_t*);
|
||||||
void buffer_append(buffer_t*, const char*, int);
|
void buffer_append(buffer_t*, const char*, int);
|
||||||
void buffer_append_str(buffer_t*, const char*);
|
void buffer_append_str(buffer_t*, const char*);
|
||||||
|
|
||||||
char* buffer_read(buffer_t*, int*);
|
int buffer_peek(buffer_t*, char*, int);
|
||||||
char* buffer_read_str(buffer_t*, int*);
|
int buffer_peek_str(buffer_t*, char*, int);
|
||||||
char* buffer_flush(buffer_t*, int*);
|
int buffer_read(buffer_t*, char**);
|
||||||
char* buffer_flush_str(buffer_t*, int*);
|
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_clear(buffer_t*);
|
||||||
void buffer_free(buffer_t*);
|
void buffer_free(buffer_t*);
|
||||||
|
@ -44,7 +54,9 @@ typedef enum {
|
||||||
// block until a full packet is received
|
// block until a full packet is received
|
||||||
WS_FULL_RECV = 2,
|
WS_FULL_RECV = 2,
|
||||||
// block until a full packet is sent
|
// 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;
|
} ws_mode_t;
|
||||||
// mode options that are not mutually exclusive can be
|
// mode options that are not mutually exclusive can be
|
||||||
// concatenated using the OR (|) operator. note that
|
// concatenated using the OR (|) operator. note that
|
||||||
|
@ -73,14 +85,16 @@ typedef enum {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int sock, mode;
|
int sock, mode;
|
||||||
buffer_t* buffer;
|
buffer_t *recv_buf, *send_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);
|
||||||
void wsock_mode_set(wsock_t*, int);
|
void wsock_mode_set(wsock_t*, int);
|
||||||
int wsock_mode_get(wsock_t*);
|
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*);
|
int wsock_is_open(wsock_t*);
|
||||||
void wsock_close(wsock_t*);
|
void wsock_close(wsock_t*);
|
||||||
|
|
Loading…
Reference in a new issue