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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int onmessage(char *msg, int64_t length) {
|
int onmessage(libwsclient_message *msg) {
|
||||||
fprintf(stderr, "Received message (%ull): %s\n", length, msg);
|
fprintf(stderr, "Received (%llu): %s\n", msg->payload_len, msg->payload);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
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) {
|
if(!client) {
|
||||||
fprintf(stderr, "Unable to initialize new WS client.\n");
|
fprintf(stderr, "Unable to initialize new WS client.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
160
wsclient.c
160
wsclient.c
@ -8,14 +8,166 @@
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
#include "wsclient.h"
|
#include "wsclient.h"
|
||||||
#include "sha1.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) {
|
int libwsclient_open_connection(const char *host, const char *port) {
|
||||||
struct addrinfo hints, *servinfo, *p;
|
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");
|
fprintf(stderr, "Server did not send valid Sec-WebSocket-Accept header, failing.\n");
|
||||||
exit(10);
|
exit(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +376,7 @@ int stricmp(const char *s1, const char *s2) {
|
|||||||
|
|
||||||
int libwsclient_send(wsclient *client, char *strdata) {
|
int libwsclient_send(wsclient *client, char *strdata) {
|
||||||
if(strdata == NULL) {
|
if(strdata == NULL) {
|
||||||
fprintf(stderr, "Will not send empty message.\n");
|
fprintf(stderr, "NULL pointer psased to libwsclient_send\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int sockfd = client->sockfd;
|
int sockfd = client->sockfd;
|
||||||
@ -267,7 +421,7 @@ int libwsclient_send(wsclient *client, char *strdata) {
|
|||||||
memset(data, 0, frame_size);
|
memset(data, 0, frame_size);
|
||||||
payload_len_small |= 0x80;
|
payload_len_small |= 0x80;
|
||||||
memcpy(data, &finNopcode, 1);
|
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) {
|
if(payload_len_small == 126) {
|
||||||
payload_len &= 0xffff;
|
payload_len &= 0xffff;
|
||||||
len_size = 2;
|
len_size = 2;
|
||||||
|
34
wsclient.h
34
wsclient.h
@ -3,6 +3,8 @@
|
|||||||
#ifndef WSCLIENT_H_
|
#ifndef WSCLIENT_H_
|
||||||
#define WSCLIENT_H_
|
#define WSCLIENT_H_
|
||||||
|
|
||||||
|
#define FRAME_CHUNK_LENGTH 1024
|
||||||
|
|
||||||
#define CLIENT_IS_SSL (1 << 0)
|
#define CLIENT_IS_SSL (1 << 0)
|
||||||
|
|
||||||
#define REQUEST_HAS_CONNECTION (1 << 0)
|
#define REQUEST_HAS_CONNECTION (1 << 0)
|
||||||
@ -10,14 +12,35 @@
|
|||||||
#define REQUEST_VALID_STATUS (1 << 2)
|
#define REQUEST_VALID_STATUS (1 << 2)
|
||||||
#define REQUEST_VALID_ACCEPT (1 << 3)
|
#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 {
|
typedef struct _wsclient {
|
||||||
int sockfd;
|
int sockfd;
|
||||||
int flags;
|
int flags;
|
||||||
int (*onopen)(void);
|
int (*onopen)(void);
|
||||||
int (*onclose)(void);
|
int (*onclose)(void);
|
||||||
int (*onerror)(void);
|
int (*onerror)(void);
|
||||||
int (*onmessage)(char *message, int64_t length);
|
int (*onmessage)(libwsclient_message *msg);
|
||||||
void (*run)(void);
|
libwsclient_frame *current_frame;
|
||||||
|
|
||||||
} wsclient;
|
} wsclient;
|
||||||
|
|
||||||
//Function defs
|
//Function defs
|
||||||
@ -25,5 +48,10 @@ typedef struct _wsclient {
|
|||||||
wsclient *libwsclient_new(const char *URI);
|
wsclient *libwsclient_new(const char *URI);
|
||||||
int libwsclient_open_connection(const char *host, const char *port);
|
int libwsclient_open_connection(const char *host, const char *port);
|
||||||
int stricmp(const char *s1, const char *s2);
|
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_ */
|
#endif /* WSCLIENT_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user