Stole a lot of stuff from libwebsock

For frame processing mostly.
master
Payden Sutherland 12 years ago
parent f4cbcd61d1
commit b670d894f3

@ -9,13 +9,13 @@ int onopen(void) {
return 0;
}
int onmessage(char *msg, int64_t length) {
fprintf(stderr, "Received message (%ull): %s\n", length, msg);
int onmessage(libwsclient_message *msg) {
fprintf(stderr, "Received (%llu): %s\n", msg->payload_len, msg->payload);
return 0;
}
int main(int argc, char **argv) {
wsclient *client = libwsclient_new("ws://localhost:3333/mtgox");
wsclient *client = libwsclient_new("ws://websocket.mtgox.com/mtgox");
if(!client) {
fprintf(stderr, "Unable to initialize new WS client.\n");
exit(1);

@ -8,15 +8,167 @@
#include <netinet/in.h>
#include <sys/socket.h>
#include <pthread.h>
#include "wsclient.h"
#include "sha1.h"
int libwsclient_run(wsclient *c) {
void libwsclient_run(wsclient *c) {
char buf[1024];
int n, i;
do {
memset(buf, 0, 1024);
n = recv(c->sockfd, buf, 1023, 0);
for(i = 0; i < n; i++)
libwsclient_in_data(c, buf[i]);
} while(n > 0);
if(n == -1) {
perror("recv");
}
close(c->sockfd);
free(c);
}
void libwsclient_in_data(wsclient *c, char in) {
libwsclient_frame *current = NULL, *new = NULL;
unsigned char payload_len_short;
if(c->current_frame == NULL) {
c->current_frame = (libwsclient_frame *)malloc(sizeof(libwsclient_frame));
memset(c->current_frame, 0, sizeof(libwsclient_frame));
c->current_frame->payload_len = -1;
c->current_frame->rawdata_sz = FRAME_CHUNK_LENGTH;
c->current_frame->rawdata = (char *)malloc(c->current_frame->rawdata_sz);
memset(c->current_frame->rawdata, 0, c->current_frame->rawdata_sz);
}
current = c->current_frame;
if(current->rawdata_idx >= current->rawdata_sz) {
current->rawdata_sz += FRAME_CHUNK_LENGTH;
current->rawdata = (char *)realloc(current->rawdata, current->rawdata_sz);
memset(current->rawdata + current->rawdata_idx, 0, current->rawdata_sz - current->rawdata_idx);
}
*(current->rawdata + current->rawdata_idx++) = in;
if(libwsclient_complete_frame(current) == 1) {
if(current->fin == 1) {
//is control frame
if((current->opcode & 0x08) == 0x08) {
//handle control frame
} else {
libwsclient_dispatch_message(c, current);
c->current_frame = NULL;
}
} else {
new = (libwsclient_frame *)malloc(sizeof(libwsclient_frame));
memset(new, 0, sizeof(libwsclient_frame));
new->payload_len = -1;
new->rawdata = (char *)malloc(FRAME_CHUNK_LENGTH);
memset(new->rawdata, 0, FRAME_CHUNK_LENGTH);
new->prev_frame = current;
current->next_frame = new;
c->current_frame = new;
}
}
}
void libwsclient_dispatch_message(wsclient *c, libwsclient_frame *current) {
unsigned long long message_payload_len, message_offset;
int message_opcode, i;
char *message_payload;
libwsclient_frame *first = NULL;
libwsclient_message *msg = NULL;
if(current == NULL) {
fprintf(stderr, "Somehow, null pointer passed to libwsclient_dispatch_message.\n");
exit(1);
}
message_offset = 0;
message_payload_len = current->payload_len;
for(;current->prev_frame != NULL;current = current->prev_frame) {
message_payload_len += current->payload_len;
}
first = current;
message_opcode = current->opcode;
message_payload = (char *)malloc(message_payload_len + 1);
memset(message_payload, 0, message_payload_len + 1);
for(;current != NULL; current = current->next_frame) {
memcpy(message_payload + message_offset, current->rawdata + current->payload_offset, current->payload_len);
message_offset += current->payload_len;
}
libwsclient_cleanup_frames(first);
msg = (libwsclient_message *)malloc(sizeof(libwsclient_message));
memset(msg, 0, sizeof(libwsclient_message));
msg->opcode = message_opcode;
msg->payload_len = message_offset;
msg->payload = message_payload;
if(c->onmessage != NULL) {
c->onmessage(msg);
} else {
fprintf(stderr, "No onmessage call back registered with libwsclient.\n");
}
free(msg->payload);
free(msg);
}
void libwsclient_cleanup_frames(libwsclient_frame *first) {
libwsclient_frame *this = NULL;
libwsclient_frame *next = first;
while(next != NULL) {
this = next;
next = this->next_frame;
if(this->rawdata != NULL) {
free(this->rawdata);
}
free(this);
}
}
int libwsclient_complete_frame(libwsclient_frame *frame) {
int payload_len_short, i;
unsigned long long payload_len = 0;
if(frame->rawdata_idx < 2) {
return 0;
}
frame->fin = (*(frame->rawdata) & 0x80) == 0x80 ? 1 : 0;
frame->opcode = *(frame->rawdata) & 0x0f;
frame->payload_offset = 2;
if((*(frame->rawdata+1) & 0x80) != 0x0) {
fprintf(stderr, "Received masked frame from server. FAIL\n");
exit(1);
}
payload_len_short = *(frame->rawdata+1) & 0x7f;
switch(payload_len_short) {
case 126:
if(frame->rawdata_idx < 4) {
return 0;
}
for(i = 0; i < 2; i++) {
memcpy((void *)&payload_len+i, frame->rawdata+3-i, 1);
}
frame->payload_offset += 2;
frame->payload_len = payload_len;
break;
case 127:
if(frame->rawdata_idx < 10) {
return 0;
}
for(i = 0; i < 8; i++) {
memcpy((void *)&payload_len+i, frame->rawdata+9-i, 1);
}
frame->payload_offset += 8;
frame->payload_len = payload_len;
break;
default:
frame->payload_len = payload_len_short;
break;
}
if(frame->rawdata_idx < frame->payload_offset + frame->payload_len) {
return 0;
}
return 1;
}
int libwsclient_open_connection(const char *host, const char *port) {
struct addrinfo hints, *servinfo, *p;
int rv, sockfd;
@ -204,6 +356,8 @@ wsclient *libwsclient_new(const char *URI) {
fprintf(stderr, "Server did not send valid Sec-WebSocket-Accept header, failing.\n");
exit(10);
}
return client;
}
@ -222,7 +376,7 @@ int stricmp(const char *s1, const char *s2) {
int libwsclient_send(wsclient *client, char *strdata) {
if(strdata == NULL) {
fprintf(stderr, "Will not send empty message.\n");
fprintf(stderr, "NULL pointer psased to libwsclient_send\n");
return -1;
}
int sockfd = client->sockfd;
@ -267,7 +421,7 @@ int libwsclient_send(wsclient *client, char *strdata) {
memset(data, 0, frame_size);
payload_len_small |= 0x80;
memcpy(data, &finNopcode, 1);
memcpy(data+1, &payload_len_small, 1); //mask bit om, 7 bit payload len
memcpy(data+1, &payload_len_small, 1); //mask bit on, 7 bit payload len
if(payload_len_small == 126) {
payload_len &= 0xffff;
len_size = 2;

@ -3,6 +3,8 @@
#ifndef WSCLIENT_H_
#define WSCLIENT_H_
#define FRAME_CHUNK_LENGTH 1024
#define CLIENT_IS_SSL (1 << 0)
#define REQUEST_HAS_CONNECTION (1 << 0)
@ -10,14 +12,35 @@
#define REQUEST_VALID_STATUS (1 << 2)
#define REQUEST_VALID_ACCEPT (1 << 3)
typedef struct _libwsclient_frame {
unsigned int fin;
unsigned int opcode;
unsigned int mask_offset;
unsigned int payload_offset;
unsigned int rawdata_idx;
unsigned int rawdata_sz;
unsigned long long payload_len;
char *rawdata;
struct _libwsclient_frame *next_frame;
struct _libwsclient_frame *prev_frame;
unsigned char mask[4];
} libwsclient_frame;
typedef struct _libwsclient_message {
unsigned int opcode;
unsigned long long payload_len;
char *payload;
} libwsclient_message;
typedef struct _wsclient {
int sockfd;
int flags;
int (*onopen)(void);
int (*onclose)(void);
int (*onerror)(void);
int (*onmessage)(char *message, int64_t length);
void (*run)(void);
int (*onmessage)(libwsclient_message *msg);
libwsclient_frame *current_frame;
} wsclient;
//Function defs
@ -25,5 +48,10 @@ typedef struct _wsclient {
wsclient *libwsclient_new(const char *URI);
int libwsclient_open_connection(const char *host, const char *port);
int stricmp(const char *s1, const char *s2);
void libwsclient_run(wsclient *c);
void *libwsclient_run_thread(void *ptr);
void libwsclient_cleanup_frames(libwsclient_frame *first);
void libwsclient_in_data(wsclient *c, char in);
int libwsclient_complete_frame(libwsclient_frame *frame);
void libwsclient_dispatch_message(wsclient *c, libwsclient_frame *current);
#endif /* WSCLIENT_H_ */

Loading…
Cancel
Save