diff --git a/Makefile.am b/Makefile.am index b37e14b..33e4984 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,4 +2,5 @@ lib_LTLIBRARIES=libwsclient.la libwsclient_la_SOURCES = wsclient.c base64.c sha1.c library_includedir=$(includedir)/wsclient library_include_HEADERS = wsclient.h +AM_LDFLAGS = -lpthread ACLOCAL_AMFLAGS = -I m4 diff --git a/config.h.in b/config.h.in index bac670e..6529273 100644 --- a/config.h.in +++ b/config.h.in @@ -6,6 +6,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#undef HAVE_LIBPTHREAD + /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC diff --git a/configure.ac b/configure.ac index e2bbf1d..c7968ae 100644 --- a/configure.ac +++ b/configure.ac @@ -23,6 +23,9 @@ AC_TYPE_SIZE_T AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([memset socket strstr strchr]) - +AC_CHECK_LIB(pthread, pthread_create, [], [ + echo "This library requires pthread" + exit -1 + ]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/test.c b/test.c index ec3011f..b705d36 100644 --- a/test.c +++ b/test.c @@ -20,9 +20,8 @@ int main(int argc, char **argv) { fprintf(stderr, "Unable to initialize new WS client.\n"); exit(1); } - client->onopen = &onopen; - client->onmessage = &onmessage; - libwsclient_send(client, "Testing"); + libwsclient_onopen(client, &onopen); + libwsclient_onmessage(client, &onmessage); libwsclient_run(client); return 0; } diff --git a/wsclient.c b/wsclient.c index c5c81bf..c25a44e 100644 --- a/wsclient.c +++ b/wsclient.c @@ -17,6 +17,16 @@ void libwsclient_run(wsclient *c) { char buf[1024]; int n, i; + pthread_mutex_lock(&c->lock); + if(c->flags & CLIENT_CONNECTING) { + pthread_mutex_unlock(&c->lock); + pthread_join(c->handshake_thread, NULL); + pthread_mutex_lock(&c->lock); + c->flags &= ~CLIENT_CONNECTING; + free(c->URI); + c->URI = NULL; + } + pthread_mutex_unlock(&c->lock); do { memset(buf, 0, 1024); n = recv(c->sockfd, buf, 1023, 0); @@ -31,6 +41,18 @@ void libwsclient_run(wsclient *c) { free(c); } +void libwsclient_onopen(wsclient *client, int (*cb)(void)) { + pthread_mutex_lock(&client->lock); + client->onopen = cb; + pthread_mutex_unlock(&client->lock); +} + +void libwsclient_onmessage(wsclient *client, int (*cb)(libwsclient_message *msg)) { + pthread_mutex_lock(&client->lock); + client->onmessage = cb; + pthread_mutex_unlock(&client->lock); +} + void libwsclient_in_data(wsclient *c, char in) { libwsclient_frame *current = NULL, *new = NULL; unsigned char payload_len_short; @@ -201,6 +223,38 @@ int libwsclient_open_connection(const char *host, const char *port) { } wsclient *libwsclient_new(const char *URI) { + wsclient *client = NULL; + + client = (wsclient *)malloc(sizeof(wsclient)); + if(!client) { + fprintf(stderr, "Unable to allocate memory in libwsclient_new.\n"); + exit(1); + } + memset(client, 0, sizeof(wsclient)); + if(pthread_mutex_init(&client->lock, NULL) != 0) { + fprintf(stderr, "Unable to init mutex in libwsclient_new.\n"); + exit(5); + } + pthread_mutex_lock(&client->lock); + client->URI = (char *)malloc(strlen(URI)+1); + if(!client->URI) { + fprintf(stderr, "Unable to allocate memory in libwsclient_new.\n"); + exit(3); + } + memset(client->URI, 0, strlen(URI)+1); + strncpy(client->URI, URI, strlen(URI)); + client->flags |= CLIENT_CONNECTING; + pthread_mutex_unlock(&client->lock); + + if(pthread_create(&(client->handshake_thread), NULL, libwsclient_handshake_thread, (void *)client)) { + perror("pthread"); + exit(4); + } + return client; +} +void *libwsclient_handshake_thread(void *ptr) { + wsclient *client = (wsclient *)ptr; + const char *URI = client->URI; SHA1Context shactx; const char *UUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; char pre_encode[256]; @@ -217,12 +271,6 @@ wsclient *libwsclient_new(const char *URI) { char recv_buf[1024]; char *URI_copy = NULL, *p = NULL, *rcv = NULL, *tok = NULL; int i, z, sockfd, n, flags = 0, headers_space = 1024; - wsclient *client = (wsclient *)malloc(sizeof(wsclient)); - if(!client) { - fprintf(stderr, "Unable to allocate memory in libwsclient_new.\n"); - exit(1); - } - memset(client, 0, sizeof(wsclient)); URI_copy = (char *)malloc(strlen(URI)+1); if(!URI_copy) { fprintf(stderr, "Unable to allocate memory in libwsclient_new.\n"); @@ -254,11 +302,15 @@ wsclient *libwsclient_new(const char *URI) { strncpy(port, "80", 9); } else { strncpy(port, "443", 9); + pthread_mutex_lock(&client->lock); client->flags |= CLIENT_IS_SSL; + pthread_mutex_unlock(&client->lock); } } else { i++; p = strchr(URI_copy+i, '/'); + if(!p) + p = strchr(URI_copy+i, '\0'); strncpy(port, URI_copy+i, (p - (URI_copy+i))); port[p-(URI_copy+i)] = '\0'; i += p-(URI_copy+i); @@ -271,7 +323,9 @@ wsclient *libwsclient_new(const char *URI) { fprintf(stderr, "Error opening socket.\n"); exit(5); } + pthread_mutex_lock(&client->lock); client->sockfd = sockfd; + pthread_mutex_unlock(&client->lock); //perform handshake //generate nonce @@ -358,7 +412,13 @@ wsclient *libwsclient_new(const char *URI) { } - return client; + pthread_mutex_lock(&client->lock); + client->flags &= ~CLIENT_CONNECTING; + if(client->onopen != NULL) { + client->onopen(); + } + pthread_mutex_unlock(&client->lock); + return NULL; } //somewhat hackish stricmp @@ -375,11 +435,22 @@ int stricmp(const char *s1, const char *s2) { } int libwsclient_send(wsclient *client, char *strdata) { + pthread_mutex_lock(&client->lock); + if(client->flags & CLIENT_CONNECTING) { + pthread_mutex_unlock(&client->lock); + pthread_join(client->handshake_thread, NULL); + pthread_mutex_lock(&client->lock); + client->flags &= ~CLIENT_CONNECTING; + free(client->URI); + client->URI = NULL; + } + int sockfd = client->sockfd; + pthread_mutex_unlock(&client->lock); if(strdata == NULL) { fprintf(stderr, "NULL pointer psased to libwsclient_send\n"); return -1; } - int sockfd = client->sockfd; + struct timeval tv; unsigned char mask[4]; unsigned int mask_int; diff --git a/wsclient.h b/wsclient.h index 2c8bc9d..97fb99e 100644 --- a/wsclient.h +++ b/wsclient.h @@ -1,4 +1,5 @@ #include +#include #ifndef WSCLIENT_H_ #define WSCLIENT_H_ @@ -6,6 +7,8 @@ #define FRAME_CHUNK_LENGTH 1024 #define CLIENT_IS_SSL (1 << 0) +#define CLIENT_CONNECTING (1 << 1) + #define REQUEST_HAS_CONNECTION (1 << 0) #define REQUEST_HAS_UPGRADE (1 << 1) @@ -33,6 +36,9 @@ typedef struct _libwsclient_message { } libwsclient_message; typedef struct _wsclient { + pthread_t handshake_thread; + pthread_mutex_t lock; + char *URI; int sockfd; int flags; int (*onopen)(void); @@ -43,13 +49,14 @@ typedef struct _wsclient { } wsclient; + //Function defs wsclient *libwsclient_new(const char *URI); int libwsclient_open_connection(const char *host, const char *port); int stricmp(const char *s1, const char *s2); void libwsclient_run(wsclient *c); -void *libwsclient_run_thread(void *ptr); +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);