139 lines
3.8 KiB
C
139 lines
3.8 KiB
C
#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>
|
|
#include <errno.h>
|
|
|
|
/** UTILITIES **/
|
|
/*****************/
|
|
|
|
#define __MAX(A, B) ((A) > (B) ? (A) : (B))
|
|
#define __MIN(A, B) ((A) < (B) ? (A) : (B))
|
|
|
|
void swap_order(char*, int);
|
|
void swap_order_copy(char*, char*, int);
|
|
|
|
|
|
/** DATA BUFFER **/
|
|
/*******************/
|
|
|
|
struct buffer_t {
|
|
char* data;
|
|
int length;
|
|
struct buffer_t* next;
|
|
};
|
|
typedef struct buffer_t buffer_t;
|
|
|
|
buffer_t* buffer_create();
|
|
|
|
int buffer_is_empty(buffer_t*);
|
|
int buffer_length(buffer_t*);
|
|
void buffer_append(buffer_t*, const char*, int);
|
|
void buffer_append_str(buffer_t*, const char*);
|
|
|
|
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*);
|
|
|
|
|
|
/** WEB SOCKET **/
|
|
/******************/
|
|
|
|
#define WS_MAX_LENGTH 0xFFFFFF
|
|
#define WS_INTERNAL_BUFLEN 4096
|
|
#define WS_OP_UNDEF 0xFF
|
|
#define WS_OP_IS_CTRL(A) (A >= WS_CLOSE)
|
|
|
|
typedef enum {
|
|
// block on system calls
|
|
WS_BLOCK = 0,
|
|
// do not block on system calls
|
|
WS_NOBLOCK = 1,
|
|
// block until a full packet is received
|
|
WS_FULL_RECV = 2,
|
|
// block until a full packet is sent
|
|
WS_FULL_SEND = 4,
|
|
// receive text frames as binary
|
|
WS_RECV_ALL_BIN = 8,
|
|
// send text frames as binary
|
|
WS_SEND_ALL_BIN = 16
|
|
} ws_mode_t;
|
|
// mode options that are not mutually exclusive can be
|
|
// concatenated using the OR (|) operator. note that
|
|
// WS_BLOCK and WS_NOBLOCK control blocking only on the
|
|
// system socket functions, whereas WS_FULL_RECV and
|
|
// WS_FULL_SEND will block on the protocol level, until
|
|
// a packet is fully sent or received
|
|
|
|
// for example, WS_BLOCK alone will block until data is
|
|
// available, but will immediately return nothing if the
|
|
// data received is not a full packet. however, using
|
|
// WS_BLOCK | WS_FULL_RECV will block until data is
|
|
// available, and then until a full websocket packet is
|
|
// fully received, after which the data is then returned.
|
|
// WS_NOBLOCK behaves in the same way except the system
|
|
// calls will not block, but with WS_FULL_RECV enabled
|
|
// it will then block until a full packet is received
|
|
|
|
// currently WS_FULL_SEND is set to be always enabled
|
|
// when the mode is changed because i do not currently
|
|
// see a need for partial sends in this client, thus
|
|
// all sends will block until the full packet is sent
|
|
// over the wire. if anyone else modifying this client
|
|
// has an EXTREME THIRST for partial sends, they can
|
|
// implement this behavior themselves
|
|
|
|
// !!! VERY IMPORTANT NOTE !!!
|
|
// if using WS_FULL_RECV, wsock_recv() can STILL RETURN 0
|
|
// this happens when a control frame is received from the
|
|
// server and is handled by this library. in order for
|
|
// select() or poll() to function correctly when used
|
|
// outside of the library this is a necessary behavior.
|
|
// please check for a 0 return and handle appropriately
|
|
|
|
typedef struct {
|
|
uint8_t fin, opcode, first_opcode,
|
|
masked, mask[4], head_length;
|
|
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;
|
|
|
|
typedef struct {
|
|
int sock, mode;
|
|
_ws_head_t head_buf;
|
|
buffer_t *recv_buf, *frag_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*, char**);
|
|
int wsock_send_raw(wsock_t*, int, char*, uint64_t);
|
|
int wsock_send(wsock_t*, char*, int);
|
|
int wsock_send_str(wsock_t*, char*);
|
|
int wsock_ping(wsock_t*, char*);
|
|
|
|
int wsock_is_open(wsock_t*);
|
|
void wsock_close(wsock_t*);
|
|
void wsock_free(wsock_t*);
|