From 56885f308437645d75f9cae9c6c5cdcbeaa7371d Mon Sep 17 00:00:00 2001 From: Peter Hinz Date: Wed, 2 Mar 2011 22:03:47 +0000 Subject: [PATCH] introduce win32 build capability This adds win32 build compatability to libwebsockets. The patch is from Peter Hinz, Andy Green has cleaned it up a bit and possibly broken win32 compatability since I can't test it, so there may be followup patches. It compiles fine under Linux after this patch anyway. Much of the patch is changing a reserved keyword for Visual C compiler "this" to "context", but there is no real C99 support in the MSFT compiler even though it is 2011 so C99 style array declarations have been mangled back into "ancient C" style. Some windows-isms are also added like closesocket() but these are quite localized. Win32 random is just using C library random() call at the moment vs Linux /dev/urandom. canonical hostname detection is broken in win32 at the moment. Signed-off-by: Peter Hinz Signed-off-by: Andy Green --- lib/client-handshake.c | 30 +- lib/handshake.c | 9 +- lib/libwebsockets.c | 717 ++++++++++++--------- lib/libwebsockets.h | 23 +- lib/parsers.c | 57 +- lib/private-libwebsockets.h | 34 +- lib/sha-1.c | 21 + libwebsockets-api-doc.html | 36 +- test-server/test-client.c | 22 +- test-server/test-server-extpoll.c | 30 +- test-server/test-server.c | 72 +-- win32port/client/client.vcxproj | 98 +++ win32port/client/client.vcxproj.filters | 39 ++ win32port/client/client.vcxproj.user | 7 + .../libwebsocketswin32/libwebsocketswin32.vcxproj | 89 +++ .../libwebsocketswin32.vcxproj.filters | 48 ++ .../libwebsocketswin32.vcxproj.user | 3 + win32port/server/server.vcxproj | 106 +++ win32port/server/server.vcxproj.filters | 51 ++ win32port/server/server.vcxproj.user | 3 + win32port/win32helpers/getopt.c | 153 +++++ win32port/win32helpers/getopt.h | 33 + win32port/win32helpers/getopt_long.c | 237 +++++++ win32port/win32helpers/gettimeofday.c | 48 ++ win32port/win32helpers/gettimeofday.h | 21 + win32port/win32helpers/netdb.h | 1 + win32port/win32helpers/strings.h | 0 win32port/win32helpers/sys/time.h | 1 + win32port/win32helpers/unistd.h | 0 win32port/win32helpers/websock-w32.h | 21 + win32port/win32port.sln | 35 + win32port/win32port.suo | Bin 0 -> 32256 bytes 32 files changed, 1600 insertions(+), 445 deletions(-) create mode 100644 win32port/client/client.vcxproj create mode 100644 win32port/client/client.vcxproj.filters create mode 100644 win32port/client/client.vcxproj.user create mode 100644 win32port/libwebsocketswin32/libwebsocketswin32.vcxproj create mode 100644 win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters create mode 100644 win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.user create mode 100644 win32port/server/server.vcxproj create mode 100644 win32port/server/server.vcxproj.filters create mode 100644 win32port/server/server.vcxproj.user create mode 100644 win32port/win32helpers/getopt.c create mode 100644 win32port/win32helpers/getopt.h create mode 100644 win32port/win32helpers/getopt_long.c create mode 100644 win32port/win32helpers/gettimeofday.c create mode 100644 win32port/win32helpers/gettimeofday.h create mode 100644 win32port/win32helpers/netdb.h create mode 100644 win32port/win32helpers/strings.h create mode 100644 win32port/win32helpers/sys/time.h create mode 100644 win32port/win32helpers/unistd.h create mode 100644 win32port/win32helpers/websock-w32.h create mode 100644 win32port/win32port.sln create mode 100644 win32port/win32port.suo diff --git a/lib/client-handshake.c b/lib/client-handshake.c index da585a6..05959a7 100644 --- a/lib/client-handshake.c +++ b/lib/client-handshake.c @@ -4,7 +4,7 @@ /** * libwebsocket_client_connect() - Connect to another websocket server - * @this: Websocket context + * @context: Websocket context * @address: Remote server address, eg, "myserver.com" * @port: Port to connect to on the remote server, eg, 80 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self @@ -22,7 +22,7 @@ */ struct libwebsocket * -libwebsocket_client_connect(struct libwebsocket_context *this, +libwebsocket_client_connect(struct libwebsocket_context *context, const char *address, int port, int ssl_connection, @@ -117,7 +117,7 @@ libwebsocket_client_connect(struct libwebsocket_context *this, /* force no mask if he asks for that though */ - if (this->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK) + if (context->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK) wsi->xor_mask = xor_no_mask; for (n = 0; n < WSI_TOKEN_COUNT; n++) { @@ -129,7 +129,7 @@ libwebsocket_client_connect(struct libwebsocket_context *this, * proxy? */ - if (this->http_proxy_port) { + if (context->http_proxy_port) { plen = sprintf(pkt, "CONNECT %s:%u HTTP/1.0\x0d\x0a" "User-agent: libwebsockets\x0d\x0a" /*Proxy-authorization: basic aGVsbG86d29ybGQ= */ @@ -137,8 +137,8 @@ libwebsocket_client_connect(struct libwebsocket_context *this, /* OK from now on we talk via the proxy */ - address = this->http_proxy_address; - port = this->http_proxy_port; + address = context->http_proxy_address; + port = context->http_proxy_port; } /* @@ -171,26 +171,30 @@ libwebsocket_client_connect(struct libwebsocket_context *this, /* into fd -> wsi hashtable */ - insert_wsi(this, wsi); + insert_wsi(context, wsi); /* into internal poll list */ - this->fds[this->fds_count].fd = wsi->sock; - this->fds[this->fds_count].revents = 0; - this->fds[this->fds_count++].events = POLLIN; + context->fds[context->fds_count].fd = wsi->sock; + context->fds[context->fds_count].revents = 0; + context->fds[context->fds_count++].events = POLLIN; /* external POLL support via protocol 0 */ - this->protocols[0].callback(this, wsi, + context->protocols[0].callback(context, wsi, LWS_CALLBACK_ADD_POLL_FD, (void *)(long)wsi->sock, NULL, POLLIN); /* we are connected to server, or proxy */ - if (this->http_proxy_port) { + if (context->http_proxy_port) { n = send(wsi->sock, pkt, plen, 0); if (n < 0) { +#ifdef WIN32 + closesocket(wsi->sock); +#else close(wsi->sock); +#endif fprintf(stderr, "ERROR writing to proxy socket\n"); goto bail1; } @@ -213,7 +217,7 @@ libwebsocket_client_connect(struct libwebsocket_context *this, wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE; pfd.fd = wsi->sock; pfd.revents = POLLIN; - libwebsocket_service_fd(this, &pfd); + libwebsocket_service_fd(context, &pfd); return wsi; diff --git a/lib/handshake.c b/lib/handshake.c index 38a1811..c3e9ed5 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -318,7 +318,8 @@ handshake_0405(struct libwebsocket *wsi) /* select the nonce */ - n = read(wsi->protocol->owning_server->fd_random, hash, 16); + n = libwebsockets_get_random(wsi->protocol->owning_server, + hash, 16); if (n != 16) { fprintf(stderr, "Unable to read random device %s %d\n", SYSTEM_RANDOM_FILEPATH, n); @@ -448,7 +449,7 @@ bail: */ int -libwebsocket_read(struct libwebsocket_context *this, struct libwebsocket *wsi, +libwebsocket_read(struct libwebsocket_context *context, struct libwebsocket *wsi, unsigned char * buf, size_t len) { size_t n; @@ -490,7 +491,7 @@ libwebsocket_read(struct libwebsocket_context *this, struct libwebsocket *wsi, if (!wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len || !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len) { if (wsi->protocol->callback) - (wsi->protocol->callback)(this, wsi, + (wsi->protocol->callback)(context, wsi, LWS_CALLBACK_HTTP, wsi->user_space, wsi->utf8_token[WSI_TOKEN_GET_URI].token, 0); wsi->state = WSI_STATE_HTTP; @@ -612,7 +613,7 @@ libwebsocket_read(struct libwebsocket_context *this, struct libwebsocket *wsi, return 0; bail: - libwebsocket_close_and_free_session(this, wsi, + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); return -1; diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 96d3934..d18f7a7 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -1,4 +1,4 @@ -/* +/* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010 Andy Green @@ -20,8 +20,12 @@ */ #include "private-libwebsockets.h" -#include +#ifdef WIN32 + +#else +#include +#endif /* * In-place str to lower case */ @@ -38,47 +42,47 @@ strtolower(char *s) /* file descriptor hash management */ struct libwebsocket * -wsi_from_fd(struct libwebsocket_context *this, int fd) +wsi_from_fd(struct libwebsocket_context *context, int fd) { int h = LWS_FD_HASH(fd); int n = 0; - for (n = 0; n < this->fd_hashtable[h].length; n++) - if (this->fd_hashtable[h].wsi[n]->sock == fd) - return this->fd_hashtable[h].wsi[n]; + for (n = 0; n < context->fd_hashtable[h].length; n++) + if (context->fd_hashtable[h].wsi[n]->sock == fd) + return context->fd_hashtable[h].wsi[n]; return NULL; } int -insert_wsi(struct libwebsocket_context *this, struct libwebsocket *wsi) +insert_wsi(struct libwebsocket_context *context, struct libwebsocket *wsi) { int h = LWS_FD_HASH(wsi->sock); - if (this->fd_hashtable[h].length == MAX_CLIENTS - 1) { + if (context->fd_hashtable[h].length == MAX_CLIENTS - 1) { fprintf(stderr, "hash table overflow\n"); return 1; } - this->fd_hashtable[h].wsi[this->fd_hashtable[h].length++] = wsi; + context->fd_hashtable[h].wsi[context->fd_hashtable[h].length++] = wsi; return 0; } int -delete_from_fd(struct libwebsocket_context *this, int fd) +delete_from_fd(struct libwebsocket_context *context, int fd) { int h = LWS_FD_HASH(fd); int n = 0; - for (n = 0; n < this->fd_hashtable[h].length; n++) - if (this->fd_hashtable[h].wsi[n]->sock == fd) { - while (n < this->fd_hashtable[h].length) { - this->fd_hashtable[h].wsi[n] = - this->fd_hashtable[h].wsi[n + 1]; + for (n = 0; n < context->fd_hashtable[h].length; n++) + if (context->fd_hashtable[h].wsi[n]->sock == fd) { + while (n < context->fd_hashtable[h].length) { + context->fd_hashtable[h].wsi[n] = + context->fd_hashtable[h].wsi[n + 1]; n++; } - this->fd_hashtable[h].length--; + context->fd_hashtable[h].length--; return 0; } @@ -107,6 +111,9 @@ static int interface_to_sa(const char* ifname, struct sockaddr_in *addr, size_t addrlen) { int rc = -1; +#ifdef WIN32 + // TODO +#else struct ifaddrs *ifr; struct ifaddrs *ifc; struct sockaddr_in *sin; @@ -125,12 +132,12 @@ interface_to_sa(const char* ifname, struct sockaddr_in *addr, size_t addrlen) } freeifaddrs(ifr); - +#endif return rc; } void -libwebsocket_close_and_free_session(struct libwebsocket_context *this, +libwebsocket_close_and_free_session(struct libwebsocket_context *context, struct libwebsocket *wsi, enum lws_close_status reason) { int n; @@ -148,25 +155,25 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *this, /* remove this fd from wsi mapping hashtable */ - delete_from_fd(this, wsi->sock); + delete_from_fd(context, wsi->sock); /* delete it from the internal poll list if still present */ - for (n = 0; n < this->fds_count; n++) { - if (this->fds[n].fd != wsi->sock) + for (n = 0; n < context->fds_count; n++) { + if (context->fds[n].fd != wsi->sock) continue; - while (n < this->fds_count - 1) { - this->fds[n] = this->fds[n + 1]; + while (n < context->fds_count - 1) { + context->fds[n] = context->fds[n + 1]; n++; } - this->fds_count--; + context->fds_count--; /* we only have to deal with one */ - n = this->fds_count; + n = context->fds_count; } /* remove also from external POLL support via protocol 0 */ - this->protocols[0].callback(this, wsi, + context->protocols[0].callback(context, wsi, LWS_CALLBACK_DEL_POLL_FD, (void *)(long)wsi->sock, NULL, 0); wsi->close_reason = reason; @@ -189,7 +196,7 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *this, if (wsi->protocol && wsi->protocol->callback && old_state == WSI_STATE_ESTABLISHED) - wsi->protocol->callback(this, wsi, LWS_CALLBACK_CLOSED, + wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLOSED, wsi->user_space, NULL, 0); /* free up his allocations */ @@ -204,12 +211,20 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *this, if (wsi->ssl) { n = SSL_get_fd(wsi->ssl); SSL_shutdown(wsi->ssl); +#ifdef WIN32 + closesocket(n); +#else close(n); +#endif SSL_free(wsi->ssl); } else { #endif shutdown(wsi->sock, SHUT_RDWR); +#ifdef WIN32 + closesocket(wsi->sock); +#else close(wsi->sock); +#endif #ifdef LWS_OPENSSL_SUPPORT } #endif @@ -222,19 +237,19 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *this, /** * libwebsockets_hangup_on_client() - Server calls to terminate client * connection - * @this: libwebsockets context + * @context: libwebsockets context * @fd: Connection socket descriptor */ void -libwebsockets_hangup_on_client(struct libwebsocket_context *this, int fd) +libwebsockets_hangup_on_client(struct libwebsocket_context *context, int fd) { - struct libwebsocket *wsi = wsi_from_fd(this, fd); + struct libwebsocket *wsi = wsi_from_fd(context, fd); if (wsi == NULL) return; - libwebsocket_close_and_free_session(this, wsi, + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); } @@ -304,16 +319,32 @@ libwebsockets_get_peer_addresses(int fd, char *name, int name_len, } } +int libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len) +{ + int n; + char *p = buf; + +#ifdef WIN32 + for (n = 0; n < len; n++) + p[n] = (unsigned char)rand(); +#else + n = read(context->fd_random, p, len); +#endif + + return n; +} + void libwebsockets_00_spaceout(char *key, int spaces, int seed) { char *p; - + key++; while (spaces--) { if (*key && (seed & 1)) key++; seed >>= 1; - + p = key + strlen(key); while (p >= key) { p[1] = p[0]; @@ -347,7 +378,7 @@ void libwebsockets_00_spam(char *key, int count, int seed) /** * libwebsocket_service_fd() - Service polled socket with something waiting - * @this: Websocket context + * @context: Websocket context * @pollfd: The pollfd entry describing the socket fd and which events * happened. * @@ -357,7 +388,7 @@ void libwebsockets_00_spam(char *key, int count, int seed) */ int -libwebsocket_service_fd(struct libwebsocket_context *this, +libwebsocket_service_fd(struct libwebsocket_context *context, struct pollfd *pollfd) { unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_BROADCAST_PAYLOAD + @@ -391,13 +422,13 @@ libwebsocket_service_fd(struct libwebsocket_context *this, gettimeofday(&tv, NULL); - if (this->last_timeout_check_s != tv.tv_sec) { - this->last_timeout_check_s = tv.tv_sec; + if (context->last_timeout_check_s != tv.tv_sec) { + context->last_timeout_check_s = tv.tv_sec; /* global timeout check once per second */ - for (n = 0; n < this->fds_count; n++) { - wsi = wsi_from_fd(this, this->fds[n].fd); + for (n = 0; n < context->fds_count; n++) { + wsi = wsi_from_fd(context, context->fds[n].fd); if (!wsi->pending_timeout) continue; @@ -407,8 +438,8 @@ libwebsocket_service_fd(struct libwebsocket_context *this, */ if (tv.tv_sec > wsi->pending_timeout_limit) - libwebsocket_close_and_free_session(this, wsi, - LWS_CLOSE_STATUS_NOSTATUS); + libwebsocket_close_and_free_session(context, + wsi, LWS_CLOSE_STATUS_NOSTATUS); } } @@ -419,7 +450,7 @@ libwebsocket_service_fd(struct libwebsocket_context *this, /* no, here to service a socket descriptor */ - wsi = wsi_from_fd(this, pollfd->fd); + wsi = wsi_from_fd(context, pollfd->fd); if (wsi == NULL) return 1; @@ -442,9 +473,13 @@ libwebsocket_service_fd(struct libwebsocket_context *this, break; } - if (this->fds_count >= MAX_CLIENTS) { + if (context->fds_count >= MAX_CLIENTS) { fprintf(stderr, "too busy to accept new client\n"); +#ifdef WIN32 + closesocket(accept_fd); +#else close(accept_fd); +#endif break; } @@ -454,11 +489,15 @@ libwebsocket_service_fd(struct libwebsocket_context *this, * yet so we issue this to protocols[0] */ - if ((this->protocols[0].callback)(this, wsi, + if ((context->protocols[0].callback)(context, wsi, LWS_CALLBACK_FILTER_NETWORK_CONNECTION, (void*)(long)accept_fd, NULL, 0)) { fprintf(stderr, "Callback denied network connection\n"); +#ifdef WIN32 + closesocket(accept_fd); +#else close(accept_fd); +#endif break; } @@ -477,9 +516,9 @@ libwebsocket_service_fd(struct libwebsocket_context *this, #ifdef LWS_OPENSSL_SUPPORT new_wsi->ssl = NULL; - if (this->use_ssl) { + if (context->use_ssl) { - new_wsi->ssl = SSL_new(this->ssl_ctx); + new_wsi->ssl = SSL_new(context->ssl_ctx); if (new_wsi->ssl == NULL) { fprintf(stderr, "SSL_new failed: %s\n", ERR_error_string(SSL_get_error( @@ -535,7 +574,7 @@ libwebsocket_service_fd(struct libwebsocket_context *this, * to the start of the supported list, so it can look * for matching ones during the handshake */ - new_wsi->protocol = this->protocols; + new_wsi->protocol = context->protocols; new_wsi->user_space = NULL; /* @@ -546,20 +585,20 @@ libwebsocket_service_fd(struct libwebsocket_context *this, */ new_wsi->ietf_spec_revision = 0; - insert_wsi(this, new_wsi); + insert_wsi(context, new_wsi); /* * make sure NO events are seen yet on this new socket * (otherwise we inherit old fds[client].revents from * previous socket there and die mysteriously! ) */ - this->fds[this->fds_count].revents = 0; + context->fds[context->fds_count].revents = 0; - this->fds[this->fds_count].events = POLLIN; - this->fds[this->fds_count++].fd = accept_fd; + context->fds[context->fds_count].events = POLLIN; + context->fds[context->fds_count++].fd = accept_fd; /* external POLL support via protocol 0 */ - this->protocols[0].callback(this, new_wsi, + context->protocols[0].callback(context, new_wsi, LWS_CALLBACK_ADD_POLL_FD, (void *)(long)accept_fd, NULL, POLLIN); @@ -582,10 +621,14 @@ libwebsocket_service_fd(struct libwebsocket_context *this, break; } - if (this->fds_count >= MAX_CLIENTS) { + if (context->fds_count >= MAX_CLIENTS) { fprintf(stderr, "too busy to accept new broadcast " "proxy client\n"); +#ifdef WIN32 + closesocket(accept_fd); +#else close(accept_fd); +#endif break; } @@ -599,16 +642,16 @@ libwebsocket_service_fd(struct libwebsocket_context *this, /* note which protocol we are proxying */ new_wsi->protocol_index_for_broadcast_proxy = wsi->protocol_index_for_broadcast_proxy; - insert_wsi(this, new_wsi); + insert_wsi(context, new_wsi); /* add connected socket to internal poll array */ - this->fds[this->fds_count].revents = 0; - this->fds[this->fds_count].events = POLLIN; - this->fds[this->fds_count++].fd = accept_fd; + context->fds[context->fds_count].revents = 0; + context->fds[context->fds_count].events = POLLIN; + context->fds[context->fds_count++].fd = accept_fd; /* external POLL support via protocol 0 */ - this->protocols[0].callback(this, new_wsi, + context->protocols[0].callback(context, new_wsi, LWS_CALLBACK_ADD_POLL_FD, (void *)(long)accept_fd, NULL, POLLIN); @@ -623,7 +666,7 @@ libwebsocket_service_fd(struct libwebsocket_context *this, debug("Session Socket %p (fd=%d) dead\n", (void *)wsi, pollfd->fd); - libwebsocket_close_and_free_session(this, wsi, + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NORMAL); return 1; } @@ -637,11 +680,11 @@ libwebsocket_service_fd(struct libwebsocket_context *this, pollfd->events &= ~POLLOUT; /* external POLL support via protocol 0 */ - this->protocols[0].callback(this, wsi, + context->protocols[0].callback(context, wsi, LWS_CALLBACK_CLEAR_MODE_POLL_FD, (void *)(long)wsi->sock, NULL, POLLOUT); - wsi->protocol->callback(this, wsi, + wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLIENT_WRITEABLE, wsi->user_space, NULL, 0); @@ -665,9 +708,9 @@ libwebsocket_service_fd(struct libwebsocket_context *this, for (n = 0; n < FD_HASHTABLE_MODULUS; n++) { - for (m = 0; m < this->fd_hashtable[n].length; m++) { + for (m = 0; m < context->fd_hashtable[n].length; m++) { - new_wsi = this->fd_hashtable[n].wsi[m]; + new_wsi = context->fd_hashtable[n].wsi[m]; /* only to clients we are serving to */ @@ -693,7 +736,7 @@ libwebsocket_service_fd(struct libwebsocket_context *this, /* broadcast it to this connection */ - new_wsi->protocol->callback(this, new_wsi, + new_wsi->protocol->callback(context, new_wsi, LWS_CALLBACK_BROADCAST, new_wsi->user_space, buf + LWS_SEND_BUFFER_PRE_PADDING, len); @@ -710,14 +753,14 @@ libwebsocket_service_fd(struct libwebsocket_context *this, fprintf(stderr, "Proxy connection %p (fd=%d) dead\n", (void *)wsi, pollfd->fd); - libwebsocket_close_and_free_session(this, wsi, + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); return 1; } n = recv(wsi->sock, pkt, sizeof pkt, 0); if (n < 0) { - libwebsocket_close_and_free_session(this, wsi, + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); fprintf(stderr, "ERROR reading from proxy socket\n"); return 1; @@ -725,7 +768,7 @@ libwebsocket_service_fd(struct libwebsocket_context *this, pkt[13] = '\0'; if (strcmp(pkt, "HTTP/1.0 200 ") != 0) { - libwebsocket_close_and_free_session(this, wsi, + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); fprintf(stderr, "ERROR from proxy: %s\n", pkt); return 1; @@ -742,18 +785,20 @@ libwebsocket_service_fd(struct libwebsocket_context *this, #ifdef LWS_OPENSSL_SUPPORT if (wsi->use_ssl) { - wsi->ssl = SSL_new(this->ssl_client_ctx); - wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE); + wsi->ssl = SSL_new(context->ssl_client_ctx); + wsi->client_bio = BIO_new_socket(wsi->sock, + BIO_NOCLOSE); SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio); SSL_set_ex_data(wsi->ssl, - this->openssl_websocket_private_data_index, this); + context->openssl_websocket_private_data_index, + context); if (SSL_connect(wsi->ssl) <= 0) { fprintf(stderr, "SSL connect error %s\n", ERR_error_string(ERR_get_error(), ssl_err_buf)); - libwebsocket_close_and_free_session(this, wsi, + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); return 1; } @@ -765,8 +810,8 @@ libwebsocket_service_fd(struct libwebsocket_context *this, fprintf(stderr, "server's cert didn't " "look good %d\n", n); - libwebsocket_close_and_free_session(this, wsi, - LWS_CLOSE_STATUS_NOSTATUS); + libwebsocket_close_and_free_session(context, + wsi, LWS_CLOSE_STATUS_NOSTATUS); return 1; } } else { @@ -782,7 +827,7 @@ libwebsocket_service_fd(struct libwebsocket_context *this, * create the random key */ - n = read(this->fd_random, hash, 16); + n = libwebsockets_get_random(context, hash, 16); if (n != 16) { fprintf(stderr, "Unable to read from random dev %s\n", SYSTEM_RANDOM_FILEPATH); @@ -792,7 +837,7 @@ libwebsocket_service_fd(struct libwebsocket_context *this, free(wsi->c_origin); if (wsi->c_protocol) free(wsi->c_protocol); - libwebsocket_close_and_free_session(this, wsi, + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); return 1; } @@ -839,21 +884,23 @@ libwebsocket_service_fd(struct libwebsocket_context *this, unsigned int count; char challenge[16]; - read(this->fd_random, &spaces_1, sizeof(char)); - read(this->fd_random, &spaces_2, sizeof(char)); - + libwebsockets_get_random(context, &spaces_1, + sizeof(char)); + libwebsockets_get_random(context, &spaces_2, + sizeof(char)); + spaces_1 = (spaces_1 % 12) + 1; spaces_2 = (spaces_2 % 12) + 1; - + max_1 = 4294967295 / spaces_1; max_2 = 4294967295 / spaces_2; - read(this->fd_random, &num_1, sizeof(int)); - read(this->fd_random, &num_2, sizeof(int)); - + libwebsockets_get_random(context, &num_1, sizeof(int)); + libwebsockets_get_random(context, &num_2, sizeof(int)); + num_1 = (num_1 % max_1); num_2 = (num_2 % max_2); - + challenge[0] = num_1 >> 24; challenge[1] = num_1 >> 16; challenge[2] = num_1 >> 8; @@ -862,61 +909,61 @@ libwebsocket_service_fd(struct libwebsocket_context *this, challenge[5] = num_2 >> 16; challenge[6] = num_2 >> 8; challenge[7] = num_2; - + product_1 = num_1 * spaces_1; product_2 = num_2 * spaces_2; - + sprintf(key_1, "%lu", product_1); sprintf(key_2, "%lu", product_2); - read(this->fd_random, &seed, sizeof(int)); - read(this->fd_random, &count, sizeof(int)); - + libwebsockets_get_random(context, &seed, sizeof(int)); + libwebsockets_get_random(context, &count, sizeof(int)); + libwebsockets_00_spam(key_1, (count % 12) + 1, seed); - - read(this->fd_random, &seed, sizeof(int)); - read(this->fd_random, &count, sizeof(int)); - + + libwebsockets_get_random(context, &seed, sizeof(int)); + libwebsockets_get_random(context, &count, sizeof(int)); + libwebsockets_00_spam(key_2, (count % 12) + 1, seed); - - read(this->fd_random, &seed, sizeof(int)); - + + libwebsockets_get_random(context, &seed, sizeof(int)); + libwebsockets_00_spaceout(key_1, spaces_1, seed); libwebsockets_00_spaceout(key_2, spaces_2, seed >> 16); - + p += sprintf(p, "Upgrade: websocket\x0d\x0a" "Connection: Upgrade\x0d\x0aHost: %s\x0d\x0a", - wsi->c_host); + wsi->c_host); if (wsi->c_origin) p += sprintf(p, "Origin: %s\x0d\x0a", - wsi->c_origin); - + wsi->c_origin); + if (wsi->c_protocol) - p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a", - wsi->c_protocol); - + p += sprintf(p, "Sec-WebSocket-Protocol: %s" + "\x0d\x0a", wsi->c_protocol); + p += sprintf(p, "Sec-WebSocket-Key1: %s\x0d\x0a", - key_1); + key_1); p += sprintf(p, "Sec-WebSocket-Key2: %s\x0d\x0a", - key_2); + key_2); /* give userland a chance to append, eg, cookies */ - - this->protocols[0].callback(this, wsi, - LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, NULL, &p, (pkt + sizeof(pkt)) - p - 12); p += sprintf(p, "\x0d\x0a"); - - read(this->fd_random, p, 8); + + read(context->fd_random, p, 8); memcpy(&challenge[8], p, 8); p += 8; - + /* precompute what we want to see from the server */ - + MD5((unsigned char *)challenge, 16, (unsigned char *)wsi->initial_handshake_hash_base64); - + goto issue_hdr; } @@ -934,14 +981,13 @@ libwebsocket_service_fd(struct libwebsocket_context *this, p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a", wsi->c_protocol); p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a", - wsi->ietf_spec_revision); - + wsi->ietf_spec_revision); /* give userland a chance to append, eg, cookies */ - - this->protocols[0].callback(this, wsi, - LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, - NULL, &p, (pkt + sizeof(pkt)) - p - 12); - + + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + NULL, &p, (pkt + sizeof(pkt)) - p - 12); + p += sprintf(p, "\x0d\x0a"); /* prepare the expected server accept response */ @@ -954,16 +1000,16 @@ libwebsocket_service_fd(struct libwebsocket_context *this, lws_b64_encode_string(hash, 20, wsi->initial_handshake_hash_base64, sizeof wsi->initial_handshake_hash_base64); -issue_hdr: +issue_hdr: + /* done with these now */ - + free(wsi->c_path); free(wsi->c_host); if (wsi->c_origin) free(wsi->c_origin); - /* send our request to the server */ #ifdef LWS_OPENSSL_SUPPORT @@ -975,7 +1021,7 @@ issue_hdr: if (n < 0) { fprintf(stderr, "ERROR writing to client socket\n"); - libwebsocket_close_and_free_session(this, wsi, + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); return 1; } @@ -1030,7 +1076,7 @@ issue_hdr: if (wsi->parser_state != WSI_PARSING_COMPLETE) { fprintf(stderr, "libwebsocket_client_handshake " - "server response ailed parsing\n"); + "server response failed parsing\n"); goto bail3; } @@ -1045,43 +1091,45 @@ issue_hdr: * * xxxxxxxxxxxxxxxx */ - + if (wsi->ietf_spec_revision == 0) { if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len || - !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len || - !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len || - !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len || - (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len && - wsi->c_protocol != NULL)) { + !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len || + !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len || + !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len || + (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len && + wsi->c_protocol != NULL)) { fprintf(stderr, "libwebsocket_client_handshake " - "missing required header(s)\n"); + "missing required header(s)\n"); pkt[len] = '\0'; fprintf(stderr, "%s", pkt); goto bail3; } - + strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token); if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token, - "101 websocket protocol handshake")) { + "101 websocket protocol handshake")) { fprintf(stderr, "libwebsocket_client_handshake " - "server sent bad HTTP response '%s'\n", - wsi->utf8_token[WSI_TOKEN_HTTP].token); + "server sent bad HTTP response '%s'\n", + wsi->utf8_token[WSI_TOKEN_HTTP].token); goto bail3; } - if (wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len < 16) { + if (wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len < + 16) { fprintf(stderr, "libwebsocket_client_handshake " - "challenge reply too short %d\n", - wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len); + "challenge reply too short %d\n", + wsi->utf8_token[ + WSI_TOKEN_CHALLENGE].token_len); pkt[len] = '\0'; fprintf(stderr, "%s", pkt); goto bail3; - + } - + goto select_protocol; } - + /* * well, what the server sent looked reasonable for syntax. * Now let's confirm it sent all the necessary headers @@ -1135,7 +1183,6 @@ issue_hdr: } select_protocol: - pc = wsi->c_protocol; /* @@ -1149,7 +1196,7 @@ select_protocol: * no protocol name to work from, * default to first protocol */ - wsi->protocol = &this->protocols[0]; + wsi->protocol = &context->protocols[0]; free(wsi->c_protocol); @@ -1189,10 +1236,10 @@ select_protocol: */ n = 0; wsi->protocol = NULL; - while (this->protocols[n].callback) { + while (context->protocols[n].callback) { if (strcmp(wsi->utf8_token[WSI_TOKEN_PROTOCOL].token, - this->protocols[n].name) == 0) - wsi->protocol = &this->protocols[n]; + context->protocols[n].name) == 0) + wsi->protocol = &context->protocols[n]; n++; } @@ -1207,20 +1254,19 @@ select_protocol: check_accept: if (wsi->ietf_spec_revision == 0) { - + if (memcmp(wsi->initial_handshake_hash_base64, - wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 16)) { + wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 16)) { fprintf(stderr, "libwebsocket_client_handshake " - "failed 00 challenge compare\n"); - - pkt[len] = '\0'; - fprintf(stderr, "%s", pkt); - goto bail2; + "failed 00 challenge compare\n"); + pkt[len] = '\0'; + fprintf(stderr, "%s", pkt); + goto bail2; } - + goto accept_ok; } - + /* * Confirm his accept token is the one we precomputed */ @@ -1247,7 +1293,6 @@ select_protocol: strcpy(p, magic_websocket_04_masking_guid); SHA1(buf, strlen((char *)buf), wsi->masking_key_04); } - accept_ok: /* allocate the per-connection user memory (if any) */ @@ -1277,7 +1322,7 @@ accept_ok: /* call him back to inform him he is up */ - wsi->protocol->callback(this, wsi, + wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLIENT_ESTABLISHED, wsi->user_space, NULL, 0); @@ -1289,7 +1334,7 @@ bail3: free(wsi->c_protocol); bail2: - libwebsocket_close_and_free_session(this, wsi, + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); return 1; @@ -1304,7 +1349,7 @@ bail2: fprintf(stderr, "Session Socket %p (fd=%d) dead\n", (void *)wsi, pollfd->fd); - libwebsocket_close_and_free_session(this, wsi, + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); return 1; } @@ -1316,11 +1361,11 @@ bail2: pollfd->events &= ~POLLOUT; /* external POLL support via protocol 0 */ - this->protocols[0].callback(this, wsi, + context->protocols[0].callback(context, wsi, LWS_CALLBACK_CLEAR_MODE_POLL_FD, (void *)(long)wsi->sock, NULL, POLLOUT); - wsi->protocol->callback(this, wsi, + wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLIENT_WRITEABLE, wsi->user_space, NULL, 0); @@ -1343,14 +1388,14 @@ bail2: break; } if (!n) { - libwebsocket_close_and_free_session(this, wsi, + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); return 1; } /* service incoming data */ - n = libwebsocket_read(this, wsi, buf, n); + n = libwebsocket_read(context, wsi, buf, n); if (n >= 0) break; @@ -1365,41 +1410,48 @@ bail2: /** * libwebsocket_context_destroy() - Destroy the websocket context - * @this: Websocket context + * @context: Websocket context * * This function closes any active connections and then frees the * context. After calling this, any further use of the context is * undefined. */ void -libwebsocket_context_destroy(struct libwebsocket_context *this) +libwebsocket_context_destroy(struct libwebsocket_context *context) { int n; int m; struct libwebsocket *wsi; for (n = 0; n < FD_HASHTABLE_MODULUS; n++) - for (m = 0; m < this->fd_hashtable[n].length; m++) { - wsi = this->fd_hashtable[n].wsi[m]; - libwebsocket_close_and_free_session(this, wsi, + for (m = 0; m < context->fd_hashtable[n].length; m++) { + wsi = context->fd_hashtable[n].wsi[m]; + libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_GOINGAWAY); } - close(this->fd_random); +#ifdef WIN32 +#else + close(context->fd_random); +#endif #ifdef LWS_OPENSSL_SUPPORT - if (this->ssl_ctx) - SSL_CTX_free(this->ssl_ctx); - if (this->ssl_client_ctx) - SSL_CTX_free(this->ssl_client_ctx); + if (context->ssl_ctx) + SSL_CTX_free(context->ssl_ctx); + if (context->ssl_client_ctx) + SSL_CTX_free(context->ssl_client_ctx); #endif - free(this); + free(context); + +#ifdef WIN32 + WSACleanup(); +#endif } /** * libwebsocket_service() - Service any pending websocket activity - * @this: Websocket context + * @context: Websocket context * @timeout_ms: Timeout for poll; 0 means return immediately if nothing needed * service otherwise block and service immediately, returning * after the timeout if nothing needed service. @@ -1434,18 +1486,18 @@ libwebsocket_context_destroy(struct libwebsocket_context *this) int -libwebsocket_service(struct libwebsocket_context *this, int timeout_ms) +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms) { int n; /* stay dead once we are dead */ - if (this == NULL) + if (context == NULL) return 1; /* wait for something to need service */ - n = poll(this->fds, this->fds_count, timeout_ms); + n = poll(context->fds, context->fds_count, timeout_ms); if (n == 0) /* poll timeout */ return 0; @@ -1458,9 +1510,9 @@ libwebsocket_service(struct libwebsocket_context *this, int timeout_ms) /* handle accept on listening socket? */ - for (n = 0; n < this->fds_count; n++) - if (this->fds[n].revents) - libwebsocket_service_fd(this, &this->fds[n]); + for (n = 0; n < context->fds_count; n++) + if (context->fds[n].revents) + libwebsocket_service_fd(context, &context->fds[n]); return 0; } @@ -1470,24 +1522,24 @@ libwebsocket_service(struct libwebsocket_context *this, int timeout_ms) * becomes able to be written to without * blocking * - * @this: libwebsockets context + * @context: libwebsockets context * @wsi: Websocket connection instance to get callback for */ int -libwebsocket_callback_on_writable(struct libwebsocket_context *this, +libwebsocket_callback_on_writable(struct libwebsocket_context *context, struct libwebsocket *wsi) { int n; - for (n = 0; n < this->fds_count; n++) - if (this->fds[n].fd == wsi->sock) { - this->fds[n].events |= POLLOUT; - n = this->fds_count; + for (n = 0; n < context->fds_count; n++) + if (context->fds[n].fd == wsi->sock) { + context->fds[n].events |= POLLOUT; + n = context->fds_count; } /* external POLL support via protocol 0 */ - this->protocols[0].callback(this, wsi, + context->protocols[0].callback(context, wsi, LWS_CALLBACK_SET_MODE_POLL_FD, (void *)(long)wsi->sock, NULL, POLLOUT); @@ -1507,19 +1559,19 @@ int libwebsocket_callback_on_writable_all_protocol( const struct libwebsocket_protocols *protocol) { - struct libwebsocket_context *this = protocol->owning_server; + struct libwebsocket_context *context = protocol->owning_server; int n; int m; struct libwebsocket *wsi; for (n = 0; n < FD_HASHTABLE_MODULUS; n++) { - for (m = 0; m < this->fd_hashtable[n].length; m++) { + for (m = 0; m < context->fd_hashtable[n].length; m++) { - wsi = this->fd_hashtable[n].wsi[m]; + wsi = context->fd_hashtable[n].wsi[m]; if (wsi->protocol == protocol) - libwebsocket_callback_on_writable(this, wsi); + libwebsocket_callback_on_writable(context, wsi); } } @@ -1577,27 +1629,27 @@ libwebsocket_get_socket_fd(struct libwebsocket *wsi) int libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable) { - struct libwebsocket_context *this = wsi->protocol->owning_server; + struct libwebsocket_context *context = wsi->protocol->owning_server; int n; - for (n = 0; n < this->fds_count; n++) - if (this->fds[n].fd == wsi->sock) { + for (n = 0; n < context->fds_count; n++) + if (context->fds[n].fd == wsi->sock) { if (enable) - this->fds[n].events |= POLLIN; + context->fds[n].events |= POLLIN; else - this->fds[n].events &= ~POLLIN; + context->fds[n].events &= ~POLLIN; return 0; } if (enable) /* external POLL support via protocol 0 */ - this->protocols[0].callback(this, wsi, + context->protocols[0].callback(context, wsi, LWS_CALLBACK_SET_MODE_POLL_FD, (void *)(long)wsi->sock, NULL, POLLIN); else /* external POLL support via protocol 0 */ - this->protocols[0].callback(this, wsi, + context->protocols[0].callback(context, wsi, LWS_CALLBACK_CLEAR_MODE_POLL_FD, (void *)(long)wsi->sock, NULL, POLLIN); @@ -1614,14 +1666,14 @@ libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable) * when making a client connection. You can only call it after the context * has been created. * - * @this: Websocket context + * @context: Websocket context */ extern const char * -libwebsocket_canonical_hostname(struct libwebsocket_context *this) +libwebsocket_canonical_hostname(struct libwebsocket_context *context) { - return (const char *)this->canonical_hostname; + return (const char *)context->canonical_hostname; } @@ -1636,18 +1688,19 @@ OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) SSL *ssl; int n; -// struct libwebsocket_context *this; +// struct libwebsocket_context *context; ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); /* - * !!! can't get this->openssl_websocket_private_data_index + * !!! can't get context->openssl_websocket_private_data_index * can't store as a static either */ -// this = SSL_get_ex_data(ssl, this->openssl_websocket_private_data_index); +// context = SSL_get_ex_data(ssl, +// context->openssl_websocket_private_data_index); - n = this->protocols[0].callback(NULL, NULL, + n = context->protocols[0].callback(NULL, NULL, LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, x509_ctx, ssl, preverify_ok); @@ -1668,7 +1721,7 @@ OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) * @port: Port to listen on... you can use 0 to suppress listening on * any port, that's what you want if you are not running a * websocket server at all but just using it as a client - * @interface: NULL to bind the listen socket to all interfaces, or the + * @interf: NULL to bind the listen socket to all interfaces, or the * interface name, eg, "eth2" * @protocols: Array of structures listing supported protocols and a protocol- * specific callback for each one. The list is ended with an @@ -1710,7 +1763,7 @@ OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) */ struct libwebsocket_context * -libwebsocket_create_context(int port, const char *interface, +libwebsocket_create_context(int port, const char *interf, struct libwebsocket_protocols *protocols, const char *ssl_cert_filepath, const char *ssl_private_key_filepath, @@ -1721,7 +1774,7 @@ libwebsocket_create_context(int port, const char *interface, int fd; struct sockaddr_in serv_addr, cli_addr; int opt = 1; - struct libwebsocket_context *this = NULL; + struct libwebsocket_context *context = NULL; unsigned int slen; char *p; char hostname[1024]; @@ -1733,67 +1786,98 @@ libwebsocket_create_context(int port, const char *interface, char ssl_err_buf[512]; #endif - this = malloc(sizeof(struct libwebsocket_context)); - if (!this) { +#ifdef _WIN32 + { + WORD wVersionRequested; + WSADATA wsaData; + int err; + + /* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */ + wVersionRequested = MAKEWORD(2, 2); + + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { + /* Tell the user that we could not find a usable */ + /* Winsock DLL. */ + fprintf(stderr, "WSAStartup failed with error: %d\n", + err); + return NULL; + } + } +#endif + + + context = malloc(sizeof(struct libwebsocket_context)); + if (!context) { fprintf(stderr, "No memory for websocket context\n"); return NULL; } - this->protocols = protocols; - this->listen_port = port; - this->http_proxy_port = 0; - this->http_proxy_address[0] = '\0'; - this->options = options; - this->fds_count = 0; - - this->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY); - if (this->fd_random < 0) { + context->protocols = protocols; + context->listen_port = port; + context->http_proxy_port = 0; + context->http_proxy_address[0] = '\0'; + context->options = options; + context->fds_count = 0; + +#ifdef WIN32 + context->fd_random = 0; +#else + context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY); + if (context->fd_random < 0) { fprintf(stderr, "Unable to open random device %s %d\n", - SYSTEM_RANDOM_FILEPATH, this->fd_random); + SYSTEM_RANDOM_FILEPATH, context->fd_random); return NULL; } +#endif +#ifdef LWS_OPENSSL_SUPPORT + context->use_ssl = 0; + context->ssl_ctx = NULL; + context->ssl_client_ctx = NULL; + context->openssl_websocket_private_data_index = 0; +#endif /* find canonical hostname */ hostname[(sizeof hostname) - 1] = '\0'; gethostname(hostname, (sizeof hostname) - 1); he = gethostbyname(hostname); if (he) { - strncpy(this->canonical_hostname, he->h_name, - sizeof this->canonical_hostname - 1); - this->canonical_hostname[sizeof this->canonical_hostname - 1] = - '\0'; + strncpy(context->canonical_hostname, he->h_name, + sizeof context->canonical_hostname - 1); + context->canonical_hostname[ + sizeof context->canonical_hostname - 1] = '\0'; } else - strncpy(this->canonical_hostname, hostname, - sizeof this->canonical_hostname - 1); + strncpy(context->canonical_hostname, hostname, + sizeof context->canonical_hostname - 1); /* split the proxy ads:port if given */ p = getenv("http_proxy"); if (p) { - strncpy(this->http_proxy_address, p, - sizeof this->http_proxy_address - 1); - this->http_proxy_address[ - sizeof this->http_proxy_address - 1] = '\0'; + strncpy(context->http_proxy_address, p, + sizeof context->http_proxy_address - 1); + context->http_proxy_address[ + sizeof context->http_proxy_address - 1] = '\0'; - p = strchr(this->http_proxy_address, ':'); + p = strchr(context->http_proxy_address, ':'); if (p == NULL) { fprintf(stderr, "http_proxy needs to be ads:port\n"); return NULL; } *p = '\0'; - this->http_proxy_port = atoi(p + 1); + context->http_proxy_port = atoi(p + 1); fprintf(stderr, "Using proxy %s:%u\n", - this->http_proxy_address, - this->http_proxy_port); + context->http_proxy_address, + context->http_proxy_port); } if (port) { #ifdef LWS_OPENSSL_SUPPORT - this->use_ssl = ssl_cert_filepath != NULL && + context->use_ssl = ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL; - if (this->use_ssl) + if (context->use_ssl) fprintf(stderr, " Compiled with SSL support, " "using it\n"); else @@ -1812,8 +1896,10 @@ libwebsocket_create_context(int port, const char *interface, } /* ignore SIGPIPE */ - +#ifdef WIN32 +#else signal(SIGPIPE, sigpipe_handler); +#endif #ifdef LWS_OPENSSL_SUPPORT @@ -1825,7 +1911,7 @@ libwebsocket_create_context(int port, const char *interface, OpenSSL_add_all_algorithms(); SSL_load_error_strings(); - this->openssl_websocket_private_data_index = + context->openssl_websocket_private_data_index = SSL_get_ex_new_index(0, "libwebsockets", NULL, NULL, NULL); /* @@ -1839,55 +1925,57 @@ libwebsocket_create_context(int port, const char *interface, ERR_error_string(ERR_get_error(), ssl_err_buf)); return NULL; } - this->ssl_ctx = SSL_CTX_new(method); /* create context */ - if (!this->ssl_ctx) { + context->ssl_ctx = SSL_CTX_new(method); /* create context */ + if (!context->ssl_ctx) { fprintf(stderr, "problem creating ssl context: %s\n", ERR_error_string(ERR_get_error(), ssl_err_buf)); return NULL; } /* client context */ + if (port == CONTEXT_PORT_NO_LISTEN) + { + method = (SSL_METHOD *)SSLv23_client_method(); + if (!method) { + fprintf(stderr, "problem creating ssl method: %s\n", + ERR_error_string(ERR_get_error(), ssl_err_buf)); + return NULL; + } + /* create context */ + context->ssl_client_ctx = SSL_CTX_new(method); + if (!context->ssl_client_ctx) { + fprintf(stderr, "problem creating ssl context: %s\n", + ERR_error_string(ERR_get_error(), ssl_err_buf)); + return NULL; + } - method = (SSL_METHOD *)SSLv23_client_method(); - if (!method) { - fprintf(stderr, "problem creating ssl method: %s\n", - ERR_error_string(ERR_get_error(), ssl_err_buf)); - return NULL; - } - this->ssl_client_ctx = SSL_CTX_new(method); /* create context */ - if (!this->ssl_client_ctx) { - fprintf(stderr, "problem creating ssl context: %s\n", - ERR_error_string(ERR_get_error(), ssl_err_buf)); - return NULL; - } - - - /* openssl init for cert verification (used with client sockets) */ + /* openssl init for cert verification (for client sockets) */ - if (!SSL_CTX_load_verify_locations(this->ssl_client_ctx, NULL, - LWS_OPENSSL_CLIENT_CERTS)) { - fprintf(stderr, "Unable to load SSL Client certs from %s " - "(set by --with-client-cert-dir= in configure) -- " - " client ssl isn't going to work", + if (!SSL_CTX_load_verify_locations( + context->ssl_client_ctx, NULL, + LWS_OPENSSL_CLIENT_CERTS)) + fprintf(stderr, + "Unable to load SSL Client certs from %s " + "(set by --with-client-cert-dir= in configure) -- " + " client ssl isn't going to work", LWS_OPENSSL_CLIENT_CERTS); - } - /* - * callback allowing user code to load extra verification certs - * helping the client to verify server identity - */ - - this->protocols[0].callback(this, NULL, - LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, - this->ssl_client_ctx, NULL, 0); + /* + * callback allowing user code to load extra verification certs + * helping the client to verify server identity + */ + context->protocols[0].callback(context, NULL, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, + context->ssl_client_ctx, NULL, 0); + } /* as a server, are we requiring clients to identify themselves? */ if (options & LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT) { /* absolutely require the client cert */ - SSL_CTX_set_verify(this->ssl_ctx, + SSL_CTX_set_verify(context->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, OpenSSL_verify_callback); @@ -1896,17 +1984,17 @@ libwebsocket_create_context(int port, const char *interface, * allowing it to verify incoming client certs */ - this->protocols[0].callback(this, NULL, + context->protocols[0].callback(context, NULL, LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, - this->ssl_ctx, NULL, 0); + context->ssl_ctx, NULL, 0); } - if (this->use_ssl) { + if (context->use_ssl) { /* openssl init for server sockets */ /* set the local certificate from CertFile */ - n = SSL_CTX_use_certificate_file(this->ssl_ctx, + n = SSL_CTX_use_certificate_file(context->ssl_ctx, ssl_cert_filepath, SSL_FILETYPE_PEM); if (n != 1) { fprintf(stderr, "problem getting cert '%s': %s\n", @@ -1915,16 +2003,15 @@ libwebsocket_create_context(int port, const char *interface, return NULL; } /* set the private key from KeyFile */ - if (SSL_CTX_use_PrivateKey_file(this->ssl_ctx, - ssl_private_key_filepath, - SSL_FILETYPE_PEM) != 1) { + if (SSL_CTX_use_PrivateKey_file(context->ssl_ctx, + ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) { fprintf(stderr, "ssl problem getting key '%s': %s\n", ssl_private_key_filepath, ERR_error_string(ERR_get_error(), ssl_err_buf)); return NULL; } /* verify private key */ - if (!SSL_CTX_check_private_key(this->ssl_ctx)) { + if (!SSL_CTX_check_private_key(context->ssl_ctx)) { fprintf(stderr, "Private SSL key doesn't match cert\n"); return NULL; } @@ -1941,7 +2028,7 @@ libwebsocket_create_context(int port, const char *interface, /* fd hashtable init */ for (n = 0; n < FD_HASHTABLE_MODULUS; n++) - this->fd_hashtable[n].length = 0; + context->fd_hashtable[n].length = 0; /* set up our external listening socket we serve on */ @@ -1958,10 +2045,10 @@ libwebsocket_create_context(int port, const char *interface, bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; - if (interface == NULL) + if (interf == NULL) serv_addr.sin_addr.s_addr = INADDR_ANY; else - interface_to_sa(interface, &serv_addr, + interface_to_sa(interf, &serv_addr, sizeof(serv_addr)); serv_addr.sin_port = htons(port); @@ -1977,41 +2064,42 @@ libwebsocket_create_context(int port, const char *interface, memset(wsi, 0, sizeof (struct libwebsocket)); wsi->sock = sockfd; wsi->mode = LWS_CONNMODE_SERVER_LISTENER; - insert_wsi(this, wsi); + insert_wsi(context, wsi); listen(sockfd, 5); fprintf(stderr, " Listening on port %d\n", port); /* list in the internal poll array */ - this->fds[this->fds_count].fd = sockfd; - this->fds[this->fds_count++].events = POLLIN; + context->fds[context->fds_count].fd = sockfd; + context->fds[context->fds_count++].events = POLLIN; /* external POLL support via protocol 0 */ - this->protocols[0].callback(this, wsi, + context->protocols[0].callback(context, wsi, LWS_CALLBACK_ADD_POLL_FD, (void *)(long)sockfd, NULL, POLLIN); } /* drop any root privs for this process */ - +#ifdef WIN32 +#else if (gid != -1) if (setgid(gid)) fprintf(stderr, "setgid: %s\n", strerror(errno)); if (uid != -1) if (setuid(uid)) fprintf(stderr, "setuid: %s\n", strerror(errno)); - +#endif /* set up our internal broadcast trigger sockets per-protocol */ - for (this->count_protocols = 0; - protocols[this->count_protocols].callback; - this->count_protocols++) { - protocols[this->count_protocols].owning_server = this; - protocols[this->count_protocols].protocol_index = - this->count_protocols; + for (context->count_protocols = 0; + protocols[context->count_protocols].callback; + context->count_protocols++) { + protocols[context->count_protocols].owning_server = context; + protocols[context->count_protocols].protocol_index = + context->count_protocols; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { @@ -2040,12 +2128,12 @@ libwebsocket_create_context(int port, const char *interface, fprintf(stderr, "getsockname failed\n"); return NULL; } - protocols[this->count_protocols].broadcast_socket_port = + protocols[context->count_protocols].broadcast_socket_port = ntohs(cli_addr.sin_port); listen(fd, 5); debug(" Protocol %s broadcast socket %d\n", - protocols[this->count_protocols].name, + protocols[context->count_protocols].name, ntohs(cli_addr.sin_port)); /* dummy wsi per broadcast proxy socket */ @@ -2055,23 +2143,24 @@ libwebsocket_create_context(int port, const char *interface, wsi->sock = fd; wsi->mode = LWS_CONNMODE_BROADCAST_PROXY_LISTENER; /* note which protocol we are proxying */ - wsi->protocol_index_for_broadcast_proxy = this->count_protocols; - insert_wsi(this, wsi); + wsi->protocol_index_for_broadcast_proxy = + context->count_protocols; + insert_wsi(context, wsi); /* list in internal poll array */ - this->fds[this->fds_count].fd = fd; - this->fds[this->fds_count].events = POLLIN; - this->fds[this->fds_count].revents = 0; - this->fds_count++; + context->fds[context->fds_count].fd = fd; + context->fds[context->fds_count].events = POLLIN; + context->fds[context->fds_count].revents = 0; + context->fds_count++; /* external POLL support via protocol 0 */ - this->protocols[0].callback(this, wsi, + context->protocols[0].callback(context, wsi, LWS_CALLBACK_ADD_POLL_FD, (void *)(long)fd, NULL, POLLIN); } - return this; + return context; } @@ -2084,11 +2173,11 @@ libwebsocket_create_context(int port, const char *interface, * have to make sure you are calling * libwebsocket_service periodically to service * the websocket traffic - * @this: server context returned by creation function + * @context: server context returned by creation function */ int -libwebsockets_fork_service_loop(struct libwebsocket_context *this) +libwebsockets_fork_service_loop(struct libwebsocket_context *context) { int fd; struct sockaddr_in cli_addr; @@ -2108,7 +2197,7 @@ libwebsockets_fork_service_loop(struct libwebsocket_context *this) * service process context */ - for (p = 0; p < this->count_protocols; p++) { + for (p = 0; p < context->count_protocols; p++) { fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { fprintf(stderr, "Unable to create socket\n"); @@ -2116,7 +2205,7 @@ libwebsockets_fork_service_loop(struct libwebsocket_context *this) } cli_addr.sin_family = AF_INET; cli_addr.sin_port = htons( - this->protocols[p].broadcast_socket_port); + context->protocols[p].broadcast_socket_port); cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); n = connect(fd, (struct sockaddr *)&cli_addr, sizeof cli_addr); @@ -2127,7 +2216,7 @@ libwebsockets_fork_service_loop(struct libwebsocket_context *this) return -1; } - this->protocols[p].broadcast_socket_user_fd = fd; + context->protocols[p].broadcast_socket_user_fd = fd; } return 0; @@ -2139,7 +2228,7 @@ libwebsockets_fork_service_loop(struct libwebsocket_context *this) /* in this forked process, sit and service websocket connections */ while (1) - if (libwebsocket_service(this, 1000)) + if (libwebsocket_service(context, 1000)) return -1; return 0; @@ -2189,7 +2278,7 @@ int libwebsockets_broadcast(const struct libwebsocket_protocols *protocol, unsigned char *buf, size_t len) { - struct libwebsocket_context *this = protocol->owning_server; + struct libwebsocket_context *context = protocol->owning_server; int n; int m; struct libwebsocket * wsi; @@ -2209,9 +2298,9 @@ libwebsockets_broadcast(const struct libwebsocket_protocols *protocol, for (n = 0; n < FD_HASHTABLE_MODULUS; n++) { - for (m = 0; m < this->fd_hashtable[n].length; m++) { + for (m = 0; m < context->fd_hashtable[n].length; m++) { - wsi = this->fd_hashtable[n].wsi[m]; + wsi = context->fd_hashtable[n].wsi[m]; if (wsi->mode != LWS_CONNMODE_WS_SERVING) continue; @@ -2229,7 +2318,7 @@ libwebsockets_broadcast(const struct libwebsocket_protocols *protocol, if (wsi->protocol != protocol) continue; - wsi->protocol->callback(this, wsi, + wsi->protocol->callback(context, wsi, LWS_CALLBACK_BROADCAST, wsi->user_space, buf, len); diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 5d0f047..1bf43bf 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -22,7 +22,22 @@ #ifndef __LIBWEBSOCKET_H__ #define __LIBWEBSOCKET_H__ +#ifdef WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include "websock-w32.h" +#include "gettimeofday.h" + +#ifdef __cplusplus +extern "C" { +#endif +#else #include +#endif #define CONTEXT_PORT_NO_LISTEN 0 @@ -48,7 +63,6 @@ enum libwebsocket_callback_reasons { LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, - /* external poll() management support */ LWS_CALLBACK_ADD_POLL_FD, LWS_CALLBACK_DEL_POLL_FD, @@ -388,7 +402,7 @@ struct libwebsocket_protocols { }; extern struct libwebsocket_context * -libwebsocket_create_context(int port, const char * interface, +libwebsocket_create_context(int port, const char * interf, struct libwebsocket_protocols *protocols, const char *ssl_cert_filepath, const char *ssl_private_key_filepath, int gid, int uid, @@ -500,4 +514,9 @@ extern void libwebsocket_close_and_free_session(struct libwebsocket_context *context, struct libwebsocket *wsi, enum lws_close_status); +#ifdef WIN32 +#ifdef __cplusplus +} +#endif +#endif #endif diff --git a/lib/parsers.c b/lib/parsers.c index 60a9096..3b72b58 100644 --- a/lib/parsers.c +++ b/lib/parsers.c @@ -22,25 +22,29 @@ #include "private-libwebsockets.h" const struct lws_tokens lws_tokens[WSI_TOKEN_COUNT] = { - [WSI_TOKEN_GET_URI] = { "GET ", 4 }, - [WSI_TOKEN_HOST] = { "Host:", 5 }, - [WSI_TOKEN_CONNECTION] = { "Connection:", 11 }, - [WSI_TOKEN_KEY1] = { "Sec-WebSocket-Key1:", 19 }, - [WSI_TOKEN_KEY2] = { "Sec-WebSocket-Key2:", 19 }, - [WSI_TOKEN_PROTOCOL] = { "Sec-WebSocket-Protocol:", 23 }, - [WSI_TOKEN_UPGRADE] = { "Upgrade:", 8 }, - [WSI_TOKEN_EXTENSIONS] = { "Sec-WebSocket-Extensions:", 25 }, - [WSI_TOKEN_ORIGIN] = { "Origin:", 7 }, - [WSI_TOKEN_DRAFT] = { "Sec-WebSocket-Draft:", 20 }, - [WSI_TOKEN_CHALLENGE] = { "\x0d\x0a", 2 }, - - [WSI_TOKEN_KEY] = { "Sec-WebSocket-Key:", 18 }, - [WSI_TOKEN_VERSION] = { "Sec-WebSocket-Version:", 22 }, - - [WSI_TOKEN_ACCEPT] = { "Sec-WebSocket-Accept:", 21 }, - [WSI_TOKEN_NONCE] = { "Sec-WebSocket-Nonce:", 20 }, - [WSI_TOKEN_HTTP] = { "HTTP/1.1 ", 9 }, - [WSI_TOKEN_SWORIGIN] = { "Sec-WebSocket-Origin:", 21 }, + + /* win32 can't do C99 */ + +/* [WSI_TOKEN_GET_URI] = */{ "GET ", 4 }, +/* [WSI_TOKEN_HOST] = */{ "Host:", 5 }, +/* [WSI_TOKEN_CONNECTION] = */{ "Connection:", 11 }, +/* [WSI_TOKEN_KEY1] = */{ "Sec-WebSocket-Key1:", 19 }, +/* [WSI_TOKEN_KEY2] = */{ "Sec-WebSocket-Key2:", 19 }, +/* [WSI_TOKEN_PROTOCOL] = */{ "Sec-WebSocket-Protocol:", 23 }, +/* [WSI_TOKEN_UPGRADE] = */{ "Upgrade:", 8 }, +/* [WSI_TOKEN_ORIGIN] = */{ "Origin:", 7 }, +/* [WSI_TOKEN_DRAFT] = */{ "Sec-WebSocket-Draft:", 20 }, +/* [WSI_TOKEN_CHALLENGE] = */{ "\x0d\x0a", 2 }, + +/* [WSI_TOKEN_KEY] = */{ "Sec-WebSocket-Key:", 18 }, +/* [WSI_TOKEN_VERSION] = */{ "Sec-WebSocket-Version:", 22 }, +/* [WSI_TOKEN_SWORIGIN]= */{ "Sec-WebSocket-Origin:", 21 }, + +/* [WSI_TOKEN_EXTENSIONS] = */{ "Sec-WebSocket-Extensions:", 25 }, + +/* [WSI_TOKEN_ACCEPT] = */{ "Sec-WebSocket-Accept:", 21 }, +/* [WSI_TOKEN_NONCE] = */{ "Sec-WebSocket-Nonce:", 20 }, +/* [WSI_TOKEN_HTTP] = */{ "HTTP/1.1 ", 9 }, }; @@ -116,17 +120,16 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) /* -76 has no version header ... server */ if (!wsi->utf8_token[WSI_TOKEN_VERSION].token_len && - wsi->mode != LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY && + wsi->mode != LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY && wsi->utf8_token[wsi->parser_state].token_len != 8) break; /* -76 has no version header ... client */ if (!wsi->utf8_token[WSI_TOKEN_VERSION].token_len && - wsi->mode == LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY && - wsi->utf8_token[wsi->parser_state].token_len != 16) + wsi->mode == LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY && + wsi->utf8_token[wsi->parser_state].token_len != 16) break; - /* <= 03 has old handshake with version header needs 8 bytes */ if (wsi->utf8_token[WSI_TOKEN_VERSION].token_len && atoi(wsi->utf8_token[WSI_TOKEN_VERSION].token) < 4 && @@ -1019,7 +1022,7 @@ libwebsocket_0405_frame_mask_generate(struct libwebsocket *wsi) /* fetch the per-frame nonce */ - n = read(wsi->protocol->owning_server->fd_random, + n = libwebsockets_get_random(wsi->protocol->owning_server, wsi->frame_masking_nonce_04, 4); if (n != 4) { fprintf(stderr, "Unable to read from random device %s %d\n", @@ -1336,7 +1339,7 @@ int libwebsockets_serve_http_file(struct libwebsocket *wsi, const char *file, const char *content_type) { int fd; - struct stat stat; + struct stat stat_buf; char buf[512]; char *p = buf; int n; @@ -1353,12 +1356,12 @@ int libwebsockets_serve_http_file(struct libwebsocket *wsi, const char *file, return -1; } - fstat(fd, &stat); + fstat(fd, &stat_buf); p += sprintf(p, "HTTP/1.0 200 OK\x0d\x0a" "Server: libwebsockets\x0d\x0a" "Content-Type: %s\x0d\x0a" "Content-Length: %u\x0d\x0a" - "\x0d\x0a", content_type, (unsigned int)stat.st_size); + "\x0d\x0a", content_type, (unsigned int)stat_buf.st_size); libwebsocket_write(wsi, (unsigned char *)buf, p - buf, LWS_WRITE_HTTP); diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index e876870..db96732 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -29,9 +29,20 @@ #include #include #include +#include -#include #include + +#ifdef WIN32 + +#include +#include +#include +#include + +#else + +#include #include #ifndef LWS_NO_FORK #include @@ -43,6 +54,8 @@ #include #include +#endif + #ifdef LWS_OPENSSL_SUPPORT #include #include @@ -59,7 +72,12 @@ #endif #ifdef DEBUG -static inline void debug(const char *format, ...) +#ifdef WIN32 +static +#else +static inline +#endif +void debug(const char *format, ...) { va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); @@ -271,7 +289,7 @@ libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi, unsigned char *buf, size_t len); extern int -libwebsocket_read(struct libwebsocket_context *this, struct libwebsocket *wsi, +libwebsocket_read(struct libwebsocket_context *context, struct libwebsocket *wsi, unsigned char * buf, size_t len); extern int @@ -293,18 +311,22 @@ extern unsigned char xor_mask_05(struct libwebsocket *wsi, unsigned char c); extern struct libwebsocket * -wsi_from_fd(struct libwebsocket_context *this, int fd); +wsi_from_fd(struct libwebsocket_context *context, int fd); extern int -insert_wsi(struct libwebsocket_context *this, struct libwebsocket *wsi); +insert_wsi(struct libwebsocket_context *context, struct libwebsocket *wsi); extern int -delete_from_fd(struct libwebsocket_context *this, int fd); +delete_from_fd(struct libwebsocket_context *context, int fd); extern void libwebsocket_set_timeout(struct libwebsocket *wsi, enum pending_timeout reason, int secs); +extern int +libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len); + #ifndef LWS_OPENSSL_SUPPORT unsigned char * diff --git a/lib/sha-1.c b/lib/sha-1.c index aea5d6a..180bb45 100644 --- a/lib/sha-1.c +++ b/lib/sha-1.c @@ -33,8 +33,29 @@ */ #include +#ifdef WIN32 + +typedef unsigned char u_int8_t; +typedef unsigned int u_int32_t; +typedef unsigned __int64 u_int64_t; +typedef void* caddr_t; + +#undef __P +#ifndef __P +#if __STDC__ +#define __P(protos) protos +#else +#define __P(protos) () +#endif +#endif + +#define bzero(b,len) (memset((b), '\0', (len)), (void) 0) + +#else #include #include +#endif + #include struct sha1_ctxt { diff --git a/libwebsockets-api-doc.html b/libwebsockets-api-doc.html index 8cc72c4..70bf4f2 100644 --- a/libwebsockets-api-doc.html +++ b/libwebsockets-api-doc.html @@ -1,11 +1,11 @@

libwebsockets_hangup_on_client - Server calls to terminate client connection

void libwebsockets_hangup_on_client -(struct libwebsocket_context * this, +(struct libwebsocket_context * context, int fd)

Arguments

-
this +
context
libwebsockets context
fd
Connection socket descriptor @@ -43,11 +43,11 @@ determined, they will be returned as valid zero-length strings.

libwebsocket_service_fd - Service polled socket with something waiting

int libwebsocket_service_fd -(struct libwebsocket_context * this, +(struct libwebsocket_context * context, struct pollfd * pollfd)

Arguments

-
this +
context
Websocket context
pollfd
The pollfd entry describing the socket fd and which events @@ -63,10 +63,10 @@ undefined.

libwebsocket_context_destroy - Destroy the websocket context

void libwebsocket_context_destroy -(struct libwebsocket_context * this) +(struct libwebsocket_context * context)

Arguments

-
this +
context
Websocket context

Description

@@ -79,11 +79,11 @@ undefined.

libwebsocket_service - Service any pending websocket activity

int libwebsocket_service -(struct libwebsocket_context * this, +(struct libwebsocket_context * context, int timeout_ms)

Arguments

-
this +
context
Websocket context
timeout_ms
Timeout for poll; 0 means return immediately if nothing needed @@ -123,11 +123,11 @@ nothing is pending, or as soon as it services whatever was pending.

libwebsocket_callback_on_writable - Request a callback when this socket becomes able to be written to without blocking

int libwebsocket_callback_on_writable -(struct libwebsocket_context * this, +(struct libwebsocket_context * context, struct libwebsocket * wsi)

Arguments

-
this +
context
libwebsockets context
wsi
Websocket connection instance to get callback for @@ -201,10 +201,10 @@ control for the input side.

libwebsocket_canonical_hostname - returns this host's hostname

const char * libwebsocket_canonical_hostname -(struct libwebsocket_context * this) +(struct libwebsocket_context * context)

Arguments

-
this +
context
Websocket context

Description

@@ -219,7 +219,7 @@ has been created. struct libwebsocket_context * libwebsocket_create_context (int port, -const char * interface, +const char * interf, struct libwebsocket_protocols * protocols, const char * ssl_cert_filepath, const char * ssl_private_key_filepath, @@ -232,7 +232,7 @@ has been created.
Port to listen on... you can use 0 to suppress listening on any port, that's what you want if you are not running a websocket server at all but just using it as a client -
interface +
interf
NULL to bind the listen socket to all interfaces, or the interface name, eg, "eth2"
protocols @@ -285,10 +285,10 @@ one place; they're all handled in the user callback.

libwebsockets_fork_service_loop - Optional helper function forks off a process for the websocket server loop. You don't have to use this but if not, you have to make sure you are calling libwebsocket_service periodically to service the websocket traffic

int libwebsockets_fork_service_loop -(struct libwebsocket_context * this) +(struct libwebsocket_context * context)

Arguments

-
this +
context
server context returned by creation function

@@ -425,7 +425,7 @@ Many protocols won't care becuse their packets are always small.

libwebsocket_client_connect - Connect to another websocket server

struct libwebsocket * libwebsocket_client_connect -(struct libwebsocket_context * this, +(struct libwebsocket_context * context, const char * address, int port, int ssl_connection, @@ -436,7 +436,7 @@ Many protocols won't care becuse their packets are always small. int ietf_version_or_minus_one)

Arguments

-
this +
context
Websocket context
address
Remote server address, eg, "myserver.com" diff --git a/test-server/test-client.c b/test-server/test-client.c index 09528c2..c1abff7 100644 --- a/test-server/test-client.c +++ b/test-server/test-client.c @@ -26,7 +26,6 @@ #include #include "../lib/libwebsockets.h" -#include static unsigned int opts; static int was_closed; @@ -147,17 +146,20 @@ callback_lws_mirror(struct libwebsocket_context * this, /* list of supported protocols and callbacks */ static struct libwebsocket_protocols protocols[] = { - - [PROTOCOL_DUMB_INCREMENT] = { - .name = "dumb-increment-protocol", - .callback = callback_dumb_increment, + { + "dumb-increment-protocol", + callback_dumb_increment, + 0, }, - [PROTOCOL_LWS_MIRROR] = { - .name = "lws-mirror-protocol", - .callback = callback_lws_mirror, + { + "lws-mirror-protocol", + callback_lws_mirror, + 0, }, - [DEMO_PROTOCOL_COUNT] = { /* end of list */ - .callback = NULL + { /* end of list */ + NULL, + NULL, + 0 } }; diff --git a/test-server/test-server-extpoll.c b/test-server/test-server-extpoll.c index 29595a1..803d5dc 100644 --- a/test-server/test-server-extpoll.c +++ b/test-server/test-server-extpoll.c @@ -393,24 +393,24 @@ callback_lws_mirror(struct libwebsocket_context * this, static struct libwebsocket_protocols protocols[] = { /* first protocol must always be HTTP handler */ - [PROTOCOL_HTTP] = { - .name = "http-only", - .callback = callback_http, + + { + "http-only", /* name */ + callback_http, /* callback */ + 0 /* per_session_data_size */ }, - [PROTOCOL_DUMB_INCREMENT] = { - .name = "dumb-increment-protocol", - .callback = callback_dumb_increment, - .per_session_data_size = - sizeof(struct per_session_data__dumb_increment), + { + "dumb-increment-protocol", + callback_dumb_increment, + sizeof(struct per_session_data__dumb_increment), }, - [PROTOCOL_LWS_MIRROR] = { - .name = "lws-mirror-protocol", - .callback = callback_lws_mirror, - .per_session_data_size = - sizeof(struct per_session_data__lws_mirror), + { + "lws-mirror-protocol", + callback_lws_mirror, + sizeof(struct per_session_data__lws_mirror) }, - [DEMO_PROTOCOL_COUNT] = { /* end of list */ - .callback = NULL + { + NULL, NULL, 0 /* End of list */ } }; diff --git a/test-server/test-server.c b/test-server/test-server.c index 2620908..3cecb7f 100644 --- a/test-server/test-server.c +++ b/test-server/test-server.c @@ -60,7 +60,7 @@ enum demo_protocols { /* this protocol server (always the first one) just knows how to do HTTP */ -static int callback_http(struct libwebsocket_context * this, +static int callback_http(struct libwebsocket_context * context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) @@ -124,29 +124,29 @@ dump_handshake_info(struct lws_tokens *lwst) { int n; static const char *token_names[] = { - [WSI_TOKEN_GET_URI] = "GET URI", - [WSI_TOKEN_HOST] = "Host", - [WSI_TOKEN_CONNECTION] = "Connection", - [WSI_TOKEN_KEY1] = "key 1", - [WSI_TOKEN_KEY2] = "key 2", - [WSI_TOKEN_PROTOCOL] = "Protocol", - [WSI_TOKEN_UPGRADE] = "Upgrade", - [WSI_TOKEN_ORIGIN] = "Origin", - [WSI_TOKEN_DRAFT] = "Draft", - [WSI_TOKEN_CHALLENGE] = "Challenge", + /*[WSI_TOKEN_GET_URI] =*/ "GET URI", + /*[WSI_TOKEN_HOST] =*/ "Host", + /*[WSI_TOKEN_CONNECTION] =*/ "Connection", + /*[WSI_TOKEN_KEY1] =*/ "key 1", + /*[WSI_TOKEN_KEY2] =*/ "key 2", + /*[WSI_TOKEN_PROTOCOL] =*/ "Protocol", + /*[WSI_TOKEN_UPGRADE] =*/ "Upgrade", + /*[WSI_TOKEN_ORIGIN] =*/ "Origin", + /*[WSI_TOKEN_DRAFT] =*/ "Draft", + /*[WSI_TOKEN_CHALLENGE] =*/ "Challenge", /* new for 04 */ - [WSI_TOKEN_KEY] = "Key", - [WSI_TOKEN_VERSION] = "Version", - [WSI_TOKEN_SWORIGIN] = "Sworigin", + /*[WSI_TOKEN_KEY] =*/ "Key", + /*[WSI_TOKEN_VERSION] =*/ "Version", + /*[WSI_TOKEN_SWORIGIN] =*/ "Sworigin", /* new for 05 */ - [WSI_TOKEN_EXTENSIONS] = "Extensions", + /*[WSI_TOKEN_EXTENSIONS] =*/ "Extensions", /* client receives these */ - [WSI_TOKEN_ACCEPT] = "Accept", - [WSI_TOKEN_NONCE] = "Nonce", - [WSI_TOKEN_HTTP] = "Http", + /*[WSI_TOKEN_ACCEPT] =*/ "Accept", + /*[WSI_TOKEN_NONCE] =*/ "Nonce", + /*[WSI_TOKEN_HTTP] =*/ "Http", }; for (n = 0; n < WSI_TOKEN_COUNT; n++) { @@ -172,7 +172,7 @@ struct per_session_data__dumb_increment { }; static int -callback_dumb_increment(struct libwebsocket_context * this, +callback_dumb_increment(struct libwebsocket_context * context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) @@ -249,7 +249,7 @@ static int ringbuffer_head; static int -callback_lws_mirror(struct libwebsocket_context * this, +callback_lws_mirror(struct libwebsocket_context * context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) @@ -286,7 +286,7 @@ callback_lws_mirror(struct libwebsocket_context * this, MAX_MESSAGE_QUEUE) < (MAX_MESSAGE_QUEUE - 15)) libwebsocket_rx_flow_control(wsi, 1); - libwebsocket_callback_on_writable(this, wsi); + libwebsocket_callback_on_writable(context, wsi); } break; @@ -343,24 +343,24 @@ callback_lws_mirror(struct libwebsocket_context * this, static struct libwebsocket_protocols protocols[] = { /* first protocol must always be HTTP handler */ - [PROTOCOL_HTTP] = { - .name = "http-only", - .callback = callback_http, + + { + "http-only", /* name */ + callback_http, /* callback */ + 0 /* per_session_data_size */ }, - [PROTOCOL_DUMB_INCREMENT] = { - .name = "dumb-increment-protocol", - .callback = callback_dumb_increment, - .per_session_data_size = - sizeof(struct per_session_data__dumb_increment), + { + "dumb-increment-protocol", + callback_dumb_increment, + sizeof(struct per_session_data__dumb_increment), }, - [PROTOCOL_LWS_MIRROR] = { - .name = "lws-mirror-protocol", - .callback = callback_lws_mirror, - .per_session_data_size = - sizeof(struct per_session_data__lws_mirror), + { + "lws-mirror-protocol", + callback_lws_mirror, + sizeof(struct per_session_data__lws_mirror) }, - [DEMO_PROTOCOL_COUNT] = { /* end of list */ - .callback = NULL + { + NULL, NULL, 0 /* End of list */ } }; diff --git a/win32port/client/client.vcxproj b/win32port/client/client.vcxproj new file mode 100644 index 0000000..91a758d --- /dev/null +++ b/win32port/client/client.vcxproj @@ -0,0 +1,98 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + {332bf17e-fd30-4363-975a-aa731a827b4f} + + + + + + + + {6265650C-4799-451C-A687-94DE48759A8B} + Win32Proj + client + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + + + Console + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + + + Console + true + true + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/win32port/client/client.vcxproj.filters b/win32port/client/client.vcxproj.filters new file mode 100644 index 0000000..76f1121 --- /dev/null +++ b/win32port/client/client.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/win32port/client/client.vcxproj.user b/win32port/client/client.vcxproj.user new file mode 100644 index 0000000..871eccc --- /dev/null +++ b/win32port/client/client.vcxproj.user @@ -0,0 +1,7 @@ + + + + 127.0.0.1 + WindowsLocalDebugger + + \ No newline at end of file diff --git a/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj b/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj new file mode 100644 index 0000000..ecb92d1 --- /dev/null +++ b/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj @@ -0,0 +1,89 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {332BF17E-FD30-4363-975A-AA731A827B4F} + Win32Proj + libwebsocketswin32 + + + + StaticLibrary + true + Unicode + + + StaticLibrary + false + true + Unicode + + + + + + + + + + + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters b/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters new file mode 100644 index 0000000..37ff7b6 --- /dev/null +++ b/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters @@ -0,0 +1,48 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.user b/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.user new file mode 100644 index 0000000..695b5c7 --- /dev/null +++ b/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/win32port/server/server.vcxproj b/win32port/server/server.vcxproj new file mode 100644 index 0000000..56b08a9 --- /dev/null +++ b/win32port/server/server.vcxproj @@ -0,0 +1,106 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + ../win32helpers + + + + + + + + + + + + + + + + {332bf17e-fd30-4363-975a-aa731a827b4f} + + + + {E585B64F-9365-4C58-9EF8-56393EB27F8B} + Win32Proj + server + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + + + Console + true + + + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + + + Console + true + true + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/win32port/server/server.vcxproj.filters b/win32port/server/server.vcxproj.filters new file mode 100644 index 0000000..d4a9c7d --- /dev/null +++ b/win32port/server/server.vcxproj.filters @@ -0,0 +1,51 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/win32port/server/server.vcxproj.user b/win32port/server/server.vcxproj.user new file mode 100644 index 0000000..695b5c7 --- /dev/null +++ b/win32port/server/server.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/win32port/win32helpers/getopt.c b/win32port/win32helpers/getopt.c new file mode 100644 index 0000000..3bb21f6 --- /dev/null +++ b/win32port/win32helpers/getopt.c @@ -0,0 +1,153 @@ +/* $NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $ */ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif + +#include +#include +#include +#include + +#define __P(x) x +#define _DIAGASSERT(x) assert(x) + +#ifdef __weak_alias +__weak_alias(getopt,_getopt); +#endif + + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +static char * _progname __P((char *)); +int getopt_internal __P((int, char * const *, const char *)); + +static char * +_progname(nargv0) + char * nargv0; +{ + char * tmp; + + _DIAGASSERT(nargv0 != NULL); + + tmp = strrchr(nargv0, '/'); + if (tmp) + tmp++; + else + tmp = nargv0; + return(tmp); +} + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(nargc, nargv, ostr) + int nargc; + char * const nargv[]; + const char *ostr; +{ + static char *__progname = 0; + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + __progname = __progname?__progname:_progname(*nargv); + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(ostr != NULL); + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-' /* found "--" */ + && place[1] == '\0') { + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} + diff --git a/win32port/win32helpers/getopt.h b/win32port/win32helpers/getopt.h new file mode 100644 index 0000000..7137f03 --- /dev/null +++ b/win32port/win32helpers/getopt.h @@ -0,0 +1,33 @@ +#ifndef __GETOPT_H__ +#define __GETOPT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int opterr; /* if error message should be printed */ +extern int optind; /* index into parent argv vector */ +extern int optopt; /* character checked for validity */ +extern int optreset; /* reset getopt */ +extern char *optarg; /* argument associated with option */ + +struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}; + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +int getopt(int, char**, char*); +int getopt_long(int, char**, char*, struct option*, int*); + +#ifdef __cplusplus +} +#endif + +#endif /* __GETOPT_H__ */ diff --git a/win32port/win32helpers/getopt_long.c b/win32port/win32helpers/getopt_long.c new file mode 100644 index 0000000..5bcf400 --- /dev/null +++ b/win32port/win32helpers/getopt_long.c @@ -0,0 +1,237 @@ + +/* + * Copyright (c) 1987, 1993, 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include "getopt.h" + +extern int opterr; /* if error message should be printed */ +extern int optind; /* index into parent argv vector */ +extern int optopt; /* character checked for validity */ +extern int optreset; /* reset getopt */ +extern char *optarg; /* argument associated with option */ + +#define __P(x) x +#define _DIAGASSERT(x) assert(x) + +static char * __progname __P((char *)); +int getopt_internal __P((int, char * const *, const char *)); + +static char * +__progname(nargv0) + char * nargv0; +{ + char * tmp; + + _DIAGASSERT(nargv0 != NULL); + + tmp = strrchr(nargv0, '/'); + if (tmp) + tmp++; + else + tmp = nargv0; + return(tmp); +} + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt_internal(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(ostr != NULL); + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + /* ++optind; */ + place = EMSG; + return (-2); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname(nargv[0]), optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if ((opterr) && (*ostr != ':')) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname(nargv[0]), optopt); + return (BADARG); + } else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} + +#if 0 +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt2(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + int retval; + + if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) { + retval = -1; + ++optind; + } + return(retval); +} +#endif + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(nargc, nargv, options, long_options, index) + int nargc; + char ** nargv; + char * options; + struct option * long_options; + int * index; +{ + int retval; + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(options != NULL); + _DIAGASSERT(long_options != NULL); + /* index may be NULL */ + + if ((retval = getopt_internal(nargc, nargv, options)) == -2) { + char *current_argv = nargv[optind++] + 2, *has_equal; + int i, current_argv_len, match = -1; + + if (*current_argv == '\0') { + return(-1); + } + if ((has_equal = strchr(current_argv, '=')) != NULL) { + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + if (strncmp(current_argv, long_options[i].name, current_argv_len)) + continue; + + if (strlen(long_options[i].name) == (unsigned)current_argv_len) { + match = i; + break; + } + if (match == -1) + match = i; + } + if (match != -1) { + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else + optarg = nargv[optind++]; + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument, leading : + * indicates no error should be generated + */ + if ((opterr) && (*options != ':')) + (void)fprintf(stderr, + "%s: option requires an argument -- %s\n", + __progname(nargv[0]), current_argv); + return (BADARG); + } + } else { /* No matching argument */ + if ((opterr) && (*options != ':')) + (void)fprintf(stderr, + "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv); + return (BADCH); + } + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + retval = 0; + } else + retval = long_options[match].val; + if (index) + *index = match; + } + return(retval); +} diff --git a/win32port/win32helpers/gettimeofday.c b/win32port/win32helpers/gettimeofday.c new file mode 100644 index 0000000..be0a5df --- /dev/null +++ b/win32port/win32helpers/gettimeofday.c @@ -0,0 +1,48 @@ +#include < time.h > +#include //I've ommited context line. +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + unsigned __int64 tmpres = 0; + static int tzflag; + + if (NULL != tv) + { + GetSystemTimeAsFileTime(&ft); + + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + + /*converting file time to unix epoch*/ + tmpres -= DELTA_EPOCH_IN_MICROSECS; + tmpres /= 10; /*convert into microseconds*/ + tv->tv_sec = (long)(tmpres / 1000000UL); + tv->tv_usec = (long)(tmpres % 1000000UL); + } + + if (NULL != tz) + { + if (!tzflag) + { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return 0; +} diff --git a/win32port/win32helpers/gettimeofday.h b/win32port/win32helpers/gettimeofday.h new file mode 100644 index 0000000..c2440dd --- /dev/null +++ b/win32port/win32helpers/gettimeofday.h @@ -0,0 +1,21 @@ +#ifndef _GET_TIME_OF_DAY_H +#define _GET_TIME_OF_DAY_H + +#include < time.h > +#include //I've ommited context line. +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +int gettimeofday(struct timeval *tv, struct timezone *tz); + + +#endif \ No newline at end of file diff --git a/win32port/win32helpers/netdb.h b/win32port/win32helpers/netdb.h new file mode 100644 index 0000000..45304b7 --- /dev/null +++ b/win32port/win32helpers/netdb.h @@ -0,0 +1 @@ +// Left blank for win32 \ No newline at end of file diff --git a/win32port/win32helpers/strings.h b/win32port/win32helpers/strings.h new file mode 100644 index 0000000..e69de29 diff --git a/win32port/win32helpers/sys/time.h b/win32port/win32helpers/sys/time.h new file mode 100644 index 0000000..258af63 --- /dev/null +++ b/win32port/win32helpers/sys/time.h @@ -0,0 +1 @@ +// left blank \ No newline at end of file diff --git a/win32port/win32helpers/unistd.h b/win32port/win32helpers/unistd.h new file mode 100644 index 0000000..e69de29 diff --git a/win32port/win32helpers/websock-w32.h b/win32port/win32helpers/websock-w32.h new file mode 100644 index 0000000..1d88153 --- /dev/null +++ b/win32port/win32helpers/websock-w32.h @@ -0,0 +1,21 @@ +#ifndef __WEB_SOCK_W32_H__ +#define __WEB_SOCK_W32_H__ + +// Windows uses _DEBUG and NDEBUG +#ifdef _DEBUG +#undef DEBUG +#define DEBUG 1 +#endif + +#define bzero(b,len) (memset((b), '\0', (len)), (void) 0) + +#define MSG_NOSIGNAL 0 +#define SHUT_RDWR SD_BOTH + +#define poll WSAPoll + +#define LWS_NO_FORK + +#define DATADIR "." + +#endif \ No newline at end of file diff --git a/win32port/win32port.sln b/win32port/win32port.sln new file mode 100644 index 0000000..d0b7497 --- /dev/null +++ b/win32port/win32port.sln @@ -0,0 +1,35 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server", "server\server.vcxproj", "{E585B64F-9365-4C58-9EF8-56393EB27F8B}" + ProjectSection(ProjectDependencies) = postProject + {332BF17E-FD30-4363-975A-AA731A827B4F} = {332BF17E-FD30-4363-975A-AA731A827B4F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwebsocketswin32", "libwebsocketswin32\libwebsocketswin32.vcxproj", "{332BF17E-FD30-4363-975A-AA731A827B4F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client\client.vcxproj", "{6265650C-4799-451C-A687-94DE48759A8B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Debug|Win32.ActiveCfg = Debug|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Debug|Win32.Build.0 = Debug|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Release|Win32.ActiveCfg = Release|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Release|Win32.Build.0 = Release|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Debug|Win32.ActiveCfg = Debug|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Debug|Win32.Build.0 = Debug|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Release|Win32.ActiveCfg = Release|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Release|Win32.Build.0 = Release|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Debug|Win32.ActiveCfg = Debug|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Debug|Win32.Build.0 = Debug|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Release|Win32.ActiveCfg = Release|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/win32port/win32port.suo b/win32port/win32port.suo new file mode 100644 index 0000000000000000000000000000000000000000..0b044f5e0cc6dec90e22c2f377862df7b0dbbdf8 GIT binary patch literal 32256 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 Z*PZEqtzmS2rPpdTk@zhb*l4#8e+NfPXl4Ka literal 0 HcmV?d00001 -- 2.7.4