clii/src/wsock.c
2023-12-17 08:30:44 -06:00

179 lines
3.3 KiB
C

#include "wsock.h"
/** DATA BUFFER **/
/*******************/
buffer_t* buffer_create() {
buffer_t* buf = malloc(sizeof(buffer_t));
buf->data = NULL;
buf->next = NULL;
buf->length = 0;
return buf;
}
int buffer_is_empty(buffer_t* buf) {
return buf->data == NULL;
}
int buffer_length(buffer_t* buf) {
if(buf == NULL)
return 0;
return buf->length + buffer_length(buf->next);
}
void buffer_append
(buffer_t* buf, const char* data, int length)
{
if(buf->data != NULL) {
buf->next = buffer_create();
buffer_append(buf->next, data, 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 i = 0;
while(buf != NULL) {
strncpy(out + i, buf->data, buf->length);
i += buf->length;
}
}
char* buffer_read(buffer_t* buf, int* plen) {
int length = buffer_length(buf);
if(plen != NULL)
*plen = length;
char* out = malloc(length);
_buffer_read(buf, out);
return out;
}
char* buffer_read_str(buffer_t* buf, int* plen) {
int length = buffer_length(buf);
if(plen != NULL)
*plen = length;
char* out = malloc(length + 1);
out[length] = '\0';
_buffer_read(buf, out);
return out;
}
char* buffer_flush(buffer_t* buf, int* plen) {
char* out = buffer_read(buf, plen);
buffer_clear(buf);
return out;
}
char* buffer_flush_str(buffer_t* buf, int* plen) {
char* out = buffer_read_str(buf, plen);
buffer_clear(buf);
return out;
}
void _buffer_clear(buffer_t* buf, int root) {
if(buf == NULL)
return;
_buffer_clear(buf->next, 0);
free(buf->data);
if(!root)
free(buf);
else {
buf->data = NULL;
buf->next = NULL;
buf->length = 0;
}
}
void buffer_clear(buffer_t* buf) {
_buffer_clear(buf, 1);
}
void buffer_free(buffer_t* buf) {
buffer_clear(buf);
free(buf);
}
/** WEB SOCKET **/
/******************/
wsock_t* wsock_open
(const char* host, const char* path, uint16_t port)
{
char s_port[6];
sprintf(s_port, "%i", port);
int sock;
struct addrinfo hints, *result, *rp;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
if(getaddrinfo(host, s_port, &hints, &result) != 0)
return NULL;
for(rp = result; rp != NULL; rp = rp->ai_next) {
if((sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1)
continue;
if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
break;
}
freeaddrinfo(result);
if(rp == NULL)
return NULL;
// todo: randomize wsock key
char s_shake[4096];
sprintf(s_shake,
"GET %s HTTP/1.1\r\n"
"Host: %s:%i\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Key: AQIDBAUGBwgJCgsMDQ4PEC==\r\n"
"Sec-WebSocket-Version: 13\r\n\r\n",
path,
host, port
);
if(send(sock, s_shake, strlen(s_shake), 0) <= 0) {
shutdown(sock, SHUT_RDWR);
return NULL;
}
s_shake[0] = '\0';
struct pollfd pfd;
pfd.fd = sock;
pfd.events = POLLIN;
char* end;
int total = 0;
while((end = strstr(s_shake, "\r\n\r\n")) == NULL) {
if(total + 1 >= sizeof(s_shake)
|| poll(&pfd, 1, 5000) <= 0)
{
shutdown(sock,SHUT_RDWR);
return NULL;
}
total += recv(sock, s_shake + total,
sizeof(s_shake) - total - 1, 0);
s_shake[total] = '\0';
}
shutdown(sock, SHUT_RDWR);
return NULL;
}