diff --git a/test.c b/test.c index 1b6aef8..20d5075 100644 --- a/test.c +++ b/test.c @@ -18,13 +18,12 @@ int onmessage(wsclient *c, wsclient_message *msg) { } int onopen(wsclient *c) { - fprintf(stderr, "onopen called.\n"); - libwsclient_send(c, "testing::testing::demo.paydensutherland.com"); + fprintf(stderr, "onopen called: %d\n", c->sockfd); return 0; } int main(int argc, char **argv) { - wsclient *client = libwsclient_new("ws://ip6-localhost:8080"); + wsclient *client = libwsclient_new("ws://websocket.mtgox.com/mtgox"); if(!client) { fprintf(stderr, "Unable to initialize new WS client.\n"); exit(1); @@ -33,6 +32,7 @@ int main(int argc, char **argv) { libwsclient_onmessage(client, &onmessage); libwsclient_onerror(client, &onerror); libwsclient_onclose(client, &onclose); + libwsclient_helper_socket(client, "test.sock"); libwsclient_run(client); libwsclient_finish(client); return 0; diff --git a/wsclient.c b/wsclient.c index 1e5f6ad..1a9f64e 100644 --- a/wsclient.c +++ b/wsclient.c @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -351,6 +352,88 @@ int libwsclient_open_connection(const char *host, const char *port) { return sockfd; } +int libwsclient_helper_socket(wsclient *c, const char *path) { + socklen_t len; + int sockfd; + if(c->helper_sa.sun_family) { + fprintf(stderr, "Can only bind one UNIX socket for helper program communications.\n"); + return WS_HELPER_ALREADY_BOUND_ERR; + } + c->helper_sa.sun_family = AF_UNIX; + strncpy(c->helper_sa.sun_path, path, sizeof(c->helper_sa.sun_path) - 1); + unlink(c->helper_sa.sun_path); + len = strlen(c->helper_sa.sun_path) + sizeof(c->helper_sa.sun_family); + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if(sockfd == -1) { + fprintf(stderr, "Error creating UNIX socket.\n"); + return WS_HELPER_CREATE_SOCK_ERR; + } + + if(bind(sockfd, (struct sockaddr *)&c->helper_sa, len) == -1) { + fprintf(stderr, "Error binding UNIX socket.\n"); + perror("bind"); + close(sockfd); + memset(&c->helper_sa, 0, sizeof(struct sockaddr_un)); + return WS_HELPER_BIND_ERR; + } + + if(listen(sockfd, 5) == -1) { + fprintf(stderr, "Error listening on UNIX socket.\n"); + close(sockfd); + memset(&c->helper_sa, 0, sizeof(struct sockaddr_un)); + return WS_HELPER_LISTEN_ERR; + } + + c->helper_sock = sockfd; + pthread_create(&c->helper_thread, NULL, libwsclient_helper_socket_thread, (void *)c); +} + +void *libwsclient_helper_socket_thread(void *ptr) { + wsclient *c = ptr; + struct sockaddr_un remote; + socklen_t len; + int remote_sock, n, payload_idx, payload_sz; + char recv_buf[HELPER_RECV_BUF_SIZE]; + char *payload = NULL, *payload_tmp = NULL; + + + for(;;) { //TODO: some way to cleanly break this loop + len = sizeof(remote); + if((remote_sock = accept(c->helper_sock, (struct sockaddr *)&remote, &len)) == -1) { + continue; + } + payload_idx = 0; + payload = (char *)malloc(HELPER_RECV_BUF_SIZE); + memset(payload, 0, payload_sz); + payload_sz = HELPER_RECV_BUF_SIZE; + do { + memset(recv_buf, 0, HELPER_RECV_BUF_SIZE); + n = recv(remote_sock, recv_buf, HELPER_RECV_BUF_SIZE - 1, 0); + if(n > 0) { + if(n + payload_idx >= payload_sz) { + payload_tmp = payload; + payload_sz += HELPER_RECV_BUF_SIZE; + payload = (char *)realloc(payload, payload_sz); + if(!payload) { + payload = payload_tmp; + fprintf(stderr, "Unable to realloc, data sent will be truncated.\n"); + break; + } + memset(payload + payload_idx, 0, payload_sz - payload_idx); + } + memcpy(payload + payload_idx, recv_buf, n); + payload_idx += n; + } + + } while(n > 0); + close(remote_sock); + libwsclient_send(c, payload); + free(payload); + payload = NULL; + } + return NULL; +} + wsclient *libwsclient_new(const char *URI) { wsclient *client = NULL; diff --git a/wsclient.h b/wsclient.h index 000b321..f6de600 100644 --- a/wsclient.h +++ b/wsclient.h @@ -1,10 +1,14 @@ #include #include +#include +#include +#include #ifndef WSCLIENT_H_ #define WSCLIENT_H_ #define FRAME_CHUNK_LENGTH 1024 +#define HELPER_RECV_BUF_SIZE 1024 #define CLIENT_IS_SSL (1 << 0) #define CLIENT_CONNECTING (1 << 1) @@ -41,6 +45,10 @@ #define WS_HANDSHAKE_NO_UPGRADE_ERR -16 #define WS_HANDSHAKE_NO_CONNECTION_ERR -17 #define WS_HANDSHAKE_BAD_ACCEPT_ERR -18 +#define WS_HELPER_ALREADY_BOUND_ERR -19 +#define WS_HELPER_CREATE_SOCK_ERR -20 +#define WS_HELPER_BIND_ERR -21 +#define WS_HELPER_LISTEN_ERR -22 typedef struct _wsclient_frame { unsigned int fin; @@ -69,6 +77,7 @@ typedef struct _wsclient_error { } wsclient_error; typedef struct _wsclient { + pthread_t helper_thread; pthread_t handshake_thread; pthread_t run_thread; pthread_mutex_t lock; @@ -80,6 +89,8 @@ typedef struct _wsclient { int (*onerror)(struct _wsclient *, wsclient_error *err); int (*onmessage)(struct _wsclient *, wsclient_message *msg); wsclient_frame *current_frame; + struct sockaddr_un helper_sa; + int helper_sock; } wsclient; @@ -100,6 +111,8 @@ void libwsclient_cleanup_frames(wsclient_frame *first); void libwsclient_in_data(wsclient *c, char in); void libwsclient_dispatch_message(wsclient *c, wsclient_frame *current); void libwsclient_close(wsclient *c); +int libwsclient_helper_socket(wsclient *c, const char *path); +void *libwsclient_helper_socket_thread(void *ptr); //Define errors char *errors[] = {