Previous 199869 Revisions Next

r41577 Wednesday 4th November, 2015 at 17:55:36 UTC by Miodrag Milanović
Removed mongoose due to restricted license and webserver wip till code is restructured (nw)
[3rdparty/mongoose]LICENSE README.md mongoose.c mongoose.h
[3rdparty/mongoose/docs]API.md AndroidBuild.md BasicWebsite.md Embed.md FAQ.md FileSharing.md Internals.md Options.md PhpWebsite.md ReleaseNotes.md SSL.md Usage.md
[3rdparty/mongoose/examples].gitignore Makefile
[3rdparty/mongoose/examples/array_vars]Makefile array_vars.c
[3rdparty/mongoose/examples/big_upload]Makefile big_upload.c
[3rdparty/mongoose/examples/cookie_authentication]Makefile cookie_auth.c index.html login.html
[3rdparty/mongoose/examples/csharp]example.cs mongoose.cs
[3rdparty/mongoose/examples/digest_authentication]Makefile digest_auth.c
[3rdparty/mongoose/examples/file_upload]Makefile file_upload.c
[3rdparty/mongoose/examples/form_submit]Makefile form_submit.c
[3rdparty/mongoose/examples/hello_world]Makefile hello_world.c
[3rdparty/mongoose/examples/http_client]Makefile http_client.c
[3rdparty/mongoose/examples/mjpg_streamer]Makefile mjpg_streamer.c
[3rdparty/mongoose/examples/multi_threaded_server]Makefile multi_threaded_server.c
[3rdparty/mongoose/examples/proxy_server]Makefile proxy_server.c ssl_cert.pem
[3rdparty/mongoose/examples/proxy_server/proxy_web_root]index.html
[3rdparty/mongoose/examples/proxy_server/proxy_web_root/app1]index.html
[3rdparty/mongoose/examples/proxy_server/proxy_web_root/app2]index.html
[3rdparty/mongoose/examples/restful_api]Makefile index.html restful_api.c
[3rdparty/mongoose/examples/send_file]Makefile send_file.c
[3rdparty/mongoose/examples/web_server]Makefile web_server.c
[3rdparty/mongoose/examples/web_server/certs]cert.pem
[3rdparty/mongoose/examples/websocket_chat]Makefile index.html websocket_chat.c
[3rdparty/mongoose/examples/websocket_echo_server]Makefile index.html websocket_echo_server.c
[3rdparty/mongoose/examples/websocket_ssl_proxy]Makefile net_skeleton.h ssl_wrapper.c ssl_wrapper.h ws_ssl.c ws_ssl.html
[3rdparty/mongoose/examples/websocket_ssl_proxy/certs]ws1_ca.pem ws1_client.pem ws1_server.pem ws2_ca.pem ws2_client.pem ws2_server.pem
[3rdparty/mongoose/jni]Android.mk
[3rdparty/mongoose/scripts]embed_binary_files.pl
[3rdparty/mongoose/test]Makefile unit_test.c
[scripts/src]3rdparty.lua emu.lua main.lua
[src/emu]emuopts.c emuopts.h luaengine.c machine.c mame.c mame.h webengine.c webengine.h
[src/emu/debug]debugcpu.c
[src/emu/ui]ui.c
[web]favicon.ico index.html
[web/css]jquery.mobile.css
[web/css/images]ajax-loader.gif icons-18-black.png icons-18-white.png icons-36-black.png icons-36-white.png
[web/images]logo-mame-small.png
[web/js]jquery.js jquery.mobile.js

trunk/scripts/src/3rdparty.lua
r250088r250089
461461   }
462462
463463--------------------------------------------------
464-- mongoose library objects
465--------------------------------------------------
466
467project "mongoose"
468   uuid "ff05b529-2b6f-4166-9dff-5fe2aef89c40"
469   kind "StaticLib"
470
471   configuration { "vs*" }
472      buildoptions {
473         "/wd4996", -- warning C4996: 'function': was declared deprecated
474         "/wd4100", -- warning C4100: 'xxx' : unreferenced formal parameter
475         "/wd4245", -- warning C4245: 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch         
476         "/wd4267", -- warning C4267: 'var' : conversion from 'size_t' to 'type', possible loss of data
477         "/wd4244", -- warning C4244: 'argument' : conversion from 'xxx' to 'xxx', possible loss of data
478      }
479   
480   configuration { "vs2015" }
481      buildoptions {
482         "/wd4456", -- warning C4456: declaration of 'xxx' hides previous local declaration
483   }
484   
485   configuration { }
486
487   options {
488      "ForceCPP",
489   }
490   defines {
491      "MONGOOSE_ENABLE_THREADS",
492      "NS_STACK_SIZE=0"
493   }
494
495   includedirs {
496      MAME_DIR .. "3rdparty/mongoose",
497   }
498
499   files {
500      MAME_DIR .. "3rdparty/mongoose/mongoose.c",
501   }
502
503--------------------------------------------------
504464-- jsoncpp library objects
505465--------------------------------------------------
506466
trunk/scripts/src/emu.lua
r250088r250089
245245   MAME_DIR .. "src/emu/debug/textbuf.h",
246246   MAME_DIR .. "src/emu/profiler.c",
247247   MAME_DIR .. "src/emu/profiler.h",
248   MAME_DIR .. "src/emu/webengine.c",
249   MAME_DIR .. "src/emu/webengine.h",
250248   MAME_DIR .. "src/emu/sound/filter.c",
251249   MAME_DIR .. "src/emu/sound/filter.h",
252250   MAME_DIR .. "src/devices/sound/flt_vol.c",
trunk/scripts/src/main.lua
r250088r250089
116116      "lua",
117117      "lsqlite3",
118118      "jsoncpp",
119      "mongoose",
120119   }
121120
122121   if _OPTIONS["with-bundled-zlib"] then
trunk/src/emu/debug/debugcpu.c
r250088r250089
19311931         // flush any pending updates before waiting again
19321932         machine.debug_view().flush_osd_updates();
19331933
1934         machine.manager().web()->serve();
1935
19361934         // clear the memory modified flag and wait
19371935         global->memory_modified = false;
19381936         if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED)
trunk/src/emu/emuopts.c
r250088r250089
185185   { OPTION_AUTOBOOT_COMMAND ";ab",                     NULL,        OPTION_STRING,     "command to execute after machine boot" },
186186   { OPTION_AUTOBOOT_DELAY,                             "2",         OPTION_INTEGER,    "timer delay in sec to trigger command execution on autoboot" },
187187   { OPTION_AUTOBOOT_SCRIPT ";script",                  NULL,        OPTION_STRING,     "lua script to execute after machine boot" },
188   { OPTION_HTTP,                                       "0",         OPTION_BOOLEAN,    "enable local http server" },
189   { OPTION_HTTP_PORT,                                  "8080",      OPTION_STRING,     "http server listener port" },
190   { OPTION_HTTP_PATH,                                  "web",       OPTION_STRING,     "path to web files" },
191   { OPTION_CONSOLE,                                    "0",         OPTION_BOOLEAN,    "enable emulator LUA console" },
192188   { NULL }
193189};
194190
trunk/src/emu/emuopts.h
r250088r250089
189189#define OPTION_AUTOBOOT_DELAY       "autoboot_delay"
190190#define OPTION_AUTOBOOT_SCRIPT      "autoboot_script"
191191
192#define OPTION_HTTP                 "http"
193#define OPTION_HTTP_PORT            "http_port"
194#define OPTION_HTTP_PATH            "http_path"
195#define OPTION_CONSOLE              "console"
196
197192//**************************************************************************
198193//  TYPE DEFINITIONS
199194//**************************************************************************
r250088r250089
366361   int autoboot_delay() const { return int_value(OPTION_AUTOBOOT_DELAY); }
367362   const char *autoboot_script() const { return value(OPTION_AUTOBOOT_SCRIPT); }
368363
369   bool http() const { return bool_value(OPTION_HTTP); }
370   const char *http_port() const { return value(OPTION_HTTP_PORT); }
371   const char *http_path() const { return value(OPTION_HTTP_PATH); }
372   bool console() const { return bool_value(OPTION_CONSOLE); }
373
374364   // FIXME: Couriersud: This should be in image_device_exit
375365   void remove_device_options();
376366
trunk/src/emu/luaengine.c
r250088r250089
1717#include "osdepend.h"
1818#include "drivenum.h"
1919#include "ui/ui.h"
20#include "mongoose/mongoose.h"
2120
2221//**************************************************************************
2322//  LUA ENGINE
r250088r250089
862861   } while (1);
863862}
864863
864/*
865865static void *serve_lua(void *param)
866866{
867867   lua_engine *engine = (lua_engine *)param;
868868   engine->serve_lua();
869869   return NULL;
870870}
871*/
871872
872
873873//-------------------------------------------------
874874//  lua_engine - constructor
875875//-------------------------------------------------
r250088r250089
10251025
10261026void lua_engine::start_console()
10271027{
1028   mg_start_thread(::serve_lua, this);
10291028}
10301029
10311030//-------------------------------------------------
trunk/src/emu/machine.c
r250088r250089
393393         js_set_main_loop(this);
394394#endif
395395
396         manager().web()->serve();
397
398396         // execute CPUs if not paused
399397         if (!m_paused)
400398            m_scheduler.timeslice();
trunk/src/emu/mame.c
r250088r250089
117117machine_manager::machine_manager(emu_options &options,osd_interface &osd)
118118      : m_osd(osd),
119119      m_options(options),
120      m_web(options),
121120      m_new_driver_pending(NULL),
122121      m_machine(NULL)
123122{
r250088r250089
155154void machine_manager::update_machine()
156155{
157156   m_lua.set_machine(m_machine);
158   m_web.set_machine(m_machine);
159   if (m_machine!=NULL) m_web.push_message("update_machine");
160157}
161158
162159/*-------------------------------------------------
r250088r250089
175172   int error = MAMERR_NONE;
176173
177174   m_lua.initialize();
178   if (m_options.console()) {
179      m_lua.start_console();
180   }
181175   while (error == MAMERR_NONE && !exit_pending)
182176   {
183177      m_new_driver_pending = NULL;
trunk/src/emu/mame.h
r250088r250089
1818
1919#include <time.h>
2020
21#include "webengine.h"
22
2321class osd_interface;
2422
2523//**************************************************************************
r250088r250089
8987
9088   osd_interface &osd() const;
9189   emu_options &options() const { return m_options; }
92   web_engine *web() { return &m_web; }
9390   lua_engine *lua() { return &m_lua; }
9491
9592   running_machine *machine() { return m_machine; }
r250088r250089
105102   osd_interface &         m_osd;                  // reference to OSD system
106103   emu_options &           m_options;              // reference to options
107104
108   web_engine              m_web;
109105   lua_engine              m_lua;
110106
111107   const game_driver *     m_new_driver_pending;   // pointer to the next pending driver
trunk/src/emu/ui/ui.c
r250088r250089
374374      // loop while we have a handler
375375      while (m_handler_callback != handler_ingame && !machine().scheduled_event_pending() && !ui_menu::stack_has_special_main_menu())
376376      {
377         machine().manager().web()->serve();
378377         machine().video().frame_update();
379378      }
380379
trunk/src/emu/webengine.c
r250088r250089
1// license:BSD-3-Clause
2// copyright-holders:Miodrag Milanovic
3/***************************************************************************
4
5    webengine.c
6
7    Handle MAME internal web server.
8
9***************************************************************************/
10
11#include "mongoose/mongoose.h"
12#include "jsoncpp/include/json/json.h"
13#include "emu.h"
14#include "emuopts.h"
15#include "ui/ui.h"
16#include "webengine.h"
17#include "lua.hpp"
18
19#include "osdepend.h"
20
21//**************************************************************************
22//  WEB ENGINE
23//**************************************************************************
24
25char* websanitize_statefilename ( char* unsanitized )
26{
27   // It's important that we remove any dangerous characters from any filename
28   // we receive from a web client. This can be a serious security hole.
29   // As MAME/MESS policy is lowercase filenames, also lowercase it.
30
31   char* sanitized = new char[64];
32   int insertpoint =0;
33   char charcompare;
34
35   while (*unsanitized != 0)
36   {
37   charcompare = *unsanitized;
38      // ASCII 48-57 are 0-9
39      // ASCII 97-122 are lowercase A-Z
40
41      if ((charcompare >= 48 && charcompare <= 57) || (charcompare >= 97 && charcompare <= 122))
42      {
43         sanitized[insertpoint] = charcompare;
44         insertpoint++;
45         sanitized[insertpoint] = '\0'; // Make sure we're null-terminated.
46      }
47      // ASCII 65-90 are uppercase A-Z. These need to be lowercased.
48      if (charcompare >= 65 && charcompare <= 90)
49      {
50         sanitized[insertpoint] = tolower(charcompare); // Lowercase it
51         insertpoint++;
52         sanitized[insertpoint] = '\0'; // Make sure we're null-terminated.
53      }
54      unsanitized++;
55   }
56   return (sanitized);
57}
58
59int web_engine::json_game_handler(struct mg_connection *conn)
60{
61   Json::Value data;
62   data["name"] = m_machine->system().name;
63   data["description"] = m_machine->system().description;
64   data["year"] = m_machine->system().year;
65   data["manufacturer"] = m_machine->system().manufacturer;
66   data["parent"] = m_machine->system().parent;
67   data["source_file"] = m_machine->system().source_file;
68   data["flags"] = m_machine->system().flags;
69   data["ispaused"] = m_machine->paused();
70
71   Json::FastWriter writer;
72   std::string json = writer.write(data);
73   // Send HTTP reply to the client
74   mg_printf(conn,
75         "HTTP/1.1 200 OK\r\n"
76         "Content-Type: application/json\r\n"
77         "Content-Length: %d\r\n"        // Always set Content-Length
78         "\r\n"
79         "%s",
80         (int)json.length(), json.c_str());
81
82   // Returning non-zero tells mongoose that our function has replied to
83   // the client, and mongoose should not send client any more data.
84
85   return MG_TRUE;
86}
87
88int web_engine::json_slider_handler(struct mg_connection *conn)
89{
90   const slider_state *curslider;
91   std::string tempstring;
92   Json::Value array(Json::arrayValue);
93
94   // add all sliders
95   for (curslider = machine().ui().get_slider_list(); curslider != NULL; curslider = curslider->next)
96   {
97      INT32 curval = (*curslider->update)(machine(), curslider->arg, &tempstring, SLIDER_NOCHANGE);
98      Json::Value data;
99      data["description"] = curslider->description;
100      data["minval"] = curslider->minval;
101      data["maxval"] = curslider->maxval;
102      data["defval"] = curslider->defval;
103      data["incval"] = curslider->incval;
104      data["curval"] = curval;
105      array.append(data);
106   }
107
108   // add all sliders
109   for (curslider = (slider_state*)machine().osd().get_slider_list(); curslider != NULL; curslider = curslider->next)
110   {
111      INT32 curval = (*curslider->update)(machine(), curslider->arg, &tempstring, SLIDER_NOCHANGE);
112      Json::Value data;
113      data["description"] = curslider->description;
114      data["minval"] = curslider->minval;
115      data["maxval"] = curslider->maxval;
116      data["defval"] = curslider->defval;
117      data["incval"] = curslider->incval;
118      data["curval"] = curval;
119      array.append(data);
120   }
121   Json::FastWriter writer;
122   std::string json = writer.write(array);
123   // Send HTTP reply to the client
124   mg_printf(conn,
125         "HTTP/1.1 200 OK\r\n"
126         "Content-Type: application/json\r\n"
127         "Content-Length: %d\r\n"        // Always set Content-Length
128         "\r\n"
129         "%s",
130         (int)json.length(), json.c_str());
131
132   return MG_TRUE;
133}
134
135void reg_string(struct lua_State *L, const char *name, const char *val) {
136   lua_pushstring(L, name);
137   lua_pushstring(L, val);
138   lua_rawset(L, -3);
139}
140
141void reg_int(struct lua_State *L, const char *name, int val) {
142   lua_pushstring(L, name);
143   lua_pushinteger(L, val);
144   lua_rawset(L, -3);
145}
146
147void reg_function(struct lua_State *L, const char *name,
148                     lua_CFunction func, struct mg_connection *conn) {
149   lua_pushstring(L, name);
150   lua_pushlightuserdata(L, conn);
151   lua_pushcclosure(L, func, 1);
152   lua_rawset(L, -3);
153}
154
155static int lua_write(lua_State *L) {
156   int i, num_args;
157   const char *str;
158   size_t size;
159   struct mg_connection *conn = (struct mg_connection *)
160   lua_touserdata(L, lua_upvalueindex(1));
161
162   num_args = lua_gettop(L);
163   for (i = 1; i <= num_args; i++) {
164   if (lua_isstring(L, i)) {
165      str = lua_tolstring(L, i, &size);
166      mg_send_data(conn, str, size);
167   }
168   }
169
170   return 0;
171}
172
173static int lua_header(lua_State *L) {
174   struct mg_connection *conn = (struct mg_connection *)
175   lua_touserdata(L, lua_upvalueindex(1));
176
177   const char *header = luaL_checkstring(L,1);
178   const char *value  = luaL_checkstring(L,2);
179
180   mg_send_header(conn, header, value);
181
182   return 0;
183}
184
185
186static void prepare_lua_environment(struct mg_connection *ri, lua_State *L) {
187   extern void luaL_openlibs(lua_State *);
188   int i;
189
190   luaL_openlibs(L);
191
192   if (ri == NULL) return;
193
194   // Register mg module
195   lua_newtable(L);
196   reg_function(L, "write", lua_write, ri);
197   reg_function(L, "header", lua_header, ri);
198
199   // Export request_info
200   lua_pushstring(L, "request_info");
201   lua_newtable(L);
202   reg_string(L, "request_method", ri->request_method);
203   reg_string(L, "uri", ri->uri);
204   reg_string(L, "http_version", ri->http_version);
205   reg_string(L, "query_string", ri->query_string);
206   reg_string(L, "remote_ip", ri->remote_ip);
207   reg_int(L, "remote_port", ri->remote_port);
208   reg_string(L, "local_ip", ri->local_ip);
209   reg_int(L, "local_port", ri->local_port);
210   lua_pushstring(L, "content");
211   lua_pushlstring(L, ri->content == NULL ? "" : ri->content, ri->content_len);
212   lua_rawset(L, -3);
213   reg_int(L, "num_headers", ri->num_headers);
214   lua_pushstring(L, "http_headers");
215   lua_newtable(L);
216   for (i = 0; i < ri->num_headers; i++) {
217   reg_string(L, ri->http_headers[i].name, ri->http_headers[i].value);
218   }
219   lua_rawset(L, -3);
220   lua_rawset(L, -3);
221
222   lua_setglobal(L, "mg");
223
224}
225
226
227static void lsp(struct mg_connection *conn, const char *p, int len, lua_State *L) {
228   int i, j, pos = 0;
229   for (i = 0; i < len; i++) {
230   if (p[i] == '<' && p[i + 1] == '?') {
231      for (j = i + 1; j < len ; j++) {
232      if (p[j] == '?' && p[j + 1] == '>') {
233         if (i-pos!=0) mg_send_data(conn, p + pos, i - pos);
234         if (luaL_loadbuffer(L, p + (i + 2), j - (i + 2), "") == 0) {
235         lua_pcall(L, 0, LUA_MULTRET, 0);
236         }
237         pos = j + 2;
238         i = pos - 1;
239         break;
240      }
241      }
242   }
243   }
244   if (i > pos) {
245   mg_send_data(conn, p + pos, i - pos);
246   }
247}
248
249static int filename_endswith(const char *str, const char *suffix)
250{
251   if (!str || !suffix)
252      return 0;
253   size_t lenstr = strlen(str);
254   size_t lensuffix = strlen(suffix);
255   if (lensuffix >  lenstr)
256      return 0;
257   return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
258}
259
260// This function will be called by mongoose on every new request.
261int web_engine::begin_request_handler(struct mg_connection *conn)
262{
263   std::string file_path = std::string(mg_get_option(m_server, "document_root")).append(PATH_SEPARATOR).append(conn->uri);
264   if (filename_endswith(file_path.c_str(), ".lp"))
265   {
266      FILE *fp = NULL;
267      if ((fp = fopen(file_path.c_str(), "rb")) != NULL) {
268      fseek (fp, 0, SEEK_END);
269      size_t size = ftell(fp);
270      fseek (fp, 0, SEEK_SET);
271      char *data = (char*)mg_mmap(fp,size);
272
273      lua_State *L = luaL_newstate();
274      prepare_lua_environment(conn, L);
275      lsp(conn, data, (int) size, L);
276      if (L != NULL) lua_close(L);
277      mg_munmap(data,size);
278      fclose(fp);
279      return MG_TRUE;
280      } else {
281      return MG_FALSE;
282      }
283   }
284   else if (!strncmp(conn->uri, "/json/",6))
285   {
286      if (!strcmp(conn->uri, "/json/game"))
287      {
288         return json_game_handler(conn);
289      }
290      if (!strcmp(conn->uri, "/json/slider"))
291      {
292         return json_slider_handler(conn);
293      }
294   }
295   else if (!strncmp(conn->uri, "/keypost",8))
296   {
297      // Is there any sane way to determine the length of the buffer before getting it?
298      // A request for a way was previously filed with the mongoose devs,
299      // but it looks like it was never implemented.
300
301      // For now, we'll allow a paste buffer of 32k.
302      // To-do: Send an error if the paste is too big?
303      char cmd_val[32768];
304
305      int pastelength = mg_get_var(conn, "val", cmd_val, sizeof(cmd_val));
306      if (pastelength > 0) {
307         machine().ioport().natkeyboard().post_utf8(cmd_val);
308      }
309      // Send HTTP reply to the client
310      mg_printf(conn,
311         "HTTP/1.1 200 OK\r\n"
312         "Content-Type: text/plain\r\n"
313         "Content-Length: 2\r\n"        // Always set Content-Length
314         "\r\n"
315         "OK");
316
317      // Returning non-zero tells mongoose that our function has replied to
318      // the client, and mongoose should not send client any more data.
319      return MG_TRUE;
320   }
321   else if (!strncmp(conn->uri, "/keyupload",8))
322   {
323      char *upload_data;
324      int data_length, ofs = 0;
325      char var_name[100], file_name[255];
326      while ((ofs = mg_parse_multipart(conn->content + ofs, conn->content_len - ofs, var_name, sizeof(var_name), file_name, sizeof(file_name), (const char **)&upload_data, &data_length)) > 0) {
327            mg_printf_data(conn, "File: %s, size: %d bytes", file_name, data_length);
328      }
329
330      // That upload_data contains more than we need. It also has the headers.
331      // We'll need to strip it down to just what we want.
332
333      if ((&data_length > 0) && (sizeof(file_name) > 0))
334      {
335         // MSVC doesn't yet support variable-length arrays, so chop the string the old-fashioned way
336         upload_data[data_length] = '\0';
337
338         // Now paste the stripped down paste_data..
339         machine().ioport().natkeyboard().post_utf8(upload_data);
340      }
341      return MG_TRUE;
342   }
343   else if (!strncmp(conn->uri, "/cmd",4))
344   {
345      char cmd_name[64];
346      mg_get_var(conn, "name", cmd_name, sizeof(cmd_name));
347
348      if(!strcmp(cmd_name,"softreset"))
349      {
350         m_machine->schedule_soft_reset();
351      }
352      else if(!strcmp(cmd_name,"hardreset"))
353      {
354         m_machine->schedule_hard_reset();
355      }
356      else if(!strcmp(cmd_name,"exit"))
357      {
358         m_machine->schedule_exit();
359      }
360      else if(!strcmp(cmd_name,"togglepause"))
361      {
362         if (m_machine->paused())
363            m_machine->resume();
364      else
365            m_machine->pause();
366      }
367      else if(!strcmp(cmd_name,"savestate"))
368      {
369         char cmd_val[64];
370         mg_get_var(conn, "val", cmd_val, sizeof(cmd_val));
371         char *filename = websanitize_statefilename(cmd_val);
372         m_machine->schedule_save(filename);
373      }
374      else if(!strcmp(cmd_name,"loadstate"))
375      {
376         char cmd_val[64];
377         mg_get_var(conn, "val", cmd_val, sizeof(cmd_val));
378         char *filename = cmd_val;
379         m_machine->schedule_load(filename);
380      }
381      else if(!strcmp(cmd_name,"loadauto"))
382      {
383         // This is here to just load the autosave and only the autosave.
384         m_machine->schedule_load("auto");
385      }
386
387      // Send HTTP reply to the client
388      mg_printf(conn,
389            "HTTP/1.1 200 OK\r\n"
390            "Content-Type: text/plain\r\n"
391            "Content-Length: 2\r\n"        // Always set Content-Length
392            "\r\n"
393            "OK");
394
395      // Returning non-zero tells mongoose that our function has replied to
396      // the client, and mongoose should not send client any more data.
397      return MG_TRUE;
398   }
399   else if (!strncmp(conn->uri, "/slider",7))
400   {
401      char cmd_id[64];
402      char cmd_val[64];
403      mg_get_var(conn, "id", cmd_id, sizeof(cmd_id));
404      mg_get_var(conn, "val", cmd_val, sizeof(cmd_val));
405      int cnt = 0;
406      int id = atoi(cmd_id);
407      const slider_state *curslider;
408      for (curslider = machine().ui().get_slider_list(); curslider != NULL; curslider = curslider->next)
409      {
410         if (cnt==id)
411            (*curslider->update)(machine(), curslider->arg, NULL, atoi(cmd_val));
412         cnt++;
413      }
414      for (curslider = (slider_state*)machine().osd().get_slider_list(); curslider != NULL; curslider = curslider->next)
415      {
416         if (cnt==id)
417            (*curslider->update)(machine(), curslider->arg, NULL, atoi(cmd_val));
418         cnt++;
419      }
420
421      // Send HTTP reply to the client
422      mg_printf(conn,
423            "HTTP/1.1 200 OK\r\n"
424            "Content-Type: text/plain\r\n"
425            "Content-Length: 2\r\n"        // Always set Content-Length
426            "\r\n"
427            "OK");
428
429      // Returning non-zero tells mongoose that our function has replied to
430      // the client, and mongoose should not send client any more data.
431      return MG_TRUE;
432   }
433   else if (!strncmp(conn->uri, "/screenshot.png",15))
434   {
435      screen_device_iterator iter(m_machine->root_device());
436      screen_device *screen = iter.first();
437
438      if (screen == NULL)
439      {
440         return 0;
441      }
442
443      std::string fname("screenshot.png");
444      emu_file file(m_machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
445      file_error filerr = file.open(fname.c_str());
446
447      if (filerr != FILERR_NONE)
448      {
449         return 0;
450      }
451
452      m_machine->video().save_snapshot(screen, file);
453      std::string fullpath(file.fullpath());
454      file.close();
455      mg_send_header(conn, "Cache-Control", "no-cache, no-store, must-revalidate");
456      mg_send_header(conn, "Pragma", "no-cache");
457      mg_send_header(conn, "Expires", "0");
458      mg_send_file(conn, fullpath.c_str(), NULL);
459      return MG_MORE; // It is important to return MG_MORE after mg_send_file!
460   }
461   return 0;
462}
463
464static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
465   if (ev == MG_REQUEST) {
466   if (conn->is_websocket) {
467      // This handler is called for each incoming websocket frame, one or more
468      // times for connection lifetime.
469      // Echo websocket data back to the client.
470      return conn->content_len == 4 && !memcmp(conn->content, "exit", 4) ? MG_FALSE : MG_TRUE;
471   } else {
472      web_engine *engine = static_cast<web_engine *>(conn->server_param);
473      return engine->begin_request_handler(conn);
474   }
475   } else if (ev== MG_WS_CONNECT) {
476   // New websocket connection. Send connection ID back to the client.
477   mg_websocket_printf(conn, WEBSOCKET_OPCODE_TEXT, "update_machine");
478   return MG_FALSE;
479   } else if (ev == MG_AUTH) {
480   return MG_TRUE;
481   } else {
482   return MG_FALSE;
483   }
484}
485
486//-------------------------------------------------
487//  web_engine - constructor
488//-------------------------------------------------
489
490web_engine::web_engine(emu_options &options)
491   : m_options(options),
492      m_machine(NULL),
493      m_server(NULL),
494      //m_lastupdatetime(0),
495      m_exiting_core(false),
496      m_http(m_options.http())
497
498{
499   if (m_http) {
500      m_server = mg_create_server(this, ev_handler);
501
502      mg_set_option(m_server, "listening_port", options.http_port());
503      mg_set_option(m_server, "document_root",  options.http_path());
504   }
505
506}
507
508//-------------------------------------------------
509//  ~web_engine - destructor
510//-------------------------------------------------
511
512web_engine::~web_engine()
513{
514   if (m_http)
515      close();
516}
517
518//-------------------------------------------------
519//  close - close and cleanup of lua engine
520//-------------------------------------------------
521
522void web_engine::close()
523{
524   m_exiting_core = 1;
525   // Cleanup, and free server instance
526   mg_destroy_server(&m_server);
527}
528
529void web_engine::serve()
530{
531   if (m_http) mg_poll_server(m_server, 0);
532}
533
534void web_engine::push_message(const char *message)
535{
536   struct mg_connection *c;
537   if (m_server!=NULL) {
538      // Iterate over all connections, and push current time message to websocket ones.
539      for (c = mg_next(m_server, NULL); c != NULL; c = mg_next(m_server, c)) {
540         if (c->is_websocket) {
541            mg_websocket_write(c, 1, message, strlen(message));
542         }
543      }
544   }
545}
trunk/src/emu/webengine.h
r250088r250089
1// license:BSD-3-Clause
2// copyright-holders:Miodrag Milanovic
3/***************************************************************************
4
5    webengine.h
6
7    Handle MAME internal web server.
8
9***************************************************************************/
10
11#pragma once
12
13#ifndef __WEB_ENGINE_H__
14#define __WEB_ENGINE_H__
15
16struct mg_server;      // Handle for the HTTP server itself
17struct mg_connection;  // Handle for the individual connection
18
19class web_engine
20{
21public:
22   // construction/destruction
23   web_engine(emu_options &options);
24   ~web_engine();
25
26   void serve();
27   void push_message(const char *message);
28   void close();
29
30   void set_machine(running_machine *machine) { m_machine = machine; }
31   int begin_request_handler(struct mg_connection *conn);
32protected:
33   // getters
34   running_machine &machine() const { return *m_machine; }
35
36   int json_game_handler(struct mg_connection *conn);
37   int json_slider_handler(struct mg_connection *conn);
38private:
39   // internal state
40   emu_options &       m_options;
41   running_machine *   m_machine;
42   struct mg_server *  m_server;
43   //osd_ticks_t         m_lastupdatetime;
44   bool                m_exiting_core;
45   bool                m_http;
46};
47
48#endif  /* __web_engine_H__ */


Previous 199869 Revisions Next


© 1997-2024 The MAME Team