Modify the API a little bit

Needed to have wsclient structure passed to callbacks for references
to sockfd or other API functions that need it. (libwsclient_close)

Also, respond to close frames correctly.  Right now, we just wait
on server to close TCP connection without a timeout.
master
Payden Sutherland 12 years ago
parent c24b62d0db
commit a10c910559

@ -4,24 +4,26 @@
#include <wsclient/wsclient.h>
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;
}

@ -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;i<ctl_frame->payload_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;

@ -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_ */

Loading…
Cancel
Save