Added wsclient_error type

Working on passing most errors to client code through
onerror callback.
master
Payden Sutherland 12 years ago
parent e8a7956336
commit afe050ba79

@ -4,25 +4,35 @@
#include <wsclient/wsclient.h> #include <wsclient/wsclient.h>
int onmessage(wsclient *c, libwsclient_message *msg) { int onclose(wsclient *c) {
fprintf(stderr, "Closing websocket with: %d\n", c->sockfd);
}
int onerror(wsclient *c, wsclient_error *err) {
fprintf(stderr, "Error occured (%d): %s\n", err->code, err->str);
}
int onmessage(wsclient *c, wsclient_message *msg) {
fprintf(stderr, "Received (%llu): %s\n", msg->payload_len, msg->payload); fprintf(stderr, "Received (%llu): %s\n", msg->payload_len, msg->payload);
return 0; return 0;
} }
int onopen(wsclient *c) { int onopen(wsclient *c) {
fprintf(stderr, "onopen called.\n"); fprintf(stderr, "onopen called.\n");
libwsclient_send(c, "testing"); libwsclient_send(c, "testing::testing::demo.paydensutherland.com");
return 0; return 0;
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
wsclient *client = libwsclient_new("ws://websocket.mtgox.com/mtgox"); wsclient *client = libwsclient_new("ws://ip6-localhost:8080");
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);
} }
libwsclient_onopen(client, &onopen); libwsclient_onopen(client, &onopen);
libwsclient_onmessage(client, &onmessage); libwsclient_onmessage(client, &onmessage);
libwsclient_onerror(client, &onerror);
libwsclient_onclose(client, &onclose);
libwsclient_run(client); libwsclient_run(client);
libwsclient_finish(client); libwsclient_finish(client);
return 0; return 0;

@ -14,21 +14,25 @@
#include "sha1.h" #include "sha1.h"
void libwsclient_run(wsclient *c) { void libwsclient_run(wsclient *c) {
pthread_mutex_lock(&c->lock);
if(c->flags & CLIENT_CONNECTING) { if(c->flags & CLIENT_CONNECTING) {
pthread_mutex_unlock(&c->lock); fprintf(stderr, "Address of handshake thread: %08x\n", &c->handshake_thread);
pthread_join(c->handshake_thread, NULL); pthread_join(c->handshake_thread, NULL);
pthread_mutex_lock(&c->lock); pthread_mutex_lock(&c->lock);
c->flags &= ~CLIENT_CONNECTING; c->flags &= ~CLIENT_CONNECTING;
free(c->URI); free(c->URI);
c->URI = NULL; c->URI = NULL;
pthread_mutex_unlock(&c->lock);
}
if(c->sockfd) {
pthread_create(&c->run_thread, NULL, libwsclient_run_thread, (void *)c);
} }
pthread_mutex_unlock(&c->lock);
pthread_create(&c->run_thread, NULL, libwsclient_run_thread, (void *)c);
} }
void *libwsclient_run_thread(void *ptr) { void *libwsclient_run_thread(void *ptr) {
wsclient *c = (wsclient *)ptr; wsclient *c = (wsclient *)ptr;
wsclient_error *err = NULL;
int sockfd;
char buf[1024]; char buf[1024];
int n, i; int n, i;
do { do {
@ -38,11 +42,24 @@ void *libwsclient_run_thread(void *ptr) {
libwsclient_in_data(c, buf[i]); libwsclient_in_data(c, buf[i]);
} while(n > 0); } while(n > 0);
if(n == -1) {
perror("recv"); if(n < 0) {
if(c->onerror) {
err = libwsclient_new_error(WS_RUN_THREAD_RECV_ERR);
err->extra_code = n;
c->onerror(c, err);
free(err);
err = NULL;
}
}
if(c->onclose) {
c->onclose(c);
} }
close(c->sockfd); close(c->sockfd);
free(c); free(c);
return NULL;
} }
void libwsclient_finish(wsclient *client) { void libwsclient_finish(wsclient *client) {
@ -61,13 +78,20 @@ void libwsclient_onopen(wsclient *client, int (*cb)(wsclient *c)) {
pthread_mutex_unlock(&client->lock); pthread_mutex_unlock(&client->lock);
} }
void libwsclient_onmessage(wsclient *client, int (*cb)(wsclient *c, libwsclient_message *msg)) { void libwsclient_onmessage(wsclient *client, int (*cb)(wsclient *c, wsclient_message *msg)) {
pthread_mutex_lock(&client->lock); pthread_mutex_lock(&client->lock);
client->onmessage = cb; client->onmessage = cb;
pthread_mutex_unlock(&client->lock); pthread_mutex_unlock(&client->lock);
} }
void libwsclient_onerror(wsclient *client, int (*cb)(wsclient *c, wsclient_error *err)) {
pthread_mutex_lock(&client->lock);
client->onerror = cb;
pthread_mutex_unlock(&client->lock);
}
void libwsclient_close(wsclient *client) { void libwsclient_close(wsclient *client) {
wsclient_error *err = NULL;
char data[6]; char data[6];
int i = 0, n, mask_int; int i = 0, n, mask_int;
struct timeval tv; struct timeval tv;
@ -81,13 +105,25 @@ void libwsclient_close(wsclient *client) {
n = send(client->sockfd, data, 6, 0); n = send(client->sockfd, data, 6, 0);
i += n; i += n;
} while(i < 6 && n > 0); } while(i < 6 && n > 0);
if(n < 0) {
if(client->onerror) {
err = libwsclient_new_error(WS_DO_CLOSE_SEND_ERR);
err->extra_code = n;
client->onerror(client, err);
free(err);
err = NULL;
}
return;
}
pthread_mutex_lock(&client->lock); pthread_mutex_lock(&client->lock);
client->flags |= CLIENT_SENT_CLOSE_FRAME; client->flags |= CLIENT_SENT_CLOSE_FRAME;
pthread_mutex_unlock(&client->lock); pthread_mutex_unlock(&client->lock);
} }
void libwsclient_handle_control_frame(wsclient *c, libwsclient_frame *ctl_frame) { void libwsclient_handle_control_frame(wsclient *c, wsclient_frame *ctl_frame) {
int i; wsclient_error *err = NULL;
wsclient_frame *ptr = NULL;
int i, n = 0;
char mask[4]; char mask[4];
int mask_int; int mask_int;
struct timeval tv; struct timeval tv;
@ -95,9 +131,9 @@ void libwsclient_handle_control_frame(wsclient *c, libwsclient_frame *ctl_frame)
srand(tv.tv_sec * tv.tv_usec); srand(tv.tv_sec * tv.tv_usec);
mask_int = rand(); mask_int = rand();
memcpy(mask, &mask_int, 4); memcpy(mask, &mask_int, 4);
pthread_mutex_lock(&c->lock);
switch(ctl_frame->opcode) { switch(ctl_frame->opcode) {
case 0x8: case 0x8:
fprintf(stderr, "Recived close frame.\n");
//close frame //close frame
if((c->flags & CLIENT_SENT_CLOSE_FRAME) == 0) { if((c->flags & CLIENT_SENT_CLOSE_FRAME) == 0) {
//server request close. Send close frame as acknowledgement. //server request close. Send close frame as acknowledgement.
@ -105,33 +141,43 @@ void libwsclient_handle_control_frame(wsclient *c, libwsclient_frame *ctl_frame)
*(ctl_frame->rawdata + ctl_frame->payload_offset + i) ^= (mask[i % 4] & 0xff); //mask payload *(ctl_frame->rawdata + ctl_frame->payload_offset + i) ^= (mask[i % 4] & 0xff); //mask payload
*(ctl_frame->rawdata + 1) |= 0x80; //turn mask bit on *(ctl_frame->rawdata + 1) |= 0x80; //turn mask bit on
i = 0; i = 0;
while(i < ctl_frame->payload_offset + ctl_frame->payload_len) { while(i < ctl_frame->payload_offset + ctl_frame->payload_len && n >= 0) {
i += send(c->sockfd, ctl_frame->rawdata + i, ctl_frame->payload_offset + ctl_frame->payload_len - i, 0); n = send(c->sockfd, ctl_frame->rawdata + i, ctl_frame->payload_offset + ctl_frame->payload_len - i, 0);
i += n;
}
if(n < 0) {
if(c->onerror) {
err = libwsclient_new_error(WS_HANDLE_CTL_FRAME_SEND_ERR);
err->extra_code = n;
c->onerror(c, err);
free(err);
err = NULL;
}
} }
} }
pthread_mutex_lock(&c->lock);
c->flags |= CLIENT_SHOULD_CLOSE; c->flags |= CLIENT_SHOULD_CLOSE;
pthread_mutex_unlock(&c->lock);
break; break;
default: default:
fprintf(stderr, "Unhandled control frame received. Opcode: %d\n", ctl_frame->opcode); fprintf(stderr, "Unhandled control frame received. Opcode: %d\n", ctl_frame->opcode);
break; break;
} }
libwsclient_frame *ptr = NULL;
ptr = ctl_frame->prev_frame; //This very well may be a NULL pointer, but just in case we preserve it. ptr = ctl_frame->prev_frame; //This very well may be a NULL pointer, but just in case we preserve it.
free(ctl_frame->rawdata); free(ctl_frame->rawdata);
memset(ctl_frame, 0, sizeof(libwsclient_frame)); memset(ctl_frame, 0, sizeof(wsclient_frame));
ctl_frame->prev_frame = ptr; ctl_frame->prev_frame = ptr;
ctl_frame->rawdata = (char *)malloc(FRAME_CHUNK_LENGTH); ctl_frame->rawdata = (char *)malloc(FRAME_CHUNK_LENGTH);
memset(ctl_frame->rawdata, 0, FRAME_CHUNK_LENGTH); memset(ctl_frame->rawdata, 0, FRAME_CHUNK_LENGTH);
pthread_mutex_unlock(&c->lock);
} }
void libwsclient_in_data(wsclient *c, char in) { inline void libwsclient_in_data(wsclient *c, char in) {
libwsclient_frame *current = NULL, *new = NULL; wsclient_frame *current = NULL, *new = NULL;
unsigned char payload_len_short; unsigned char payload_len_short;
pthread_mutex_lock(&c->lock);
if(c->current_frame == NULL) { if(c->current_frame == NULL) {
c->current_frame = (libwsclient_frame *)malloc(sizeof(libwsclient_frame)); c->current_frame = (wsclient_frame *)malloc(sizeof(wsclient_frame));
memset(c->current_frame, 0, sizeof(libwsclient_frame)); memset(c->current_frame, 0, sizeof(wsclient_frame));
c->current_frame->payload_len = -1; c->current_frame->payload_len = -1;
c->current_frame->rawdata_sz = FRAME_CHUNK_LENGTH; c->current_frame->rawdata_sz = FRAME_CHUNK_LENGTH;
c->current_frame->rawdata = (char *)malloc(c->current_frame->rawdata_sz); c->current_frame->rawdata = (char *)malloc(c->current_frame->rawdata_sz);
@ -144,7 +190,8 @@ void libwsclient_in_data(wsclient *c, char in) {
memset(current->rawdata + current->rawdata_idx, 0, current->rawdata_sz - current->rawdata_idx); memset(current->rawdata + current->rawdata_idx, 0, current->rawdata_sz - current->rawdata_idx);
} }
*(current->rawdata + current->rawdata_idx++) = in; *(current->rawdata + current->rawdata_idx++) = in;
if(libwsclient_complete_frame(current) == 1) { pthread_mutex_unlock(&c->lock);
if(libwsclient_complete_frame(c, current) == 1) {
if(current->fin == 1) { if(current->fin == 1) {
//is control frame //is control frame
if((current->opcode & 0x08) == 0x08) { if((current->opcode & 0x08) == 0x08) {
@ -154,8 +201,8 @@ void libwsclient_in_data(wsclient *c, char in) {
c->current_frame = NULL; c->current_frame = NULL;
} }
} else { } else {
new = (libwsclient_frame *)malloc(sizeof(libwsclient_frame)); new = (wsclient_frame *)malloc(sizeof(wsclient_frame));
memset(new, 0, sizeof(libwsclient_frame)); memset(new, 0, sizeof(wsclient_frame));
new->payload_len = -1; new->payload_len = -1;
new->rawdata = (char *)malloc(FRAME_CHUNK_LENGTH); new->rawdata = (char *)malloc(FRAME_CHUNK_LENGTH);
memset(new->rawdata, 0, FRAME_CHUNK_LENGTH); memset(new->rawdata, 0, FRAME_CHUNK_LENGTH);
@ -166,15 +213,21 @@ void libwsclient_in_data(wsclient *c, char in) {
} }
} }
void libwsclient_dispatch_message(wsclient *c, libwsclient_frame *current) { void libwsclient_dispatch_message(wsclient *c, wsclient_frame *current) {
unsigned long long message_payload_len, message_offset; unsigned long long message_payload_len, message_offset;
int message_opcode, i; int message_opcode, i;
char *message_payload; char *message_payload;
libwsclient_frame *first = NULL; wsclient_frame *first = NULL;
libwsclient_message *msg = NULL; wsclient_message *msg = NULL;
wsclient_error *err = NULL;
if(current == NULL) { if(current == NULL) {
fprintf(stderr, "Somehow, null pointer passed to libwsclient_dispatch_message.\n"); if(c->onerror) {
exit(1); err = libwsclient_new_error(WS_DISPATCH_MESSAGE_NULL_PTR_ERR);
c->onerror(c, err);
free(err);
err = NULL;
}
return;
} }
message_offset = 0; message_offset = 0;
message_payload_len = current->payload_len; message_payload_len = current->payload_len;
@ -192,8 +245,8 @@ void libwsclient_dispatch_message(wsclient *c, libwsclient_frame *current) {
libwsclient_cleanup_frames(first); libwsclient_cleanup_frames(first);
msg = (libwsclient_message *)malloc(sizeof(libwsclient_message)); msg = (wsclient_message *)malloc(sizeof(wsclient_message));
memset(msg, 0, sizeof(libwsclient_message)); memset(msg, 0, sizeof(wsclient_message));
msg->opcode = message_opcode; msg->opcode = message_opcode;
msg->payload_len = message_offset; msg->payload_len = message_offset;
msg->payload = message_payload; msg->payload = message_payload;
@ -205,9 +258,9 @@ void libwsclient_dispatch_message(wsclient *c, libwsclient_frame *current) {
free(msg->payload); free(msg->payload);
free(msg); free(msg);
} }
void libwsclient_cleanup_frames(libwsclient_frame *first) { void libwsclient_cleanup_frames(wsclient_frame *first) {
libwsclient_frame *this = NULL; wsclient_frame *this = NULL;
libwsclient_frame *next = first; wsclient_frame *next = first;
while(next != NULL) { while(next != NULL) {
this = next; this = next;
next = this->next_frame; next = this->next_frame;
@ -218,7 +271,8 @@ void libwsclient_cleanup_frames(libwsclient_frame *first) {
} }
} }
int libwsclient_complete_frame(libwsclient_frame *frame) { int libwsclient_complete_frame(wsclient *c, wsclient_frame *frame) {
wsclient_error *err = NULL;
int payload_len_short, i; int payload_len_short, i;
unsigned long long payload_len = 0; unsigned long long payload_len = 0;
if(frame->rawdata_idx < 2) { if(frame->rawdata_idx < 2) {
@ -228,8 +282,16 @@ int libwsclient_complete_frame(libwsclient_frame *frame) {
frame->opcode = *(frame->rawdata) & 0x0f; frame->opcode = *(frame->rawdata) & 0x0f;
frame->payload_offset = 2; frame->payload_offset = 2;
if((*(frame->rawdata+1) & 0x80) != 0x0) { if((*(frame->rawdata+1) & 0x80) != 0x0) {
fprintf(stderr, "Received masked frame from server. FAIL\n"); if(c->onerror) {
exit(1); err = libwsclient_new_error(WS_COMPLETE_FRAME_MASKED_ERR);
c->onerror(c, err);
free(err);
err = NULL;
}
pthread_mutex_lock(&c->lock);
c->flags |= CLIENT_SHOULD_CLOSE;
pthread_mutex_unlock(&c->lock);
return 0;
} }
payload_len_short = *(frame->rawdata+1) & 0x7f; payload_len_short = *(frame->rawdata+1) & 0x7f;
switch(payload_len_short) { switch(payload_len_short) {
@ -271,26 +333,21 @@ int libwsclient_open_connection(const char *host, const char *port) {
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
if((rv = getaddrinfo(host, port, &hints, &servinfo)) != 0) { if((rv = getaddrinfo(host, port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return WS_OPEN_CONNECTION_ADDRINFO_ERR;
return -1;
} }
for(p = servinfo; p != NULL; p = p->ai_next) { for(p = servinfo; p != NULL; p = p->ai_next) {
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("socket");
continue; continue;
} }
if(connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { if(connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd); close(sockfd);
perror("connect");
continue; continue;
} }
break; break;
} }
if(p == NULL) { if(p == NULL) {
fprintf(stderr, "Failed to connect.\n"); return WS_OPEN_CONNECTION_ADDRINFO_EXHAUSTED_ERR;
freeaddrinfo(servinfo);
return -1;
} }
return sockfd; return sockfd;
} }
@ -327,6 +384,7 @@ wsclient *libwsclient_new(const char *URI) {
} }
void *libwsclient_handshake_thread(void *ptr) { void *libwsclient_handshake_thread(void *ptr) {
wsclient *client = (wsclient *)ptr; wsclient *client = (wsclient *)ptr;
wsclient_error *err = NULL;
const char *URI = client->URI; const char *URI = client->URI;
SHA1Context shactx; SHA1Context shactx;
const char *UUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; const char *UUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
@ -392,9 +450,14 @@ void *libwsclient_handshake_thread(void *ptr) {
strncpy(path, URI_copy+i, 254); strncpy(path, URI_copy+i, 254);
free(URI_copy); free(URI_copy);
sockfd = libwsclient_open_connection(host, port); sockfd = libwsclient_open_connection(host, port);
if(sockfd == -1) { if(sockfd < 0) {
fprintf(stderr, "Error opening socket.\n"); if(client->onerror) {
exit(5); err = libwsclient_new_error(sockfd);
client->onerror(client, err);
free(err);
err = NULL;
}
return NULL;
} }
pthread_mutex_lock(&client->lock); pthread_mutex_lock(&client->lock);
client->sockfd = sockfd; client->sockfd = sockfd;
@ -507,38 +570,110 @@ int stricmp(const char *s1, const char *s2) {
return c1 - c2; return c1 - c2;
} }
wsclient_error *libwsclient_new_error(int errcode) {
wsclient_error *err = NULL;
err = (wsclient_error *)malloc(sizeof(wsclient_error));
if(!err) {
//one of the few places we will fail and exit
fprintf(stderr, "Unable to allocate memory in libwsclient_new_error.\n");
exit(errcode);
}
memset(err, 0, sizeof(wsclient_error));
err->code = errcode;
switch(err->code) {
case WS_OPEN_CONNECTION_ADDRINFO_ERR:
err->str = *(errors + 1);
break;
case WS_OPEN_CONNECTION_ADDRINFO_EXHAUSTED_ERR:
err->str = *(errors + 2);
break;
case WS_RUN_THREAD_RECV_ERR:
err->str = *(errors + 3);
break;
case WS_DO_CLOSE_SEND_ERR:
err->str = *(errors + 4);
break;
case WS_HANDLE_CTL_FRAME_SEND_ERR:
err->str = *(errors + 5);
break;
case WS_COMPLETE_FRAME_MASKED_ERR:
err->str = *(errors + 6);
break;
case WS_DISPATCH_MESSAGE_NULL_PTR_ERR:
err->str = *(errors + 7);
break;
case WS_SEND_AFTER_CLOSE_FRAME_ERR:
err->str = *(errors + 8);
break;
case WS_SEND_DURING_CONNECT_ERR:
err->str = *(errors + 9);
break;
case WS_SEND_NULL_DATA_ERR:
err->str = *(errors + 10);
break;
case WS_SEND_DATA_TOO_LARGE_ERR:
err->str = *(errors + 11);
break;
case WS_SEND_SEND_ERR:
err->str = *(errors + 12);
break;
default:
err->str = *errors;
break;
}
return err;
}
int libwsclient_send(wsclient *client, char *strdata) { int libwsclient_send(wsclient *client, char *strdata) {
wsclient_error *err = NULL;
struct timeval tv;
unsigned char mask[4];
unsigned int mask_int;
unsigned long long payload_len;
unsigned char finNopcode;
unsigned int payload_len_small;
unsigned int payload_offset = 6;
unsigned int len_size;
unsigned long long be_payload_len;
unsigned int sent = 0;
int i;
unsigned int frame_size;
char *data;
pthread_mutex_lock(&client->lock); pthread_mutex_lock(&client->lock);
if(client->flags & CLIENT_SENT_CLOSE_FRAME) { if(client->flags & CLIENT_SENT_CLOSE_FRAME) {
fprintf(stderr, "Trying to send data after sending close frame. Not sending.\n"); if(client->onerror) {
err = libwsclient_new_error(WS_SEND_AFTER_CLOSE_FRAME_ERR);
client->onerror(client, err);
free(err);
err = NULL;
}
pthread_mutex_unlock(&client->lock); pthread_mutex_unlock(&client->lock);
return 0; return 0;
} }
if(client->flags & CLIENT_CONNECTING) { if(client->flags & CLIENT_CONNECTING) {
fprintf(stderr, "Attempted to send message before client was connected. Not sending.\n"); if(client->onerror) {
err = libwsclient_new_error(WS_SEND_DURING_CONNECT_ERR);
client->onerror(client, err);
free(err);
err = NULL;
}
pthread_mutex_unlock(&client->lock); pthread_mutex_unlock(&client->lock);
return 0; return 0;
} }
int sockfd = client->sockfd; int sockfd = client->sockfd;
pthread_mutex_unlock(&client->lock); pthread_mutex_unlock(&client->lock);
if(strdata == NULL) { if(strdata == NULL) {
fprintf(stderr, "NULL pointer psased to libwsclient_send\n"); if(client->onerror) {
err = libwsclient_new_error(WS_SEND_NULL_DATA_ERR);
client->onerror(client, err);
free(err);
err = NULL;
}
return -1; return -1;
} }
struct timeval tv;
unsigned char mask[4];
unsigned int mask_int;
unsigned long long payload_len;
unsigned char finNopcode;
unsigned int payload_len_small;
unsigned int payload_offset = 6;
unsigned int len_size;
unsigned long long be_payload_len;
unsigned int sent = 0;
int i;
unsigned int frame_size;
char *data;
gettimeofday(&tv); gettimeofday(&tv);
srand(tv.tv_usec * tv.tv_sec); srand(tv.tv_usec * tv.tv_sec);
mask_int = rand(); mask_int = rand();
@ -561,7 +696,12 @@ int libwsclient_send(wsclient *client, char *strdata) {
payload_len_small = 127; payload_len_small = 127;
payload_offset += 8; payload_offset += 8;
} else { } else {
fprintf(stderr, "Whoa man. What are you trying to send?\n"); if(client->onerror) {
err = libwsclient_new_error(WS_SEND_DATA_TOO_LARGE_ERR);
client->onerror(client, err);
free(err);
err = NULL;
}
return -1; return -1;
} }
memset(data, 0, frame_size); memset(data, 0, frame_size);
@ -589,10 +729,22 @@ int libwsclient_send(wsclient *client, char *strdata) {
for(i=0;i<strlen(strdata);i++) for(i=0;i<strlen(strdata);i++)
*(data+payload_offset+i) ^= mask[i % 4] & 0xff; *(data+payload_offset+i) ^= mask[i % 4] & 0xff;
sent = 0; sent = 0;
i = 0;
while(sent < frame_size) { while(sent < frame_size && i >= 0) {
sent += send(sockfd, data+sent, frame_size - sent, 0); i = send(sockfd, data+sent, frame_size - sent, 0);
sent += i;
} }
if(i < 0) {
if(client->onerror) {
err = libwsclient_new_error(WS_SEND_SEND_ERR);
client->onerror(client, err);
free(err);
err = NULL;
}
}
free(data); free(data);
return sent; return sent;
} }

@ -17,7 +17,20 @@
#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 { #define WS_OPEN_CONNECTION_ADDRINFO_ERR -1
#define WS_OPEN_CONNECTION_ADDRINFO_EXHAUSTED_ERR -2
#define WS_RUN_THREAD_RECV_ERR -3
#define WS_DO_CLOSE_SEND_ERR -4
#define WS_HANDLE_CTL_FRAME_SEND_ERR -5
#define WS_COMPLETE_FRAME_MASKED_ERR -6
#define WS_DISPATCH_MESSAGE_NULL_PTR_ERR -7
#define WS_SEND_AFTER_CLOSE_FRAME_ERR -8
#define WS_SEND_DURING_CONNECT_ERR -9
#define WS_SEND_NULL_DATA_ERR -10
#define WS_SEND_DATA_TOO_LARGE_ERR -11
#define WS_SEND_SEND_ERR -12
typedef struct _wsclient_frame {
unsigned int fin; unsigned int fin;
unsigned int opcode; unsigned int opcode;
unsigned int mask_offset; unsigned int mask_offset;
@ -26,16 +39,22 @@ typedef struct _libwsclient_frame {
unsigned int rawdata_sz; unsigned int rawdata_sz;
unsigned long long payload_len; unsigned long long payload_len;
char *rawdata; char *rawdata;
struct _libwsclient_frame *next_frame; struct _wsclient_frame *next_frame;
struct _libwsclient_frame *prev_frame; struct _wsclient_frame *prev_frame;
unsigned char mask[4]; unsigned char mask[4];
} libwsclient_frame; } wsclient_frame;
typedef struct _libwsclient_message { typedef struct _wsclient_message {
unsigned int opcode; unsigned int opcode;
unsigned long long payload_len; unsigned long long payload_len;
char *payload; char *payload;
} libwsclient_message; } wsclient_message;
typedef struct _wsclient_error {
int code;
int extra_code;
char *str;
} wsclient_error;
typedef struct _wsclient { typedef struct _wsclient {
pthread_t handshake_thread; pthread_t handshake_thread;
@ -46,9 +65,9 @@ typedef struct _wsclient {
int flags; int flags;
int (*onopen)(struct _wsclient *); int (*onopen)(struct _wsclient *);
int (*onclose)(struct _wsclient *); int (*onclose)(struct _wsclient *);
int (*onerror)(struct _wsclient *); int (*onerror)(struct _wsclient *, wsclient_error *err);
int (*onmessage)(struct _wsclient *, libwsclient_message *msg); int (*onmessage)(struct _wsclient *, wsclient_message *msg);
libwsclient_frame *current_frame; wsclient_frame *current_frame;
} wsclient; } wsclient;
@ -56,16 +75,37 @@ typedef struct _wsclient {
//Function defs //Function defs
wsclient *libwsclient_new(const char *URI); wsclient *libwsclient_new(const char *URI);
wsclient_error *libwsclient_new_error(int errcode);
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);
int libwsclient_complete_frame(libwsclient_frame *frame); int libwsclient_complete_frame(wsclient *c, wsclient_frame *frame);
void libwsclient_handle_control_frame(wsclient *c, libwsclient_frame *ctl_frame); void libwsclient_handle_control_frame(wsclient *c, wsclient_frame *ctl_frame);
void libwsclient_run(wsclient *c); void libwsclient_run(wsclient *c);
void libwsclient_finish(wsclient *client); void libwsclient_finish(wsclient *client);
void *libwsclient_run_thread(void *ptr); void *libwsclient_run_thread(void *ptr);
void *libwsclient_handshake_thread(void *ptr); void *libwsclient_handshake_thread(void *ptr);
void libwsclient_cleanup_frames(libwsclient_frame *first); void libwsclient_cleanup_frames(wsclient_frame *first);
void libwsclient_in_data(wsclient *c, char in); void libwsclient_in_data(wsclient *c, char in);
void libwsclient_dispatch_message(wsclient *c, libwsclient_frame *current); void libwsclient_dispatch_message(wsclient *c, wsclient_frame *current);
void libwsclient_close(wsclient *c); void libwsclient_close(wsclient *c);
//Define errors
char *errors[] = {
"Unknown error occured",
"Error while getting address info",
"Could connect to any address returned by getaddrinfo",
"Error sending data in client run thread",
"Error during libwsclient_close",
"Error sending while handling control frame",
"Received masked frame from server",
"Got null pointer during message dispatch",
"Attempted to send after close frame was sent",
"Attempted to send during connect",
"Attempted to send null payload",
"Attempted to send too much data",
"Error during send in libwsclient_send",
NULL
};
#endif /* WSCLIENT_H_ */ #endif /* WSCLIENT_H_ */

Loading…
Cancel
Save