diff --git a/test.c b/test.c index b705d36..0d2fe81 100644 --- a/test.c +++ b/test.c @@ -4,24 +4,26 @@ #include -int onopen(void) { - fprintf(stderr, "Connection opened.\n"); +int onmessage(wsclient *c, libwsclient_message *msg) { + fprintf(stderr, "Received (%llu): %s\n", msg->payload_len, msg->payload); return 0; } -int onmessage(libwsclient_message *msg) { - fprintf(stderr, "Received (%llu): %s\n", msg->payload_len, msg->payload); +int onopen(wsclient *c) { + fprintf(stderr, "onopen called.\n"); + libwsclient_close(c); return 0; } int main(int argc, char **argv) { - wsclient *client = libwsclient_new("ws://websocket.mtgox.com/mtgox"); + wsclient *client = libwsclient_new("ws://localhost:3333"); if(!client) { fprintf(stderr, "Unable to initialize new WS client.\n"); exit(1); } libwsclient_onopen(client, &onopen); libwsclient_onmessage(client, &onmessage); + libwsclient_send(client, "testing"); libwsclient_run(client); return 0; } diff --git a/wsclient.c b/wsclient.c index c25a44e..1ed3097 100644 --- a/wsclient.c +++ b/wsclient.c @@ -13,7 +13,6 @@ #include "wsclient.h" #include "sha1.h" - void libwsclient_run(wsclient *c) { char buf[1024]; int n, i; @@ -41,18 +40,80 @@ void libwsclient_run(wsclient *c) { free(c); } -void libwsclient_onopen(wsclient *client, int (*cb)(void)) { +void libwsclient_onclose(wsclient *client, int (*cb)(wsclient *c)) { + pthread_mutex_lock(&client->lock); + client->onclose = cb; + pthread_mutex_unlock(&client->lock); +} + +void libwsclient_onopen(wsclient *client, int (*cb)(wsclient *c)) { pthread_mutex_lock(&client->lock); client->onopen = cb; pthread_mutex_unlock(&client->lock); } -void libwsclient_onmessage(wsclient *client, int (*cb)(libwsclient_message *msg)) { +void libwsclient_onmessage(wsclient *client, int (*cb)(wsclient *c, libwsclient_message *msg)) { pthread_mutex_lock(&client->lock); client->onmessage = cb; pthread_mutex_unlock(&client->lock); } +void libwsclient_close(wsclient *client) { + char data[6]; + int i = 0, n, mask_int; + struct timeval tv; + gettimeofday(&tv); + srand(tv.tv_sec * tv.tv_usec); + mask_int = rand(); + memcpy(data+2, &mask_int, 4); + data[0] = 0x88; + data[1] = 0x80; + do { + n = send(client->sockfd, data, 6, 0); + i += n; + } while(i < 6 && n > 0); + pthread_mutex_lock(&client->lock); + client->flags |= CLIENT_SENT_CLOSE_FRAME; + pthread_mutex_unlock(&client->lock); +} + +void libwsclient_handle_control_frame(wsclient *c, libwsclient_frame *ctl_frame) { + int i; + char mask[4]; + int mask_int; + struct timeval tv; + gettimeofday(&tv); + srand(tv.tv_sec * tv.tv_usec); + mask_int = rand(); + memcpy(mask, &mask_int, 4); + switch(ctl_frame->opcode) { + case 0x8: + fprintf(stderr, "Recived close frame.\n"); + //close frame + if((c->flags & CLIENT_SENT_CLOSE_FRAME) == 0) { + //server request close. Send close frame as acknowledgement. + for(i=0;ipayload_len;i++) + *(ctl_frame->rawdata + ctl_frame->payload_offset + i) ^= (mask[i % 4] & 0xff); //mask payload + *(ctl_frame->rawdata + 1) |= 0x80; //turn mask bit on + i = 0; + while(i < ctl_frame->payload_offset + ctl_frame->payload_len) { + i += send(c->sockfd, ctl_frame->rawdata + i, ctl_frame->payload_offset + ctl_frame->payload_len - i, 0); + } + } + pthread_mutex_lock(&c->lock); + c->flags |= CLIENT_SHOULD_CLOSE; + pthread_mutex_unlock(&c->lock); + 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. + free(ctl_frame->rawdata); + memset(ctl_frame, 0, sizeof(libwsclient_frame)); + ctl_frame->prev_frame = ptr; + ctl_frame->rawdata = (char *)malloc(FRAME_CHUNK_LENGTH); + memset(ctl_frame->rawdata, 0, FRAME_CHUNK_LENGTH); +} + void libwsclient_in_data(wsclient *c, char in) { libwsclient_frame *current = NULL, *new = NULL; unsigned char payload_len_short; @@ -75,7 +136,7 @@ void libwsclient_in_data(wsclient *c, char in) { if(current->fin == 1) { //is control frame if((current->opcode & 0x08) == 0x08) { - //handle control frame + libwsclient_handle_control_frame(c, current); } else { libwsclient_dispatch_message(c, current); c->current_frame = NULL; @@ -125,7 +186,7 @@ void libwsclient_dispatch_message(wsclient *c, libwsclient_frame *current) { msg->payload_len = message_offset; msg->payload = message_payload; if(c->onmessage != NULL) { - c->onmessage(msg); + c->onmessage(c, msg); } else { fprintf(stderr, "No onmessage call back registered with libwsclient.\n"); } @@ -415,7 +476,7 @@ void *libwsclient_handshake_thread(void *ptr) { pthread_mutex_lock(&client->lock); client->flags &= ~CLIENT_CONNECTING; if(client->onopen != NULL) { - client->onopen(); + client->onopen(client); } pthread_mutex_unlock(&client->lock); return NULL; diff --git a/wsclient.h b/wsclient.h index 97fb99e..f05127c 100644 --- a/wsclient.h +++ b/wsclient.h @@ -8,6 +8,8 @@ #define CLIENT_IS_SSL (1 << 0) #define CLIENT_CONNECTING (1 << 1) +#define CLIENT_SHOULD_CLOSE (1 << 2) +#define CLIENT_SENT_CLOSE_FRAME (1 << 3) #define REQUEST_HAS_CONNECTION (1 << 0) @@ -41,10 +43,10 @@ typedef struct _wsclient { char *URI; int sockfd; int flags; - int (*onopen)(void); - int (*onclose)(void); - int (*onerror)(void); - int (*onmessage)(libwsclient_message *msg); + int (*onopen)(struct _wsclient *); + int (*onclose)(struct _wsclient *); + int (*onerror)(struct _wsclient *); + int (*onmessage)(struct _wsclient *, libwsclient_message *msg); libwsclient_frame *current_frame; } wsclient; @@ -55,10 +57,12 @@ 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); +int libwsclient_complete_frame(libwsclient_frame *frame); +void libwsclient_handle_control_frame(wsclient *c, libwsclient_frame *ctl_frame); void libwsclient_run(wsclient *c); void *libwsclient_handshake_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); +void libwsclient_close(wsclient *c); #endif /* WSCLIENT_H_ */