Initial webui code (that does nothing useful)

I plan to port over the existing nulldc debugger stuff to a webui so we can do remote debugging on android and more
This commit is contained in:
Stefanos Kornilios Mitsis Poiitidis 2014-04-22 17:32:04 +03:00 committed by ptitSeb
parent eb3f1ca687
commit 528d0c6d7a
12 changed files with 1325 additions and 5 deletions

398
WorkDir/webui/debugger.html Normal file
View File

@ -0,0 +1,398 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8 http-equiv="Content-Language" content="en"/>
<title>Minimal Websocket test app</title>
<style type="text/css">
div.title { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#000000; }
.browser { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#ffff00; vertical-align:middle; text-align:center; background:#d0b070; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px;}
.group2 { width:600px; vertical-align:middle; text-align:center; background:#f0f0e0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; }
.explain { vertical-align:middle; text-align:center; background:#f0f0c0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; color:#404000; }
.content { vertical-align:top; text-align:center; background:#fffff0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; }
.canvas { vertical-align:top; text-align:center; background:#efefd0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; }
</style>
</head>
<body>
<header></header>
<article>
<table><tr><td>
<table width="100%"><tr><td valign=middle align=center><a href="http://libwebsockets.org"><img src="/libwebsockets.org-logo.png"></a></td><td>
<section class="browser">Detected Browser: <div id=brow>...</div></section></td></tr></table>
</td></tr><tr><td>
<section id="increment" class="group2">
<div class="title">libwebsockets "dumb-increment-protocol"</div>
<table><tr><td>
<table class="content" width="200px">
<tr><td align=center><input type=button id=offset value="Reset counter" onclick="reset();" ></td></tr>
<tr><td width=200px align=center><div id=number> </div></td></tr>
<tr><td id=wsdi_statustd align=center class="explain"><div id=wsdi_status>Not initialized</div></td></tr>
</tr>
</table>
</td><td class="explain">
The incrementing number is coming from the server and is individual for
each connection to the server... try opening a second browser window.
<br/><br/>
The button zeros just this connection's number.
<br/><br/>
</td></tr></table>
</section>
<br>
<section id="mirror" class="group2">
<div class="title">libwebsockets "lws-mirror-protocol"</div>
<div class="explain">
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.
<br/><br/>
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.
<br/><br/>
<b>libwebsockets-test-client</b> joins in by spamming circles on to this shared canvas when
run.
</div>
<table class="content">
<tr>
<td>Drawing color:
<select id="color" onchange="update_color();">
<option value=#000000>Black</option>
<option value=#0000ff>Blue</option>
<option value=#20ff20>Green</option>
<option value=#802020>Dark Red</option>
</select>
</td>
<td id=wslm_statustd align=center class="explain"><div id=wslm_status>Not initialized</div></td>
</tr>
<tr>
<td colspan=2 width=500 class="content">
<div id="wslm_drawing">
</div></td>
</tr>
</table>
</section>
</td></tr><tr><td>
Looking for support? <a href="http://libwebsockets.org">http://libwebsockets.org</a><br/>
Join the mailing list: <a href="http://ml.libwebsockets.org/mailman/listinfo/libwebsockets">http://ml.libwebsockets.org/mailman/listinfo/libwebsockets</a>
</td></tr></table>
</article>
<script>
/* BrowserDetect came from http://www.quirksmode.org/js/detect.html */
var BrowserDetect = {
init: function () {
this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
this.version = this.searchVersion(navigator.userAgent)
|| this.searchVersion(navigator.appVersion)
|| "an unknown version";
this.OS = this.searchString(this.dataOS) || "an unknown OS";
},
searchString: function (data) {
for (var i=0;i<data.length;i++) {
var dataString = data[i].string;
var dataProp = data[i].prop;
this.versionSearchString = data[i].versionSearch || data[i].identity;
if (dataString) {
if (dataString.indexOf(data[i].subString) != -1)
return data[i].identity;
}
else if (dataProp)
return data[i].identity;
}
},
searchVersion: function (dataString) {
var index = dataString.indexOf(this.versionSearchString);
if (index == -1) return;
return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
},
dataBrowser: [
{
string: navigator.userAgent,
subString: "Chrome",
identity: "Chrome"
},
{ string: navigator.userAgent,
subString: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
},
{
string: navigator.vendor,
subString: "Apple",
identity: "Safari",
versionSearch: "Version"
},
{
prop: window.opera,
identity: "Opera",
versionSearch: "Version"
},
{
string: navigator.vendor,
subString: "iCab",
identity: "iCab"
},
{
string: navigator.vendor,
subString: "KDE",
identity: "Konqueror"
},
{
string: navigator.userAgent,
subString: "Firefox",
identity: "Firefox"
},
{
string: navigator.vendor,
subString: "Camino",
identity: "Camino"
},
{ // for newer Netscapes (6+)
string: navigator.userAgent,
subString: "Netscape",
identity: "Netscape"
},
{
string: navigator.userAgent,
subString: "MSIE",
identity: "Explorer",
versionSearch: "MSIE"
},
{
string: navigator.userAgent,
subString: "Gecko",
identity: "Mozilla",
versionSearch: "rv"
},
{ // for older Netscapes (4-)
string: navigator.userAgent,
subString: "Mozilla",
identity: "Netscape",
versionSearch: "Mozilla"
}
],
dataOS : [
{
string: navigator.platform,
subString: "Win",
identity: "Windows"
},
{
string: navigator.platform,
subString: "Mac",
identity: "Mac"
},
{
string: navigator.userAgent,
subString: "iPhone",
identity: "iPhone/iPod"
},
{
string: navigator.platform,
subString: "Linux",
identity: "Linux"
}
]
};
BrowserDetect.init();
document.getElementById("brow").textContent = " " + BrowserDetect.browser + " "
+ BrowserDetect.version +" " + BrowserDetect.OS +" ";
var pos = 0;
function get_appropriate_ws_url()
{
var pcol;
var u = document.URL;
/*
* We open the websocket encrypted if this page came on an
* https:// url itself, otherwise unencrypted
*/
if (u.substring(0, 5) == "https") {
pcol = "wss://";
u = u.substr(8);
} else {
pcol = "ws://";
if (u.substring(0, 4) == "http")
u = u.substr(7);
}
u = u.split('/');
/* + "/xxx" bit is for IE10 workaround */
return pcol + u[0] + "/xxx";
}
document.getElementById("number").textContent = get_appropriate_ws_url();
/* dumb increment protocol */
var socket_di;
if (typeof MozWebSocket != "undefined") {
socket_di = new MozWebSocket(get_appropriate_ws_url(),
"dumb-increment-protocol");
} else {
socket_di = new WebSocket(get_appropriate_ws_url(),
"dumb-increment-protocol");
}
try {
socket_di.onopen = function() {
document.getElementById("wsdi_statustd").style.backgroundColor = "#40ff40";
document.getElementById("wsdi_status").textContent = " websocket connection opened ";
}
socket_di.onmessage =function got_packet(msg) {
document.getElementById("number").textContent = msg.data + "\n";
}
socket_di.onclose = function(){
document.getElementById("wsdi_statustd").style.backgroundColor = "#ff4040";
document.getElementById("wsdi_status").textContent = " websocket connection CLOSED ";
}
} catch(exception) {
alert('<p>Error' + exception);
}
function reset() {
socket_di.send("reset\n");
}
/* lws-mirror protocol */
var down = 0;
var no_last = 1;
var last_x = 0, last_y = 0;
var ctx;
var socket_lm;
var color = "#000000";
if (typeof MozWebSocket != "undefined") {
socket_lm = new MozWebSocket(get_appropriate_ws_url(),
"lws-mirror-protocol");
} else {
socket_lm = new WebSocket(get_appropriate_ws_url(),
"lws-mirror-protocol");
}
try {
socket_lm.onopen = function() {
document.getElementById("wslm_statustd").style.backgroundColor = "#40ff40";
document.getElementById("wslm_status").textContent = " websocket connection opened ";
}
socket_lm.onmessage =function got_packet(msg) {
j = msg.data.split(';');
f = 0;
while (f < j.length - 1) {
i = j[f].split(' ');
if (i[0] == 'd') {
ctx.strokeStyle = i[1];
ctx.beginPath();
ctx.moveTo(+(i[2]), +(i[3]));
ctx.lineTo(+(i[4]), +(i[5]));
ctx.stroke();
}
if (i[0] == 'c') {
ctx.strokeStyle = i[1];
ctx.beginPath();
ctx.arc(+(i[2]), +(i[3]), +(i[4]), 0, Math.PI*2, true);
ctx.stroke();
}
f++;
}
}
socket_lm.onclose = function(){
document.getElementById("wslm_statustd").style.backgroundColor = "#ff4040";
document.getElementById("wslm_status").textContent = " websocket connection CLOSED ";
}
} catch(exception) {
alert('<p>Error' + exception);
}
var canvas = document.createElement('canvas');
canvas.height = 300;
canvas.width = 480;
ctx = canvas.getContext("2d");
document.getElementById('wslm_drawing').appendChild(canvas);
canvas.addEventListener('mousemove', ev_mousemove, false);
canvas.addEventListener('mousedown', ev_mousedown, false);
canvas.addEventListener('mouseup', ev_mouseup, false);
offsetX = offsetY = 0;
element = canvas;
if (element.offsetParent) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
function update_color() {
color = document.getElementById("color").value;
}
function ev_mousedown (ev) {
down = 1;
}
function ev_mouseup(ev) {
down = 0;
no_last = 1;
}
function ev_mousemove (ev) {
var x, y;
if (ev.offsetX) {
x = ev.offsetX;
y = ev.offsetY;
} else {
x = ev.layerX - offsetX;
y = ev.layerY - offsetY;
}
if (!down)
return;
if (no_last) {
no_last = 0;
last_x = x;
last_y = y;
return;
}
socket_lm.send("d " + color + " " + last_x + " " + last_y + " " + x + ' ' + y + ';');
last_x = x;
last_y = y;
}
</script>
</body>
</html>

BIN
WorkDir/webui/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,5 +1,5 @@
#include <zlib.h>
#include "deps/zlib/zlib.h"
#define DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER 1
#define DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT Z_DEFAULT_COMPRESSION

View File

@ -1,5 +1,5 @@
#include <zlib.h>
#include "deps/zlib/zlib.h"
#define DEFLATE_STREAM_CHUNK 128
#define DEFLATE_STREAM_COMPRESSION_LEVEL 1

View File

@ -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;

View File

@ -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

View File

@ -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"

View File

@ -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;

873
core/webui/server.cpp Normal file
View File

@ -0,0 +1,873 @@
/*
* libwebsockets-test-server - libwebsockets test implementation
*
* Copyright (C) 2010-2011 Andy Green <andy@warmcat.com>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#ifdef _WIN32
#include <io.h>
#ifdef EXTERNAL_POLL
#define poll WSAPoll
#endif
#else
#include <syslog.h>
#include <sys/time.h>
#include <unistd.h>
#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 <andy@warmcat.com> - "
"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;
}

1
core/webui/server.h Normal file
View File

@ -0,0 +1 @@
void webui_start();

View File

@ -43,6 +43,7 @@
<ClCompile Include="..\core\deps\libwebsocket\extension-deflate-frame.c" />
<ClCompile Include="..\core\deps\libwebsocket\extension-deflate-stream.c" />
<ClCompile Include="..\core\deps\libwebsocket\extension.c" />
<ClCompile Include="..\core\deps\libwebsocket\handshake.c" />
<ClCompile Include="..\core\deps\libwebsocket\libwebsockets.c" />
<ClCompile Include="..\core\deps\libwebsocket\lws-plat-unix.c" />
<ClCompile Include="..\core\deps\libwebsocket\lws-plat-win.c" />
@ -147,6 +148,7 @@
<ClCompile Include="..\core\rend\gles\gltex.cpp" />
<ClCompile Include="..\core\rend\TexCache.cpp" />
<ClCompile Include="..\core\stdclass.cpp" />
<ClCompile Include="..\core\webui\server.cpp" />
<ClCompile Include="..\core\windows\win86_driver.cpp" />
<ClCompile Include="..\core\windows\win86_il.cpp" />
<ClCompile Include="..\core\windows\win86_ngen.cpp" />
@ -271,6 +273,7 @@
<ClInclude Include="..\core\rend\TexCache.h" />
<ClInclude Include="..\core\stdclass.h" />
<ClInclude Include="..\core\types.h" />
<ClInclude Include="..\core\webui\server.h" />
<ClInclude Include="..\core\windows\win86_ngen.h" />
</ItemGroup>
<ItemGroup>

View File

@ -390,6 +390,12 @@
<ClCompile Include="..\core\deps\libwebsocket\sha-1.c">
<Filter>deps\libwebsocket</Filter>
</ClCompile>
<ClCompile Include="..\core\deps\libwebsocket\handshake.c">
<Filter>deps\libwebsocket</Filter>
</ClCompile>
<ClCompile Include="..\core\webui\server.cpp">
<Filter>webui</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="hw">
@ -503,6 +509,9 @@
<Filter Include="deps\libwebsocket">
<UniqueIdentifier>{3d3de3ff-9e79-4920-a95a-61d190e73004}</UniqueIdentifier>
</Filter>
<Filter Include="webui">
<UniqueIdentifier>{81193efc-656a-4154-9adf-146856d4c7d3}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\core\hw\aica\aica.h">
@ -847,6 +856,9 @@
<ClInclude Include="..\core\deps\libwebsocket\private-libwebsockets.h">
<Filter>deps\libwebsocket</Filter>
</ClInclude>
<ClInclude Include="..\core\webui\server.h">
<Filter>webui</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\core\deps\zlib\Makefile">