diff --git a/WorkDir/webui/debugger.html b/WorkDir/webui/debugger.html new file mode 100644 index 0000000000..241b4e9988 --- /dev/null +++ b/WorkDir/webui/debugger.html @@ -0,0 +1,398 @@ + + + + + Minimal Websocket test app + + + + +
+
+ +
+ +
+
Detected Browser:
...
+ +
+ +
+
libwebsockets "dumb-increment-protocol"
+
+ + + + + +
Not initialized
+
+The incrementing number is coming from the server and is individual for +each connection to the server... try opening a second browser window. +

+The button zeros just this connection's number. +

+ +
+
+
+
+
libwebsockets "lws-mirror-protocol"
+
+Use the mouse to draw on the canvas below -- all other browser windows open +on this page see your drawing in realtime and you can see any of theirs as +well. +

+The lws-mirror protocol doesn't interpret what is being sent to it, it just +re-sends it to every other websocket it has a connection with using that +protocol, including the guy who sent the packet. +

+libwebsockets-test-client joins in by spamming circles on to this shared canvas when +run. +
+ + + + + + + + +
Drawing color: + +
Not initialized
+
+
+
+ +
+Looking for support? http://libwebsockets.org
+Join the mailing list: ​http://ml.libwebsockets.org/mailman/listinfo/libwebsockets + +
+ +
+ + + + + diff --git a/WorkDir/webui/favicon.ico b/WorkDir/webui/favicon.ico new file mode 100644 index 0000000000..c0cc2e3dff Binary files /dev/null and b/WorkDir/webui/favicon.ico differ diff --git a/core/deps/libwebsocket/extension-deflate-frame.h b/core/deps/libwebsocket/extension-deflate-frame.h index 00a4447aae..194d42f6ff 100644 --- a/core/deps/libwebsocket/extension-deflate-frame.h +++ b/core/deps/libwebsocket/extension-deflate-frame.h @@ -1,5 +1,5 @@ -#include +#include "deps/zlib/zlib.h" #define DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER 1 #define DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT Z_DEFAULT_COMPRESSION diff --git a/core/deps/libwebsocket/extension-deflate-stream.h b/core/deps/libwebsocket/extension-deflate-stream.h index fcadc07abd..ff17741fd2 100644 --- a/core/deps/libwebsocket/extension-deflate-stream.h +++ b/core/deps/libwebsocket/extension-deflate-stream.h @@ -1,5 +1,5 @@ -#include +#include "deps/zlib/zlib.h" #define DEFLATE_STREAM_CHUNK 128 #define DEFLATE_STREAM_COMPRESSION_LEVEL 1 diff --git a/core/deps/libwebsocket/libwebsockets.c b/core/deps/libwebsocket/libwebsockets.c index 40a56e8381..3e02529eb2 100644 --- a/core/deps/libwebsocket/libwebsockets.c +++ b/core/deps/libwebsocket/libwebsockets.c @@ -19,8 +19,13 @@ * MA 02110-1301 USA */ + #include "private-libwebsockets.h" +#if HOST_OS == OS_WINDOWS + #pragma comment(lib, "Ws2_32.lib") +#endif + int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE; static void (*lwsl_emit)(int level, const char *line) = lwsl_emit_stderr; diff --git a/core/deps/libwebsocket/lws-plat-unix.c b/core/deps/libwebsocket/lws-plat-unix.c index 279a3be4ad..05b3e61a9c 100644 --- a/core/deps/libwebsocket/lws-plat-unix.c +++ b/core/deps/libwebsocket/lws-plat-unix.c @@ -1,5 +1,8 @@ #include "private-libwebsockets.h" +#include "build.h" + +#if HOST_OS != OS_WINDOWS /* * included from libwebsockets.c for unix builds */ @@ -387,4 +390,5 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) { return inet_ntop(af, src, dst, cnt); } +#endif #endif \ No newline at end of file diff --git a/core/deps/libwebsocket/private-libwebsockets.h b/core/deps/libwebsocket/private-libwebsockets.h index cf65ebf73f..b1ec6edaa4 100644 --- a/core/deps/libwebsocket/private-libwebsockets.h +++ b/core/deps/libwebsocket/private-libwebsockets.h @@ -19,11 +19,20 @@ * MA 02110-1301 USA */ +#include "build.h" + +/* The Libwebsocket version */ +#define LWS_LIBRARY_VERSION "1.3" + +/* The current git commit hash that we're building from */ +#define LWS_BUILD_HASH "c11b847" + + /* System introspection configs */ #ifdef CMAKE_BUILD #include "lws_config.h" #else -#if defined(WIN32) || defined(_WIN32) +#if HOST_OS == OS_WINDOWS #define inline __inline #else /* not WIN32 */ #include "config.h" diff --git a/core/nullDC.cpp b/core/nullDC.cpp index 30bd51ca19..5e78b51ebd 100755 --- a/core/nullDC.cpp +++ b/core/nullDC.cpp @@ -12,6 +12,8 @@ #include "hw/maple/maple_cfg.h" #include "hw/sh4/sh4_mem.h" +#include "webui/server.h" + settings_t settings; /* @@ -41,7 +43,7 @@ int GetFile(char *szFileName, char *szParse=0,u32 flags=0) if (strcmp(szFileName,"null")==0) { #if defined(OMAP4) - strcpy(szFileName,GetPath("gdimage/crazy_taxi.chd").c_str()); + strcpy(szFileName,GetPath("/gdimage/crazy_taxi.chd").c_str()); #else #if HOST_OS==OS_WINDOWS OPENFILENAME ofn; @@ -64,7 +66,7 @@ int GetFile(char *szFileName, char *szParse=0,u32 flags=0) //strcpy(szFileName,ofn.lpstrFile); } #else - strcpy(szFileName,GetPath("discs/game.gdi").c_str()); + strcpy(szFileName,GetPath("/discs/game.gdi").c_str()); #endif #endif } @@ -127,6 +129,17 @@ void plugins_Reset(bool Manual) } +void* webui_th(void* p) +{ + #if HOST_OS == OS_WINDOWS + webui_start(); + #endif + + return 0; +} + +cThread webui_thd(&webui_th,0); + int dc_init(int argc,wchar* argv[]) { setbuf(stdin,0); @@ -138,6 +151,8 @@ int dc_init(int argc,wchar* argv[]) return -1; } + webui_thd.Start(); + if(ParseCommandLine(argc,argv)) { return 69; diff --git a/core/webui/server.cpp b/core/webui/server.cpp new file mode 100644 index 0000000000..6e02442e06 --- /dev/null +++ b/core/webui/server.cpp @@ -0,0 +1,873 @@ +/* + * libwebsockets-test-server - libwebsockets test implementation + * + * Copyright (C) 2010-2011 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +#ifdef CMAKE_BUILD +#include "lws_config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#ifdef EXTERNAL_POLL +#define poll WSAPoll +#endif +#else +#include +#include +#include +#endif + +#include "deps/libwebsocket/libwebsockets.h" +#include "oslib/oslib.h" + +static int close_testing; +int max_poll_elements; + +struct pollfd *pollfds; +int *fd_lookup; +int count_pollfds; +static volatile int force_exit = 0; +static struct libwebsocket_context *context; + +/* + * This demo server shows how to use libwebsockets for one or more + * websocket protocols in the same server + * + * It defines the following websocket protocols: + * + * dumb-increment-protocol: once the socket is opened, an incrementing + * ascii string is sent down it every 50ms. + * If you send "reset\n" on the websocket, then + * the incrementing number is reset to 0. + * + * lws-mirror-protocol: copies any received packet to every connection also + * using this protocol, including the sender + */ + +enum demo_protocols { + /* always first */ + PROTOCOL_HTTP = 0, + + PROTOCOL_DUMB_INCREMENT, + PROTOCOL_LWS_MIRROR, + + /* always last */ + DEMO_PROTOCOL_COUNT +}; + +#define WEBUI_PATH GetPath("/webui") + +/* + * We take a strict whitelist approach to stop ../ attacks + */ + +struct serveable { + const char *urlpath; + const char *mimetype; +}; + +struct per_session_data__http { + int fd; +}; + +/* + * this is just an example of parsing handshake headers, you don't need this + * in your code unless you will filter allowing connections by the header + * content + */ + +static void +dump_handshake_info(struct libwebsocket *wsi) +{ + int n; + static const char *token_names[] = { + /*[WSI_TOKEN_GET_URI] =*/ "GET URI", + /*[WSI_TOKEN_POST_URI] =*/ "POST 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", + + /* new for 05 */ + /*[WSI_TOKEN_EXTENSIONS] =*/ "Extensions", + + /* client receives these */ + /*[WSI_TOKEN_ACCEPT] =*/ "Accept", + /*[WSI_TOKEN_NONCE] =*/ "Nonce", + /*[WSI_TOKEN_HTTP] =*/ "Http", + + "Accept:", + "If-Modified-Since:", + "Accept-Encoding:", + "Accept-Language:", + "Pragma:", + "Cache-Control:", + "Authorization:", + "Cookie:", + "Content-Length:", + "Content-Type:", + "Date:", + "Range:", + "Referer:", + "Uri-Args:", + + /*[WSI_TOKEN_MUXURL] =*/ "MuxURL", + }; + char buf[256]; + + for (n = 0; n < sizeof(token_names) / sizeof(token_names[0]); n++) { + if (!lws_hdr_total_length(wsi, (lws_token_indexes)n)) + continue; + + lws_hdr_copy(wsi, buf, sizeof buf, (lws_token_indexes)n); + + fprintf(stderr, " %s = %s\n", token_names[n], buf); + } +} + +const char * get_mimetype(const char *file) +{ + int n = strlen(file); + + if (n < 5) + return NULL; + + if (!strcmp(&file[n - 4], ".ico")) + return "image/x-icon"; + + if (!strcmp(&file[n - 4], ".png")) + return "image/png"; + + if (!strcmp(&file[n - 5], ".html")) + return "text/html"; + + return NULL; +} + +/* this protocol server (always the first one) just knows how to do HTTP */ + +static int callback_http(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len) +{ +#if 0 + char client_name[128]; + char client_ip[128]; +#endif + char buf[256]; + char leaf_path[1024]; + char b64[64]; + struct timeval tv; + int n, m; + unsigned char *p; + char *other_headers = 0; + static unsigned char buffer[4096]; + struct stat stat_buf; + struct per_session_data__http *pss = + (struct per_session_data__http *)user; + const char *mimetype; +#ifdef EXTERNAL_POLL + struct libwebsocket_pollargs *pa = (struct libwebsocket_pollargs *)in; +#endif + + const string path = WEBUI_PATH; + + const char* resource_path = path.c_str(); + + switch (reason) { + case LWS_CALLBACK_HTTP: + + dump_handshake_info(wsi); + + if (len < 1) { + libwebsockets_return_http_status(context, wsi, + HTTP_STATUS_BAD_REQUEST, NULL); + return -1; + } + + /* this server has no concept of directories */ + if (strchr((const char *)in + 1, '/')) { + libwebsockets_return_http_status(context, wsi, + HTTP_STATUS_FORBIDDEN, NULL); + return -1; + } + + /* if a legal POST URL, let it continue and accept data */ + if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) + return 0; + + /* check for the "send a big file by hand" example case */ + + if (!strcmp((const char *)in, "/leaf.jpg")) { + if (strlen(resource_path) > sizeof(leaf_path) - 10) + return -1; + sprintf(leaf_path, "%s/leaf.jpg", resource_path); + + /* well, let's demonstrate how to send the hard way */ + + p = buffer; + +#ifdef WIN32 + pss->fd = open(leaf_path, O_RDONLY | _O_BINARY); +#else + pss->fd = open(leaf_path, O_RDONLY); +#endif + + if (pss->fd < 0) + return -1; + + fstat(pss->fd, &stat_buf); + + /* + * we will send a big jpeg file, but it could be + * anything. Set the Content-Type: appropriately + * so the browser knows what to do with it. + */ + + p += sprintf((char *)p, + "HTTP/1.0 200 OK\x0d\x0a" + "Server: libwebsockets\x0d\x0a" + "Content-Type: image/jpeg\x0d\x0a" + "Content-Length: %u\x0d\x0a\x0d\x0a", + (unsigned int)stat_buf.st_size); + + /* + * send the http headers... + * this won't block since it's the first payload sent + * on the connection since it was established + * (too small for partial) + */ + + n = libwebsocket_write(wsi, buffer, + p - buffer, LWS_WRITE_HTTP); + + if (n < 0) { + close(pss->fd); + return -1; + } + /* + * book us a LWS_CALLBACK_HTTP_WRITEABLE callback + */ + libwebsocket_callback_on_writable(context, wsi); + break; + } + + /* if not, send a file the easy way */ + strcpy(buf, resource_path); + if (strcmp((const char*)in, "/")) { + if (*((const char *)in) != '/') + strcat(buf, "/"); + strncat(buf, (const char*)in, sizeof(buf) - strlen(resource_path)); + } else /* default file to serve */ + strcat(buf, "/debugger.html"); + buf[sizeof(buf) - 1] = '\0'; + + /* refuse to serve files we don't understand */ + mimetype = get_mimetype(buf); + if (!mimetype) { + lwsl_err("Unknown mimetype for %s\n", buf); + libwebsockets_return_http_status(context, wsi, + HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL); + return -1; + } + + if (libwebsockets_serve_http_file(context, wsi, buf, + mimetype, other_headers)) + return -1; /* through completion or error, close the socket */ + + /* + * notice that the sending of the file completes asynchronously, + * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when + * it's done + */ + + break; + + case LWS_CALLBACK_HTTP_BODY: + strncpy(buf, (const char*)in, 20); + buf[20] = '\0'; + if (len < 20) + buf[len] = '\0'; + + lwsl_notice("LWS_CALLBACK_HTTP_BODY: %s... len %d\n", + (const char *)buf, (int)len); + + break; + + case LWS_CALLBACK_HTTP_BODY_COMPLETION: + lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); + /* the whole of the sent body arried, close the connection */ + libwebsockets_return_http_status(context, wsi, + HTTP_STATUS_OK, NULL); + + return -1; + + case LWS_CALLBACK_HTTP_FILE_COMPLETION: +// lwsl_info("LWS_CALLBACK_HTTP_FILE_COMPLETION seen\n"); + /* kill the connection after we sent one file */ + return -1; + + case LWS_CALLBACK_HTTP_WRITEABLE: + /* + * we can send more of whatever it is we were sending + */ + + do { + n = read(pss->fd, buffer, sizeof buffer); + /* problem reading, close conn */ + if (n < 0) + goto bail; + /* sent it all, close conn */ + if (n == 0) + goto flush_bail; + /* + * because it's HTTP and not websocket, don't need to take + * care about pre and postamble + */ + m = libwebsocket_write(wsi, buffer, n, LWS_WRITE_HTTP); + if (m < 0) + /* write failed, close conn */ + goto bail; + if (m != n) + /* partial write, adjust */ + lseek(pss->fd, m - n, SEEK_CUR); + + if (m) /* while still active, extend timeout */ + libwebsocket_set_timeout(wsi, + PENDING_TIMEOUT_HTTP_CONTENT, 5); + + } while (!lws_send_pipe_choked(wsi)); + libwebsocket_callback_on_writable(context, wsi); + break; +flush_bail: + /* true if still partial pending */ + if (lws_send_pipe_choked(wsi)) { + libwebsocket_callback_on_writable(context, wsi); + break; + } + +bail: + close(pss->fd); + return -1; + + /* + * callback for confirming to continue with client IP appear in + * protocol 0 callback since no websocket protocol has been agreed + * yet. You can just ignore this if you won't filter on client IP + * since the default uhandled callback return is 0 meaning let the + * connection continue. + */ + + case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: +#if 0 + libwebsockets_get_peer_addresses(context, wsi, (int)(long)in, client_name, + sizeof(client_name), client_ip, sizeof(client_ip)); + + fprintf(stderr, "Received network connect from %s (%s)\n", + client_name, client_ip); +#endif + /* if we returned non-zero from here, we kill the connection */ + break; + +#ifdef EXTERNAL_POLL + /* + * callbacks for managing the external poll() array appear in + * protocol 0 callback + */ + + case LWS_CALLBACK_LOCK_POLL: + /* + * lock mutex to protect pollfd state + * called before any other POLL related callback + */ + break; + + case LWS_CALLBACK_UNLOCK_POLL: + /* + * unlock mutex to protect pollfd state when + * called after any other POLL related callback + */ + break; + + case LWS_CALLBACK_ADD_POLL_FD: + + if (count_pollfds >= max_poll_elements) { + lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n"); + return 1; + } + + fd_lookup[pa->fd] = count_pollfds; + pollfds[count_pollfds].fd = pa->fd; + pollfds[count_pollfds].events = pa->events; + pollfds[count_pollfds++].revents = 0; + break; + + case LWS_CALLBACK_DEL_POLL_FD: + if (!--count_pollfds) + break; + m = fd_lookup[pa->fd]; + /* have the last guy take up the vacant slot */ + pollfds[m] = pollfds[count_pollfds]; + fd_lookup[pollfds[count_pollfds].fd] = m; + break; + + case LWS_CALLBACK_CHANGE_MODE_POLL_FD: + pollfds[fd_lookup[pa->fd]].events = pa->events; + break; + +#endif + + case LWS_CALLBACK_GET_THREAD_ID: + /* + * if you will call "libwebsocket_callback_on_writable" + * from a different thread, return the caller thread ID + * here so lws can use this information to work out if it + * should signal the poll() loop to exit and restart early + */ + + /* return pthread_getthreadid_np(); */ + + break; + + default: + break; + } + + return 0; +} + + +/* dumb_increment protocol */ + +/* + * one of these is auto-created for each connection and a pointer to the + * appropriate instance is passed to the callback in the user parameter + * + * for this example protocol we use it to individualize the count for each + * connection. + */ + +struct per_session_data__dumb_increment { + int number; +}; + +static int +callback_dumb_increment(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) +{ + int n, m; + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 + + LWS_SEND_BUFFER_POST_PADDING]; + unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING]; + struct per_session_data__dumb_increment *pss = (struct per_session_data__dumb_increment *)user; + + switch (reason) { + + case LWS_CALLBACK_ESTABLISHED: + lwsl_info("callback_dumb_increment: " + "LWS_CALLBACK_ESTABLISHED\n"); + pss->number = 0; + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + n = sprintf((char *)p, "%d", pss->number++); + m = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT); + if (m < n) { + lwsl_err("ERROR %d writing to di socket\n", n); + return -1; + } + if (close_testing && pss->number == 50) { + lwsl_info("close tesing limit, closing\n"); + return -1; + } + break; + + case LWS_CALLBACK_RECEIVE: +// fprintf(stderr, "rx %d\n", (int)len); + if (len < 6) + break; + if (strcmp((const char *)in, "reset\n") == 0) + pss->number = 0; + break; + /* + * this just demonstrates how to use the protocol filter. If you won't + * study and reject connections based on header content, you don't need + * to handle this callback + */ + + case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: + dump_handshake_info(wsi); + /* you could return non-zero here and kill the connection */ + break; + + default: + break; + } + + return 0; +} + + +/* lws-mirror_protocol */ + +#define MAX_MESSAGE_QUEUE 32 + +struct per_session_data__lws_mirror { + struct libwebsocket *wsi; + int ringbuffer_tail; +}; + +struct a_message { + void *payload; + size_t len; +}; + +static struct a_message ringbuffer[MAX_MESSAGE_QUEUE]; +static int ringbuffer_head; + +static int +callback_lws_mirror(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) +{ + int n; + struct per_session_data__lws_mirror *pss = (struct per_session_data__lws_mirror *)user; + + switch (reason) { + + case LWS_CALLBACK_ESTABLISHED: + lwsl_info("callback_lws_mirror: LWS_CALLBACK_ESTABLISHED\n"); + pss->ringbuffer_tail = ringbuffer_head; + pss->wsi = wsi; + break; + + case LWS_CALLBACK_PROTOCOL_DESTROY: + lwsl_notice("mirror protocol cleaning up\n"); + for (n = 0; n < sizeof ringbuffer / sizeof ringbuffer[0]; n++) + if (ringbuffer[n].payload) + free(ringbuffer[n].payload); + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + if (close_testing) + break; + while (pss->ringbuffer_tail != ringbuffer_head) { + + n = libwebsocket_write(wsi, (unsigned char *) + ringbuffer[pss->ringbuffer_tail].payload + + LWS_SEND_BUFFER_PRE_PADDING, + ringbuffer[pss->ringbuffer_tail].len, + LWS_WRITE_TEXT); + if (n < 0) { + lwsl_err("ERROR %d writing to mirror socket\n", n); + return -1; + } + if (n < ringbuffer[pss->ringbuffer_tail].len) + lwsl_err("mirror partial write %d vs %d\n", + n, ringbuffer[pss->ringbuffer_tail].len); + + if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1)) + pss->ringbuffer_tail = 0; + else + pss->ringbuffer_tail++; + + if (((ringbuffer_head - pss->ringbuffer_tail) & + (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15)) + libwebsocket_rx_flow_allow_all_protocol( + libwebsockets_get_protocol(wsi)); + + // lwsl_debug("tx fifo %d\n", (ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)); + + if (lws_send_pipe_choked(wsi)) { + libwebsocket_callback_on_writable(context, wsi); + break; + } + /* + * for tests with chrome on same machine as client and + * server, this is needed to stop chrome choking + */ +#ifdef _WIN32 + Sleep(1); +#else + usleep(1); +#endif + } + break; + + case LWS_CALLBACK_RECEIVE: + + if (((ringbuffer_head - pss->ringbuffer_tail) & + (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) { + lwsl_err("dropping!\n"); + goto choke; + } + + if (ringbuffer[ringbuffer_head].payload) + free(ringbuffer[ringbuffer_head].payload); + + ringbuffer[ringbuffer_head].payload = + malloc(LWS_SEND_BUFFER_PRE_PADDING + len + + LWS_SEND_BUFFER_POST_PADDING); + ringbuffer[ringbuffer_head].len = len; + memcpy((char *)ringbuffer[ringbuffer_head].payload + + LWS_SEND_BUFFER_PRE_PADDING, in, len); + if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1)) + ringbuffer_head = 0; + else + ringbuffer_head++; + + if (((ringbuffer_head - pss->ringbuffer_tail) & + (MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2)) + goto done; + +choke: + lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi); + libwebsocket_rx_flow_control(wsi, 0); + +// lwsl_debug("rx fifo %d\n", (ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)); +done: + libwebsocket_callback_on_writable_all_protocol( + libwebsockets_get_protocol(wsi)); + break; + + /* + * this just demonstrates how to use the protocol filter. If you won't + * study and reject connections based on header content, you don't need + * to handle this callback + */ + + case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: + dump_handshake_info(wsi); + /* you could return non-zero here and kill the connection */ + break; + + default: + break; + } + + return 0; +} + + +/* list of supported protocols and callbacks */ + +static struct libwebsocket_protocols protocols[] = { + /* first protocol must always be HTTP handler */ + + { + "http-only", /* name */ + callback_http, /* callback */ + sizeof (struct per_session_data__http), /* per_session_data_size */ + 0, /* max frame size / rx buffer */ + }, + { + "dumb-increment-protocol", + callback_dumb_increment, + sizeof(struct per_session_data__dumb_increment), + 10, + }, + { + "lws-mirror-protocol", + callback_lws_mirror, + sizeof(struct per_session_data__lws_mirror), + 128, + }, + { NULL, NULL, 0, 0 } /* terminator */ +}; + +void sighandler(int sig) +{ + force_exit = 1; + libwebsocket_cancel_service(context); +} + +void webui_start() +{ + char cert_path[1024]; + char key_path[1024]; + int n = 0; + int use_ssl = 0; + int opts = 0; + char interface_name[128] = ""; + const char *iface = NULL; +#ifndef WIN32 + int syslog_options = LOG_PID | LOG_PERROR; +#endif + struct lws_context_creation_info info; + + int debug_level = 7; +#ifndef LWS_NO_DAEMONIZE + int daemonize = 0; +#endif + + memset(&info, 0, sizeof info); + info.port = 5678; + + const string path = WEBUI_PATH; + + const char* resource_path = path.c_str(); + +#ifndef WIN32 + /* we will only try to log things according to our debug_level */ + setlogmask(LOG_UPTO (LOG_DEBUG)); + openlog("lwsts", syslog_options, LOG_DAEMON); +#endif + + /* tell the library what debug level to emit and to send it to syslog */ + lws_set_log_level(debug_level, lwsl_emit_syslog); + + lwsl_notice("libwebsockets test server - " + "(C) Copyright 2010-2013 Andy Green - " + "licensed under LGPL2.1\n"); +#ifdef EXTERNAL_POLL + max_poll_elements = getdtablesize(); + pollfds = malloc(max_poll_elements * sizeof (struct pollfd)); + fd_lookup = malloc(max_poll_elements * sizeof (int)); + if (pollfds == NULL || fd_lookup == NULL) { + lwsl_err("Out of memory pollfds=%d\n", max_poll_elements); + return -1; + } +#endif + + info.iface = iface; + info.protocols = protocols; +#ifndef LWS_NO_EXTENSIONS + info.extensions = libwebsocket_get_internal_extensions(); +#endif + if (!use_ssl) { + info.ssl_cert_filepath = NULL; + info.ssl_private_key_filepath = NULL; + } else { + if (strlen(resource_path) > sizeof(cert_path) - 32) { + lwsl_err("resource path too long\n"); + return ; + } + sprintf(cert_path, "%s/libwebsockets-test-server.pem", + resource_path); + if (strlen(resource_path) > sizeof(key_path) - 32) { + lwsl_err("resource path too long\n"); + return; + } + sprintf(key_path, "%s/libwebsockets-test-server.key.pem", + resource_path); + + info.ssl_cert_filepath = cert_path; + info.ssl_private_key_filepath = key_path; + } + info.gid = -1; + info.uid = -1; + info.options = opts; + + context = libwebsocket_create_context(&info); + if (context == NULL) { + lwsl_err("libwebsocket init failed\n"); + return ; + } + + n = 0; + double old_time = 0; + + while (n >= 0 && !force_exit) { + + double time = os_GetSeconds(); + + /* + * This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every + * live websocket connection using the DUMB_INCREMENT protocol, + * as soon as it can take more packets (usually immediately) + */ + + if ((time - old_time ) > 0.050) { + libwebsocket_callback_on_writable_all_protocol(&protocols[PROTOCOL_DUMB_INCREMENT]); + old_time = time; + } + +#ifdef EXTERNAL_POLL + + /* + * this represents an existing server's single poll action + * which also includes libwebsocket sockets + */ + + n = poll(pollfds, count_pollfds, 50); + if (n < 0) + continue; + + + if (n) + for (n = 0; n < count_pollfds; n++) + if (pollfds[n].revents) + /* + * returns immediately if the fd does not + * match anything under libwebsockets + * control + */ + if (libwebsocket_service_fd(context, + &pollfds[n]) < 0) + goto done; +#else + /* + * If libwebsockets sockets are all we care about, + * you can use this api which takes care of the poll() + * and looping through finding who needed service. + * + * If no socket needs service, it'll return anyway after + * the number of ms in the second argument. + */ + + n = libwebsocket_service(context, 50); +#endif + } + +#ifdef EXTERNAL_POLL +done: +#endif + + libwebsocket_context_destroy(context); + + lwsl_notice("libwebsockets-test-server exited cleanly\n"); + +#ifndef WIN32 + closelog(); +#endif + + return; +} diff --git a/core/webui/server.h b/core/webui/server.h new file mode 100644 index 0000000000..2dd42c05bd --- /dev/null +++ b/core/webui/server.h @@ -0,0 +1 @@ +void webui_start(); \ No newline at end of file diff --git a/shell/reicast.vcxproj b/shell/reicast.vcxproj index 8118a54c30..2b94234dd8 100644 --- a/shell/reicast.vcxproj +++ b/shell/reicast.vcxproj @@ -43,6 +43,7 @@ + @@ -147,6 +148,7 @@ + @@ -271,6 +273,7 @@ + diff --git a/shell/reicast.vcxproj.filters b/shell/reicast.vcxproj.filters index e5028c219f..d6aae57dfe 100644 --- a/shell/reicast.vcxproj.filters +++ b/shell/reicast.vcxproj.filters @@ -390,6 +390,12 @@ deps\libwebsocket + + deps\libwebsocket + + + webui + @@ -503,6 +509,9 @@ {3d3de3ff-9e79-4920-a95a-61d190e73004} + + {81193efc-656a-4154-9adf-146856d4c7d3} + @@ -847,6 +856,9 @@ deps\libwebsocket + + webui +