mirror of
https://github.com/payden/libwsclient
synced 2024-10-27 17:54:01 +00:00
Stole a lot of stuff from libwebsock
For frame processing mostly.
This commit is contained in:
parent
f4cbcd61d1
commit
b670d894f3
6
test.c
6
test.c
@ -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);
|
||||
|
160
wsclient.c
160
wsclient.c
@ -8,14 +8,166 @@
|
||||
#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;
|
||||
@ -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;
|
||||
|
34
wsclient.h
34
wsclient.h
@ -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…
Reference in New Issue
Block a user