Previous 199869 Revisions Next

r41598 Wednesday 4th November, 2015 at 16:18:52 UTC by Shideravan
It's better to snes to use IPT_START...

...Rather IPT_START1, for start button.
[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/devices/bus/snes_ctrl]joypad.c
[src/devices/cpu/am29000]am29ops.h
[src/devices/cpu/avr8]avr8dasm.c
[src/devices/cpu/e132xs]e132xs.c
[src/devices/cpu/hd61700]hd61700.c
[src/devices/cpu/score]scoredsm.c
[src/devices/cpu/tms7000]tms70op.inc
[src/devices/machine]mos6530n.c
[src/devices/video]315_5313.c mc6845.c
[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
[src/mame]arcade.lst
[src/mame/drivers]a2600.c aristmk5.c atarittl.c champbas.c dorachan.c equites.c goldnpkr.c mz700.c pacman.c polyplay.c pong.c
[src/mame/includes]mz700.h
[src/mame/machine]alpha8201.c megadriv.c mz700.c namcoio.c
[src/mame/video]fuukifg3.c mcr.c mcr3.c mcr68.c mz700.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/3rdparty/mongoose/LICENSE
r0r250110
1Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
2Copyright (c) 2013-2015 Cesanta Software Limited
3All rights reserved
4
5This code is dual-licensed: you can redistribute it and/or modify
6it under the terms of the GNU General Public License version 2 as
7published by the Free Software Foundation. For the terms of this
8license, see <http://www.gnu.org/licenses>.
9
10You are free to use this code under the terms of the GNU General
11Public License, but WITHOUT ANY WARRANTY; without even the implied
12warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13See the GNU General Public License for more details.
14
15Alternatively, you can license this code under a commercial
16license, as set out in <http://cesanta.com/>.
trunk/3rdparty/mongoose/README.md
r0r250110
1# <img src="http://cesanta.com/images/mongoose_logo.png" width="64" height="64"> Mongoose Web Server
2
3[![Join the chat at https://gitter.im/cesanta/mongoose](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cesanta/mongoose?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4
5Mongoose is the most easy to use web server on the planet. A web server of choice for Web developers (PHP, Ruby, Python, etc) and Web designers.
6
7Mongoose is built on top of Libmongoose embedded library, which can turn
8anything into a web server in 5 minutes worth of effort and few lines of code.
9Libmongoose is used to serve Web GUI on embedded devices, implement RESTful
10services, RPC frameworks (e.g. JSON-RPC), handle telemetry data exchange, and
11perform many other tasks in various different industries including aerospace,
12manufacturing, finance, research, automotive, gaming, IT.
13
14
15   * [Mailing list](http://groups.google.com/group/mongoose-users)
16   * [Downloads](http://cesanta.com/products.shtml)
17   * [Documentation](http://cesanta.com/docs.shtml)
18
19Check out Fossa - our [embedded multi-protocol library](https://github.com/cesanta/fossa) with TCP,UDP,HTTP,Websocket,MQTT,DNS support, designed for Internet Of Things!
20
21# Features
22
23- Works on Windows, Mac, UNIX/Linux, iPhone, Android eCos, QNX
24and many other platforms
25- CGI, SSI, SSL, Digest auth, Websocket, WEbDAV, Resumed download,
26  URL rewrite, file blacklist
27- Custom error pages, Virtual hosts, IP-based ACL, Windows service,
28  HTTP/HTTPS client
29- Simple and clean
30  [embedding API](https://github.com/cesanta/mongoose/blob/master/mongoose.h).
31  The source is in single
32  [mongoose.c](https://github.com/cesanta/mongoose/blob/master/mongoose.c) file
33  to make embedding easy
34- Extremely lightweight, has a core of under 40kB and tiny runtime footprint
35- Asynchronous, non-blocking core supporting single- or multi-threaded usage
36- On the market since 2004 with over 1 million cumulative downloads
37- Stable, mature and tested, has several man-years invested
38  in continuous improvement and refinement
39
40# Screenshots
41
42Download, double-click to start, run browser -- that's all!
43
44![shot1](http://cesanta.com/images/tut_sharing/tut1.png)
45![shot2](http://cesanta.com/images/tut_sharing/tut2.png)
46
47![shot3](http://cesanta.com/images/tut_sharing/tut3.png)
48![shot4](http://cesanta.com/images/tut_sharing/tut4.png)
49
50# Contributions
51
52People who have agreed to the
53[Cesanta CLA](http://cesanta.com/contributors_la.html)
54can make contributions. Note that the CLA isn't a copyright
55_assigment_ but rather a copyright _license_.
56You retain the copyright on your contributions.
57
58# Licensing
59
60Mongoose is released under commercial and
61[GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) open
62source licenses. The GPLv2 open source License does not generally permit
63incorporating this software into non-open source programs.
64For those customers who do not wish to comply with the GPLv2 open
65source license requirements,
66[Cesanta](http://cesanta.com) offers a full,
67royalty-free commercial license and professional support
68without any of the GPL restrictions.
69
70# Other products by Cesanta
71
72- [Fossa](http://github.com/cesanta/fossa) - Multi-protocol networking library
73- [SSL Wrapper](https://github.com/cesanta/ssl_wrapper) - application to
74  secure network communications
75- [Frozen](https://github.com/cesanta/frozen) - JSON parser and generator
76- [SLRE](https://github.com/cesanta/slre) - Super Light Regular Expression
77  library
78- [V7](https://github.com/cesanta/v7) - Embedded JavaScript engine
trunk/3rdparty/mongoose/docs/API.md
r0r250110
1# Mongoose API Reference
2
3    struct mg_server *mg_create_server(void *server_param, mg_handler_t handler);
4
5Creates web server instance. Returns opaque instance pointer, or NULL if
6there is not enough memory. `server_param`: Could be any pointer, or NULL.
7This pointer will be passed
8to the callback functions as `struct mg_connection::server_param` field.
9A common use case is to pass `this` pointer of the C++ wrapper class
10as `user_param`, to let the callback get the pointer to the C++ object.
11
12Note that this function doesn't make the
13server instance to serve. Serving is done by `mg_poll_server()` function.
14Mongoose has single-threaded, event-driven, asynchronous, non-blocking core.
15When server instance is created, it contains an information about
16the configuration and the state of each connection.
17Server instance is capable on listening on only one port. After creation,
18`struct mg_server` has a list
19of active connections and configuration parameters.
20
21Side-effect: on UNIX, `mg_create_server()` ignores SIGPIPE signals. If custom
22processing is required SIGPIPE, signal handler must be set up after
23calling `mg_create_server()`.
24
25Important: Mongoose does not install `SIGCHLD` handler. If CGI is used,
26`SIGCHLD` handler must be set up to reap CGI zombie processes.
27
28
29    void mg_destroy_server(struct mg_server **server);
30
31Deallocates web server instance, closes all pending connections, and makes
32server pointer a NULL pointer.
33
34    const char mg_set_option(struct mg_server *server, const char *name,
35                             const char *value);
36
37Sets a particular server option. Note that at least one option,
38`listening_port`, must be specified. To serve static files, `document_root`
39must be specified too. If `document_root` option is left unset, Mongoose
40will not access filesystem at all. `mg_set_option()` returns NULL if option was
41set successfully, otherwise it returns human-readable error string. It is
42allowed to call `mg_set_option()` by the same thread that does
43`mg_poll_server()` (Mongoose thread) and change server configuration while it
44is serving, in between `mg_poll_server()` calls.
45
46    int mg_poll_server(struct mg_server *server, int milliseconds);
47
48Performs one iteration of IO loop by iterating over all
49active connections, performing `select()` syscall on all sockets with a timeout
50of `milliseconds`. When `select()` returns, Mongoose
51does an IO for each socket that has data to be sent or received. Application
52code must call `mg_poll_server()` in a loop. It is an error to have more then
53one thread calling `mg_poll_server()`, `mg_set_option()` or any other function
54that take `struct mg_server *` parameter. Mongoose does not
55mutex-protect `struct mg_server *`, therefore only single thread
56(Mongoose thread) should make Mongoose calls.
57
58`mg_poll_server()` calls user-specified event handler when certain events
59occur. Sequence of events for the accepted connection is this:
60
61   * `MG_AUTH` - Mongoose asks whether this connection is authorized. If event
62      handler returns `MG_FALSE`, then Mongoose does not serve the request but
63      sends authorization request to the client. If `MG_TRUE` is returned,
64      then Mongoose continues on with the request.
65   * `MG_REQUEST` - Mongoose asks event handler to serve the request. If
66      event handler serves the request by sending a reply,
67      it should return `MG_TRUE`. Otherwise,
68      it should return `MG_FALSE` which tells Mongoose that request is not
69      served and Mongoose should serve it. For example, event handler might
70      choose to serve only RESTful API requests with URIs that start with
71      certain prefix, and let Mongoose serve all static files.
72      If event handler decides to serve the request, but doesn't have
73      all the data at the moment, it should return `MG_MORE`. That tells
74      Mongoose to keep the connection open after callback returns.
75
76      `mg_connection::connection_param` pointer is a placeholder to keep
77      user-specific data. For example, handler could decide to open a DB
78      connection and store DB connection handle in `connection_param`.
79   * `MG_POLL` is sent to every connection on every iteration of
80      `mg_poll_server()`. Event handler should return `MG_FALSE` to ignore
81      this event. If event handler returns `MG_TRUE`, then Mongoose assumes
82      that event handler has finished sending data, and Mongoose will
83      close the connection.
84   * `MG_HTTP_ERROR` sent when Mongoose is about to send HTTP error back
85      to the client. Event handler can choose to send a reply itself, in which
86      case event handler must return `MG_TRUE`. Otherwise, event handler must
87      return `MG_FALSE`.
88   * `MG_CLOSE` is sent when the connection is closed. This event is used
89      to cleanup per-connection state stored in `connection_param`
90      if it was allocated. Event handler return value is ignored.
91
92Sequence of events for the client connection is this:
93
94   * `MG_CONNECT` sent when Mongoose has connected to the remote host.
95   This event is sent to the connection initiated by `mg_connect()` call.
96   Connection status is held in `mg_connection::status_code`: if zero,
97   then connection was successful, otherwise connection was not established.
98   User should send a request upon successful connection.
99   Event handler should return `MG_TRUE` if connection was successful and
100   HTTP request has been sent. Otherwise, it should send `MG_FALSE`.
101   * `MG_REPLY` is sent when response has been received from the remote host.
102   If event handler sends another request, then it should return `MG_TRUE`.
103   Otherwise it should return `MG_FALSE` and Mongoose will close the connection.
104   * `MG_CLOSE` same as for the accepted connection.
105
106
107When mongoose buffers in HTTP request and successfully parses it, it sends
108`MG_REQUEST` event for GET requests immediately. For POST requests,
109Mongoose delays the call until the whole POST request is buffered in memory.
110POST data is available to the callback as `struct mg_connection::content`,
111and POST data length is in `struct mg_connection::content_len`.
112
113Note that websocket connections are treated the same way. Mongoose buffers
114websocket frame in memory, and calls event handler when frame is fully
115buffered. Frame data is available `struct mg_connection::content`, and
116data length is in `struct mg_connection::content_len`, i.e. very similar to
117the POST request. `struct mg_connection::is_websocket` flag indicates
118whether the request is websocket or not. Also, for websocket requests,
119there is `struct mg_connection::wsbits` field which contains first byte
120of the websocket frame which URI handler can examine. Note that to
121reply to the websocket client, `mg_websocket_write()` should be used.
122To reply to the plain HTTP client, `mg_write_data()` should be used.
123
124Return value: number of active connections.
125
126
127    const char **mg_get_valid_option_names(void);
128
129Returns a NULL-terminated array of option names and their default values.
130There are two entries per option in an array: an option name followed by a
131default value. A default value could be NULL. A NULL name indicates an end
132of the array.
133
134    const char *mg_get_option(const struct mg_server *server, const char *name);
135
136Returns the value of particular configuration parameter. If
137given parameter name is not valid, NULL is returned. For valid names, return
138value is guaranteed to be non-NULL. If parameter is not set, zero-length string
139is returned.
140
141    void mg_wakeup_server_ex(struct mg_server *, mg_handler_t func,
142                             const char *fmt, ...);
143
144Sends string message to a server. Function `func` is called for every active
145connection. String message is passed in `struct mg_connection::callback_param`.
146This function is designed to push data to the connected clients, and
147can be called from any thread. There is a limitation on the length of
148the message, currently at 8 kilobytes.
149
150    void mg_send_status(struct mg_connection *, int status_code);
151    void mg_send_header(struct mg_connection *, const char *name,
152                        const char *value);
153    void mg_send_data(struct mg_connection *, const void *data, int data_len);
154    void mg_printf_data(struct mg_connection *, const char *format, ...);
155
156These functions are used to construct a response to the client. HTTP response
157consists of three parts: a status line, zero or more HTTP headers,
158a response body.  Mongoose provides functions for all three parts:
159   * `mg_send_status()` is used to create status line. This function can be
160      called zero or once. If `mg_send_status()` is not called, then Mongoose
161      will send status 200 (success) implicitly.
162   * `mg_send_header()` adds HTTP header to the response. This function could
163      be called zero or more times.
164   * `mg_send_data()` and `mg_printf_data()` are used to send data to the
165     client. Note that Mongoose adds `Transfer-Encoding: chunked` header
166     implicitly, and sends data in chunks. Therefore, it is not necessary to
167     set `Content-Length` header. Note that `mg_send_data()` and
168     `mg_printf_data()` do not send data immediately. Instead, they spool
169     data in memory, and Mongoose sends that data later after URI handler
170     returns. If data to be sent is huge, an URI handler might
171     send data in pieces by saving state in
172     `struct mg_connection::connection_param` variable and returning `0`. Then
173     Mongoose will call a handler repeatedly after each socket write.
174
175<!-- -->
176
177     void mg_send_file(struct mg_connection *, const char *path);
178
179Tells Mongoose to serve given file. Mongoose handles file according to
180it's extensions, i.e. Mongoose will invoke CGI script if `path` has CGI
181extension, it'll render SSI file if `path` has SSI extension, etc. If `path`
182points to a directory, Mongoose will show directory listing. If this function
183is used, no calls to `mg_send*` or `mg_printf*` functions must be made, and
184event handler must return `MG_MORE`.
185
186    size_t mg_websocket_write(struct mg_connection* conn, int opcode,
187                              const char *data, size_t data_len);
188    size_t mg_websocket_printf(struct mg_connection* conn, int opcode,
189                               const char *fmt, ...);
190
191
192Similar to `mg_write()` and `mg_printf()`, but wraps the data into a
193websocket frame with a given websocket `opcode`.
194
195    const char *mg_get_header(const struct mg_connection *, const char *name);
196
197Get the value of particular HTTP header. This is a helper function.
198It traverses http_headers array, and if the header is present in the array,
199returns its value. If it is not present, NULL is returned.
200
201
202    int mg_get_var(const struct mg_connection *conn, const char *var_name,
203                   char *buf, size_t buf_len);
204
205Gets HTTP form variable. Both POST buffer and query string are inspected.
206Form variable is url-decoded and written to the buffer. On success, this
207function returns the length of decoded variable. On error, -1 is returned if
208variable not found, and -2 is returned if destination buffer is too small
209to hold the variable. Destination buffer is guaranteed to be
210'\0' - terminated if it is not NULL or zero length.
211
212    int mg_parse_header(const char *hdr, const char *var_name, char *buf,
213                        size_t buf_size);
214
215This function parses HTTP header and fetches given variable's value in a buffer.
216A header should be like `x=123, y=345, z="other value"`. This function is
217designed to parse Cookie headers, Authorization headers, and similar. Returns
218the length of the fetched value, or 0 if variable not found.
219
220    int mg_modify_passwords_file(const char *passwords_file_name,
221                                 const char *domain,
222                                 const char *user,
223                                 const char *password);
224
225Add, edit or delete the entry in the passwords file.
226This function allows an application to manipulate .htpasswd files on the
227fly by adding, deleting and changing user records. This is one of the
228several ways of implementing authentication on the server side.
229If password is not NULL, entry is added (or modified if already exists).
230If password is NULL, entry is deleted.
231Return: 1 on success, 0 on error.
232
233
234    int mg_parse_multipart(const char *buf, int buf_len,
235                           char *var_name, int var_name_len,
236                           char *file_name, int file_name_len,
237                           const char **data, int *data_len);
238
239Parses a buffer that contains multipart form data. Stores chunk name
240in a `var_name` buffer. If chunk is an uploaded file, then `file_name`
241will have a file name. `data` and `data_len` will point to the chunk data.
242Returns number of bytes to skip to the next chunk.
243
244     struct mg_connection *mg_connect(struct mg_server *server,
245                                      const char *host, int port, int use_ssl);
246
247Create connection to the remote host. Returns `NULL` on error, non-null
248if the connection has been scheduled for connection. Upon a connection,
249Mongoose will send `MG_CONNECT` event to the event handler.
trunk/3rdparty/mongoose/docs/AndroidBuild.md
r0r250110
1# Mongoose Build on Android
2
3This is a small guide to help you run mongoose on Android. Currently it is
4tested on the HTC Wildfire. If you have managed to run it on other devices
5as well, please comment or drop an email in the mailing list.
6Note : You dont need root access to run mongoose on Android.
7
8- Clone Mongoose Git repo
9- Download the Android NDK from [http://developer.android.com/tools/sdk/ndk/index.html](http://developer.android.com/tools/sdk/ndk/index.html)
10- Run `/path-to-ndk/ndk-build -C /path/to/mongoose`
11  That should generate mongoose/lib/armeabi/mongoose
12- Using the adb tool (you need to have Android SDK installed for that),
13  push the generated mongoose binary to `/data/local` folder on device.
14- From adb shell, navigate to `/data/local` and execute `./mongoose`.
15- To test if the server is running fine, visit your web-browser and
16  navigate to `http://127.0.0.1:8080` You should see the `Index of /` page.
17
18![screenshot](http://cesanta.com/images/android_build.png)
19
20
21Notes:
22
23- `jni` stands for Java Native Interface. Read up on Android NDK if you want
24  to know how to interact with the native C functions of mongoose in Android
25  Java applications.
26- TODO: A Java application that interacts with the native binary or a
27  shared library.
trunk/3rdparty/mongoose/docs/BasicWebsite.md
r0r250110
1How To Create Basic Website With Mongoose
2===========================================
3
4## 1. Create a directory which will contain your website files. For example, on drive `C:\`, create a directory called `my_website`:
5
6![screenshot](http://cesanta.com/images/tut_basic/tut1.png)
7
8## 2. Inside `my_website` directory, create a new file called "index". This will be the default web page shown when the website is visited.
9
10![screenshot](http://cesanta.com/images/tut_basic/tut2.png)
11
12## 3. Open index file with your favorite editor (for example, Notepad) and enter some HTML code:
13
14![screenshot](http://cesanta.com/images/tut_basic/tut3.png)
15
16## 4. Save this file as `index.html`:
17
18![screenshot](http://cesanta.com/images/tut_basic/tut4.png)
19
20
21## 5. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside `my_website` directory:
22
23![screenshot](http://cesanta.com/images/tut_basic/tut5.png)
24
25## 6. Double-click mongoose executable. An icon will appear on a system tray in the bottom right corner of the desktop:
26
27![screenshot](http://cesanta.com/images/tut_basic/tut6.png)
28
29## 7. Click on the mongoose icon and choose "Go to my address" menu:
30![screenshot](http://cesanta.com/images/tut_basic/tut7.png)
31
32## 8. A browser will popup displaying `index.html` file. Now, you can expand your website by adding more content.
33
34![screenshot](http://cesanta.com/images/tut_basic/tut8.png)
trunk/3rdparty/mongoose/docs/Embed.md
r0r250110
1# Mongoose Embedding Guide
2
3Embedding Mongoose is done in two steps:
4
5   1. Copy
6    [mongoose.c](https://raw.github.com/cesanta/mongoose/master/mongoose.c) and
7    [mongoose.h](https://raw.github.com/cesanta/mongoose/master/mongoose.h)
8    to your application's source tree and include them in the build.
9   2. Somewhere in the application code, call `mg_create_server()` to create
10    a server, configure it with `mg_set_option()` and loop with
11    `mg_poll_server()` until done. Call `mg_destroy_server()` to cleanup.
12
13Here's a minimal application `app.c` that embeds mongoose:
14
15    #include "mongoose.h"
16
17    int main(void) {
18      struct mg_server *server = mg_create_server(NULL, NULL);
19      mg_set_option(server, "document_root", ".");      // Serve current directory
20      mg_set_option(server, "listening_port", "8080");  // Open port 8080
21
22      for (;;) {
23        mg_poll_server(server, 1000);   // Infinite loop, Ctrl-C to stop
24      }
25      mg_destroy_server(&server);
26
27      return 0;
28    }
29
30To compile it, put `mongoose.c`, `mongoose.h` and `app.c` into one
31folder, start terminal on UNIX or Visual Studio command line prompt on Windows,
32and run the following command:
33
34    cc app.c mongoose.c -pthread -o app     # on Unix
35    cl.exe app.c mongoose.c /TC /MD         # on Windows
36
37When run, this simple application opens port 8080 and serves static files,
38CGI files and lists directory content in the current working directory.
39
40It is possible to generate HTML page content. Mongoose can call user-defined
41function when certain events occur.
42That function is called _an event handler_, and it is the second parameter
43to `mg_create_server()` function. Here is the example event handler function:
44
45    int event_handler(struct mg_connection *conn, enum mg_event ev) {
46      switch (ev) {
47        case MG_AUTH: return MG_TRUE;
48        default: return MG_FALSE;
49      }
50    }
51
52Event handler is called by Mongoose with `struct mg_connection *`
53pointer and an event number. `struct mg_connection *conn`
54has all information about the request: HTTP headers, POST or websocket
55data buffer, etcetera. `enum mg_event ev` tells which exactly event is sent.
56For each event, an event handler returns a value which tells Mongoose how
57to behave.
58
59The sequence of events for every connection is this:
60
61   * `MG_AUTH` - Mongoose asks whether this connection is authorized. If event
62      handler returns `MG_FALSE`, then Mongoose does not serve the request but
63      sends authorization request to the client. If `MG_TRUE` is returned,
64      then Mongoose continues on with the request.
65   * `MG_REQUEST` - Mongoose asks event handler to serve the request. If
66      event handler serves the request by sending a reply,
67      it should return `MG_TRUE`. Otherwise,
68      it should return `MG_FALSE` which tells Mongoose that request is not
69      served and Mongoose should serve it. For example, event handler might
70      choose to serve only RESTful API requests with URIs that start with
71      certain prefix, and let Mongoose serve all static files.
72      If event handler decides to serve the request, but doesn't have
73      all the data at the moment, it should return `MG_MORE`. That tells
74      Mongoose to keep the connection open after callback returns.
75
76      `mg_connection::connection_param` pointer is a placeholder to keep
77      user-specific data. For example, handler could decide to open a DB
78      connection and store DB connection handle in `connection_param`.
79   * `MG_POLL` is sent to every connection on every iteration of
80      `mg_poll_server()`. Event handler should return `MG_FALSE` to ignore
81      this event. If event handler returns `MG_TRUE`, then Mongoose assumes
82      that event handler has finished sending data, and Mongoose will
83      close the connection.
84   * `MG_HTTP_ERROR` sent when Mongoose is about to send HTTP error back
85      to the client. Event handler can choose to send a reply itself, in which
86      case event handler must return `MG_TRUE`. Otherwise, event handler must
87      return `MG_FALSE`
88   * `MG_CLOSE` is sent when the connection is closed. This event is used
89      to cleanup per-connection state stored in `connection_param`
90      if it was allocated.
91
92Let's extend our minimal application example and
93create an URI that will be served by user's C code. The app will handle
94`/hello` URI by showing a hello message. So, when app is run,
95http://127.0.0.1:8080/hello will say hello, and here's the code:
96
97    #include <string.h>
98    #include "mongoose.h"
99
100    static int event_handler(struct mg_connection *conn, enum mg_event ev) {
101      if (ev == MG_AUTH) {
102        return MG_TRUE;   // Authorize all requests
103      } else if (ev == MG_REQUEST && !strcmp(conn->uri, "/hello")) {
104        mg_printf_data(conn, "%s", "Hello world");
105        return MG_TRUE;   // Mark as processed
106      } else {
107        return MG_FALSE;  // Rest of the events are not processed
108      }
109    }
110
111    int main(void) {
112      struct mg_server *server = mg_create_server(NULL, event_handler);
113      mg_set_option(server, "document_root", ".");
114      mg_set_option(server, "listening_port", "8080");
115
116      for (;;) {
117        mg_poll_server(server, 1000);  // Infinite loop, Ctrl-C to stop
118      }
119      mg_destroy_server(&server);
120
121      return 0;
122    }
123
124## Example code
125
126Mongoose source code contains number of examples, located in the
127[examples](https://github.com/cesanta/mongoose/blob/master/examples/) directory.
128To build any example, go to the respective directory and run `make`.
129
130## Compilation flags
131
132Below is the list of compilation flags that enable or disable certain
133features. By default, some features are enabled, and could be disabled
134by setting appropriate `NO_*` flag. Features that are disabled by default
135could be enabled by setting appropriate `USE_*` flag. Bare bones Mongoose
136is quite small, about 30 kilobytes of compiled x86 code. Each feature adds
137a couple of kilobytes to the executable size, and also has some runtime penalty.
138
139Note that some flags start with `NS_` prefix. This is because Mongoose uses
140[Net Skeleton](http://github.com/cesanta/net_skeleton) as a low-level
141networking engine. If user code has `#include <net_skeleton.h>`, then
142all Net Skeleton functions will be available too.
143
144
145    -DMONGOOSE_NO_AUTH          Disable MD5 authorization support
146    -DMONGOOSE_NO_CGI           Disable CGI support
147    -DMONGOOSE_NO_DAV           Disable WebDAV support
148                                (PUT, DELETE, MKCOL, PROPFIND methods)
149    -DMONGOOSE_NO_DIRECTORY_LISTING  Disable directory listing
150    -DMONGOOSE_NO_FILESYSTEM    Disables all file IO, serving from memory only
151    -DMONGOOSE_NO_LOGGING       Disable access/error logging
152    -DMONGOOSE_ENABLE_THREADS   Enable mg_start_thread() function
153    -DMONGOOSE_NO_WEBSOCKET     Disable WebSocket support
154    -DMONGOOSE_NO_USER          No concept of a user on used platform.
155                                (Platform does not provide getpwnam, setgid or setuid)
156
157    -DMONGOOSE_USE_IDLE_TIMEOUT_SECONDS=X Idle connection timeout, default is 30
158    -DMONGOOSE_USE_LUA          Enable Lua scripting
159    -DMONGOOSE_USE_LUA_SQLITE3  Enable sqlite3 binding for Lua
160    -DMONGOOSE_USE_POST_SIZE_LIMIT=X      POST requests larger than X will be
161                                          rejected, not set by default
162    -DMONGOOSE_USE_EXTRA_HTTP_HEADERS=X   Append X to the HTTP headers
163                                          for static files, empty by default
164
165    -DNS_ENABLE_DEBUG         Enables debug messages on stdout, very noisy
166    -DNS_ENABLE_SSL           Enable SSL
167    -DNS_ENABLE_IPV6          Enable IPv6 support
168    -DNS_ENABLE_HEXDUMP       Enables hexdump of sent and received traffic
169    -DNS_STACK_SIZE=X         Sets stack size to X for  ns_start_thread()
170    -DNS_DISABLE_THREADS      Disable threads support
171    -DNS_DISABLE_SOCKETPAIR   For systems without loopback interface
172    -DMONGOOSE_SEND_NS_EVENTS Send Net Skeleton events to the event handler
173                              in addition to the Mongoose events
trunk/3rdparty/mongoose/docs/FAQ.md
r0r250110
1# Mongoose FAQ
2
3## My Antivirus Software reports Mongoose as a security threat
4
5Mongoose doesn't contain any malicious logic. Antivirus reports a
6[false positive](http://en.wikipedia.org/wiki/Type_I_and_type_II_errors#False_positive_error).
7This is when certain byte sequence in Mongoose accidentally matches
8virus signature in the Antivirus database.
9
10## Download page doesn't work
11
12Please make sure Javascript is enabled in your browser, and that the
13antivirus software is not blocking the download.
14
15
16## MacOS message: "Mongoose.app is damaged and can’t be opened. You should move it to the Trash"
17
18This happens on newer MacOS systems. The reason for the message
19is the fact Mongoose.app is not digitally signed.
20Mongoose download procedure changes the app on the fly by injecting
21user information in the binary, making any prior digital signature void.
22Open "System Preferences" -> "Security"  and set "Allow apps downloaded from"
23to "Anywhere".  Revert the settings once Mongoose is installed.
24
25## PHP doesn't work: getting empty page, or 'File not found' error
26
27The reason for that is wrong paths to the interpreter. Remember that with PHP,
28correct interpreter is `php-cgi.exe` (`php-cgi` on UNIX). Solution: specify
29full path to the PHP interpreter, e.g.:
30
31    mongoose -cgi_interpreter /full/path/to/php-cgi
32
33## Mongoose fails to start
34
35If Mongoose exits immediately when run, this
36usually indicates a syntax error in the configuration file
37(named `mongoose.conf` by default) or the command-line arguments.
38Syntax checking is omitted from Mongoose to keep its size low. However,
39the Manual should be of help. Note: the syntax changes from time to time,
40so updating the config file might be necessary after executable update.
41
42### Embedding with OpenSSL on Windows might fail because of calling convention
43
44To force Mongoose to use `__stdcall` convention, add `/Gz` compilation
45flag to the Visual Studio project settings.
trunk/3rdparty/mongoose/docs/FileSharing.md
r0r250110
1How To Share Files With Mongoose
2===========================================
3
4## 1. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside the directory you want to share:
5
6![screenshot](http://cesanta.com/images/tut_sharing/tut1.png)
7
8## 2. Double-click mongoose executable. A browser will start automatically, an icon will appear on a system tray in the bottom right corner of the desktop:
9
10![screenshot](http://cesanta.com/images/tut_sharing/tut2.png)
11
12## 3. Click on the mongoose icon
13![screenshot](http://cesanta.com/images/tut_sharing/tut3.png)
14
15
16## 4. Click on "Go to my address" to launch a browser locally. Or, to access a folder from another machine, launch a browser and type in the URL:
17
18![screenshot](http://cesanta.com/images/tut_sharing/tut4.png)
trunk/3rdparty/mongoose/docs/Internals.md
r0r250110
1# Mongoose Internals
2
3Mongoose has single-threaded, event-driven, asynchronous, non-blocking core.
4`mg_create_server()` creates a web server instance. An instance is a container
5for the config options and list of active connections. To do the actual
6serving, user must call `mg_poll_server()`, which iterates over all
7active connections, performing `select()` syscall on all sockets with a
8timeout of specified number of milliseconds. When `select()` returns, Mongoose
9does an IO for each socket that has data to be sent or received. Application
10code must call `mg_poll_server()` in a loop.
11
12Mongoose server instance is designed to be used by a single thread.
13It is an error to have more then
14one thread calling `mg_poll_server()`, `mg_set_option()` or any other function
15that take `struct mg_server *` parameter. Mongoose does not
16mutex-protect `struct mg_server *`, therefore the best practice is
17to call server management functions from the same thread (an IO thread).
18On a multi-core systems, many server instances can be created, sharing the
19same listening socket and managed by separate threads (see [multi_threaded.c](https://github.com/cesanta/mongoose/blob/master/examples/multi_threaded.c))
20example.
21
22It is an error to pass and store `struct mg_connection *` pointers for
23later use to send data. The reason is that they can be invalidated by the
24next `mg_poll_server()` call. For such a task,
25there is `mg_iterate_over_connections()` API
26exists, which sends a callback function to the IO thread, then IO thread
27calls specified function for all active connection.
28
29When mongoose buffers in HTTP request and successfully parses it, it calls
30appropriate URI handler immediately for GET requests. For POST requests,
31Mongoose delays the call until the whole POST request is buffered in memory.
32POST data is available to the callback as `struct mg_connection::content`,
33and POST data length is in `struct mg_connection::content_len`.
34
35Note that websocket connections are treated the same way. Mongoose buffers
36websocket frame in memory, and calls URI handler when frame is fully
37buffered. Frame data is available `struct mg_connection::content`, and
38data length is in `struct mg_connection::content_len`, i.e. very similar to
39the POST request. `struct mg_connection::is_websocket` flag indicates
40whether the request is websocket or not. Also, for websocket requests,
41there is `struct mg_connection::wsbits` field which contains first byte
42of the websocket frame which URI handler can examine. Note that to
43reply to the websocket client, `mg_websocket_write()` should be used.
44To reply to the plain HTTP client, `mg_write()` should be used.
trunk/3rdparty/mongoose/docs/Options.md
r0r250110
1# Mongoose Configuration Options
2
3### access\_control\_list
4An Access Control List (ACL) allows restrictions to be put on the list of IP
5addresses which have access to the web server. In the case of the Mongoose
6web server, the ACL is a comma separated list of IP subnets, where each
7subnet is prepended by either a `-` or a `+` sign. A plus sign means allow,
8where a minus sign means deny. If a subnet mask is omitted, such as `-1.2.3.4`,
9this means to deny only that single IP address.
10
11Subnet masks may vary from 0 to 32, inclusive. The default setting is to allow
12all accesses. On each request the full list is traversed, and
13the last match wins. Example: `$ mongoose -access_control_list -0.0.0.0/0,+192.168/16` to deny all acccesses except those from `192.168/16` subnet. Note that if the option is set, then all accesses are forbidden
14by default. Thus in a previous example, `-0.0.0.0` part is not necessary.
15For example, `$mongoose access_control_list +10.0.0.0/8`
16means disallow all, allow subnet 10/8 only.
17
18To learn more about subnet masks, see the
19[Wikipedia page on Subnetwork](http://en.wikipedia.org/wiki/Subnetwork)
20
21Default: not set, all accesses are allowed.
22
23### access\_log\_file
24Path to a file for access logs. Either full path, or relative to the
25mongoose executable. Default: not set, no query logging is done.
26
27### auth_domain
28Authorization realm used in `.htpasswd` authorization. Default: `mydomain.com`
29
30### cgi_interpreter
31Path to an executable to be used use as an interpreter for __all__ CGI scripts
32regardless script extension.  Default: not set, Mongoose looks at
33[shebang line](http://en.wikipedia.org/wiki/Shebang_(Unix\).
34
35For example, if both PHP and perl CGIs are used, then
36`#!/path/to/php-cgi.exe` and `#!/path/to/perl.exe` must be first lines of the
37respective CGI scripts. Note that paths should be either full file paths,
38or file paths relative to the directory where mongoose executable is located.
39
40If all CGIs use the same interpreter, for example they are all PHP, then
41`cgi_interpreter` option can be set to the path to `php-cgi.exe` executable and
42shebang line in the CGI scripts can be omitted.
43**Note**: PHP scripts must use `php-cgi.exe`, not `php.exe`.
44
45### cgi_pattern
46All files that match `cgi_pattern` are treated as CGI files. Default pattern
47allows CGI files be anywhere. To restrict CGIs to a certain directory,
48use `/path/to/cgi-bin/**.cgi` as a pattern. Note that **full file path** is
49matched against the pattern, not the URI.
50
51When Mongoose starts CGI program, it creates new environment for it (in
52contrast, usually child program inherits the environment from parent). Several
53environment variables however are inherited from Mongoose's environment,
54they are: `PATH`, `TMP`, `TEMP`, `TMPDIR`, `PERLLIB`, `MONGOOSE_CGI`. On UNIX
55it is also `LD_LIBRARY_PATH`. On Windows it is also `COMSPEC`, `SYSTEMROOT`,
56`SystemDrive`, `ProgramFiles`, `ProgramFiles(x86)`, `CommonProgramFiles(x86)`.
57
58Default: `**.cgi$|**.pl$|**.php$`
59
60### dav\_auth\_file
61Authentication file for WebDAV mutation requests: `PUT`, `DELETE`, `MKCOL`.
62The format of that file is the same as for the `.htpasswd` file
63used for digest authentication. It can be created and managed by
64`mongoose -A` command. Default: not set, WebDAV mutations are disallowed.
65
66### document_root
67A directory to serve. Default: current working directory.
68
69### enable\_directory\_listing
70Enable directory listing, either `yes` or `no`. Default: `yes`.
71
72### enable\_proxy
73Enable proxy functionality, either `yes` or `no`. If set to `yes`, then
74browsers can be configured to use Mongoose as a proxy. Default: `no`.
75
76
77### extra\_mime\_types
78Extra mime types to recognize, in form `extension1=type1,extension2=type2,...`.
79Extension must include dot.  Example:
80`mongoose -extra_mime_types .cpp=plain/text,.java=plain/text`. Default: not set.
81
82
83### global\_auth\_file
84Path to a global passwords file, either full path or relative to the mongoose
85executable. If set, per-directory `.htpasswd` files are ignored,
86and all requests are authorised against that file. Use `mongoose -A` to
87manage passwords, or third party utilities like
88[htpasswd-generator](http://www.askapache.com/online-tools/htpasswd-generator).
89Default: not set, per-directory `.htpasswd` files are respected.
90
91### hide\_files\_patterns
92A pattern for the files to hide. Files that match the pattern will not
93show up in directory listing and return `404 Not Found` if requested. Pattern
94must be for a file name only, not including directory name, e.g.
95`mongoose -hide_files_patterns secret.txt|even_more_secret.txt`. Default:
96not set.
97
98### index_files
99Comma-separated list of files to be treated as directory index
100files. Default: `index.html,index.htm,index.cgi,index.shtml,index.php`
101
102### listening_port
103Port to listen on. Port could be prepended by the specific IP address to bind
104to, e.g. `mongoose -listening_port 127.0.0.1:8080`. Otherwise Mongoose
105will bind to all addresses. To enable SSL, build Mongoose with
106`-DNS_ENABLE_SSL` compilation option, and specify `listening_port` as
107`ssl://PORT:SSL_CERTIFICATE.PEM`. Example SSL listener:
108`mongoose -listening_port ssl://8043:ssl_cert.pem`. Note that PEM file should
109be in PEM format, and must have both certificate and private key in it,
110concatenated together. More than one listening port can be specified,
111separated by comma,
112for example `mongoose -listening_port 8080,8000`. Default: 8080.
113
114### run\_as\_user
115Switch to given user credentials after startup. UNIX-only. This option is
116required when mongoose needs to bind on privileged port on UNIX, e.g.
117
118    $ sudo mongoose -listening_port 80 -run_as_user nobody
119
120Default: not set.
121
122### url\_rewrites
123Comma-separated list of URL rewrites in the form of
124`uri_pattern=file_or_directory_path`. When Mongoose receives the request,
125it constructs the file name to show by combining `document_root` and the URI.
126However, if the rewrite option is used and `uri_pattern` matches the
127requested URI, then `document_root` is ignored. Instead,
128`file_or_directory_path` is used, which should be a full path name or
129a path relative to the web server's current working directory. Note that
130`uri_pattern`, as all mongoose patterns, is a prefix pattern. If `uri_pattern`
131is a number, then it is treated as HTTP error code, and `file_or_directory_path`
132should be an URI to redirect to. Mongoose will issue `302` temporary redirect
133to the specified URI with following parameters:
134`?code=HTTP_ERROR_CODE&orig_uri=ORIGINAL_URI&query_string=QUERY_STRING`.
135
136If `uri_pattern` starts with `@` symbol, then Mongoose compares
137it with the `HOST` header of the request. If they are equal, Mongoose sets
138document root to `file_or_directory_path`, implementing virtual hosts support.
139
140Examples:
141
142    # Redirect all accesses to `.doc` files to a special script
143    mongoose -url_rewrites **.doc$=/path/to/cgi-bin/handle_doc.cgi
144
145    # Implement user home directories support
146    mongoose -url_rewrites /~joe/=/home/joe/,/~bill=/home/bill/
147
148    # Redirect 404 errors to a specific error page
149    mongoose -url_rewrites 404=/cgi-bin/error.cgi
150
151    # Virtual hosts example: serve foo.com domain from different directory
152    mongoose -url_rewrites @foo.com=/var/www/foo.com
153
154Default: not set.
trunk/3rdparty/mongoose/docs/PhpWebsite.md
r0r250110
1How To Create A PHP Website With Mongoose
2===========================================
3
4## 1. Create a directory which will contain your website files. For example, on drive `C:\`, create a directory called `my_website`:
5
6![screenshot](http://cesanta.com/images/tut_php/tut1.png)
7
8## 2. Inside `my_website` directory, create a new file called "index". This will be the default web page shown when the website is visited.
9
10![screenshot](http://cesanta.com/images/tut_php/tut2.png)
11
12## 3. Open index file with your favorite editor (for example, Notepad) and enter some HTML / PHP code:
13
14![screenshot](http://cesanta.com/images/tut_php/tut3.png)
15
16## 4. Save this file as `index.php`:
17
18![screenshot](http://cesanta.com/images/tut_php/tut4.png)
19
20
21## 5. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside `my_website` directory:
22
23![screenshot](http://cesanta.com/images/tut_php/tut5.png)
24
25## 6. Double-click mongoose executable. An icon will appear on a system tray in the bottom right corner of the desktop:
26
27![screenshot](http://cesanta.com/images/tut_php/tut6.png)
28
29## 7. Download PHP 5.3 zip (do NOT download PHP 5.5 cause you might have missing DLLs problem) from http://windows.php.net/download and extract it to `C:\php5` directory:
30![screenshot](http://cesanta.com/images/tut_php/tut7.png)
31
32## 8. Click on the mongoose icon and choose "Edit Settings" menu.:
33![screenshot](http://cesanta.com/images/tut_php/tut8.png)
34
35## 9. A settings dialog will appear. Click on `cgi_interpreter` button:
36
37![screenshot](http://cesanta.com/images/tut_php/tut9.png)
38
39## 10. Choose `C:\php5\php-cgi.exe` and click "Save Settings":
40
41![screenshot](http://cesanta.com/images/tut_php/tut10.png)
42
43## 11. Click on the mongoose icon and choose "Go to my address" menu:
44![screenshot](http://cesanta.com/images/tut_php/tut11.png)
45
46
47## 12. A browser will popup displaying `index.php`.
48
49![screenshot](http://cesanta.com/images/tut_php/tut12.png)
trunk/3rdparty/mongoose/docs/ReleaseNotes.md
r0r250110
1# Mongoose Release Notes
2
3## Release 5.6, 2015-03-17
4
5Changes in Libmongoose library:
6
7- Added `-dav_root` configuration option that gives an ability to mount
8  a different root directory (not document_root)
9- Fixes for build under Win23 and MinGW
10- Bugfix: Double dots removal
11- Bugfix: final chunked response double-send
12- Fixed compilation in 64-bit environments
13- Added OS/2 compatibility
14- Added `getaddrinfo()` call and `NS_ENABLE_GETADDRINFO`
15- Various SSL-related fixes
16- Added integer overflow protection in `iobuf_append()` and `deliver_websocket_frame()`
17- Fixed NetBSD build
18- Enabled `NS_ENABLE_IPV6` build for Visual Studio 2008+
19- Enhanced comma detection in `parse_header()`
20- Fixed unchanged memory accesses on ARM
21- Added ability to use custom memory allocator through NS_MALLOC, NS_FREE, NS_REALLOC
22
23Changes in Mongoose binary:
24
25- Added `-start_browser` option to disable automatic browser launch
26- Added experimental SSL support. To listen on HTTPS port, use `ssl://PORT:SSL_CERT` format. For example, to listen on HTTP port 8080 and HTTPS port 8043, use `-listening_port 8080,ssl://8043:ssl_cert.pem`
27
28## Release 5.5, October 28 2014
29
30Changes in Libmongoose library:
31
32- Added new API function: `mg_forward()` for proxying functionality
33- Added new API function: `mg_send_file_data()` for sending file data
34- Added new utility API functions: `mg_mmap() and mg_munmap()`
35- Changed the way SSL settings are handled: removed `ssl_certificate` and
36  `ssl_ca_certificate` options, and instead made `listening_port` accept
37  `ssl://PORT:SSL_CERT:CA_CERT` notation
38- Added ability to listen on multiple ports, see `listening_port` documentation
39- Added `enable_proxy` option
40- Added [cookie_authentication](https://github.com/cesanta/mongoose/tree/master/examples/cookie_authentication) example
41- Added [websocket\_ssl\_proxy](https://github.com/cesanta/mongoose/tree/master/examples/websocket_ssl_proxy) example
42- Added [http_client](https://github.com/cesanta/mongoose/tree/master/examples/http_client) example
43- Increased default 'idle connection' timeout from 30 to 300 seconds
44- Fixed MinGW build
45- Refactored all examples, put each in it's own directory with dedicated build
46- Many smaller bugfixed, including SSL, CGI, API, proxy, etc
47
48Changes in pre-compiled binaries:
49
50- Support for multiple listening ports
51- Fixed CGI handling for scripts that specify interpreter in the hashbang line
52
53## Release 5.4, July 28 2014
54
55Changes in Libmongoose library:
56
57- Added `hexdump_file` option for low-level request/reply debugging
58- Added `mg_template()` API function for generating HTML pages from
59    templates with expansions
60- Fixed `struct mg_connection::local_ip` handling, `mg_set_option()`
61    behavior with NULL values
62- Added `mg_send_file()` call to send arbitrary file to the client
63- Added `mg_terminate_ssl()` for SSL termination functionality
64- Added HTTP proxy support, `enable_proxy` config option
65- Added `mg_next()` for iterating over existing active connections
66- Added client-side SSL auth, `ssl_ca_certificate` option
67- Added `mg_wakeup_server_ex()` for pushing messages to existing connections
68- Added `MG_WS_HANDSHAKE` and `MG_WS_CONNECT` events that are sent on
69     Websocket handshake is connection establishment, respectively
70- Removed server-side Lua support
71- Filesystem access, reading from socket/SSL performance improvements
72- DAV PROPFIND memory leak fixed
73- Added `big_upload.c` and enhanced `upload.c` example
74- Added `proxy.c` example that demonstrates proxy functionality and SSE pushes
75- Added `websocket2.c` example that shows simple web chat implementation
76    over websockets
77- Various minor fixes
78
79
80Changes in pre-compiled binaries:
81
82- Created HTML administration console
83- When server is started, browser is started automatically
84- Fixed directory listing bug when directory contains `#` character
85- Removed built-in Lua Server Pages in the binary, and instead
86  added Mongoose + Lua developer bundle which has Lua Server Pages support.
87  That also solves external Lua modules loading problem.
88
89
90## Release 5.3, March 10 2014
91
92Changes in Libmongoose library:
93
94   * Moved to the evented API. Updated API documentation is at
95       http://cesanta.com/docs/Embed.shtml
96       http://cesanta.com/docs/API.shtml
97   *  Added `MG_LUA` event for exporting custom variables to the Lua environment
98   *  Added virtual hosts capability, see `url_rewrites` option description at
99       http://cesanta.com/docs/Options.shtml
100   *  Added mjpg serving example
101   *  Cleaned up and documented HTTP client API, with unit tests
102   *  Added `mg_wakeup_server()` to awaken `mg_poll_server()`
103      from another thread
104   *  Moved Mongoose IO core to [https://github.com/cesanta/net_skeleton](Net Skeleton)
105   *  Added connection hexdump functionality for developers
106   *  Bug fixes
107
108Changes in pre-compiled binaries:
109
110   *  New awesome Mongoose logos by our designer Katrin - thanks Katrin!
111        Check them out at http://cesanta.com/products.shtml
112   *  Added Lua Server Pages support to the free version, quick intro is at
113        http://cesanta.com/docs/Lua.shtml
114   *  Added quick "Set shared directory" menu item to set `document_root`
115   *  Added SSI support to the Pro version
116   *  Removed SSL support from the Pro version
117
118## Release 5.2, Feb 1 2014
119
120   *  Windows binary made fully UNICODE aware. In previous versions,
121      the presence of non-ASCII chars in document root, CGI script name,
122      or directory name might have broken Mongoose as stand-alone
123      or as Windows service. Now Mongoose works with non-ASCII paths properly.
124      Internally, Mongoose uses UTF8 encoding. When making WinAPI calls,
125      mongoose converts UTF8 strings to wide chars and calls UNICODE API.
126   *  Enhanced authorization API by providing `mg_set_auth_handler()` and
127      `mg_authorize_digest()`
128   *  Removed `mg_add_uri_handler()`, added `mg_set_request_handler()`.
129      There is only oneURI handler that handles all requests, just like in 4.x.
130      The reason for this change is to provide an ability to catch all URIs,
131      and at the same time signal Mongoose to continue handling specific URIs.
132  *  Added `mg_parse_multipart()` API for file uploads.
133      Note that the restriction on uploading huge files still exists,
134      and will be eliminated in the next release.
135  *  Allowing mongoose to bind to port 0, in which case it'll bind to any
136      random unused port.
137  *  Moved `idle_timeout_ms` run-time option to compile-time flag
138  *  Added asynchronous HTTP client, not documented yet. Documentation and
139      examples are coming in the next couple of weeks. Async Websocket client
140      is scheduled for the next release. See usage examples at `unit_test.c`
141  *  Windows and MacOS pre-built binaries are now split to free and paid ones,
142    paid binaries include CGI, SSL, Lua, Sqlite, support and updates.
143    Linux pre-built binary includes all functionality and is free, and will
144    continue to be free.  Source code for Windows and MacOS GUI is closed.
145    Disclaimer: source code for the command line stand-alone server,
146    as well as Mongoose library itself, will never be closed.
147  *  Multiple bug fixes and minor enhancements
148
149## Release 5.1, Jan 10 2014
150
151   *  CGI-related bugs where fixed, primarily for Windows platform
152   *  Bugs on Windows related to UNICODE support were fixed
153   *  Added a feature to support "error pages" through redirect.
154      Done using `-url_redirects` option, details are on
155      http://cesanta.com/docs/Options.shtml
156
157## Release 5.0, Jan 6 2014
158
159   *  Internal core has been changed from blocking, thread-per-connection to
160      non-blocking, asynchronous, one thread for all.
161   *  API modification for server creation and response creation. That allowed
162     keep-alive support for dynamic requests, boosting the embedded performance
163     to 100+ thousands requests per second on a single core
164     (as measured on my development MacBook laptop)
165   * Unified handling of POST requests and Websocket requests by putting a
166    payload into `conn->content`, `conn->content_len` attributes.
167    That simplified user code and eliminated the need of `mg_read()`,
168    since mongoose buffers all data prior to calling the callback
169   * keep-alive support is the default
170   * Dropped SSI support and throttling support
171   *  Several configuration parameters are gone:
172    *  `cgi_environment` (replaced with MONGOOSE_CGI),
173    *  `protect_uri` (not useful)
174    *  `ssi_pattern` (SSI support is gone)
175    *  `throttle` (throttling support is gone)
176    *  `error_log_file` (not used)
177    *   `enable_keep_alive` (enabled by default)
178    *   `listening_ports` (renamed to listening_port)
179    *   `num_threads` (core has changed to single thread)
180    *   `put_delete_auth_file` (renamed to dav_auth_file)
181    *   `authentication_domain` (renamed to auth_domain)
182   * Due to the async, non-blocking nature of the core, few restrictions
183      are now in place:
184    * user callbacks must not block
185    * POST and Websocket data are now buffered, and cannot be huge
186   * mongoose is now capable on listening on only one port
187
188## Release 4.1, Oct 2013
189## Release 4.0, Oct 2013
190## Release 3.8, Sep 2013
191
192## Release 3.7, Feb 2 2013
193
194  *  Added "redirect to SSL port" functionality, e.g. if you specify
195      `-listening_ports 8080r,8043s`
196      then all requests to HTTP port 8080 will be redirected to HTTPS port 8043
197  *  Added `mg_download()` API, an HTTP client interface!
198  *  Lua server pages now must output HTTP headers -- full control for Lua
199  *  Added pre-built binary for MacOS, with initial GUI support
200  *  API change: got rid of events, moved to struct `mg_callbacks`
201  *  Bugfixes, thanks to contributors
202
203
204## Release 3.7, Jan 18 2013
205  *  Fixed source code archive (main.c was missing)
206  *  Extended Windows GUI functionality:
207   * Added "Start browser" systray popup menu item
208   *  Enhanced configuration editor
209  *  Renamed config options:
210   * `put_delete_passwords_file` -> `put_delete_auth_file`
211   * `global_passwords_file` -> `global_auth_file`
212  *  `select()` changed to `poll()`, to avoid big file descriptor
213  `FD_SET` problem on UNIX
214  *  Couple of bugfixes, thanks to contributors
215
216
217Earlier release notes could be found by searching
218[Mongoose mailing list](https://groups.google.com/forum/#!forum/mongoose-users)
trunk/3rdparty/mongoose/docs/SSL.md
r0r250110
1# Mongoose SSL guide
2
3SSL is a protocol that makes web communication secure. To enable SSL
4in mongoose, 2 steps are required:
5
6   1. Create valid SSL certificate file
7   2. Append SSL certificate file path to the `listening_ports` option
8
9Below is the `mongoose.conf` file snippet for typical SSL setup:
10
11    document_root     www_root         # Serve files in www_root directory
12    listening_ports   80,443:cert.pem  # Listen on ports 80 and 443
13
14## How to create SSL certificate file
15
16SSL certificate file is a text file that must contain at least two
17sections:
18
19   1. A private key
20   2. A certificate
21
22Both sections should be chunks of text in PEM format. When PEM file is
23opened in a text editor, it looks like this:
24
25    -----BEGIN RSA PRIVATE KEY-----
26    MIIEogIBAAKCAQEAwONaLOP7EdegqjRuQKSDXzvHmFMZfBufjhELhNjo5KsL4ieH
27    hYN0Zii2yTb63jGxKY6gH1R/r9dL8kXaJmcZrfSa3AgywnteJWg=
28    -----END RSA PRIVATE KEY-----
29    -----BEGIN CERTIFICATE-----
30    MIIDBjCCAe4CCQCX05m0b053QzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJB
31    SEGI4JSxV56lYg==
32    -----END CERTIFICATE-----
33
34Two aforementioned sections are clearly seen. Typically, those section
35are bigger then in the example shown. The text between the `BEGIN` and
36`END` is the text representation of binary data, a private key and a
37certificate. Therefore, in order to create a certificate file,
38
39   * private key must be converted to PEM format
40   * certificate must be converted to PEM format
41   * those two should be concatenated into a single file
42
43If the certificate chain in used, a chain file also needs to be
44converted into PEM format and appended to the certificate file.
45
46## How SSL works
47
48SSL is a protocol that can encrypt communication between two parties. If third
49party observes all messages passed by, it would be very
50hard for the third party (though not impossible) to decrypt the communication.
51
52The idea is based on so-called public key encryption. Communicating parties
53have two keys: a public key and a private key. A public key is advertised
54to everybody, and it is contained in a certificate. A private key is kept
55secret. Security algorithm works in a way that anybody can encrypt
56a message using public key, and only private key can decrypt it.
57
58This is why web server needs both private key and certificate: private key
59is used to decrypt incoming messages, and certificate is used to tell the
60public key to the other party. When communication starts, parties exchange
61their public keys, and keep private keys to themselves. Man-in-the-middle
62who observes the communication is unable to decrypt the messages cause
63private keys are required for decryption.
64
65Encryption algorithms are built on top of hard mathematical problem, which
66makes it very expensive for man-in-the-middle to compute private keys.
67For example, RSA algorithm is based on a mathematical problem of factorization.
68It is easy to generate two very large prime numbers `P` and `Q` and make
69a product `P * Q`. But given a product, it is very hard to recover these
70two prime numbers - this is called factorization.
trunk/3rdparty/mongoose/docs/Usage.md
r0r250110
1# Mongoose User Guide
2
3Mongoose is small and easy to use web server built on top of
4mongoose library. It is designed with maximum simplicity in mind. For example,
5to share any directory, just drop mongoose executable in that directory,
6double-click it (on UNIX, run it from shell) and launch a browser at
7[http://localhost:8080](http://localhost:8080) Note that 'localhost' should
8be changed to a machine's name if a folder is accessed from other computer.
9
10On Windows and Mac, Mongoose iconifies itself to the system tray when started.
11Right-click on the icon to pop up a menu, where it is possible to stop
12mongoose, or configure it.
13
14On UNIX, `mongoose` is a command line utility. Running `mongoose` in
15terminal, optionally followed by configuration parameters
16(`mongoose [OPTIONS]`) or configuration file name
17(`mongoose [config_file_name]`) starts the
18web server:
19
20    $ mongoose -document_root /var/www  # Running mongoose with cmdline options
21    $ mongoose /etc/my_config.txt       # Running mongoose with config file
22    $ mongoose                          # Running with no parameters. This will
23                                        # serve current directory on port 8080
24
25Mongoose does not detach from terminal. Pressing `Ctrl-C` keys
26stops the server.
27
28When started, mongoose first searches for the configuration file.
29If configuration file is specified explicitly in the command line, then
30specified configuration file is used.
31Otherwise, mongoose would search for file `mongoose.conf` in the same directory
32where binary is located, and use it. Configuration file can be absent.
33
34Configuration file is a sequence of lines, each line containing
35command line argument name and it's value. Empty lines and lines beginning
36with `#` are ignored. Here is the example of `mongoose.conf` file:
37
38    # This is a comment
39    document_root C:\www
40    listening_port 80
41    ssl_certificate C:\mongoose\ssl_cert.pem
42
43Command line arguments are highest priority and can override
44configuration file settings. For example, if `mongoose.conf` has line
45`document_root /var/www`, and mongoose has been started as
46`mongoose -document_root /etc`, then `/etc` directory will be used as
47document root.
48
49Note that configuration options on the command line must start with `-`,
50and their names are the same as in the config file. Exampli gratia,
51the following two setups are equivalent:
52
53    $ mongoose -listening_port 1234 -document_root /var/www
54
55    $ cat > mongoose.conf
56    listening_ports 1234
57    document_root /var/www
58    ^D
59    $ mongoose
60
61Mongoose can also be used to modify `.htpasswd` passwords file:
62
63    $ mongoose -A .htpasswd mydomain.com user_name user_password
64
65Unlike other web servers, mongoose does not require CGI scripts be located in
66a special directory. CGI scripts can be anywhere. CGI (and SSI) files are
67recognized by the file name pattern. Mongoose uses shell-like glob
68patterns. Pattern match starts at the beginning of the string, so essentially
69patterns are prefix patterns. Syntax is as follows:
70
71     **         Matches everything
72     *          Matches everything but slash character, '/'
73     ?          Matches any character
74     $          Matches the end of the string
75     |          Matches if pattern on the left side or the right side matches.
76
77All other characters in the pattern match themselves. Examples:
78
79    # Pattern   Meaning
80    **.cgi$     Any string that ends with .cgi
81    /foo        Any string that begins with /foo
82    **a$|**b$   Any string that ends with a or b
83
84To restrict CGI files only to `/cgi-bin/` directory, use this setting:
85
86    $ mongoose -cgi_pattern /cgi-bin/*.cgi # Emulate /cgi-bin/ restriction
trunk/3rdparty/mongoose/examples/.gitignore
r0r250110
1*.exe
trunk/3rdparty/mongoose/examples/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4SUBDIRS = $(sort $(filter-out csharp/, $(dir $(wildcard */))))
5X = $(SUBDIRS)
6ifdef WINDIR
7    # appending the Winsock2 library at the end of the compiler
8   # invocation
9    CFLAGS_EXTRA += -lws2_32
10endif
11
12.PHONY: $(SUBDIRS)
13
14all: $(SUBDIRS)
15
16$(SUBDIRS):
17   @$(MAKE) CFLAGS_EXTRA="$(CFLAGS_EXTRA)" -C $@
18
19clean:
20   for d in $(SUBDIRS) ; do $(MAKE) -C $$d clean ; done
trunk/3rdparty/mongoose/examples/array_vars/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = array_vars
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8all: $(PROG)
9
10run: $(PROG)
11   ./$(PROG)
12
13$(PROG): $(SOURCES) Makefile
14   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
15
16win:
17   wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe
18   wine $(PROG).exe
19
20clean:
21   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc*
trunk/3rdparty/mongoose/examples/array_vars/array_vars.c
r0r250110
1// Copyright (c) 2014 Cesanta Software
2// All rights reserved
3//
4// This example demostrates how to use array get variables using mg_get_n_var
5// $Date: 2014-09-09 22:20:23 UTC $
6
7#include <stdio.h>
8#include <string.h>
9#include "mongoose.h"
10
11static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
12  switch (ev) {
13    case MG_AUTH: return MG_TRUE;
14    case MG_REQUEST:
15    {
16      mg_printf_data(conn, "Hello! Requested URI is [%s] ", conn->uri);
17      char buffer[1024];
18      int i, ret;
19      for(i=0; (ret = mg_get_var_n(conn, "foo[]", buffer, 1024, i)) > 0; i++)
20        mg_printf_data(conn, "\nfoo[%d] = %s", i, buffer);
21
22      return MG_TRUE;
23    }
24    default: return MG_FALSE;
25  }
26}
27
28int main(void) {
29  struct mg_server *server;
30
31  // Create and configure the server
32  server = mg_create_server(NULL, ev_handler);
33  mg_set_option(server, "listening_port", "8080");
34
35  // Serve request. Hit Ctrl-C to terminate the program
36  printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
37  for (;;) {
38    mg_poll_server(server, 1000);
39  }
40
41  // Cleanup, and free server instance
42  mg_destroy_server(&server);
43
44  return 0;
45}
trunk/3rdparty/mongoose/examples/big_upload/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = big_upload
5CFLAGS = -W -Wall -pthread -I../.. -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8$(PROG): $(SOURCES)
9   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
10
11clean:
12   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
trunk/3rdparty/mongoose/examples/big_upload/big_upload.c
r0r250110
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include "mongoose.h"
5
6static int handle_request(struct mg_connection *conn) {
7  if (strcmp(conn->uri, "/upload") == 0) {
8    FILE *fp = (FILE *) conn->connection_param;
9    if (fp != NULL) {
10      fwrite(conn->content, 1, conn->content_len, fp); // Write last bits
11      mg_printf(conn, "HTTP/1.1 200 OK\r\n"
12                "Content-Type: text/plain\r\n"
13                "Connection: close\r\n\r\n"
14                "Written %ld of POST data to a temp file:\n\n",
15                (long) ftell(fp));
16
17      // Temp file will be destroyed after fclose(), do something with the
18      // data here -- for example, parse it and extract uploaded files.
19      // As an example, we just echo the whole POST buffer back to the client.
20      rewind(fp);
21      mg_send_file_data(conn, fileno(fp));
22      return MG_MORE;  // Tell Mongoose reply is not completed yet
23    } else {
24      mg_printf_data(conn, "%s", "Had no data to write...");
25      return MG_TRUE; // Tell Mongoose we're done with this request
26    }
27  } else {
28    mg_printf_data(conn, "%s",
29                   "<html><body>Upload example."
30                   "<form method=\"POST\" action=\"/upload\" "
31                   "  enctype=\"multipart/form-data\">"
32                   "<input type=\"file\" name=\"file\" /> <br/>"
33                   "<input type=\"submit\" value=\"Upload\" />"
34                   "</form></body></html>");
35    return MG_TRUE;   // Tell mongoose to close this connection
36  }
37}
38
39// Mongoose sends MG_RECV for every received POST chunk.
40// When last POST chunk is received, Mongoose sends MG_REQUEST, then MG_CLOSE.
41static int handle_recv(struct mg_connection *conn) {
42  FILE *fp = (FILE *) conn->connection_param;
43
44  // Open temporary file where we going to write data
45  if (fp == NULL && ((conn->connection_param = fp = tmpfile())) == NULL) {
46    return -1;  // Close connection on error
47  }
48
49  // Return number of bytes written to a temporary file: that is how many
50  // bytes we want to discard from the receive buffer
51  return fwrite(conn->content, 1, conn->content_len, fp);
52}
53
54// Make sure we free all allocated resources
55static int handle_close(struct mg_connection *conn) {
56  if (conn->connection_param != NULL) {
57    fclose((FILE *) conn->connection_param);
58    conn->connection_param = NULL;
59  }
60  return MG_TRUE;
61}
62
63static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
64  switch (ev) {
65    case MG_AUTH:     return MG_TRUE;
66    case MG_REQUEST:  return handle_request(conn);
67    case MG_RECV:     return handle_recv(conn);
68    case MG_CLOSE:    return handle_close(conn);
69    default:          return MG_FALSE;
70  }
71}
72
73int main(void) {
74  struct mg_server *server = mg_create_server(NULL, ev_handler);
75  mg_set_option(server, "listening_port", "8080");
76  printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
77
78  for (;;) {
79    mg_poll_server(server, 1000);
80  }
81
82  mg_destroy_server(&server);
83  return 0;
84}
trunk/3rdparty/mongoose/examples/cookie_authentication/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = cookie_auth
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8$(PROG): $(SOURCES)
9   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
10
11clean:
12   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
trunk/3rdparty/mongoose/examples/cookie_authentication/cookie_auth.c
r0r250110
1// Copyright (c) 2014 Cesanta Software
2// All rights reserved
3
4#include <stdio.h>
5#include <string.h>
6#include <time.h>
7#include "mongoose.h"
8
9static const char *s_login_uri = "/login.html";
10static const char *s_secret = ":-)";  // Must be known only to server
11
12static void generate_ssid(const char *user_name, const char *expiration_date,
13                          char *ssid, size_t ssid_size) {
14  char hash[33];
15  mg_md5(hash, user_name, ":", expiration_date, ":", s_secret, NULL);
16  snprintf(ssid, ssid_size, "%s|%s|%s", user_name, expiration_date, hash);
17}
18
19static int check_auth(struct mg_connection *conn) {
20  char ssid[100], calculated_ssid[100], name[100], expire[100];
21
22  // Always authenticate requests to login page
23  if (strcmp(conn->uri, s_login_uri) == 0) {
24    return MG_TRUE;
25  }
26
27  // Look for session ID in the Cookie.
28  // That session ID can be validated against the database that stores
29  // current active sessions.
30  mg_parse_header(mg_get_header(conn, "Cookie"), "ssid", ssid, sizeof(ssid));
31  if (sscanf(ssid, "%[^|]|%[^|]|", name, expire) == 2) {
32    generate_ssid(name, expire, calculated_ssid, sizeof(calculated_ssid));
33    if (strcmp(ssid, calculated_ssid) == 0) {
34      return MG_TRUE;  // Authenticate
35    }
36  }
37
38  // Auth failed, do NOT authenticate, redirect to login page
39  mg_printf(conn, "HTTP/1.1 302 Moved\r\nLocation: %s\r\n\r\n", s_login_uri);
40  return MG_FALSE;
41}
42
43static int check_login_form_submission(struct mg_connection *conn) {
44  char name[100], password[100], ssid[100], expire[100], expire_epoch[100];
45
46  mg_get_var(conn, "name", name, sizeof(name));
47  mg_get_var(conn, "password", password, sizeof(password));
48
49  // A real authentication mechanism should be employed here.
50  // Also, the whole site should be served through HTTPS.
51  if (strcmp(name, "Joe") == 0 && strcmp(password, "Doe") == 0) {
52    // Generate expiry date
53    time_t t = time(NULL) + 3600;  // Valid for 1 hour
54    snprintf(expire_epoch, sizeof(expire_epoch), "%lu", (unsigned long) t);
55    strftime(expire, sizeof(expire), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
56    generate_ssid(name, expire_epoch, ssid, sizeof(ssid));
57    // Set "session id" cookie, there could be some data encoded in it.
58    mg_printf(conn,
59              "HTTP/1.1 302 Moved\r\n"
60              "Set-Cookie: ssid=%s; expire=\"%s\"; http-only; HttpOnly;\r\n"
61              "Content-Length: 0\r\n"
62              "Location: /\r\n\r\n",
63              ssid, expire);
64    return MG_TRUE;
65  }
66  return MG_FALSE;
67}
68
69static int serve_request(struct mg_connection *conn) {
70  if (strcmp(conn->uri, s_login_uri) == 0 &&
71      strcmp(conn->request_method, "POST") == 0) {
72    return check_login_form_submission(conn);
73  }
74  return MG_FALSE;  // Serve files in the document_root
75}
76
77static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
78  switch (ev) {
79    case MG_AUTH: return check_auth(conn);
80    case MG_REQUEST: return serve_request(conn);
81    default: return MG_FALSE;
82  }
83}
84
85int main(void) {
86  struct mg_server *server = mg_create_server(NULL, ev_handler);
87  mg_set_option(server, "listening_port", "8080");
88  mg_set_option(server, "document_root", ".");
89
90  printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
91  for (;;) {
92    mg_poll_server(server, 1000);
93  }
94  mg_destroy_server(&server);
95
96  return 0;
97}
trunk/3rdparty/mongoose/examples/cookie_authentication/index.html
r0r250110
1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="utf-8" />
5  <title>WebSocket Test</title>
6  <meta name="viewport" content="width=device-width, initial-scale=1" />
7  <style type="text/css">
8    body {
9      background-color: #cde; margin: 0;
10      padding: 0; font: 14px Helvetica, Arial, sans-serif;
11    }
12    * { outline: none; }
13    div.content {
14      width: 800px; margin: 2em auto; padding: 20px 50px;
15      background-color: #fff; border-radius: 1em;
16    }
17    label { display: inline-block; min-width: 7em; }
18    input { border: 1px solid #ccc; padding: 0.4em; margin: 0 0 10px 0; }
19    a:link, a:visited { color: #69c; text-decoration: none; }
20    @media (max-width: 700px) {
21      body { background-color: #fff; }
22      div.content {
23        width: auto; margin: 0 auto; border-radius: 0; padding: 1em;
24      }
25    }
26</style>
27
28<body>
29  <div class="content">
30    <h1>Mongoose Cookie Base Authentication</h1>
31    <p>This is an index page. Authentication succeeded.</p>
32</body>
33</html>
No newline at end of file
trunk/3rdparty/mongoose/examples/cookie_authentication/login.html
r0r250110
1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="utf-8" />
5  <title>WebSocket Test</title>
6  <meta name="viewport" content="width=device-width, initial-scale=1" />
7  <style type="text/css">
8    body {
9      background-color: #cde; margin: 0;
10      padding: 0; font: 14px Helvetica, Arial, sans-serif;
11    }
12    * { outline: none; }
13    div.content {
14      width: 800px; margin: 2em auto; padding: 20px 50px;
15      background-color: #fff; border-radius: 1em;
16    }
17    label { display: inline-block; min-width: 7em; }
18    input { border: 1px solid #ccc; padding: 0.4em; margin: 0 0 10px 0; }
19    a:link, a:visited { color: #69c; text-decoration: none; }
20    @media (max-width: 700px) {
21      body { background-color: #fff; }
22      div.content {
23        width: auto; margin: 0 auto; border-radius: 0; padding: 1em;
24      }
25    }
26</style>
27
28<body>
29  <div class="content">
30    <h1>Mongoose Cookie Based Authentication</h1>
31    <p>Use name "Joe", password "Doe" to login.</p>
32    <form method="POST">
33      <div>
34        <label>Name:</label>
35        <input type="text" name="name"/>
36      </div><div>
37        <label>Password:</label>
38        <input type="password" name="password"/>
39      </div><div>
40        <input type="submit" value="Login"/>
41      </div>
42    </form>
43</body>
44</html>
No newline at end of file
trunk/3rdparty/mongoose/examples/csharp/example.cs
r0r250110
1// This file is part of mongoose web server project,
2// https://github.com/cesanta/mongoose
3
4using System;
5
6public class Program {
7  static private int EventHandler(IntPtr conn_ptr, int ev) {
8      MongooseConnection conn = (MongooseConnection)
9         System.Runtime.InteropServices.Marshal.PtrToStructure(
10            conn_ptr , typeof(MongooseConnection));
11
12      if (ev == 102) {
13         // MG_AUTH
14         return 1;
15      } else if (ev == 103) {
16         // MG_REQUEST
17       Mongoose.send_data(conn_ptr, "Hello from C#!\n");
18         Mongoose.send_data(conn_ptr, "URI: " + conn.uri + "\n");
19         Mongoose.send_data(conn_ptr, "HTTP Headers:\n");
20         
21         for (int i = 0; i < conn.num_headers; i++) {
22            IntPtr name = conn.http_headers[i].name;
23            IntPtr val = conn.http_headers[i].value;
24            System.Runtime.InteropServices.Marshal.PtrToStringAnsi(name);
25            Mongoose.send_data(conn_ptr, "  " +
26               System.Runtime.InteropServices.Marshal.PtrToStringAnsi(name) + ": " +
27                  System.Runtime.InteropServices.Marshal.PtrToStringAnsi(val) + "\n");
28         }         
29      return 1;
30      }
31      return 0;
32  }
33
34  static void Main() {
35    Mongoose web_server = new Mongoose(".", "9001",
36        new MongooseEventHandler(EventHandler));
37
38    Console.WriteLine("Mongoose started, press Ctrl-C to exit.");
39      for (;;) {
40         web_server.poll(1000);
41      }
42  }
43}
trunk/3rdparty/mongoose/examples/csharp/mongoose.cs
r0r250110
1// This file is part of mongoose web server project,
2// https://github.com/cesanta/mongoose
3
4using System;
5using System.Runtime.InteropServices;
6
7[StructLayout(LayoutKind.Sequential)] public struct MongooseHeader {
8  [MarshalAs(UnmanagedType.LPTStr)] public IntPtr name;
9  [MarshalAs(UnmanagedType.LPTStr)] public IntPtr value;
10};
11
12// mongoose.h :: struct mg_connection
13[StructLayout(LayoutKind.Sequential)] public struct MongooseConnection {
14  [MarshalAs(UnmanagedType.LPTStr)] public string request_method;
15  [MarshalAs(UnmanagedType.LPTStr)] public string uri;
16  [MarshalAs(UnmanagedType.LPTStr)] public string http_version;
17  [MarshalAs(UnmanagedType.LPTStr)] public string query_string;
18
19   [MarshalAs(UnmanagedType.ByValArray,SizeConst=48)] public char[] remote_ip;
20   [MarshalAs(UnmanagedType.LPTStr)] public string local_ip;
21   [MarshalAs(UnmanagedType.U2)] public short remote_port;
22   [MarshalAs(UnmanagedType.U2)] public short local_port;
23   
24   [MarshalAs(UnmanagedType.SysInt)] public int num_headers;
25  [MarshalAs(UnmanagedType.ByValArray,SizeConst=30)]
26    public MongooseHeader[] http_headers;
27   
28   [MarshalAs(UnmanagedType.LPTStr)] public IntPtr content;
29   [MarshalAs(UnmanagedType.SysInt)] public int content_len;
30   
31   [MarshalAs(UnmanagedType.SysInt)] public int is_websocket;
32   [MarshalAs(UnmanagedType.SysInt)] public int status_code;
33   [MarshalAs(UnmanagedType.SysInt)] public int wsbits;
34};
35
36public delegate int MongooseEventHandler(IntPtr c, int ev);
37
38public class Mongoose {
39  public const string dll_ = "mongoose";
40  private IntPtr server_;
41
42   [DllImport(dll_)] private static extern IntPtr
43      mg_create_server(IntPtr user_data, MongooseEventHandler eh);
44   [DllImport(dll_)] private static extern int
45      mg_poll_server(IntPtr server, int milli);
46  [DllImport(dll_)] private static extern IntPtr
47      mg_set_option(IntPtr server, string name, string value);
48   [DllImport(dll_)] public static extern int
49      mg_send_data(IntPtr conn, string data, int length);   
50
51  public Mongoose(string document_root,
52                  string listening_port,
53                  MongooseEventHandler event_handler) {
54    server_ = mg_create_server(IntPtr.Zero, event_handler);
55      mg_set_option(server_, "document_root", document_root);
56      mg_set_option(server_, "listening_port", listening_port);
57  }
58   
59  public static int send_data(IntPtr conn, string data) {
60    return mg_send_data(conn, data, data.Length);
61  }
62   
63   public void poll(int milli) {
64    mg_poll_server(server_, milli);
65  }
66   
67   // TODO: add destructor and call mg_destroy_server()
68}
trunk/3rdparty/mongoose/examples/digest_authentication/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = digest_auth
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8$(PROG): $(SOURCES)
9   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
10
11clean:
12   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
trunk/3rdparty/mongoose/examples/digest_authentication/digest_auth.c
r0r250110
1#include <stdio.h>
2#include <string.h>
3#include "mongoose.h"
4
5static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
6
7  if (ev == MG_AUTH) {
8    int result = MG_FALSE; // Not authorized
9    FILE *fp;
10
11    // To populate passwords file, do
12    // mongoose -A my_passwords.txt mydomain.com admin admin
13    if ((fp = fopen("my_passwords.txt", "r")) != NULL) {
14      result = mg_authorize_digest(conn, fp);
15      fclose(fp);
16    }
17
18    return result;
19  }
20
21  return MG_FALSE;
22}
23
24int main(void) {
25  struct mg_server *server = mg_create_server(NULL, ev_handler);
26  mg_set_option(server, "listening_port", "8080");
27  mg_set_option(server, "document_root", ".");
28
29  printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
30  for (;;) {
31    mg_poll_server(server, 1000);
32  }
33  mg_destroy_server(&server);
34
35  return 0;
36}
trunk/3rdparty/mongoose/examples/file_upload/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = file_upload
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8all: $(PROG)
9
10run: $(PROG)
11   ./$(PROG)
12
13$(PROG): $(SOURCES) Makefile
14   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
15
16win:
17   wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe
18
19clean:
20   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc*
trunk/3rdparty/mongoose/examples/file_upload/file_upload.c
r0r250110
1// Copyright (c) 2004-2012 Sergey Lyubka
2// This file is a part of mongoose project, http://github.com/valenok/mongoose
3
4#include <stdio.h>
5#include <string.h>
6#include "mongoose.h"
7
8static int send_index_page(struct mg_connection *conn) {
9  const char *data;
10  int data_len, n1, n2;
11  char var_name[100], file_name[100];
12
13  mg_printf_data(conn, "%s",
14                 "<html><body>Upload example."
15                 "<form method=\"POST\" action=\"/handle_post_request\" "
16                 "  enctype=\"multipart/form-data\">"
17                 "<input type=\"file\" name=\"file1\" /> <br/>"
18                 "<input type=\"file\" name=\"file2\" /> <br/>"
19                 "<input type=\"submit\" value=\"Upload\" />"
20                 "</form>");
21
22  n1 = n2 = 0;
23  while ((n2 = mg_parse_multipart(conn->content + n1, conn->content_len - n1,
24                                  var_name, sizeof(var_name), file_name,
25                                  sizeof(file_name), &data, &data_len)) > 0) {
26    mg_printf_data(conn, "var: %s, file_name: %s, size: %d bytes<br>",
27                   var_name, file_name, data_len);
28    n1 += n2;
29  }
30
31  mg_printf_data(conn, "%s", "</body></html>");
32
33  return MG_TRUE;
34}
35
36static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
37  switch (ev) {
38    case MG_AUTH:     return MG_TRUE;
39    case MG_REQUEST:  return send_index_page(conn);
40    default:          return MG_FALSE;
41  }
42}
43
44int main(void) {
45  struct mg_server *server;
46
47  // Create and configure the server
48  server = mg_create_server(NULL, ev_handler);
49  mg_set_option(server, "listening_port", "8080");
50
51  // Serve request. Hit Ctrl-C to terminate the program
52  printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
53  for (;;) {
54    mg_poll_server(server, 1000);
55  }
56
57  // Cleanup, and free server instance
58  mg_destroy_server(&server);
59
60  return 0;
61}
trunk/3rdparty/mongoose/examples/form_submit/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = form_submit
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8$(PROG): $(SOURCES)
9   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
10
11clean:
12   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
trunk/3rdparty/mongoose/examples/form_submit/form_submit.c
r0r250110
1#include <stdio.h>
2#include <string.h>
3#include "mongoose.h"
4
5static const char *html_form =
6  "<html><body>POST example."
7  "<form method=\"POST\" action=\"/handle_post_request\">"
8  "Input 1: <input type=\"text\" name=\"input_1\" /> <br/>"
9  "Input 2: <input type=\"text\" name=\"input_2\" /> <br/>"
10  "<input type=\"submit\" />"
11  "</form></body></html>";
12
13static void send_reply(struct mg_connection *conn) {
14  char var1[500], var2[500];
15
16  if (strcmp(conn->uri, "/handle_post_request") == 0) {
17    // User has submitted a form, show submitted data and a variable value
18    // Parse form data. var1 and var2 are guaranteed to be NUL-terminated
19    mg_get_var(conn, "input_1", var1, sizeof(var1));
20    mg_get_var(conn, "input_2", var2, sizeof(var2));
21
22    // Send reply to the client, showing submitted form values.
23    // POST data is in conn->content, data length is in conn->content_len
24    mg_send_header(conn, "Content-Type", "text/plain");
25    mg_printf_data(conn,
26                   "Submitted data: [%.*s]\n"
27                   "Submitted data length: %d bytes\n"
28                   "input_1: [%s]\n"
29                   "input_2: [%s]\n",
30                   conn->content_len, conn->content,
31                   conn->content_len, var1, var2);
32  } else {
33    // Show HTML form.
34    mg_send_data(conn, html_form, strlen(html_form));
35  }
36}
37
38static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
39  if (ev == MG_REQUEST) {
40    send_reply(conn);
41    return MG_TRUE;
42  } else if (ev == MG_AUTH) {
43    return MG_TRUE;
44  } else {
45    return MG_FALSE;
46  }
47}
48
49int main(void) {
50  struct mg_server *server = mg_create_server(NULL, ev_handler);
51
52  mg_set_option(server, "listening_port", "8080");
53
54  printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
55  for (;;) {
56    mg_poll_server(server, 1000);
57  }
58
59  mg_destroy_server(&server);
60
61  return 0;
62}
trunk/3rdparty/mongoose/examples/hello_world/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = hello_world
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8all: $(PROG)
9
10run: $(PROG)
11   ./$(PROG)
12
13$(PROG): $(SOURCES) Makefile
14   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
15
16win:
17   wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe
18   wine $(PROG).exe
19
20clean:
21   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc*
trunk/3rdparty/mongoose/examples/hello_world/hello_world.c
r0r250110
1// Copyright (c) 2014 Cesanta Software
2// All rights reserved
3//
4// This example demostrates basic use of Mongoose embedded web server.
5// $Date: 2014-09-09 22:20:23 UTC $
6
7#include <stdio.h>
8#include <string.h>
9#include "mongoose.h"
10
11static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
12  switch (ev) {
13    case MG_AUTH: return MG_TRUE;
14    case MG_REQUEST:
15      mg_printf_data(conn, "Hello! Requested URI is [%s]", conn->uri);
16      return MG_TRUE;
17    default: return MG_FALSE;
18  }
19}
20
21int main(void) {
22  struct mg_server *server;
23
24  // Create and configure the server
25  server = mg_create_server(NULL, ev_handler);
26  mg_set_option(server, "listening_port", "8080");
27
28  // Serve request. Hit Ctrl-C to terminate the program
29  printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
30  for (;;) {
31    mg_poll_server(server, 1000);
32  }
33
34  // Cleanup, and free server instance
35  mg_destroy_server(&server);
36
37  return 0;
38}
trunk/3rdparty/mongoose/examples/http_client/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = http_client
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8unix: $(SOURCES)
9   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
10
11clean:
12   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp *.o *.lib
trunk/3rdparty/mongoose/examples/http_client/http_client.c
r0r250110
1// Copyright (c) 2014 Cesanta Software
2// All rights reserved
3//
4// This example demostrates how to connect to the remote Web server,
5// download data, process it and send back a reply.
6
7#include <signal.h>
8#include <stdlib.h>
9
10#include "mongoose.h"
11
12static int s_received_signal = 0;
13static struct mg_server *s_server = NULL;
14static const char *s_remote_addr = "glosbe.com:80";
15
16static void signal_handler(int sig_num) {
17  signal(sig_num, signal_handler);
18  s_received_signal = sig_num;
19}
20
21static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
22  struct mg_connection *client, *orig;
23
24  switch (ev) {
25    case MG_AUTH:
26      return MG_TRUE;
27
28    case MG_CONNECT:
29      // Send request to the remote host.
30      // TODO(lsm): handle connect error here.
31      mg_printf(conn, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n",
32                "/gapi/translate?from=eng&dest=fra&format=json&phrase=cat",
33                s_remote_addr);
34      return MG_TRUE;
35
36    case MG_REPLY:
37      // Send reply to the original connection
38      orig = (struct mg_connection *) conn->connection_param;
39      mg_send_status(orig, conn->status_code);
40      mg_send_header(orig, "Content-Type", "text/plain");
41      mg_send_data(orig, conn->content, conn->content_len);
42      mg_send_data(orig, "", 0);  // Last chunk: mark the end of reply
43
44      // Disconnect connections
45      orig->connection_param = NULL;
46      conn->connection_param = NULL;
47      return MG_TRUE;
48
49    case MG_REQUEST:
50      if ((client = mg_connect(s_server, s_remote_addr)) != NULL) {
51        // Interconnect requests
52        client->connection_param = conn;
53        conn->connection_param = client;
54        return MG_MORE;
55      } else {
56        mg_printf_data(conn, "%s", "cannot send API request");
57        return MG_TRUE;
58      }
59
60    default:
61      return MG_FALSE;
62  }
63}
64
65int main(void) {
66  s_server = mg_create_server(NULL, ev_handler);
67
68  mg_set_option(s_server, "listening_port", "8080");
69
70  // Setup signal handlers
71  signal(SIGTERM, signal_handler);
72  signal(SIGINT, signal_handler);
73
74  printf("Listening on port %s\n", mg_get_option(s_server, "listening_port"));
75  while (s_received_signal == 0) {
76    mg_poll_server(s_server, 1000);
77  }
78  mg_destroy_server(&s_server);
79  printf("Existing on signal %d\n", s_received_signal);
80
81  return EXIT_SUCCESS;
82}
trunk/3rdparty/mongoose/examples/mjpg_streamer/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = mjpg_streamer
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8$(PROG): $(SOURCES)
9   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
10
11clean:
12   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
trunk/3rdparty/mongoose/examples/mjpg_streamer/mjpg_streamer.c
r0r250110
1#include <sys/stat.h>
2#include <stdio.h>
3#include <string.h>
4#include <stdlib.h>
5#include <time.h>
6#include "mongoose.h"
7
8static void send_file(struct mg_connection *conn, const char *path) {
9  char buf[1024];
10  struct stat st;
11  int n;
12  FILE *fp;
13
14  if (stat(path, &st) == 0 && (fp = fopen(path, "rb")) != NULL) {
15    mg_printf(conn, "--w00t\r\nContent-Type: image/jpeg\r\n"
16              "Content-Length: %lu\r\n\r\n", (unsigned long) st.st_size);
17    while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
18      mg_write(conn, buf, n);
19    }
20    fclose(fp);
21    mg_write(conn, "\r\n", 2);
22  }
23}
24
25struct conn_state {
26  int file_index;
27  time_t last_poll;
28};
29
30static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
31  const char **file_names = (const char **) conn->server_param;
32  struct conn_state *state;
33  time_t now = time(NULL);
34
35  switch (ev) {
36
37    case MG_AUTH:
38      return MG_TRUE;
39
40    case MG_REQUEST:
41      if (strcmp(conn->uri, "/stream") != 0) {
42        mg_send_header(conn, "Content-Type", "text/html");
43        mg_printf_data(conn, "%s",
44                       "Go to <a href=/stream>/stream</a> for MJPG stream");
45        return MG_TRUE;
46      }
47
48      mg_printf(conn, "%s",
49                "HTTP/1.0 200 OK\r\n" "Cache-Control: no-cache\r\n"
50                "Pragma: no-cache\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\n"
51                "Connection: close\r\nContent-Type: multipart/x-mixed-replace; "
52                "boundary=--w00t\r\n\r\n");
53
54      send_file(conn, file_names[0]);
55
56      state = (struct conn_state *) malloc(sizeof(*state));
57      conn->connection_param = state;
58      state->file_index = 1;  // First file is already sent
59      state->last_poll = time(NULL);
60      return MG_MORE;
61
62    case MG_POLL:
63      state = (struct conn_state *) conn->connection_param;
64
65      if (state != NULL && now > state->last_poll) {
66        if (file_names[state->file_index] != NULL) {
67          send_file(conn, file_names[state->file_index]);
68          state->file_index++;
69          if (file_names[state->file_index] == NULL) {
70            return MG_TRUE;  // No more images, close connection
71          }
72        }
73        state->last_poll = now;
74      }
75      return MG_FALSE;
76
77    case MG_CLOSE:
78      free(conn->connection_param);
79      conn->connection_param = NULL;
80      return MG_FALSE;
81
82    default:
83      return MG_FALSE;
84  }
85}
86
87int main(int argc, char *argv[]) {
88  struct mg_server *server;
89
90  if (argc < 3) {
91    printf("Usage: %s image1.jpg image2.jpg ...\n", argv[0]);
92    return 1;
93  }
94
95  server = mg_create_server(&argv[1], ev_handler);
96  mg_set_option(server, "listening_port", "8080");
97
98  printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
99  for (;;) {
100    mg_poll_server(server, 1000);
101  }
102  mg_destroy_server(&server);
103
104  return 0;
105}
trunk/3rdparty/mongoose/examples/multi_threaded_server/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = multi_threaded_server
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 -DMONGOOSE_ENABLE_THREADS $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8$(PROG): $(SOURCES)
9   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
10
11clean:
12   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
trunk/3rdparty/mongoose/examples/multi_threaded_server/multi_threaded_server.c
r0r250110
1#include "mongoose.h"
2
3// Start a browser and hit refresh couple of times. The replies will
4// come from both server instances.
5static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
6  if (ev == MG_REQUEST) {
7    mg_send_header(conn, "Content-Type", "text/plain");
8    mg_printf_data(conn, "This is a reply from server instance # %s",
9                   (char *) conn->server_param);
10    return MG_TRUE;
11  } else if (ev == MG_AUTH) {
12    return MG_TRUE;
13  } else {
14    return MG_FALSE;
15  }
16}
17
18static void *serve(void *server) {
19  for (;;) mg_poll_server((struct mg_server *) server, 1000);
20  return NULL;
21}
22
23int main(void) {
24  struct mg_server *server1, *server2;
25
26  server1 = mg_create_server((void *) "1", ev_handler);
27  server2 = mg_create_server((void *) "2", ev_handler);
28
29  // Make both server1 and server2 listen on the same sockets
30  mg_set_option(server1, "listening_port", "8080");
31  mg_copy_listeners(server1, server2);
32
33  // server1 goes to separate thread, server 2 runs in main thread.
34  // IMPORTANT: NEVER LET DIFFERENT THREADS HANDLE THE SAME SERVER.
35  mg_start_thread(serve, server1);
36  mg_start_thread(serve, server2);
37  getchar();
38
39  return 0;
40}
trunk/3rdparty/mongoose/examples/proxy_server/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = proxy_server
5FLAGS = -I../..  -DNS_ENABLE_SSL
6CFLAGS = -W -Wall -g -O0 -pthread  -lssl -DMONGOOSE_ENABLE_THREADS $(FLAGS) $(CFLAGS_EXTRA)
7SOURCES = $(PROG).c ../../mongoose.c
8
9unix: $(SOURCES)
10   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
11
12clean:
13   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
trunk/3rdparty/mongoose/examples/proxy_server/proxy_server.c
r0r250110
1// Copyright (c) 2014 Cesanta Software Limited
2// All rights reserved
3//
4// To build and run this example:
5//    git clone https://github.com/cesanta/net_skeleton.git
6//    git clone https://github.com/cesanta/mongoose.git
7//    cd mongoose/examples
8//    make proxy
9//    ./proxy
10//
11//  Configure your browser to use localhost:2014 as a proxy for all protocols
12//  Then, navigate to https://cesanta.com
13
14#include <sys/stat.h>
15#include <signal.h>
16#include <stdarg.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <time.h>
21
22#ifdef _WIN32
23#define sleep(x) Sleep((x) * 1000)
24#else
25#include <unistd.h>
26#endif
27
28#include "mongoose.h"
29
30static int s_received_signal = 0;
31static struct mg_server *s_server = NULL;
32
33#define SSE_CONNECTION              ((void *) 1)
34
35static void elog(int do_exit, const char *fmt, ...) {
36  va_list ap;
37  va_start(ap, fmt);
38  vfprintf(stderr, fmt, ap);
39  va_end(ap);
40  fputc('\n', stderr);
41  if (do_exit) exit(EXIT_FAILURE);
42}
43
44static void signal_handler(int sig_num) {
45  signal(sig_num, signal_handler);
46  s_received_signal = sig_num;
47}
48
49static int sse_push(struct mg_connection *conn, enum mg_event ev) {
50  if (ev == MG_POLL && conn->connection_param == SSE_CONNECTION) {
51    mg_printf(conn, "data: %s\r\n\r\n", (const char *) conn->callback_param);
52  }
53  return MG_TRUE;
54}
55
56static void *sse_pusher_thread_func(void *param) {
57  while (s_received_signal == 0) {
58    mg_wakeup_server_ex(s_server, sse_push, "%lu %s",
59                        (unsigned long) time(NULL), (const char *) param);
60    sleep(1);
61  }
62  return NULL;
63}
64
65// Return: 1 if regular file, 2 if directory, 0 if not found
66static int exists(const char *path) {
67  struct stat st;
68  return stat(path, &st) != 0 ? 0 : S_ISDIR(st.st_mode)  == 0 ? 1 : 2;
69}
70
71// Return: 1 if regular file, 2 if directory, 0 if not found
72static int is_local_file(const char *uri, char *path, size_t path_len) {
73  snprintf(path, path_len, "%s/%s",
74           mg_get_option(s_server, "document_root"), uri);
75  return exists(path);
76}
77
78static int try_to_serve_locally(struct mg_connection *conn) {
79  char path[500], buf[2000];
80  int n, res;
81  FILE *fp = NULL;
82
83  if ((res = is_local_file(conn->uri, path, sizeof(path))) == 2) {
84    strncat(path, "/index.html", sizeof(path) - strlen(path) - 1);
85    res = exists(path);
86    printf("PATH: [%s]\n", path);
87  }
88  if (res == 0) return MG_FALSE;
89
90  if ((fp = fopen(path, "rb")) != NULL) {
91    printf("Serving [%s] locally \n", path);
92    mg_send_header(conn, "Connection", "close");
93    mg_send_header(conn, "Content-Type", mg_get_mime_type(path, "text/plain"));
94    while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
95      mg_send_data(conn, buf, n);
96    }
97    mg_send_data(conn, "", 0);
98    fclose(fp);
99  }
100  return fp == NULL ? MG_FALSE : MG_TRUE;
101}
102
103static int is_resource_present_locally(const char *uri) {
104  char path[500];
105  return is_local_file(uri, path, sizeof(path)) || strcmp(uri, "/api/sse") == 0;
106}
107
108static int proxy_event_handler(struct mg_connection *conn, enum mg_event ev) {
109  static const char target_url[] = "http://cesanta.com";
110  static int target_url_size = sizeof(target_url) - 1;
111  const char *host;
112
113  switch (ev) {
114    case MG_REQUEST:
115      host = mg_get_header(conn, "Host");
116      printf("[%s] [%s] [%s]\n", conn->request_method, conn->uri,
117             host == NULL ? "" : host);
118      if (strstr(conn->uri, "/qqq") != NULL) s_received_signal = SIGTERM;
119
120      // Proxied HTTPS requests use "CONNECT foo.com:443"
121      // Proxied HTTP requests use "GET http://..... "
122      // Serve requests for target_url from the local FS.
123      if (memcmp(conn->uri, target_url, target_url_size) == 0 &&
124          is_resource_present_locally(conn->uri + target_url_size)) {
125        conn->uri += target_url_size;   // Leave only path in the URI
126      }
127
128      if (strcmp(conn->uri, "/api/sse") == 0) {
129        conn->connection_param = SSE_CONNECTION;
130        mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n"
131                  "Content-Type: text/event-stream\r\n"
132                  "Cache-Control: no-cache\r\n\r\n");
133        return MG_MORE;
134      }
135
136      if (host != NULL && strstr(host, "cesanta") != NULL) {
137        return try_to_serve_locally(conn);
138      }
139
140      // Enable man-in-the-middle SSL mode for oracle.com
141      if (!strcmp(conn->request_method, "CONNECT") &&
142          !strcmp(host, "oracle.com")) {
143        mg_terminate_ssl(conn, "ssl_cert.pem");  // MUST return MG_MORE after
144        return MG_MORE;
145      }
146
147      return MG_FALSE;
148    case MG_AUTH:
149      return MG_TRUE;
150    default:
151      return MG_FALSE;
152  }
153}
154
155static void setopt(struct mg_server *s, const char *opt, const char *val) {
156  const char *err_msg = mg_set_option(s, opt, val);
157  if (err_msg != NULL) {
158    elog(1, "Error setting [%s]: [%s]", opt, err_msg);
159  }
160}
161
162int main(int argc, char *argv[]) {
163  const char *port = "2014", *dump = NULL, *root = "proxy_web_root";
164  int i;
165
166  // Parse command line options
167  for (i = 1; i < argc; i++) {
168    if (strcmp(argv[i], "-port") == 0 && i + 1 < argc) {
169      port = argv[++i];
170    } else if (strcmp(argv[i], "-root") == 0 && i + 1 < argc) {
171      root = argv[++i];
172    } else if (strcmp(argv[i], "-dump") == 0 && i + 1 < argc) {
173      dump = argv[++i];
174    } else {
175      elog(1, "Usage: %s [-cert FILE] [-ca_cert FILE] [-port PORT]", argv[0]);
176    }
177  }
178
179  signal(SIGTERM, signal_handler);
180  signal(SIGINT, signal_handler);
181
182  // Create and configure proxy server
183  s_server = mg_create_server(NULL, &proxy_event_handler);
184  setopt(s_server, "enable_proxy",        "yes");
185  setopt(s_server, "document_root",       root);
186  setopt(s_server, "listening_port",      port);
187  setopt(s_server, "hexdump_file",        dump);
188
189  // Start two SSE pushing threads
190  mg_start_thread(sse_pusher_thread_func, (void *) "sse_pusher_thread_1");
191  mg_start_thread(sse_pusher_thread_func, (void *) "sse_pusher_thread_2");
192
193  // Start serving in the main thread
194  printf("Starting on port %s\n", mg_get_option(s_server, "listening_port"));
195  while (s_received_signal == 0) {
196    mg_poll_server(s_server, 1000);
197  }
198  printf("Existing on signal %d\n", s_received_signal);
199  mg_destroy_server(&s_server);
200
201  return EXIT_SUCCESS;
202}
trunk/3rdparty/mongoose/examples/proxy_server/proxy_web_root/app1/index.html
r0r250110
1<html>
2<head>
3  <title>App1 Index</title>
4  <style>
5    img { height: 40px; }
6  </style>
7</head>
8<body>
9
10  <h1>App1 index page. Served locally from the the proxy server filesystem</h1>
11
12  <p>image that references non-existent local resource. Forwarded to
13    the 'real' proxy target:</p>
14    <img src="http://cesanta.com/images/logo.png" />
15
16  <p>Google logo via HTTPS (external resource, served by remote host):</p>
17  <img src="https://www.google.ie/images/srpr/logo11w.png" />
18
19  <p>Same image via HTTP:</p>
20  <img src="http://www.google.ie/images/srpr/logo11w.png" />
21
22</body>
23</html>
trunk/3rdparty/mongoose/examples/proxy_server/proxy_web_root/app2/index.html
r0r250110
1<html>
2<head>
3  <title>App2 Index</title>
4  <meta charset="utf-8">
5  <script>
6  window.onload = function() {
7    // Using secure websocket connection, wss://
8    var ws = new WebSocket('wss://echo.websocket.org');
9    var div = document.getElementById('events');
10    ws.onmessage = function(ev) {
11      var el = document.createElement('div');
12      el.innerHTML = 'websocket message: ' + ev.data;
13      div.appendChild(el);
14      // Keep only last 5 messages in the list
15      while (div.childNodes.length > 5) div.removeChild(div.firstChild);
16    };
17
18    // Send random stuff to the websocket connection periodically.
19    // websocket server much echo that stuff back.
20    window.setInterval(function() {
21      var d = new Date();
22      ws.send(d.toString());
23    }, 1000);
24  };
25  </script>
26</head>
27<body>
28  <h1>App2 index page. Served locally from the
29    the proxy's filesystem.</h1>
30  <p>
31    Following div shows proxy forwarding of websocket connection, served by
32    ws://echo.websocket.org:
33  </p>
34
35  <div id="events"></div>
36</body>
37</html>
trunk/3rdparty/mongoose/examples/proxy_server/proxy_web_root/index.html
r0r250110
1<html>
2<head>
3  <title> proxy index </title>
4  <script type="text/javascript">
5  window.onload = function() {
6    var es = new EventSource("/api/sse");
7    var div = document.getElementById('events');
8    es.onmessage = function(ev) {
9      var el = document.createElement('div');
10      el.innerHTML = 'sse message: ' + ev.data;
11      div.appendChild(el);
12      // Keep only last 5 messages in the list
13      while (div.childNodes.length > 5) div.removeChild(div.firstChild);
14    };
15  };
16  </script>
17</head>
18<body>
19  <h1> proxy index page.</h1>
20  <ul>
21    <li><a href="app1">App1</a> - App1 root</li>
22    <li><a href="app2">App2</a> - App2 root</li>
23  </ul>
24
25  <h2>SSE pushes, done by separate threads at random times:</h2>
26  <div id="events"></div>
27
28</body>
29</html>
trunk/3rdparty/mongoose/examples/proxy_server/ssl_cert.pem
r0r250110
1-----BEGIN RSA PRIVATE KEY-----
2MIIEogIBAAKCAQEAwONaLOP7EdegqjRuQKSDXzvHmFMZfBufjhELhNjo5KsL4ieH
3hMSGCcSV6y32hzhqR5lvTViaQez+xhc58NZRu+OUgEhodRBW/vAOjpz/xdMz5HaC
4EhP3E9W1pkitVseS8B5rrgJo1BfCGai1fPav1nutPq2Kj7vMy24+g460Lonf6ln1
5di4aTIRtAqXtUU6RFpPJP35PkCXbTK65O8HJSxxt/XtfoezHCU5+UIwmZGYx46UB
6Wzg3IfK6bGPSiHU3pdiTol0uMPt/GUK+x4NyZJ4/ImsNAicRwMBdja4ywHKXJehH
7gXBthsVIHbL21x+4ibsg9eVM/XioTV6tW3IrdwIDAQABAoIBACFfdLutmkQFBcRN
8HAJNNHmmsyr0vcUOVnXTFyYeDXV67qxrYHQlOHe6LqIpKq1Mon7O2kYMnWvooFAP
9trOnsS6L+qaTYJdYg2TKjgo4ubw1hZXytyB/mdExuaMSkgMgtpia+tB5lD+V+LxN
10x1DesZ+veFMO3Zluyckswt4qM5yVa04YFrt31H0E1rJfIen61lidXIKYmHHWuRxK
11SadjFfbcqJ6P9ZF22BOkleg5Fm5NaxJmyQynOWaAkSZa5w1XySFfRjRfsbDr64G6
12+LSG8YtRuvfxnvUNhynVPHcpE40eiPo6v8Ho6yZKXpV5klCKciodXAORsswSoGJa
13N3nnu/ECgYEA6Yb2rM3QUEPIALdL8f/OzZ1GBSdiQB2WSAxzl9pR/dLF2H+0pitS
14to0830mk92ppVmRVD3JGxYDRZQ56tlFXyGaCzJBMRIcsotAhBoNbjV0i9n5bLJYf
15BmjU9yvWcgsTt0tr3B0FrtYyp2tCvwHqlxvFpFdUCj2oRw2uGpkhmNkCgYEA03M6
16WxFhsix3y6eVCVvShfbLBSOqp8l0qiTEty+dgVQcWN4CO/5eyaZXKxlCG9KMmKxy
17Yx+YgxZrDhfaZ0cxhHGPRKEAxM3IKwT2C8/wCaSiLWXZZpTifnSD99vtOt4wEfrG
18+AghNd5kamFiM9tU0AyvhJc2vdJFuXrfeC7ntM8CgYBGDA+t4cZcbRhu7ow/OKYF
19kulP3nJgHP/Y+LMrl3cEldZ2jEfZmCElVNQvfd2XwTl7injhOzvzPiKRF3jDez7D
20g8w0JAxceddvttJRK9GoY4l7OoeKpjUELSnEQkf+yUfOsTbXPXVY7jMfeNL6jE6b
21qN7t3qv8rmXtejMBE3G6cQKBgGR5W2BMiRSlxqKx1cKlrApV87BUe1HRCyuR3xuA
22d6Item7Lx1oEi7vb242yKdSYnpApWQ06xTh83Y/Ly87JaIEbiM0+h+P8OEIg0F1a
23iB+86AcUX1I8KseVy+Np0HbpfwP8GrFfA5DaRPK7pXMopEtby8cAJ1XZZaI1/ZvZ
24BebHAoGAcQU9WvCkT+nIp9FpXfBybYUsvgkaizMIqp66/l3GYgYAq8p1VLGvN4v5
25ec0dW58SJrCpqsM3NP78DtEzQf9OOsk+FsjBFzDU2RkeUreyt2/nQBj/2mN/+hEy
26hYN0Zii2yTb63jGxKY6gH1R/r9dL8kXaJmcZrfSa3AgywnteJWg=
27-----END RSA PRIVATE KEY-----
28-----BEGIN CERTIFICATE-----
29MIIDBjCCAe4CCQCX05m0b053QzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJB
30VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
31cyBQdHkgTHRkMB4XDTA4MTIwNzEwMjUyMloXDTE4MTIwNTEwMjUyMlowRTELMAkG
32A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
33IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
34AMDjWizj+xHXoKo0bkCkg187x5hTGXwbn44RC4TY6OSrC+Inh4TEhgnElest9oc4
35akeZb01YmkHs/sYXOfDWUbvjlIBIaHUQVv7wDo6c/8XTM+R2ghIT9xPVtaZIrVbH
36kvAea64CaNQXwhmotXz2r9Z7rT6tio+7zMtuPoOOtC6J3+pZ9XYuGkyEbQKl7VFO
37kRaTyT9+T5Al20yuuTvByUscbf17X6HsxwlOflCMJmRmMeOlAVs4NyHyumxj0oh1
38N6XYk6JdLjD7fxlCvseDcmSePyJrDQInEcDAXY2uMsBylyXoR4FwbYbFSB2y9tcf
39uIm7IPXlTP14qE1erVtyK3cCAwEAATANBgkqhkiG9w0BAQQFAAOCAQEAW4yZdqpB
40oIdiuXRosr86Sg9FiMg/cn+2OwQ0QIaA8ZBwKsc+wIIHEgXCS8J6316BGQeUvMD+
41plNe0r4GWzzmlDMdobeQ5arPRB89qd9skE6pAMdLg3FyyfEjz3A0VpskolW5VBMr
42P5R7uJ1FLgH12RyAjZCWYcCRqEMOffqvyMCH6oAjyDmQOA5IssRKX/HsHntSH/HW
43W7slTcP45ty1b44Nq22/ubYk0CJRQgqKOIQ3cLgPomN1jNFQbAbfVTaK1DpEysrQ
445V8a8gNW+3sVZmV6d1Mj3pN2Le62wUKuV2g6BNU7iiwcoY8HI68aRxz2hVMS+t5f
45SEGI4JSxV56lYg==
46-----END CERTIFICATE-----
47-----BEGIN DH PARAMETERS-----
48MEYCQQD+ef8hZ4XbdoyIpJyCTF2UrUEfX6mYDvxuS5O1UNYcslUqlj6JkA11e/yS
496DK8Z86W6mSj5CEk4IjbyEOECXH7AgEC
50-----END DH PARAMETERS-----
trunk/3rdparty/mongoose/examples/restful_api/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = restful_api
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8$(PROG): $(SOURCES)
9   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
10
11clean:
12   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
trunk/3rdparty/mongoose/examples/restful_api/index.html
r0r250110
1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="utf-8" />
5  <title>RESTful API demo</title>
6  <meta name="viewport" content="width=device-width, initial-scale=1" />
7  <style type="text/css">
8    * { outline: none; font: 16px/1.4 Helvetica, Arial, sans-serif; }
9    body {
10      background-color: #cde; margin: 0;
11      padding: 0; font: 16px/1.4 Helvetica, Arial, sans-serif;
12    }
13    div.content {
14      width: 800px; margin: 2em auto; padding: 20px 50px;
15      background-color: #fff; border-radius: 1em;
16    }
17    label { display: inline-block; min-width: 7em; }
18    input { border: 1px solid #ccc; padding: 0.2em; }
19    a:link, a:visited { color: #69c; text-decoration: none; }
20    @media (max-width: 700px) {
21      body { background-color: #fff; }
22      div.content { width: auto; margin: 0 auto; padding: 1em; }
23    }
24</style>
25
26<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
27<script language="javascript" type="text/javascript">
28  jQuery(function() {
29
30    $(document).on('keyup', '#n1, #n2', function() {
31      $.ajax({
32        url: '/api/sum',
33        method: 'POST',
34        dataType: 'json',
35        data: { n1: $('#n1').val(), n2: $('#n2').val() },
36        success: function(json) {
37          $('#result').html(json.result);
38        }
39      });
40    });
41
42  });
43</script>
44</head>
45<body>
46  <div class="content">
47    <h1>RESTful API demo.</h1>
48
49    <p>
50      This page demonstrates how Mongoose web server could be used to implement
51      RESTful APIs. Enter numbers below, and press Submit. Browser will send
52      two numbers to <tt>/api/sum</tt> URI, Mongoose calclulates the sum of
53      two and returns the result.
54    </p>
55
56    <div>
57      <label>Number 1:</label> <input type="text" id="n1" />
58    </div><div>
59      <label>Number 2:</label> <input type="text" id="n2" />
60    </div><div>
61     <label>Result:</label> <span id="result">&nbsp;</span>
62    </div><div>
63
64  </div>
65</body>
66</html>
trunk/3rdparty/mongoose/examples/restful_api/restful_api.c
r0r250110
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include "mongoose.h"
5
6static const char *s_no_cache_header =
7  "Cache-Control: max-age=0, post-check=0, "
8  "pre-check=0, no-store, no-cache, must-revalidate\r\n";
9
10static void handle_restful_call(struct mg_connection *conn) {
11  char n1[100], n2[100];
12
13  // Get form variables
14  mg_get_var(conn, "n1", n1, sizeof(n1));
15  mg_get_var(conn, "n2", n2, sizeof(n2));
16
17  mg_printf_data(conn, "{ \"result\": %lf }", strtod(n1, NULL) + strtod(n2, NULL));
18}
19
20static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
21  switch (ev) {
22    case MG_AUTH: return MG_TRUE;
23    case MG_REQUEST:
24      if (!strcmp(conn->uri, "/api/sum")) {
25        handle_restful_call(conn);
26        return MG_TRUE;
27      }
28      mg_send_file(conn, "index.html", s_no_cache_header);
29      return MG_MORE;
30    default: return MG_FALSE;
31  }
32}
33
34int main(void) {
35  struct mg_server *server;
36
37  // Create and configure the server
38  server = mg_create_server(NULL, ev_handler);
39  mg_set_option(server, "listening_port", "8000");
40
41  // Serve request. Hit Ctrl-C to terminate the program
42  printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
43  for (;;) {
44    mg_poll_server(server, 1000);
45  }
46
47  // Cleanup, and free server instance
48  mg_destroy_server(&server);
49
50  return 0;
51}
trunk/3rdparty/mongoose/examples/send_file/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = send_file
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8all: $(PROG)
9
10run: $(PROG)
11   ./$(PROG)
12
13$(PROG): $(SOURCES) Makefile
14   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
15
16win:
17   wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe
18   wine $(PROG).exe
19
20clean:
21   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc*
trunk/3rdparty/mongoose/examples/send_file/send_file.c
r0r250110
1// Copyright (c) 2014 Cesanta Software
2// All rights reserved
3//
4// This example demostrates how to send arbitrary files to the client.
5
6#include "mongoose.h"
7
8static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
9  switch (ev) {
10    case MG_REQUEST:
11      mg_send_file(conn, "send_file.c", NULL);  // Also could be a dir, or CGI
12      return MG_MORE; // It is important to return MG_MORE after mg_send_file!
13    case MG_AUTH: return MG_TRUE;
14    default: return MG_FALSE;
15  }
16}
17
18int main(void) {
19  struct mg_server *server = mg_create_server(NULL, ev_handler);
20  mg_set_option(server, "listening_port", "8080");
21
22  printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
23  for (;;) mg_poll_server(server, 1000);
24  mg_destroy_server(&server);
25
26  return 0;
27}
trunk/3rdparty/mongoose/examples/web_server/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = web_server
5CFLAGS = -W -Wall -I../.. -g -O0  $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7OPENSSL_FLAGS = -DNS_ENABLE_SSL -lssl
8
9# PolarSSL paths and flags
10POLARSSL_PATH = /usr/local
11POLARSSLCOMPAT_PATH = ./../../../polar
12SOURCES_POLAR = $(SOURCES) $(POLARSSLCOMPAT_PATH)/polarssl_compat.c
13INCDIR_POLAR = -I$(POLARSSLCOMPAT_PATH) -I$(POLARSSL_PATH)/include
14LDFLAGS_POLAR = -L$(POLARSSL_PATH)/lib -lmbedtls
15CFLAGS_POLAR = $(CFLAGS) $(INCDIR_POLAR) -DNS_ENABLE_SSL
16
17$(PROG): $(SOURCES)
18   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
19
20$(PROG).exe: $(SOURCES)
21   cl -Fo $(PROG) $(SOURCES) -nologo -MD -I../..
22
23openssl:
24   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) $(OPENSSL_FLAGS)
25
26polarssl:
27   $(CC) -o $(PROG) $(SOURCES_POLAR) $(LDFLAGS_POLAR) $(CFLAGS_POLAR)
28
29clean:
30   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
trunk/3rdparty/mongoose/examples/web_server/certs/cert.pem
r0r250110
1-----BEGIN CERTIFICATE-----
2MIIC+zCCAeOgAwIBAgIJAPhB8jbL+G82MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
3BAMMCTEyNy4wLjAuMTAeFw0xNTAzMDYxMjQzMzNaFw0yNTAzMDMxMjQzMzNaMBQx
4EjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
5ggEBALi3b3daMgzUEROKob1Caf68i+//cTRkPdBJv2cOBak21CdQzY0Nvx73GLzf
65TKB347BCHNbYRKGJXDbYdmFp20/WeBHkY7RS3Ad2Q5lzyx66u9PxNx7hJIiqBgF
758VU+E3o/I+o8QNIoOT+wtCiq3Nwkp+zGBJmS32rzMEV9bcKxSzMrkfRhF+XAREd
8DwM9vfPg6WRb/b+vv06uvVwcw390RprLautGfBdaRddVYkIAKJGRRTqZAvTRFW1J
9FcIVOxlN+iA7qP7xjr3tUP78qMmlu0MXsHrUR2cgfveZK2sdUW5G804yHsU5sC8l
10FbtLKMEOyLsk2bEIScOXgum7g2sCAwEAAaNQME4wHQYDVR0OBBYEFHtLzUqAsXkH
11Il8S5sMhJuVhRJLdMB8GA1UdIwQYMBaAFHtLzUqAsXkHIl8S5sMhJuVhRJLdMAwG
12A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEzHc0AOr+qs0OFvWMfcSMi7
13O/aYlLS6f7Sos+lli69+61EcmCTJVarVeAVUsAoqmzBKDbeOpAK1hGX6/GGcXjR2
14BmuU0hUKyX9l1lwdMKU45BayH/riElwnvAyj2GxKoPpdIjlHns4SAITOCUx9NfpM
15agd7kjolton0ZQ5DI/2a43PkqHv1lY4Dp60wJlxit9U68bsGOycCJ/BsAyrPROb2
16D1MkpMBIdfHc8uxRywM3/l9buFX8yrrMUGOYKgfjDwdzbj0iwIixoGpHL7IfeBtu
17dvGO/g2rEhbtAP+xIgOR3GvzqjZh30er3no7zjDMn65tTME18Aq3tBQY7vPDKms=
18-----END CERTIFICATE-----
19-----BEGIN PRIVATE KEY-----
20MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4t293WjIM1BET
21iqG9Qmn+vIvv/3E0ZD3QSb9nDgWpNtQnUM2NDb8e9xi83+Uygd+OwQhzW2EShiVw
2222HZhadtP1ngR5GO0UtwHdkOZc8seurvT8Tce4SSIqgYBefFVPhN6PyPqPEDSKDk
23/sLQoqtzcJKfsxgSZkt9q8zBFfW3CsUszK5H0YRflwERHQ8DPb3z4OlkW/2/r79O
24rr1cHMN/dEaay2rrRnwXWkXXVWJCACiRkUU6mQL00RVtSRXCFTsZTfogO6j+8Y69
257VD+/KjJpbtDF7B61EdnIH73mStrHVFuRvNOMh7FObAvJRW7SyjBDsi7JNmxCEnD
26l4Lpu4NrAgMBAAECggEAaFuqbAHXOQwuwZ2XFzgIblTTsrncmT7w9VZU/sIbTKif
27X771AnX7vmDX5w2PjeN2DE7emV3NEAwd5w7qz1wFZWFfQ6jrgYaZWjRixxGZ5IVl
28aeLlU7OtCGrwEPJ1KTWCO3IgDoHh+Hr1+6o7Imhk+QlmrTcfqHWGvO9s9MGVWt2S
29RLAnSTFiOe5brdJnmlqq1sKZmnLmpydBaPUOYpZGAgRasrjdMZB+lZOazd1x23/5
30GAcm0rDREMnO9b2Jt+TNEZHT6d5KpVoExztZEZj8QCLXoic/SpFIqHGtpNlQXa+d
31BVqgQbIYjO8ldldxZ8YIyJDVF+9e/uBBwu6jBIIsEQKBgQDspEHCyyuh4LG+7BbZ
32eXlsfCxPTM6K9w31ZwHAwRtAuGqrOrE+pFJG9CEsFZbAI1aOGmZZdjexuSMcOlXl
33TIVJTQHoFtoGEsanYEXO4O1t02Ab/DCYSpXusXUraRBRPpsTC77Sh5mxLUNd23d9
34NhnDBuwChAmC+IYexjkXeqPYFwKBgQDH08PEd+2PVo4MD8UVKUlEcgoyCr6ESiyp
35HfYyhhfd5x3DbZLoKCkunDfBs/hakQk8DA2nn4tl4ZjfmzXmX0EBx+E5YTdYshW7
36ZcjN5x64B5PEOAR/NZA6agNlp3XGXXXgX+gnN6pgE49eVU22nZ4G+QBKD6NcCviB
37LBPUxMbvzQKBgHgZYRqonGtaqzsXfP1AjmSFnMNeWtDiU95BOf2Gw/sT3WcrsXr2
38UJ+cFR3XkxvOk4YpVdp/igKT0ILqBGAMdvTdtWMB/gLpEpMt5B/7veRoS7XIRy1z
39ZSawP6QZfWOOX4vKAT29/j2SmEcRNFKC245EfBFGy8EBuqfxuFX3MyJfAoGBAJ0y
40tjsErVmpma1baosvI3g4zlR3p1CimWehLmCopHXorr1iocMIdP0535L+ZU258y3N
41vaA0HpFTW9PsYgaMwLMJ7uAY3lVkIzx84e849i2HqHMgLkl0dbW+WFXL2xblxylv
42yU2wuNNED/EB4lTawcpycAvTKYvrBXt4lVE4S9exAoGAGl6vZV3zyw4jpIw4uDfk
43LTPYUrghFDDGKExyeOnC/W9pqR2veqzfBz02C3jqwhewoqgAcnNc2sg0rJmM+6Oz
44Z2mmGZTHO9xR++7+W7e8AkQBbS6TB8a+7yNcM4USLP+b9sX5N+8gFhFs9tG7j/no
45G44qLsJ/yve7/QsOA37uEMs=
46-----END PRIVATE KEY-----
trunk/3rdparty/mongoose/examples/web_server/web_server.c
r0r250110
1// Copyright (c) 2004-2013 Sergey Lyubka
2// Copyright (c) 2013-2014 Cesanta Software Limited
3
4#undef UNICODE                    // Use ANSI WinAPI functions
5#undef _UNICODE                   // Use multibyte encoding on Windows
6#define _MBCS                     // Use multibyte encoding on Windows
7#define _WIN32_WINNT 0x500        // Enable MIIM_BITMAP
8#define _CRT_SECURE_NO_WARNINGS   // Disable deprecation warning in VS2005
9#define _XOPEN_SOURCE 600         // For PATH_MAX on linux
10#undef WIN32_LEAN_AND_MEAN        // Let windows.h always include winsock2.h
11
12#include <sys/stat.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <signal.h>
16#include <string.h>
17#include <errno.h>
18#include <limits.h>
19#include <stddef.h>
20#include <stdarg.h>
21#include <ctype.h>
22#include <time.h>
23
24#include "mongoose.h"
25
26#ifdef _WIN32
27#include <windows.h>
28#include <direct.h>  // For chdir()
29#include <winsvc.h>
30#include <shlobj.h>
31
32#ifndef PATH_MAX
33#define PATH_MAX MAX_PATH
34#endif
35
36#ifndef S_ISDIR
37#define S_ISDIR(x) ((x) & _S_IFDIR)
38#endif
39
40#define DIRSEP '\\'
41#define snprintf _snprintf
42#define vsnprintf _vsnprintf
43#ifndef sleep
44#define sleep(x) Sleep((x) * 1000)
45#endif
46#define abs_path(rel, abs, abs_size) _fullpath((abs), (rel), (abs_size))
47#define SIGCHLD 0
48typedef struct _stat file_stat_t;
49#define stat(x, y) _stat((x), (y))
50#else
51typedef struct stat file_stat_t;
52#include <sys/wait.h>
53#include <unistd.h>
54
55#ifdef IOS
56#include <ifaddrs.h>
57#endif
58
59#define DIRSEP '/'
60#define __cdecl
61#define abs_path(rel, abs, abs_size) realpath((rel), (abs))
62#endif // _WIN32
63
64#define MAX_OPTIONS 100
65#define MAX_CONF_FILE_LINE_SIZE (8 * 1024)
66
67#ifndef MVER
68#define MVER MONGOOSE_VERSION
69#endif
70
71static int exit_flag;
72static char server_name[50];        // Set by init_server_name()
73static char s_config_file[PATH_MAX];  // Set by process_command_line_arguments
74static struct mg_server *server;    // Set by start_mongoose()
75static const char *s_default_document_root = ".";
76static const char *s_default_listening_port = "8080";
77static char **s_argv = { NULL };
78
79static void set_options(char *argv[]);
80
81#if !defined(CONFIG_FILE)
82#define CONFIG_FILE "mongoose.conf"
83#endif /* !CONFIG_FILE */
84
85static void __cdecl signal_handler(int sig_num) {
86  // Reinstantiate signal handler
87  signal(sig_num, signal_handler);
88
89#ifndef _WIN32
90  // Do not do the trick with ignoring SIGCHLD, cause not all OSes (e.g. QNX)
91  // reap zombies if SIGCHLD is ignored. On QNX, for example, waitpid()
92  // fails if SIGCHLD is ignored, making system() non-functional.
93  if (sig_num == SIGCHLD) {
94    do {} while (waitpid(-1, &sig_num, WNOHANG) > 0);
95  } else
96#endif
97  { exit_flag = sig_num; }
98}
99
100static void vnotify(const char *fmt, va_list ap, int must_exit) {
101  vfprintf(stderr, fmt, ap);
102  fputc('\n', stderr);
103  if (must_exit) {
104    exit(EXIT_FAILURE);
105  }
106}
107
108static void notify(const char *fmt, ...) {
109  va_list ap;
110  va_start(ap, fmt);
111  vnotify(fmt, ap, 0);
112  va_end(ap);
113}
114
115static void die(const char *fmt, ...) {
116  va_list ap;
117  va_start(ap, fmt);
118  vnotify(fmt, ap, 1);
119  va_end(ap);
120}
121
122static void show_usage_and_exit(void) {
123  const char **names;
124  int i;
125
126  fprintf(stderr, "Mongoose version %s (c) Sergey Lyubka, built on %s\n",
127          MVER, __DATE__);
128  fprintf(stderr, "Usage:\n");
129#if !defined(MONGOOSE_NO_AUTH) && !defined(MONGOOSE_NO_FILESYSTEM)
130  fprintf(stderr, "  mongoose -A <htpasswd_file> <realm> <user> <passwd>\n");
131#endif
132  fprintf(stderr, "  mongoose [config_file]\n");
133  fprintf(stderr, "  mongoose [-option value ...]\n");
134  fprintf(stderr, "\nOPTIONS:\n");
135
136  names = mg_get_valid_option_names();
137  for (i = 0; names[i] != NULL; i += 2) {
138    fprintf(stderr, "  -%s %s\n",
139            names[i], names[i + 1] == NULL ? "<empty>" : names[i + 1]);
140  }
141  exit(EXIT_FAILURE);
142}
143
144#define EV_HANDLER NULL
145
146static char *sdup(const char *str) {
147  char *p;
148  if ((p = (char *) malloc(strlen(str) + 1)) != NULL) {
149    strcpy(p, str);
150  }
151  return p;
152}
153
154static void set_option(char **options, const char *name, const char *value) {
155  int i;
156
157  for (i = 0; i < MAX_OPTIONS - 3; i++) {
158    if (options[i] == NULL) {
159      options[i] = sdup(name);
160      options[i + 1] = sdup(value);
161      options[i + 2] = NULL;
162      break;
163    } else if (!strcmp(options[i], name)) {
164      free(options[i + 1]);
165      options[i + 1] = sdup(value);
166      break;
167    }
168  }
169
170  if (i == MAX_OPTIONS - 3) {
171    die("%s", "Too many options specified");
172  }
173}
174
175static void process_command_line_arguments(char *argv[], char **options) {
176  char line[MAX_CONF_FILE_LINE_SIZE], opt[sizeof(line)], val[sizeof(line)],
177       *p, cpath[PATH_MAX];
178  FILE *fp = NULL;
179  size_t i, cmd_line_opts_start = 1, line_no = 0;
180
181  // Should we use a config file ?
182  if (argv[1] != NULL && argv[1][0] != '-') {
183    snprintf(cpath, sizeof(cpath), "%s", argv[1]);
184    cmd_line_opts_start = 2;
185  } else if ((p = strrchr(argv[0], DIRSEP)) == NULL) {
186    // No command line flags specified. Look where binary lives
187    snprintf(cpath, sizeof(cpath), "%s", CONFIG_FILE);
188  } else {
189    snprintf(cpath, sizeof(cpath), "%.*s%c%s",
190             (int) (p - argv[0]), argv[0], DIRSEP, CONFIG_FILE);
191  }
192  abs_path(cpath, s_config_file, sizeof(s_config_file));
193
194  fp = fopen(s_config_file, "r");
195
196  // If config file was set in command line and open failed, die
197  if (cmd_line_opts_start == 2 && fp == NULL) {
198    die("Cannot open config file %s: %s", s_config_file, strerror(errno));
199  }
200
201  // Load config file settings first
202  if (fp != NULL) {
203    fprintf(stderr, "Loading config file %s\n", s_config_file);
204
205    // Loop over the lines in config file
206    while (fgets(line, sizeof(line), fp) != NULL) {
207      line_no++;
208
209      // Ignore empty lines and comments
210      for (i = 0; isspace(* (unsigned char *) &line[i]); ) i++;
211      if (line[i] == '#' || line[i] == '\0') {
212        continue;
213      }
214
215      if (sscanf(line, "%s %[^\r\n#]", opt, val) != 2) {
216        printf("%s: line %d is invalid, ignoring it:\n %s",
217               s_config_file, (int) line_no, line);
218      } else {
219        set_option(options, opt, val);
220      }
221    }
222
223    fclose(fp);
224  }
225
226  // If we're under MacOS and started by launchd, then the second
227  // argument is process serial number, -psn_.....
228  // In this case, don't process arguments at all.
229  if (argv[1] == NULL || memcmp(argv[1], "-psn_", 5) != 0) {
230    // Handle command line flags.
231    // They override config file and default settings.
232    for (i = cmd_line_opts_start; argv[i] != NULL; i += 2) {
233      if (argv[i][0] != '-' || argv[i + 1] == NULL) {
234        show_usage_and_exit();
235      }
236      set_option(options, &argv[i][1], argv[i + 1]);
237    }
238  }
239}
240
241static void init_server_name(void) {
242  const char *descr = "";
243  snprintf(server_name, sizeof(server_name), "Mongoose web server v.%s%s",
244           MVER, descr);
245}
246
247static int is_path_absolute(const char *path) {
248#ifdef _WIN32
249  return path != NULL &&
250    ((path[0] == '\\' && path[1] == '\\') ||  // UNC path, e.g. \\server\dir
251     (isalpha(path[0]) && path[1] == ':' && path[2] == '\\'));  // E.g. X:\dir
252#else
253  return path != NULL && path[0] == '/';
254#endif
255}
256
257static char *get_option(char **options, const char *option_name) {
258  int i;
259
260  for (i = 0; options[i] != NULL; i++)
261    if (!strcmp(options[i], option_name))
262      return options[i + 1];
263
264  return NULL;
265}
266
267static void *serving_thread_func(void *param) {
268  struct mg_server *srv = (struct mg_server *) param;
269  while (exit_flag == 0) {
270    mg_poll_server(srv, 1000);
271  }
272  return NULL;
273}
274
275static int path_exists(const char *path, int is_dir) {
276  file_stat_t st;
277  return path == NULL || (stat(path, &st) == 0 &&
278                          ((S_ISDIR(st.st_mode) ? 1 : 0) == is_dir));
279}
280
281static void verify_existence(char **options, const char *name, int is_dir) {
282  const char *path = get_option(options, name);
283  if (!path_exists(path, is_dir)) {
284    notify("Invalid path for %s: [%s]: (%s). Make sure that path is either "
285           "absolute, or it is relative to mongoose executable.",
286           name, path, strerror(errno));
287  }
288}
289
290static void set_absolute_path(char *options[], const char *option_name) {
291  char path[PATH_MAX], abs[PATH_MAX], *option_value;
292  const char *p;
293
294  // Check whether option is already set
295  option_value = get_option(options, option_name);
296
297  // If option is already set and it is an absolute path,
298  // leave it as it is -- it's already absolute.
299  if (option_value != NULL && !is_path_absolute(option_value)) {
300    // Not absolute. Use the directory where mongoose executable lives
301    // be the relative directory for everything.
302    // Extract mongoose executable directory into path.
303    if ((p = strrchr(s_config_file, DIRSEP)) == NULL) {
304      getcwd(path, sizeof(path));
305    } else {
306      snprintf(path, sizeof(path), "%.*s", (int) (p - s_config_file),
307               s_config_file);
308    }
309
310    strncat(path, "/", sizeof(path) - 1);
311    strncat(path, option_value, sizeof(path) - 1);
312
313    // Absolutize the path, and set the option
314    abs_path(path, abs, sizeof(abs));
315    set_option(options, option_name, abs);
316  }
317}
318
319#if !defined(MONGOOSE_NO_AUTH) && !defined(MONGOOSE_NO_FILESYSTEM)
320int modify_passwords_file(const char *fname, const char *domain,
321                          const char *user, const char *pass) {
322  int found;
323  char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX];
324  FILE *fp, *fp2;
325
326  found = 0;
327  fp = fp2 = NULL;
328
329  // Regard empty password as no password - remove user record.
330  if (pass != NULL && pass[0] == '\0') {
331    pass = NULL;
332  }
333
334  (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
335
336  // Create the file if does not exist
337  if ((fp = fopen(fname, "a+")) != NULL) {
338    fclose(fp);
339  }
340
341  // Open the given file and temporary file
342  if ((fp = fopen(fname, "r")) == NULL) {
343    return 0;
344  } else if ((fp2 = fopen(tmp, "w+")) == NULL) {
345    fclose(fp);
346    return 0;
347  }
348
349  // Copy the stuff to temporary file
350  while (fgets(line, sizeof(line), fp) != NULL) {
351    if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) {
352      continue;
353    }
354
355    if (!strcmp(u, user) && !strcmp(d, domain)) {
356      found++;
357      if (pass != NULL) {
358        mg_md5(ha1, user, ":", domain, ":", pass, NULL);
359        fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
360      }
361    } else {
362      fprintf(fp2, "%s", line);
363    }
364  }
365
366  // If new user, just add it
367  if (!found && pass != NULL) {
368    mg_md5(ha1, user, ":", domain, ":", pass, NULL);
369    fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
370  }
371
372  // Close files
373  fclose(fp);
374  fclose(fp2);
375
376  // Put the temp file in place of real file
377  remove(fname);
378  rename(tmp, fname);
379
380  return 1;
381}
382#endif
383
384static void start_mongoose(int argc, char *argv[]) {
385  s_argv = argv;
386  if ((server = mg_create_server(NULL, EV_HANDLER)) == NULL) {
387    die("%s", "Failed to start Mongoose.");
388  }
389
390#if !defined(MONGOOSE_NO_AUTH) && !defined(MONGOOSE_NO_FILESYSTEM)
391  // Edit passwords file if -A option is specified
392  if (argc > 1 && !strcmp(argv[1], "-A")) {
393    if (argc != 6) {
394      show_usage_and_exit();
395    }
396    exit(modify_passwords_file(argv[2], argv[3], argv[4], argv[5]) ?
397         EXIT_SUCCESS : EXIT_FAILURE);
398  }
399#endif
400
401  // Show usage if -h or --help options are specified
402  if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
403    show_usage_and_exit();
404  }
405  set_options(argv);
406}
407
408static void set_options(char *argv[]) {
409  char *options[MAX_OPTIONS];
410  int i;
411
412  options[0] = NULL;
413  set_option(options, "document_root", s_default_document_root);
414  set_option(options, "listening_port", s_default_listening_port);
415
416  // Update config based on command line arguments
417  process_command_line_arguments(argv, options);
418
419  // Make sure we have absolute paths for files and directories
420  // https://github.com/valenok/mongoose/issues/181
421  set_absolute_path(options, "document_root");
422  set_absolute_path(options, "dav_auth_file");
423  set_absolute_path(options, "cgi_interpreter");
424  set_absolute_path(options, "access_log_file");
425  set_absolute_path(options, "global_auth_file");
426  set_absolute_path(options, "ssl_certificate");
427
428  if (!path_exists(get_option(options, "document_root"), 1)) {
429    set_option(options, "document_root", s_default_document_root);
430    set_absolute_path(options, "document_root");
431    notify("Setting document_root to [%s]",
432           mg_get_option(server, "document_root"));
433  }
434
435  // Make extra verification for certain options
436  verify_existence(options, "document_root", 1);
437  verify_existence(options, "cgi_interpreter", 0);
438  verify_existence(options, "ssl_certificate", 0);
439
440  for (i = 0; options[i] != NULL; i += 2) {
441    const char *msg = mg_set_option(server, options[i], options[i + 1]);
442    if (msg != NULL) {
443      notify("Failed to set option [%s] to [%s]: %s",
444             options[i], options[i + 1], msg);
445      if (!strcmp(options[i], "listening_port")) {
446        mg_set_option(server, "listening_port", s_default_listening_port);
447        notify("Setting %s to [%s]", options[i], s_default_listening_port);
448      }
449    }
450    free(options[i]);
451    free(options[i + 1]);
452  }
453
454  // Change current working directory to document root. This way,
455  // scripts can use relative paths.
456  chdir(mg_get_option(server, "document_root"));
457
458#if 0
459  // Add an ability to pass listening socket to mongoose
460  {
461    const char *env = getenv("MONGOOSE_LISTENING_SOCKET");
462    if (env != NULL && atoi(env) > 0 ) {
463      mg_set_listening_socket(server, atoi(env));
464    }
465  }
466#endif
467
468  // Setup signal handler: quit on Ctrl-C
469  signal(SIGTERM, signal_handler);
470  signal(SIGINT, signal_handler);
471#ifndef _WIN32
472  signal(SIGCHLD, signal_handler);
473#endif
474}
475
476int main(int argc, char *argv[]) {
477  init_server_name();
478  start_mongoose(argc, argv);
479  printf("%s serving [%s] on port %s\n",
480         server_name, mg_get_option(server, "document_root"),
481         mg_get_option(server, "listening_port"));
482  fflush(stdout);  // Needed, Windows terminals might not be line-buffered
483  serving_thread_func(server);
484  printf("Exiting on signal %d ...", exit_flag);
485  fflush(stdout);
486  mg_destroy_server(&server);
487  printf("%s\n", " done.");
488
489  return EXIT_SUCCESS;
490}
trunk/3rdparty/mongoose/examples/websocket_chat/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = websocket_chat
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8$(PROG): $(SOURCES)
9   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
10
11clean:
12   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
trunk/3rdparty/mongoose/examples/websocket_chat/index.html
r0r250110
1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="utf-8" />
5  <title>WebSocket Test</title>
6  <meta name="viewport" content="width=device-width, initial-scale=1" />
7  <style type="text/css">
8    body {
9      background-color: #cde; margin: 0;
10      padding: 0; font: 14px Helvetica, Arial, sans-serif;
11    }
12    div.content {
13      width: 800px; margin: 2em auto; padding: 20px 50px;
14      background-color: #fff; border-radius: 1em;
15    }
16    #messages {
17      border: 2px solid #fec; border-radius: 1em;
18      height: 10em; overflow: scroll; padding: 0.5em 1em;
19    }
20    a:link, a:visited { color: #69c; text-decoration: none; }
21    @media (max-width: 700px) {
22      body { background-color: #fff; }
23      div.content {
24        width: auto; margin: 0 auto; border-radius: 0;
25        padding: 1em;
26      }
27    }
28</style>
29
30<script language="javascript" type="text/javascript">
31
32  var rooms = [];
33  var ws = new WebSocket('ws://' + location.host + '/ws');
34
35  if (!window.console) { window.console = { log: function() {} } };
36
37  ws.onopen = function(ev)  { console.log(ev); };
38  ws.onerror = function(ev) { console.log(ev); };
39  ws.onclose = function(ev) { console.log(ev); };
40  ws.onmessage = function(ev) {
41    console.log(ev);
42    var m = (ev.data || '').match(/^(\S+) (.+)/);
43    if (m[1] == 'id') {
44      document.getElementById('my_id').innerText = m[2];
45    } else if (m[1] == 'msg') {
46      var div = document.createElement('div');
47      div.innerHTML = m[2];
48      document.getElementById('messages').appendChild(div);
49    }
50  };
51
52  window.onload = function() {
53    document.getElementById('send_button').onclick = function(ev) {
54      var msg = document.getElementById('send_input').value;
55      ws.send('msg ' + msg);
56    };
57    document.getElementById('room_sel').onchange = function(ev) {
58      var roomName = this.value || '?';
59      ws.send('join ' + roomName);
60    };
61  };
62</script>
63</head>
64<body>
65  <div class="content">
66    <h1>Websocket PubSub Demonstration</h1>
67
68    <p>
69      This page demonstrates how Mongoose web server could be used to implement
70      <a href="http://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern">
71       publish–subscribe pattern</a>. Open this page in several browser
72       windows. Each window initiates persistent
73       <a href="http://en.wikipedia.org/wiki/WebSocket">WebSocket</a>
74      connection with Mongoose, making each browser window a websocket client.
75      Join a room, send messages, and see messages sent by other clients.
76    </p>
77
78    <p>
79      My ID: <b><span id="my_id"></b></span>
80    </p>
81    <p>
82      Join room: <select id="room_sel">
83        <option value="">-- select room -- </option>
84        <option>A</option>
85        <option>B</option>
86      </select>
87    </p>
88
89    <div id="messages">
90    </div>
91
92    <p>
93      <input type="text" id="send_input" />
94      <button id="send_button">Send Message</button>
95    </p>
96  </div>
97</body>
98</html>
trunk/3rdparty/mongoose/examples/websocket_chat/websocket_chat.c
r0r250110
1// Copyright (c) 2013-2014 Cesanta Software Limited
2// $Date: 2014-09-09 17:07:55 UTC $
3
4#include <string.h>
5#include <time.h>
6#include <signal.h>
7#include <stdlib.h>
8#include "mongoose.h"
9
10static int s_signal_received = 0;
11static struct mg_server *s_server = NULL;
12
13// Data associated with each websocket connection
14struct conn_data {
15  int room;
16};
17
18static void signal_handler(int sig_num) {
19  signal(sig_num, signal_handler);  // Reinstantiate signal handler
20  s_signal_received = sig_num;
21}
22
23static void handle_websocket_message(struct mg_connection *conn) {
24  struct conn_data *d = (struct conn_data *) conn->connection_param;
25  struct mg_connection *c;
26
27  printf("[%.*s]\n", (int) conn->content_len, conn->content);
28  if (conn->content_len > 5 && !memcmp(conn->content, "join ", 5)) {
29    // Client joined new room
30    d->room = conn->content[5];
31  } else if (conn->content_len > 4 && !memcmp(conn->content, "msg ", 4) &&
32             d->room != 0 && d->room != '?') {
33    // Client has sent a message. Push this message to all clients
34    // that are subscribed to the same room as client
35    for (c = mg_next(s_server, NULL); c != NULL; c = mg_next(s_server, c)) {
36      struct conn_data *d2 = (struct conn_data *) c->connection_param;
37      if (!c->is_websocket || d2->room != d->room) continue;
38      mg_websocket_printf(c, WEBSOCKET_OPCODE_TEXT, "msg %c %p %.*s",
39                          (char) d->room, conn,
40                          conn->content_len - 4, conn->content + 4);
41    }
42  }
43}
44
45static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
46  switch (ev) {
47    case MG_REQUEST:
48      if (conn->is_websocket) {
49        handle_websocket_message(conn);
50        return MG_TRUE;
51      } else {
52        mg_send_file(conn, "index.html", NULL);  // Return MG_MORE after!
53        return MG_MORE;
54      }
55    case MG_WS_CONNECT:
56      // New websocket connection. Send connection ID back to the client.
57      conn->connection_param = calloc(1, sizeof(struct conn_data));
58      mg_websocket_printf(conn, WEBSOCKET_OPCODE_TEXT, "id %p", conn);
59      return MG_FALSE;
60    case MG_CLOSE:
61      free(conn->connection_param);
62      return MG_TRUE;
63    case MG_AUTH:
64      return MG_TRUE;
65    default:
66      return MG_FALSE;
67  }
68}
69
70int main(void) {
71  s_server = mg_create_server(NULL, ev_handler);
72  mg_set_option(s_server, "listening_port", "8080");
73
74  signal(SIGTERM, signal_handler);
75  signal(SIGINT, signal_handler);
76
77  printf("Started on port %s\n", mg_get_option(s_server, "listening_port"));
78  while (s_signal_received == 0) {
79    mg_poll_server(s_server, 100);
80  }
81  mg_destroy_server(&s_server);
82  return 0;
83}
trunk/3rdparty/mongoose/examples/websocket_echo_server/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = websocket_echo_server
5CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
6SOURCES = $(PROG).c ../../mongoose.c
7
8$(PROG): $(SOURCES)
9   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
10
11clean:
12   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
trunk/3rdparty/mongoose/examples/websocket_echo_server/index.html
r0r250110
1<!DOCTYPE html>
2<meta charset="utf-8" />
3<title>WebSocket Test</title>
4<script language="javascript" type="text/javascript">
5
6  var out = function(message) {
7    var div = document.createElement('div');
8    div.innerHTML = message;
9    document.getElementById('output').appendChild(div);
10  };
11
12  window.onload = function() {
13    var url = 'ws://' + location.host + '/ws';
14    var num_messages = 0;
15
16    websocket = new WebSocket(url);
17    websocket.onopen = function(ev) {
18      out('CONNECTED');
19      var msg = 'Не всё подчиняется разуму. Но всё подчиняется упорству. ';
20      out('SENT: ' + msg);
21      websocket.send(msg);
22    };
23    websocket.onclose = function(ev) {
24      out('DISCONNECTED');
25    };
26    websocket.onmessage = function(ev) {
27      if (!ev.data) {
28        out('<span style="color: blue;">PING... </span>');
29      } else {
30        out('<span style="color: blue;">RESPONSE: ' + ev.data + ' </span>');
31        num_messages++;
32      }
33      if (num_messages > 3) {
34        websocket.send('exit');
35      }
36    };
37    websocket.onerror = function(ev) {
38      out('<span style="color: red; ">ERROR: </span> ' + ev.data);
39    };
40  };
41</script>
42<style> div {font: small Verdana; } </style>
43<h2>Mongoose WebSocket Test</h2>
44
45<div id="output"></div>
46</html>
trunk/3rdparty/mongoose/examples/websocket_echo_server/websocket_echo_server.c
r0r250110
1// Copyright (c) 2013-2014 Cesanta Software Limited
2// $Date: 2014-09-09 17:07:55 UTC $
3
4#include <string.h>
5#include <time.h>
6#include "mongoose.h"
7
8static void push_message(struct mg_server *server, time_t current_time) {
9  struct mg_connection *c;
10  char buf[20];
11  int len = sprintf(buf, "%lu", (unsigned long) current_time);
12
13  // Iterate over all connections, and push current time message to websocket ones.
14  for (c = mg_next(server, NULL); c != NULL; c = mg_next(server, c)) {
15    if (c->is_websocket) {
16      mg_websocket_write(c, 1, buf, len);
17    }
18  }
19}
20
21static int send_reply(struct mg_connection *conn) {
22  if (conn->is_websocket) {
23    // This handler is called for each incoming websocket frame, one or more
24    // times for connection lifetime.
25    // Echo websocket data back to the client.
26    mg_websocket_write(conn, 1, conn->content, conn->content_len);
27    return conn->content_len == 4 && !memcmp(conn->content, "exit", 4) ?
28      MG_FALSE : MG_TRUE;
29  } else {
30    mg_send_file(conn, "index.html", NULL);
31    return MG_MORE;
32  }
33}
34
35static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
36  switch (ev) {
37    case MG_AUTH: return MG_TRUE;
38    case MG_REQUEST: return send_reply(conn);
39    default: return MG_FALSE;
40  }
41}
42
43int main(void) {
44  struct mg_server *server = mg_create_server(NULL, ev_handler);
45  time_t current_timer = 0, last_timer = time(NULL);
46
47  mg_set_option(server, "listening_port", "8080");
48
49  printf("Started on port %s\n", mg_get_option(server, "listening_port"));
50  for (;;) {
51    mg_poll_server(server, 100);
52    current_timer = time(NULL);
53    if (current_timer - last_timer > 0) {
54      last_timer = current_timer;
55      push_message(server, current_timer);
56    }
57  }
58
59  mg_destroy_server(&server);
60  return 0;
61}
trunk/3rdparty/mongoose/examples/websocket_ssl_proxy/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = ws_ssl
5CFLAGS = -W -Wall -I../.. -I. -pthread -g -O0 -DMONGOOSE_ENABLE_THREADS -DNS_ENABLE_SSL -DSSL_WRAPPER_USE_AS_LIBRARY $(CFLAGS_EXTRA)
6LDFLAGS = -lssl
7SOURCES = ws_ssl.c ../../mongoose.c ssl_wrapper.c
8
9# PolarSSL paths and flags
10POLARSSL_PATH = /usr/local
11POLARSSLCOMPAT_PATH = ./../../../polar
12SOURCES_POLAR = $(SOURCES) $(POLARSSLCOMPAT_PATH)/polarssl_compat.c
13INCDIR_POLAR = -I$(POLARSSLCOMPAT_PATH) -I$(POLARSSL_PATH)/include
14LDFLAGS_POLAR = -L$(POLARSSL_PATH)/lib -lmbedtls
15CFLAGS_POLAR = $(CFLAGS) $(INCDIR_POLAR)
16#
17
18all: $(PROG)
19
20$(PROG): $(SOURCES)
21   $(CC) -o $(PROG) $(SOURCES) $(LDFLAGS) $(CFLAGS)
22
23polarssl: $(SOURCES_POLAR)
24   $(CC) -o $(PROG) $(SOURCES_POLAR) $(LDFLAGS_POLAR) $(CFLAGS_POLAR)
25
26clean:
27   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
trunk/3rdparty/mongoose/examples/websocket_ssl_proxy/certs/ws1_ca.pem
r0r250110
1-----BEGIN RSA PRIVATE KEY-----
2MIIEowIBAAKCAQEAwizPnrCx+/kPSdEeSJFLDXrBH+cSQsSLrCm99G1hCjzqSlIk
31BhkZMEHxBaiVLky4+M/nwhjwwRHI10h6U2Or3tbPLv7z94cPf+uCx1aF7TE3Fm3
46YnDk+CjrYVFN5GRPGOPPdFxGoc+vFvQJyAAimvchnS1ZoEQFvermwzOnKspA6gc
5Px+7wnOeju9TyJuDr5ngtDXFnkcpkBNPxz3En4MJY4xJiaueafh9pIES2vSl7uP0
6J/qot9v2rdiL7nt1H1vwseeEkZhQ+NLB5e2z4psyktJcwDX7wQ6j7JnKfHeP+ixO
7TUORgV4foBMVOqo//Guo92Q5HoLNK77V0y4+ZQIDAQABAoIBAGEsx+LlDs3JQQty
8KjOq8uKWElyC6bKcZkIMydGvg6b6AU6ceW3jnyqFJ/vMUAUSghNmQQq3yiVo2Kks
9DLKTa9sKYwisE0NeJsgoUtOhJttCTlrwU4f+t/AjtgY68f7zTLnqIV+Ql4ftM0pU
10sIFEFMExZbWsZrQb1w+Hd0wrRqNEbSOfSjHeigvuw1T3GH2tSBUTGTpcoewCzy7U
11PKS5pkYyiKySQQNqZTac3NHPjxdK6xxzwURZp1irKdiPdt04KHLVLX8KXelt/J0k
12AeYkVbpFIeQ9rNBerMEp6uRBt+nE5mvP+xx1XPqKRxuxbMyTnBXeOM2zS/a/dBiz
13fwokwcECgYEA9RSsv9AQ/AR8tt+aPEQvjhJ5pn/YbCb1DA9IDXpaq3tzacGd8JHj
143kUtb79nosu85LvSkAYmtzgfJs6xZyUkscra6q+xlsJ12QRxLzqfxcp9Y0wsdqM4
15AcOwuiPKrjkWxOQpyWPWRwbmAefLfRMekHt4Y/QY0CwhslpnsOsj3O0CgYEAytOE
168I4GBfSQfSjXwfrso++Oi75VSsl5ZeiMGihfEhYFTE8/3rEZf7nf9iFSkN3TT+7f
17pFqQzddzPBZXlpVM6k1jcEjdpJizbeR8DmICpABFrZvKz1o8pQ2Yw+FYI86ih0x4
18806snMNgg/RgcVijXKFrC5joJOI+DVgwWoQyMFkCgYBxt4MkiV2oIkjf7ca6GgVa
19zbXGjOGV5Umkq96J6nDxyplVw/IN8xOhScX4aP6kahaep4vfKguCzjaeIh/stS5e
20lLqZVKZ5Roe6B7ag7HnAI+GkVm73KWrOXse8xui/iFvJRfkhqgJ9+HR3A9/GjD2N
21Ws0Uy+lLhn6oLAya6bA9TQKBgAVfZP4aRP6TY+Bs3Io+41XUWqpI+GlqvNR+PHfU
226e/ItYs37jEv78T6X3xdlZpQxfAwG6x22a8aLetBjEBo5Aiw1Bl9VKGvidE3ZDHd
23VsSRXUckAVNMyJ52pb1KktMf/h4nYGzRgLEGW+Ai8QsPlgQ2ImfEPSH8/DfORjmf
24ltTBAoGBAMxIZ52DrJvuxogSOfA1MoCD6a90trkXCquvi+A/fXojZ8BHmMQshvhK
25rAO7SDIV1i1Nh3jQ/oFWE8KOprqrOLO6jNTyF65vh+zk7ztGsEME9FkDhHasUiXf
26t5PE9KeTChHRvIa4FGCl9We9GftE5Ii77LWMOIq22pyxYbvHQFEf
27-----END RSA PRIVATE KEY-----
28-----BEGIN CERTIFICATE-----
29MIIDlDCCAnygAwIBAgIJAIOoO+AapJ5WMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNV
30BAMTA3dzMTEMMAoGA1UEChMDd3MxMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVi
31bGluMB4XDTE0MDgwMzA5MTU0NVoXDTI0MDczMTA5MTU0NVowOjEMMAoGA1UEAxMD
32d3MxMQwwCgYDVQQKEwN3czExCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZEdWJsaW4w
33ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCLM+esLH7+Q9J0R5IkUsN
34esEf5xJCxIusKb30bWEKPOpKUiTUGGRkwQfEFqJUuTLj4z+fCGPDBEcjXSHpTY6v
35e1s8u/vP3hw9/64LHVoXtMTcWbfpicOT4KOthUU3kZE8Y4890XEahz68W9AnIACK
36a9yGdLVmgRAW96ubDM6cqykDqBw/H7vCc56O71PIm4OvmeC0NcWeRymQE0/HPcSf
37gwljjEmJq55p+H2kgRLa9KXu4/Qn+qi32/at2Ivue3UfW/Cx54SRmFD40sHl7bPi
38mzKS0lzANfvBDqPsmcp8d4/6LE5NQ5GBXh+gExU6qj/8a6j3ZDkegs0rvtXTLj5l
39AgMBAAGjgZwwgZkwHQYDVR0OBBYEFL54xAgtJTW6US4Mbr4QG0yKzvaxMGoGA1Ud
40IwRjMGGAFL54xAgtJTW6US4Mbr4QG0yKzvaxoT6kPDA6MQwwCgYDVQQDEwN3czEx
41DDAKBgNVBAoTA3dzMTELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1YmxpboIJAIOo
42O+AapJ5WMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAJz/RzMa9Wa2
43eEXed7ijH1gcWtgVsVT1xZo0ksFl+QJ5Be1AJpOIe8nKdzYjxPWUkofIoaGHdMLL
44Uc/udRzsXncup+0mD+Yos6Cqyo9yHq7L1HbXfKYZtBXIjWHdF2+RP8j9tHfITXYI
45Pb2zsQ+A6PYpp5OLGZTDAnI2qffqsmwXFNhPfFhOANrGlOjsvy1P7JDzvymj/90m
46NomlO3vjxLHOf6MvedTgCB0dRcAoUWPgbxPWifjBmGBjQjA4ukMQ58wbBQgvIoCW
47obrXmLCNZIkpWTw4gMRYquY880IYK/OuFNJH/dawxx/WzuVr7IdLmbFY15zf5TUb
48ZpIpwqRCysg=
49-----END CERTIFICATE-----
trunk/3rdparty/mongoose/examples/websocket_ssl_proxy/certs/ws1_client.pem
r0r250110
1-----BEGIN RSA PRIVATE KEY-----
2MIIEpQIBAAKCAQEAwOp1RS9RnE8L5TszDPIOmpf/1pqb+ki99l/sGhqB/KZBKCuq
3uoCc2VPK3PCByBE15/xJ7t691FnJfForI9DO5p2R0FPD6o357hqRsh0dJNBm0VgG
4iNtLQ8lyYoE72HJbkgCAUZW4N0OBibOmvp/s3Fmr7rEjW5LmZxOtX+iULKIUZ0w6
5gJlM8G5QA1SuqndN0PbPx+RZKSXZCoJj+Nboqw03nyJUexzs+lynR9ITMziUaaVM
64rzG+P6joQAnUkDNydxo/d4tj4xaioZdKxWLYEbj2BUtOlJJydotWo2wcG85ONrT
7Gw0ltR1vku1hidMm2QL30uGIL5SeqyE8TqWk4QIDAQABAoIBAQCxHtKauc45MA4g
84hCGAzvLTmETnRI2YlEfAoTYlpvf5pkOE8GFyI25r4gjACJ4GO0gWG9dBF7Pt7wZ
9EwRmttEvxV3aIv5OvRnKNdSs7rQSV9D+xc4CGy1oSG1f6X2TxbMzQoiN32OqQa2O
10S0Z94IFs8lu8JCDtc9tcqiFVXEmnC3RvJZOShWpsCsbmh5ue1Xed0MQQ47vt7Zt7
11I0cutvwSFJMsZkZUJp5+KjVNYo9TEJxVD3m2NJNJxBfBoRVHXNii3hUEHcTIdIAz
12omtRwBU8AKgJirGIRo1h2ZFyubI8ScGOJWIiWMQvQqTHKiOaz3yUar1NSG+kFn0U
13cj7s3FhdAoGBAOQbx8Jwhtp4iOkP6aW1nVTgiaTj4LMlyJZioFwgPFRIcA3oRHt9
145SRetmgFZNvcuNw1udfeaObKmlzxwUruprwOpihgAQWJFTtOjQNrt2gsYuX4l3W6
15T46dO2W1pV+mW4A5gt0aqhLv7pCS4lpreNAqyHSPqcQWcCeiTzmp/LfDAoGBANiB
16FQOTyMElR9OzKwmcGfIvnhUfJQwi5qNE3R+xXiP5x36a9HQBey5ri2lnBle0Ksr/
17G+RKoflmk1eFXVHN0w35yw0dVco//WE4vOknldNEnIT85k02ld8lDTa2Q/EJZtPH
18un6zeU0Q2/4SZ/GXPssEZPlpPM7WtQzztlH3+sqLAoGBAKnhppvAgi4ippQsLa4j
1929BiiSAsNiQ1d3XIbfUubL+4UvuIh7gQwp6biu1dVwgHEgWuXYHPOgDn0p51zaao
20pbRYlJZtKVWeChnpHkv15NnIdL8grGwZHTbxElNlPIxHsM2GB1fzi8YeumUhf0In
212AnwUum8NIq8yzo5PxeK6ZNRAoGBAIEA2Q6ankJH/nZsCbbeJq+iI+Wd+ysyGI8s
22Vz2tJ9Tz3iTYG9SLlWRhfF4/nw3fMqhmPa5Xsg+zSRQbSTGXHKz1LEISOq4aVtX5
23QscCaUnLVh//uRJE9iRSJX92NyGGYpjKJ5ubQSnkY9EOEpVnc2jwo2HhjPQKBzNC
24fF53Dh5lAoGALwTN5uxrBZLPu4DtZkOosKkv4l+kzFoOjLJR4vA7ONBx2CSe9G7F
25tSsH7lZS3b0mxBWjO90WhaSvtMWWrfqq8vrqmoTE795fYxNoLfCLK13W31aTDUsI
26pQRJIL30MPvASbcFHN2MD2dXz2nQzY8C9lvtvap/krYiDKDU2L7+iP8=
27-----END RSA PRIVATE KEY-----
28-----BEGIN CERTIFICATE-----
29MIIC7DCCAdQCBRQHBXNHMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNVBAMTA3dzMTEM
30MAoGA1UEChMDd3MxMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVibGluMB4XDTE0
31MDgwMzA5MTU0NVoXDTI0MDczMTA5MTU0NVowOjEMMAoGA1UEAxMDd3MxMQwwCgYD
32VQQKEwN3czExCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZHYWx3YXkwggEiMA0GCSqG
33SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA6nVFL1GcTwvlOzMM8g6al//Wmpv6SL32
34X+waGoH8pkEoK6q6gJzZU8rc8IHIETXn/Enu3r3UWcl8Wisj0M7mnZHQU8Pqjfnu
35GpGyHR0k0GbRWAaI20tDyXJigTvYcluSAIBRlbg3Q4GJs6a+n+zcWavusSNbkuZn
36E61f6JQsohRnTDqAmUzwblADVK6qd03Q9s/H5FkpJdkKgmP41uirDTefIlR7HOz6
37XKdH0hMzOJRppUzivMb4/qOhACdSQM3J3Gj93i2PjFqKhl0rFYtgRuPYFS06UknJ
382i1ajbBwbzk42tMbDSW1HW+S7WGJ0ybZAvfS4YgvlJ6rITxOpaThAgMBAAEwDQYJ
39KoZIhvcNAQEFBQADggEBABPLmq6zKOMY0WRjtBoSymq6f+vXeEwtWCfVejdG6RlG
40/PTdCKNvp3OL7FDnmQQ+r5rMs4+Os4fX/g315QFKXu01rqxmFb2XVNhhaECdUWtK
41QP6ZoVZviUiDjhK6a+05aerPCJpkGy/lz0W6gmj4qhuAQbobxb6UbzqTRYY+ZwGk
42+SI3TAVCdmXFlxN/M9b0DbmkseRG8GGFmyRYyRb84vbV6zemFI++5ROUT9zXT7ey
43nYfFJvAAk5jJhY5UP2aMlVWYYa4jUZrrPLoiBLUuRrp67EKGebCH9mgCIf8ztNJF
44fpuvcz++LUeRyTlAGDefe+FyHGIwFzIfZn39D7CaRvM=
45-----END CERTIFICATE-----
trunk/3rdparty/mongoose/examples/websocket_ssl_proxy/certs/ws1_server.pem
r0r250110
1-----BEGIN RSA PRIVATE KEY-----
2MIIEpAIBAAKCAQEAyal0BZKRYd+Wpxv4MB8LjjgXv/MxSN5oSAKThlCZ/AWG0FEP
3d4nrBACT2xUxwo+xbYl3joiwL/eCPAp6QNKRGhvXVOnSIFVSjKZWbdX+toqK9pDS
4QMDTL4ZJvK6pLZXknyHjEr0PxZh22F7iS1+C8HxBPj0Xgg/u5/+jPhFPPZ1d5elv
54cm/z+xy6RjFlA80aIeK7dcWssOsOIPjUNFfmoYgR63ScZIlUZj6j8VX9oX7fJID
6jumGajDxgD2nBWFbHcGKin6bz/wZ+OIhXOCDdY7oKuMW4JiBwbfBtedkQuQYS11s
7PRFFYDLoZH59Ivcu0c4F2tomE86qM8THsI910wIDAQABAoIBAG55FAQRfO8/C0rU
8eavy9eOdOvV+hltC66G3N5X3BcQYSvhHz89OkJ6KqnT0MWRCT5KQIhzFKK++SWwW
92U41jCPfaKEtzlzEIQrH/MUC3Byn3OSiBWxPteFtEWv5ytgcKzg52iljxQYcNc7m
10e9WKpzKS/zLXSM+JZvlVA9p2pRA88kUZ/EE5H+FW3kHj5eGNqX+cxUVpL0VKTiLv
11aXWjYotpmDJW/Rn9wRQethm6Gdx3bvo+LEVlJRELNq8NM5H/tZIVRzudJOgzsw5v
123OQGhfKB6Eg/vqSFoZxX6ApXDxmtaSO83B0kK550bDVv4sBnOExGjKCzybt04tet
13KtLPPoECgYEA5WUD+mFL99sCX6pzIyUVlxp9eUhVy5nvhoF6u3mvhay2XsZUY0wy
14+/qVqYSZTvuvJ6JSXc4iVIX8u/gj7914805AwujepIF/8E0AaXLBMndzDE4ze5S5
152RHI7Cy4/3AWOcQ9wFFmUdSs7/6oAkcQtvzP40hGg3J2jAEhIdCqmbMCgYEA4Q0G
16BYP9XeTdh0C+BcP9B5VUEC0jerYS8VqVqriB+9JfT3InI7K08sOG2DiQQBhAHuzL
17RhCECU2a9j0+u5F5JNeY5m3IhU73Lw+lOlUkMaAO6x7JJEzhXhonE7Kv8fWygr/0
18OB7yzqz+YsWdQ2VOPZ88ntlAYE65vzcaVswZY2ECgYEAr7Gt2VA6Ei0A5Wq0Yr+d
19iKz2WzUG2TkelqOG8B4kTDrbNz2qFp+fERV9GWgAz9i+75lIgqZF7vzsdL96LtYv
20NBLEUURwegjhh5hCb4E/7bpFOLCQh9+CdHpFrHYYfzRHIZlnPmxZ9OTyS6J85bmu
21WKjLRKXvs++wUkzvJmoesDcCgYEAkTOB6xUZ5/a+J4HSGI43NylVr4owFgBbgHVd
22k2SwGPXGoM+aCSJINUmKOv9jsrbyyAEntfD5/7aegLlLPGHDs82WzTWP5tLoEOkb
23ReOhEpOejHy0ckNYNQrSo5bqhkZsAogu3fa52jcrejbeHJnEPWX8CtFJA9pHZeP7
24jnzo9IECgYBefHg0dymSj2xxN0XmC+S5cvQu2K/NYUpatoWvHnPiQ87wIM0AWz0O
25D0ghEI+Ze57NbtSrrcTE7hY/LHrAqXGAB9XNIM5g9Pp/lM+XjzKVr1FMf4xpuHf1
26VJJRHrOU14CvMvKbgbPrL6B0d5yrYmeex7GxNw0ZVvtjCa502Eck+w==
27-----END RSA PRIVATE KEY-----
28-----BEGIN CERTIFICATE-----
29MIIC7DCCAdQCBRQHBXNGMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNVBAMTA3dzMTEM
30MAoGA1UEChMDd3MxMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVibGluMB4XDTE0
31MDgwMzA5MTU0NVoXDTI0MDczMTA5MTU0NVowOjEMMAoGA1UEAxMDd3MxMQwwCgYD
32VQQKEwN3czExCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZHYWx3YXkwggEiMA0GCSqG
33SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJqXQFkpFh35anG/gwHwuOOBe/8zFI3mhI
34ApOGUJn8BYbQUQ93iesEAJPbFTHCj7FtiXeOiLAv94I8CnpA0pEaG9dU6dIgVVKM
35plZt1f62ior2kNJAwNMvhkm8rqktleSfIeMSvQ/FmHbYXuJLX4LwfEE+PReCD+7n
36/6M+EU89nV3l6W/hyb/P7HLpGMWUDzRoh4rt1xayw6w4g+NQ0V+ahiBHrdJxkiVR
37mPqPxVf2hft8kgOO6YZqMPGAPacFYVsdwYqKfpvP/Bn44iFc4IN1jugq4xbgmIHB
38t8G152RC5BhLXWw9EUVgMuhkfn0i9y7RzgXa2iYTzqozxMewj3XTAgMBAAEwDQYJ
39KoZIhvcNAQEFBQADggEBAE20gAykuuaCoP49GnZ/Z6ZItFry4Fl6iCWBDdEsWI9R
40wRNYumeaeejdFPXfSJdTT7UlrVK1WWGLQLq+ixHRDX+V9T67ou85F92H/OxbUoPr
41iz/TZAEBTC1GvTJl49lsfPl1dTWH8T4Ej2hxCUvIJrkCkI2Ov4Wwef6A26USrwBt
42S/CPInjCe6qkE5E8xfTDl8k5IIgMadTPhi5sbV2piBJoN4floJPqR0hdDKbgUymn
435WNSiRkuI6UIDZwQEp+A8TmFBHbSwfTGt2Sz5iI27P8J6pFvR5eRA1k57dRUWNXC
44WAU1nqteP3QAjj9L3o8IO0T62scaiJX8x01gTmVVe2I=
45-----END CERTIFICATE-----
trunk/3rdparty/mongoose/examples/websocket_ssl_proxy/certs/ws2_ca.pem
r0r250110
1-----BEGIN RSA PRIVATE KEY-----
2MIIEowIBAAKCAQEAwXIMpHuTNsro2pxe6y1mu27md2Olhvfx26rO3maO0/stIC2z
3G/xQatFDLIWzfKFYOT0iSEj252ENFDCw6aDRKpiaUFtXcMAWkNkkKntEyoEgE45k
4rTrvpay0v0B+ojwjA1Jz/9v35cgvDwTs3vNFno5HhI0m2YF4ocTmeHJ6u0xRL/qy
5atfKsfuVq5s5CXOYCXp3Ux6kJ1c22J0EdZMvS75SVjAZgRkqQpqt9L3e2ZBCEgUr
6w0KwlERvpeJF+sJJOshXjfrDzvwL8IpPnGZLJNINFbSJMk5MFGcMyq/28pSZLB9E
7Dh8vk5D5gUnxM60ONUy2nYPcYr5p1PLDiC8hfQIDAQABAoIBAB0Twpi6xn8W8vdh
8R9c75NRJsDTD8q6d+GnXe+7sJY3xlG/gzqpnO8NCn0FC+57BNdystsl8xjgzW17s
9jrsfZDFt7MwlXrhg90NgkFIeY1G5JRQrdDChykHx+t1AmYhTV8P5EdykuNd+RqyQ
10RfahRJa3tkJTYUKSdoqCaU4zjwU2CSxltuJx24V+WoZE12EwewJ8HPg2XTnbsGE7
11Fnx5s29O4ItM70CC0536AY/OgfuPix5z573VQiilqqfOQkVkKa1fHd6tGpWU+3kH
12X9FnhEBf9cN9tVgmaB0sCSVVrfgqSXg1EwKHqe/+FCumuesA68Q35+/K3b+QrNiR
13ka2yliECgYEA+V/4pbgG/lPYvTwWhKxGXXdJmrSPgZC0mwE+fRuYkeptbIkS0pwt
14/UDTXk9nttj1f1ZJ3NgQbT/1w8jpXfsCJ8VeGzL9+ADhRKWVFRlu/nyFCMXawLEV
15rot7SEr8BW/m8moHgY5lYipM3dXJPk0F+KLrN60U/aNmFUtPGW802BkCgYEAxpWy
16FGL2sEQ0QaRDTcqqF5faVqw+5rVGvN+EX5o26E0QWWnoo3L2c2/5X93iBl+Fqtnm
179jSIQUC3rYOawKnZ/HcIE2ergFit/p6JaV9NiLDRtDUmSzlffEGVCj0neYFsnWp5
18zcmkUyZ6fr19EmKQWfdteNBlXue32TjVlFbfUQUCgYAfMbgi0sBdNBPaqBeRBRPQ
19QUm9xnRlGrrc4Oz2LWuKZS7G8uad3deK5H8MPxaUMtOS2DJpI8X6RJPzp8A5d1qv
20quq4sEpAqauEMMpTV1khEGZ70HQqwnwZ12zWgDrCW1siW80QkcVw4CW5YjLITk4+
216fJOhqInkDcG1uLQJa8QkQKBgQCfs8l4DbJ4RRGFbLXXvNGXkb68j18yqLxPrq3F
22OL9JiJhKYBsAP7clVPrG9ykLmQxlP0I35D1jxMkymLD+mlo9Z/itqmTJHggnyZWW
23kVdIQ3MSKuA2BNjek9tpVY8Gb2hLHFMChVRKrpo6jOclvvB5+bsnOukbLtyyq7tP
24xaFohQKBgByCmlltjOBWZLFLeA1x8j3inm9zM/FAJuANbHUOZ1RwrRcNFbDv/FXm
25rLPnPCaH5AwAWhVRJcNHo37Ee0s/xqe+Q4dG4xL943k+6KlopAw1SXhuXF6PnBfF
26y+ArVlh9d2oWN5cBEzRddnWnKJuMi70kMzYf6dIW9s/dHbq/gFDy
27-----END RSA PRIVATE KEY-----
28-----BEGIN CERTIFICATE-----
29MIIDlDCCAnygAwIBAgIJAJDtcXU2wiJIMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNV
30BAMTA3dzMjEMMAoGA1UEChMDd3MyMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVi
31bGluMB4XDTE0MDgwMzA5MTU0OFoXDTI0MDczMTA5MTU0OFowOjEMMAoGA1UEAxMD
32d3MyMQwwCgYDVQQKEwN3czIxCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZEdWJsaW4w
33ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBcgyke5M2yujanF7rLWa7
34buZ3Y6WG9/Hbqs7eZo7T+y0gLbMb/FBq0UMshbN8oVg5PSJISPbnYQ0UMLDpoNEq
35mJpQW1dwwBaQ2SQqe0TKgSATjmStOu+lrLS/QH6iPCMDUnP/2/flyC8PBOze80We
36jkeEjSbZgXihxOZ4cnq7TFEv+rJq18qx+5WrmzkJc5gJendTHqQnVzbYnQR1ky9L
37vlJWMBmBGSpCmq30vd7ZkEISBSvDQrCURG+l4kX6wkk6yFeN+sPO/Avwik+cZksk
380g0VtIkyTkwUZwzKr/bylJksH0QOHy+TkPmBSfEzrQ41TLadg9xivmnU8sOILyF9
39AgMBAAGjgZwwgZkwHQYDVR0OBBYEFLK4flD5QD/mRufsPx63xlEKM8pwMGoGA1Ud
40IwRjMGGAFLK4flD5QD/mRufsPx63xlEKM8pwoT6kPDA6MQwwCgYDVQQDEwN3czIx
41DDAKBgNVBAoTA3dzMjELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1YmxpboIJAJDt
42cXU2wiJIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAEYD+CReikYr
43Rzvk+/Vdi/7IcaH9CFknIdtineSIw1y98nxnbnNJqxwfNaRblbYvg6OFdUI3POuI
44+rdYLCFl8z3tWqRHLkGqHSJA9xcng3jLJxz0+ctiVcekJvXaB3O6eSZjhGbmmI/s
45CQhdy2zpEIVOeUq50DrSJp9CknyGu/IkaGx5GOZtkiHMrpig50CRjX1lS6qrMNYp
46vB8gfuqpjsL4Ar3vg+lgMSwNWXBNHrIRPHB5VEzBEdmLFZlvueR0ooEMCklpwX/a
47lFImVc6JcY1pBEkHTiTLGMpGAHG3I1aVUaWb3L+V+2ym/KNRNL5C2+1eiqql5u8m
48HUaOcNC90ew=
49-----END CERTIFICATE-----
trunk/3rdparty/mongoose/examples/websocket_ssl_proxy/certs/ws2_client.pem
r0r250110
1-----BEGIN RSA PRIVATE KEY-----
2MIIEpAIBAAKCAQEA0ucemqFwBFziVOgTgx4mZII4WnGDpA/rWAGHvUZOqy2dQ3Pz
3woGKxBaVPAl5kxEosROVGa7dTuq5yFZ4XIGvwCKxF30vCmdGCytqq6MMp904jG32
4KikkmjCApIMGxMO4eoBHZZxiyVvKTbg9M2CRXErwnYWhFH/qGdPnuo0CEaHJA4VK
5A9incT9dpeEhU30R6ajAe/je9rCj2OMLMFSMfd51L/VYfO60zDwUNY7YVIghQZgJ
6e44EVGsp1pXaqaD6o3PvGY3ohw2aZjJzlJ7MJHbKV9lft98R3pklbpBzMH849cEy
7Q/51L/rlfTUgCpTy7wEZpWHQNtHfu/1rhJjpNQIDAQABAoIBAQCUNIHXG/dBuZv7
8GpMLotZL7w520Co30lAJqhmfMpb5x7YpvoPffXTsUwpQBECAzqAPv7kZMT6nxF8F
9n245Y5EDrd1QqlGyN9yK4Nm2/39XPygL1wITopHsIIVmFgVdpEQxIZAKoZjx8yT4
109K1dO1Eq0CbCKzOE2lbCC51eBNUdWZIMxwC6O/j/KoIkZ/HwlG2hpUuXg8x/XawA
11ZJDCoTcWHCjYP10FxKVN3vAyWM2IM44o9IbsAGEOswR4gUwRsgq6Ehc1U59XUHi+
12x30oda55I1/8xD+SfP/zk2dDPHkv/hq5+258GU/THsw2+AAexocvSIS/g9EppTEg
13biFaDKzJAoGBAPqey10JeyiOlHbBjoSSa7lJYUjocQANFQ4ayOAgfNX72iyabrKF
14p9sVAeO/nM00+DPrm2wWws03ScsPeh+9BDJMPRBUHfSNp7+F+oyj7PWHBEFHbyO9
155HnYZP+1vhdG2dYPIY2gRSFXpiGn3j0M1D0w9c7Ilm8ee3krdR4E/mw3AoGBANdu
16EfS1dK3+m7sEgc2+3U32z83GpuCHeUIKGPYMLI0fIb1CPpboHU9YjOFJZH9iIIdl
1700JC963O3+pqLe0XbMOmBVt9QjZfhfB+AY+JHtbPgoQVLtq9X/WvW7h3xn6S971r
18Crkhqay3Cs4BzsgYDYraQCTw3oq4twR9Nuy4etfzAoGAXOsG5wWe3diO/sCggFJx
19Eg88vHVBgA1ZoxMXKtGgtw1bRHI1XIblRvqw6qmeDw72fvl5dEe0DbXT7C9ezemc
20ZrGRaj5lpMfoS7/2trIIJrfaQgGkGRJMZUhvmcbeJW8lUJHnlMS5HLWMaKn+YZAi
21GFXQrMv9ylD44mHUWD7tvV0CgYBNctPfvvCQsQ05ofgsiKa1Jbs1hmpuJCYy2MB6
22jIvjvEJ78PnhdNc8tGAJikIoDZYWN0RI+RxkDxCvDLcwGpDOkbwxVQnd1F+pwxM6
23kBhXL8kDRT5QA28hO4bk/aKN1LZeEcKMJg8C+ddXkozNoOAVgDs5TKMlCh057u41
24EmmPgwKBgQDOlYi7fPYOCy0yjHMxSrp2SZOS06AMWGbbCoGkjRtvuP+FmKSNB+LZ
25pOSEPJgzjsRutKjneww4LpV6dViAyTcP5JoeQpokHf7UVo7yq2QH/iwF3zJwsC/S
26OuVLkqpZzWuye/QCH5NOTfw27ye8jG8VcQW2QPbcbkLXLM7zg2yX7g==
27-----END RSA PRIVATE KEY-----
28-----BEGIN CERTIFICATE-----
29MIIC7DCCAdQCBRQHBXNJMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNVBAMTA3dzMjEM
30MAoGA1UEChMDd3MyMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVibGluMB4XDTE0
31MDgwMzA5MTU0OFoXDTI0MDczMTA5MTU0OFowOjEMMAoGA1UEAxMDd3MyMQwwCgYD
32VQQKEwN3czIxCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZHYWx3YXkwggEiMA0GCSqG
33SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS5x6aoXAEXOJU6BODHiZkgjhacYOkD+tY
34AYe9Rk6rLZ1Dc/PCgYrEFpU8CXmTESixE5UZrt1O6rnIVnhcga/AIrEXfS8KZ0YL
35K2qrowyn3TiMbfYqKSSaMICkgwbEw7h6gEdlnGLJW8pNuD0zYJFcSvCdhaEUf+oZ
360+e6jQIRockDhUoD2KdxP12l4SFTfRHpqMB7+N72sKPY4wswVIx93nUv9Vh87rTM
37PBQ1jthUiCFBmAl7jgRUaynWldqpoPqjc+8ZjeiHDZpmMnOUnswkdspX2V+33xHe
38mSVukHMwfzj1wTJD/nUv+uV9NSAKlPLvARmlYdA20d+7/WuEmOk1AgMBAAEwDQYJ
39KoZIhvcNAQEFBQADggEBACCCAJypO9DFU6GeOH+FwE0JCLTypHoIwERWxNL7xfjg
40rwVqIxwAEo+fJjL+QY7JbAb/eqKaXIBYkAF2lFc4iEmecXX/A3Aqw95AYi78o7HD
41MwRPqJha9mxLcCWwjX8XK8pT152BvYFPNhi+6jd++rDRxKDfmNvgdUQ2/YW6a5Wv
42zEmLDPUWRIuMQIEmOa2/JhlllDviMExTw51nbqYgCghycRvDACyQAuu8re7P6gcg
43bXObNlfxcU/8Ph6MFI+2S9ODtQ4BHyuKd4kRNsYn8vV42a0h3bCYSGPk3kSIgxd7
44XijwHT/o8E9ddH2BvDv+6Nhno9C6/MbezEOIs4nlhRk=
45-----END CERTIFICATE-----
trunk/3rdparty/mongoose/examples/websocket_ssl_proxy/certs/ws2_server.pem
r0r250110
1-----BEGIN RSA PRIVATE KEY-----
2MIIEpQIBAAKCAQEA29iFnMf4pjty6knOt4wT0joPUlU2dGCFWxQ5Eg77Yx3Lou2a
3FOzNGp7zLYH8gauOK+mgY+B9cBv8PvVtUQQKB0SKTTV8ZNKVyP3O5F2gRSJ+tHtT
4FqaPfG0WPOn/f02YbOpAe6Rk+NnlJoeuBxG4uapUSq7r0mTGJQe+52y1LcMs23ID
5ENBfDoUMVt5vCnF+cYK5ndeFVLyPO3JjohDH1zv3a9ECG28rtjKHLpNYFDsPJaD7
6UPuyyk3hIvfPCZoJOUlEVfpLT/lM+9oCPnq9PwIp5NqYofkuc3eKooCo7N4r4IlP
7Ajktaao6b0ScNwNQB3leOIdEUFSIYy8N1JszVwIDAQABAoIBAFlIvjrGG/2m9yyf
8fQyeHw6p9b8CTHNHH+G1fNgQrZe7ahBpXsJQyZueIjTBLcOb4MmEwFbPvSHiu7b2
9Bcd5VHlPJLvmlPZ9b8eJDJVCUOzC7aJu03fHfU6THwzuG42f/d9942JTiY5nL+FO
10CSdl0xfUTRdnou53buFrG+TxCUPj13HP1HY6DAVzEIq1H4TZwIZo7KRRTIYpTB3P
116yvr9xsISLlnmfQ4tp2pApl5o+bHJEhr1VO6SAT/pSyShi79KmMMqYtyTmOMz7w6
12VJkre5ybnXBDN6tfMHWqdobJ4gRWK9rqf+LIZig5XQnyzkue8k+I7aPgO4xNFh56
13dkejQcECgYEA9MDCWViqpfvof+epiKzccqnIRnz1EfHdRQjiKsKGRe39+K+pyaqJ
14FOOPFy3aOw6M4cFWwcdMYzKTItvzyLVhDqMzT5eup/NVqo5tPoy93XPf2qRYiTl4
152j5wvm0RVkYEONd3pk2lbfbUmn7XQXj0+AG60SvsqErF/UhIBGec/xsCgYEA5fLC
16EdiiC98kr4sVaE8G854WI+aAkStqO5YXyrnsMzRsqk8KVVYE1yCC9rYyymDBYmlx
17uEW+vbWqLc8PO3v4ty3o5ff303lPMWIrvKiUldjqMjS6ncWxsQjU0bygGVgOgHO7
18c8rjiDH5M0JgWSREYUVFT5mW/5+Y1LVT8mYNlHUCgYEAhMSX6N23XGkFW3Twu2qB
19/1Vohgw86OoaDNvfzDBPpFmQ3rlz0ijHSeSTd5BxBH5FICXACUgygNErjcphOSxj
20JQyUxgVTQlo2y1mNm1O/nwS/lxx1xqK9ky4x/Kqvr+w1WBxSFI2kQr2V4OUTobma
21sXpGvDcmnrhJJLd0EaefO6cCgYEA3Xw/S9tC8nZjqqYn34nHI16Q6tF54tpTf8Np
22dT4x8Xw8cqqhRGMPVHsfSi1irKYXfwgbnienuqlBmtAHVv9pKF+TJfb7gXkmO2XY
23xOYIAHGn2uYJHjCun9vmyYKLHv4/MaDH3Jd/I88mviXgEdyp9Js5UJua4utB1Rg3
24HJMJ34UCgYEAr0PpHEBMbZXZBybNU96+jRTgkrNeJpzlnMy7et2IsRAtLjZ0mpbn
25NaX8i8eO+ubweqFdhOvbh7Hd0zr7BzrYcUG1e3njhtxJE1MgWL5plnLVUbIyDAm3
26iBpIHIBASNCN3sqeq+VqXvavRmeZh5O0vyLP46/kxZx0rzR/NCi9xxU=
27-----END RSA PRIVATE KEY-----
28-----BEGIN CERTIFICATE-----
29MIIC7DCCAdQCBRQHBXNIMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNVBAMTA3dzMjEM
30MAoGA1UEChMDd3MyMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVibGluMB4XDTE0
31MDgwMzA5MTU0OFoXDTI0MDczMTA5MTU0OFowOjEMMAoGA1UEAxMDd3MyMQwwCgYD
32VQQKEwN3czIxCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZHYWx3YXkwggEiMA0GCSqG
33SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDb2IWcx/imO3LqSc63jBPSOg9SVTZ0YIVb
34FDkSDvtjHcui7ZoU7M0anvMtgfyBq44r6aBj4H1wG/w+9W1RBAoHRIpNNXxk0pXI
35/c7kXaBFIn60e1MWpo98bRY86f9/TZhs6kB7pGT42eUmh64HEbi5qlRKruvSZMYl
36B77nbLUtwyzbcgMQ0F8OhQxW3m8KcX5xgrmd14VUvI87cmOiEMfXO/dr0QIbbyu2
37Mocuk1gUOw8loPtQ+7LKTeEi988Jmgk5SURV+ktP+Uz72gI+er0/Aink2pih+S5z
38d4qigKjs3ivgiU8COS1pqjpvRJw3A1AHeV44h0RQVIhjLw3UmzNXAgMBAAEwDQYJ
39KoZIhvcNAQEFBQADggEBALi/RmqeXGazT/WRj9+ZqdcnbcHwK5wwr2/YkpFPJ0Hf
40ZDm+2vgjDdTT6cJS6fau0M5nliYdz89aQQo1j9RSRZnzlc/2YCFXyRLCOJYaINbj
411MEUAvNDGL7xTpepK9hVkXASRkbyNXERXRKFI1N+vpKu6UorT6/osEV/qM+MFJ3s
4224xE8/J3J4MirVQVt6eY6Jb+tkliOPMIugr6YQlLsqJygEWATP8Qsr81XSfcZhVq
43rXzVt7QV8dO0nStMjKK5omrtEAhVnASk7w1tFHkpBF1rqXGoo9ML40RnFZ+E5zqi
44iZtzp+NzzLnEnWMNs+fJpPJ96P0kbq2bQzuSBcUynq0=
45-----END CERTIFICATE-----
trunk/3rdparty/mongoose/examples/websocket_ssl_proxy/net_skeleton.h
r0r250110
1// Copyright (c) 2014 Cesanta Software Limited
2// All rights reserved
3//
4// This software is dual-licensed: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License version 2 as
6// published by the Free Software Foundation. For the terms of this
7// license, see <http://www.gnu.org/licenses/>.
8//
9// You are free to use this software under the terms of the GNU General
10// Public License, but WITHOUT ANY WARRANTY; without even the implied
11// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12// See the GNU General Public License for more details.
13//
14// Alternatively, you can license this software under a commercial
15// license, as set out in <http://cesanta.com/>.
16//
17// $Date: 2014-09-28 05:04:41 UTC $
18
19#ifndef NS_SKELETON_HEADER_INCLUDED
20#define NS_SKELETON_HEADER_INCLUDED
21
22#define NS_SKELETON_VERSION "2.1.0"
23
24#undef UNICODE                  // Use ANSI WinAPI functions
25#undef _UNICODE                 // Use multibyte encoding on Windows
26#define _MBCS                   // Use multibyte encoding on Windows
27#define _INTEGRAL_MAX_BITS 64   // Enable _stati64() on Windows
28#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005+
29#undef WIN32_LEAN_AND_MEAN      // Let windows.h always include winsock2.h
30#define _XOPEN_SOURCE 600       // For flockfile() on Linux
31#define __STDC_FORMAT_MACROS    // <inttypes.h> wants this for C++
32#define __STDC_LIMIT_MACROS     // C++ wants that for INT64_MAX
33#ifndef _LARGEFILE_SOURCE
34#define _LARGEFILE_SOURCE       // Enable fseeko() and ftello() functions
35#endif
36#define _FILE_OFFSET_BITS 64    // Enable 64-bit file offsets
37
38#ifdef _MSC_VER
39#pragma warning (disable : 4127)  // FD_SET() emits warning, disable it
40#pragma warning (disable : 4204)  // missing c99 support
41#endif
42
43#include <sys/types.h>
44#include <sys/stat.h>
45#include <assert.h>
46#include <ctype.h>
47#include <errno.h>
48#include <fcntl.h>
49#include <stdarg.h>
50#include <stddef.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <time.h>
55#include <signal.h>
56
57#ifdef _WIN32
58#ifdef _MSC_VER
59#pragma comment(lib, "ws2_32.lib")    // Linking with winsock library
60#endif
61#include <windows.h>
62#include <process.h>
63#ifndef EINPROGRESS
64#define EINPROGRESS WSAEINPROGRESS
65#endif
66#ifndef EWOULDBLOCK
67#define EWOULDBLOCK WSAEWOULDBLOCK
68#endif
69#ifndef __func__
70#define STRX(x) #x
71#define STR(x) STRX(x)
72#define __func__ __FILE__ ":" STR(__LINE__)
73#endif
74#ifndef va_copy
75#define va_copy(x,y) x = y
76#endif // MINGW #defines va_copy
77#define snprintf _snprintf
78#define vsnprintf _vsnprintf
79#define sleep(x) Sleep((x) * 1000)
80#define to64(x) _atoi64(x)
81typedef int socklen_t;
82typedef unsigned char uint8_t;
83typedef unsigned int uint32_t;
84typedef unsigned short uint16_t;
85typedef unsigned __int64 uint64_t;
86typedef __int64   int64_t;
87typedef SOCKET sock_t;
88typedef struct _stati64 ns_stat_t;
89#ifndef S_ISDIR
90#define S_ISDIR(x) ((x) & _S_IFDIR)
91#endif
92#else
93#include <errno.h>
94#include <fcntl.h>
95#include <netdb.h>
96#include <pthread.h>
97#include <stdarg.h>
98#include <unistd.h>
99#include <arpa/inet.h>  // For inet_pton() when NS_ENABLE_IPV6 is defined
100#include <netinet/in.h>
101#include <sys/socket.h>
102#include <sys/select.h>
103#define closesocket(x) close(x)
104#define __cdecl
105#define INVALID_SOCKET (-1)
106#define to64(x) strtoll(x, NULL, 10)
107typedef int sock_t;
108typedef struct stat ns_stat_t;
109#endif
110
111#ifdef NS_ENABLE_DEBUG
112#define DBG(x) do { printf("%-20s ", __func__); printf x; putchar('\n'); \
113  fflush(stdout); } while(0)
114#else
115#define DBG(x)
116#endif
117
118#ifndef ARRAY_SIZE
119#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
120#endif
121
122#ifdef NS_ENABLE_SSL
123#ifdef __APPLE__
124#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
125#endif
126#include <openssl/ssl.h>
127#else
128typedef void *SSL;
129typedef void *SSL_CTX;
130#endif
131
132#ifdef __cplusplus
133extern "C" {
134#endif // __cplusplus
135
136union socket_address {
137  struct sockaddr sa;
138  struct sockaddr_in sin;
139#ifdef NS_ENABLE_IPV6
140  struct sockaddr_in6 sin6;
141#else
142  struct sockaddr sin6;
143#endif
144};
145
146// Describes chunk of memory
147struct ns_str {
148  const char *p;
149  size_t len;
150};
151
152// IO buffers interface
153struct iobuf {
154  char *buf;
155  size_t len;
156  size_t size;
157};
158
159void iobuf_init(struct iobuf *, size_t initial_size);
160void iobuf_free(struct iobuf *);
161size_t iobuf_append(struct iobuf *, const void *data, size_t data_size);
162void iobuf_remove(struct iobuf *, size_t data_size);
163void iobuf_resize(struct iobuf *, size_t new_size);
164
165// Callback function (event handler) prototype, must be defined by user.
166// Net skeleton will call event handler, passing events defined above.
167struct ns_connection;
168typedef void (*ns_callback_t)(struct ns_connection *, int event_num, void *evp);
169
170// Events. Meaning of event parameter (evp) is given in the comment.
171#define NS_POLL    0  // Sent to each connection on each call to ns_mgr_poll()
172#define NS_ACCEPT  1  // New connection accept()-ed. union socket_address *addr
173#define NS_CONNECT 2  // connect() succeeded or failed. int *success_status
174#define NS_RECV    3  // Data has benn received. int *num_bytes
175#define NS_SEND    4  // Data has been written to a socket. int *num_bytes
176#define NS_CLOSE   5  // Connection is closed. NULL
177
178
179struct ns_mgr {
180  struct ns_connection *active_connections;
181  const char *hexdump_file;         // Debug hexdump file path
182  sock_t ctl[2];                    // Socketpair for mg_wakeup()
183  void *user_data;                  // User data
184};
185
186
187struct ns_connection {
188  struct ns_connection *next, *prev;  // ns_mgr::active_connections linkage
189  struct ns_connection *listener;     // Set only for accept()-ed connections
190  struct ns_mgr *mgr;
191
192  sock_t sock;                // Socket
193  union socket_address sa;    // Peer address
194  struct iobuf recv_iobuf;    // Received data
195  struct iobuf send_iobuf;    // Data scheduled for sending
196  SSL *ssl;
197  SSL_CTX *ssl_ctx;
198  void *user_data;            // User-specific data
199  void *proto_data;           // Application protocol-specific data
200  time_t last_io_time;        // Timestamp of the last socket IO
201  ns_callback_t callback;     // Event handler function
202
203  unsigned int flags;
204#define NSF_FINISHED_SENDING_DATA   (1 << 0)
205#define NSF_BUFFER_BUT_DONT_SEND    (1 << 1)
206#define NSF_SSL_HANDSHAKE_DONE      (1 << 2)
207#define NSF_CONNECTING              (1 << 3)
208#define NSF_CLOSE_IMMEDIATELY       (1 << 4)
209#define NSF_WANT_READ               (1 << 5)
210#define NSF_WANT_WRITE              (1 << 6)
211#define NSF_LISTENING               (1 << 7)
212#define NSF_UDP                     (1 << 8)
213
214#define NSF_USER_1                  (1 << 20)
215#define NSF_USER_2                  (1 << 21)
216#define NSF_USER_3                  (1 << 22)
217#define NSF_USER_4                  (1 << 23)
218#define NSF_USER_5                  (1 << 24)
219#define NSF_USER_6                  (1 << 25)
220};
221
222void ns_mgr_init(struct ns_mgr *, void *user_data);
223void ns_mgr_free(struct ns_mgr *);
224time_t ns_mgr_poll(struct ns_mgr *, int milli);
225void ns_broadcast(struct ns_mgr *, ns_callback_t, void *, size_t);
226
227struct ns_connection *ns_next(struct ns_mgr *, struct ns_connection *);
228struct ns_connection *ns_add_sock(struct ns_mgr *, sock_t,
229                                  ns_callback_t, void *);
230struct ns_connection *ns_bind(struct ns_mgr *, const char *,
231                              ns_callback_t, void *);
232struct ns_connection *ns_connect(struct ns_mgr *, const char *,
233                                 ns_callback_t, void *);
234
235int ns_send(struct ns_connection *, const void *buf, int len);
236int ns_printf(struct ns_connection *, const char *fmt, ...);
237int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap);
238
239// Utility functions
240void *ns_start_thread(void *(*f)(void *), void *p);
241int ns_socketpair(sock_t [2]);
242int ns_socketpair2(sock_t [2], int sock_type);  // SOCK_STREAM or SOCK_DGRAM
243void ns_set_close_on_exec(sock_t);
244void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags);
245int ns_hexdump(const void *buf, int len, char *dst, int dst_len);
246int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap);
247int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len);
248
249#ifdef __cplusplus
250}
251#endif // __cplusplus
252
253#endif // NS_SKELETON_HEADER_INCLUDED
trunk/3rdparty/mongoose/examples/websocket_ssl_proxy/ssl_wrapper.c
r0r250110
1// Copyright (c) 2014 Cesanta Software Limited
2// All rights reserved
3//
4// This software is dual-licensed: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License version 2 as
6// published by the Free Software Foundation. For the terms of this
7// license, see <http://www.gnu.org/licenses/>.
8//
9// You are free to use this software under the terms of the GNU General
10// Public License, but WITHOUT ANY WARRANTY; without even the implied
11// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12// See the GNU General Public License for more details.
13//
14// Alternatively, you can license this software under a commercial
15// license, as set out in <http://cesanta.com/products.html>.
16//
17// $Date$
18
19#include "net_skeleton.h"
20#include "ssl_wrapper.h"
21
22static void ev_handler(struct ns_connection *nc, int ev, void *p) {
23  const char *target_addr = (const char *) nc->mgr->user_data;
24  struct ns_connection *pc = (struct ns_connection *) nc->user_data;
25  struct iobuf *io = &nc->recv_iobuf;
26
27  (void) p;
28  switch (ev) {
29    case NS_ACCEPT:
30      // Create a connection to the target, and interlink both connections
31      nc->user_data = ns_connect(nc->mgr, target_addr, ev_handler, nc);
32      if (nc->user_data == NULL) {
33        nc->flags |= NSF_CLOSE_IMMEDIATELY;
34      }
35      break;
36
37    case NS_CLOSE:
38      // If either connection closes, unlink them and shedule closing
39      if (pc != NULL) {
40        pc->flags |= NSF_FINISHED_SENDING_DATA;
41        pc->user_data = NULL;
42      }
43      nc->user_data = NULL;
44      break;
45
46    case NS_RECV:
47      // Forward arrived data to the other connection, and discard from buffer
48      if (pc != NULL) {
49        ns_send(pc, io->buf, io->len);
50        iobuf_remove(io, io->len);
51      }
52      break;
53
54    default:
55      break;
56  }
57}
58
59void *ssl_wrapper_init(const char *local_addr, const char *target_addr,
60                       const char **err_msg) {
61  struct ns_mgr *mgr = (struct ns_mgr *) calloc(1, sizeof(mgr[0]));
62  *err_msg = NULL;
63
64  if (mgr == NULL) {
65    *err_msg = "malloc failed";
66  } else {
67    ns_mgr_init(mgr, (void *) target_addr);
68    if (ns_bind(mgr, local_addr, ev_handler, NULL) == NULL) {
69      *err_msg = "ns_bind() failed: bad listening_port";
70      ns_mgr_free(mgr);
71      free(mgr);
72      mgr = NULL;
73    }
74  }
75
76  return mgr;
77}
78
79void ssl_wrapper_serve(void *param, volatile int *quit) {
80  struct ns_mgr *mgr = (struct ns_mgr *) param;
81
82  while (*quit == 0) {
83    ns_mgr_poll(mgr, 1000);
84  }
85  ns_mgr_free(mgr);
86  free(mgr);
87}
88
89#ifndef SSL_WRAPPER_USE_AS_LIBRARY
90static int s_received_signal = 0;
91
92static void signal_handler(int sig_num) {
93  signal(sig_num, signal_handler);
94  s_received_signal = sig_num;
95}
96
97static void show_usage_and_exit(const char *prog) {
98  fprintf(stderr, "Usage: %s <listening_address> <target_address>\n", prog);
99  exit(EXIT_FAILURE);
100}
101
102int main(int argc, char *argv[]) {
103  void *wrapper;
104  const char *err_msg;
105
106  if (argc != 3) {
107    show_usage_and_exit(argv[0]);
108  }
109
110  // Setup signal handlers
111  signal(SIGTERM, signal_handler);
112  signal(SIGINT, signal_handler);
113  signal(SIGPIPE, SIG_IGN);
114
115  if ((wrapper = ssl_wrapper_init(argv[1], argv[2], &err_msg)) == NULL) {
116    fprintf(stderr, "Error: %s\n", err_msg);
117    exit(EXIT_FAILURE);
118  }
119  ssl_wrapper_serve(wrapper, &s_received_signal);
120
121  return EXIT_SUCCESS;
122}
123#endif // SSL_WRAPPER_USE_AS_LIBRARY
trunk/3rdparty/mongoose/examples/websocket_ssl_proxy/ssl_wrapper.h
r0r250110
1// Copyright (c) 2014 Cesanta Software Limited
2// All rights reserved
3//
4// This software is dual-licensed: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License version 2 as
6// published by the Free Software Foundation. For the terms of this
7// license, see <http://www.gnu.org/licenses/>.
8//
9// You are free to use this software under the terms of the GNU General
10// Public License, but WITHOUT ANY WARRANTY; without even the implied
11// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12// See the GNU General Public License for more details.
13//
14// Alternatively, you can license this software under a commercial
15// license, as set out in <http://cesanta.com/products.html>.
16//
17// $Date$
18
19#ifndef SSL_WRAPPER_HEADER_INCLUDED
20#define SSL_WRAPPER_HEADER_INCLUDED
21
22#ifdef __cplusplus
23extern "C" {
24#endif // __cplusplus
25
26void *ssl_wrapper_init(const char *listen_addr, const char *target_addr,
27                       const char **err_msg);
28void ssl_wrapper_serve(void *, volatile int *stop_marker);
29
30#ifdef __cplusplus
31}
32#endif // __cplusplus
33
34#endif // SSL_WRAPPER_HEADER_INCLUDED
trunk/3rdparty/mongoose/examples/websocket_ssl_proxy/ws_ssl.c
r0r250110
1// Copyright (c) 2014 Cesanta Software
2// All rights reserved
3//
4// This example demostrates proxying of WebSocket traffic, regardless of the
5// protocol (ws:// or wss://).
6// To use this example:
7//    1. configure your browser to use a proxy on port 2014
8//    2. import certs/ws1_ca.pem and certs/ws2_ca.pem into the trusted
9//       certificates list on your browser
10//    3. make && ./ws_ssl
11//    4. Point your browser to http://ws_ssl.com
12//  A page with 4 sections should appear, showing websocket echoes
13
14#include "net_skeleton.h"
15#include "mongoose.h"
16#include "ssl_wrapper.h"
17
18#define S1_PEM  "certs/ws1_server.pem"
19#define C1_PEM  "certs/ws1_client.pem"
20#define CA1_PEM "certs/ws1_ca.pem"
21#define S2_PEM  "certs/ws2_server.pem"
22#define C2_PEM  "certs/ws2_client.pem"
23#define CA2_PEM "certs/ws2_ca.pem"
24
25struct config {
26  const char *uri;
27  const char *wrapper_server_addr;
28  const char *wrapper_client_addr;
29  const char *target_addr;
30};
31
32static struct config s_wrappers[] = {
33  {
34    "ws1:80",
35    "tcp://127.0.0.1:7001",
36    "tcp://127.0.0.1:7001",
37    "tcp://127.0.0.1:9001"
38  },
39  {
40    "ws1:443",
41    "ssl://127.0.0.1:7002:" S1_PEM,
42    "tcp://127.0.0.1:7002",
43    "tcp://127.0.0.1:9001"
44  },
45  {
46    "ws2:80",
47    "tcp://127.0.0.1:7003",
48    "tcp://127.0.0.1:7003",
49    "ssl://127.0.0.1:9002:" C2_PEM ":" CA2_PEM
50  },
51  {
52    "ws2:443",
53    "ssl://127.0.0.1:7004:" S2_PEM,
54    "tcp://127.0.0.1:7004",
55    "ssl://127.0.0.1:9002:" C2_PEM ":" CA2_PEM
56  },
57};
58
59static int s_received_signal = 0;
60
61static void signal_handler(int sig_num) {
62  signal(sig_num, signal_handler);
63  s_received_signal = sig_num;
64}
65
66static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
67  int i;
68
69  switch (ev) {
70    case MG_AUTH:
71      return MG_TRUE;
72
73    case MG_REQUEST:
74      printf("==> [%s] [%s]\n", conn->request_method, conn->uri);
75
76      if (strcmp(conn->request_method, "CONNECT") == 0) {
77        // Iterate over configured wrappers, see if we can use one of them
78        for (i = 0; i < (int) ARRAY_SIZE(s_wrappers); i++) {
79          if (strcmp(conn->uri, s_wrappers[i].uri) == 0) {
80            mg_forward(conn, s_wrappers[i].wrapper_client_addr);
81            return MG_MORE;
82          }
83        }
84
85        // No suitable wrappers found. Disallow that CONNECT request.
86        mg_send_status(conn, 405);
87        return MG_TRUE;
88      }
89
90      // Not a CONNECT request, serve HTML file.
91      mg_send_file(conn, "ws_ssl.html", NULL);
92      return MG_MORE;
93
94    default:
95      return MG_FALSE;
96  }
97}
98
99static int ws_handler(struct mg_connection *conn, enum mg_event ev) {
100  switch (ev) {
101    case MG_AUTH:
102      return MG_TRUE;
103    case MG_REQUEST:
104      if (conn->is_websocket) {
105        // Simple websocket echo server
106        mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT,
107                           conn->content, conn->content_len);
108      } else {
109        mg_printf_data(conn, "%s", "websocket connection expected");
110      }
111      return MG_TRUE;
112    default:
113      return MG_FALSE;
114  }
115}
116
117static void *serve_thread_func(void *param) {
118  struct mg_server *server = (struct mg_server *) param;
119  printf("Listening on port %s\n", mg_get_option(server, "listening_port"));
120  while (s_received_signal == 0) {
121    mg_poll_server(server, 1000);
122  }
123  mg_destroy_server(&server);
124  return NULL;
125}
126
127static void *wrapper_thread_func(void *param) {
128  struct config *c = (struct config *) param;
129  const char *err_msg;
130  void *wrapper;
131
132  wrapper = ssl_wrapper_init(c->wrapper_server_addr, c->target_addr, &err_msg);
133  if (wrapper == NULL) {
134    fprintf(stderr, "Error: %s\n", err_msg);
135    exit(EXIT_FAILURE);
136  }
137  //((struct ns_mgr *) wrapper)->hexdump_file = "/dev/stderr";
138  ssl_wrapper_serve(wrapper, &s_received_signal);
139
140  return NULL;
141}
142
143int main(void) {
144  struct mg_server *proxy_server = mg_create_server(NULL, ev_handler);
145  struct mg_server *ws1_server = mg_create_server(NULL, ws_handler);
146  struct mg_server *ws2_server = mg_create_server(NULL, ws_handler);
147  size_t i;
148
149  ((struct ns_mgr *) proxy_server)->hexdump_file = "/dev/stderr";
150
151  // Configure proxy server to listen on port 2014
152  mg_set_option(proxy_server, "listening_port", "2014");
153  //mg_set_option(proxy_server, "enable_proxy", "yes");
154
155  // Configure two websocket echo servers:
156  //    ws1 is WS, listening on 9001
157  //    ws2 is WSS, listening on 9002
158  // Note that HTML page thinks that ws1 is WSS, and ws2 is WS,
159  // where in reality it is vice versa and proxy server makes the decision.
160  mg_set_option(ws1_server, "listening_port", "tcp://127.0.0.1:9001");
161  mg_set_option(ws2_server, "listening_port",
162                "ssl://127.0.0.1:9002:" S2_PEM ":" CA2_PEM);
163
164  // Setup signal handlers
165  signal(SIGTERM, signal_handler);
166  signal(SIGINT, signal_handler);
167
168  // Start SSL wrappers, each in it's own thread
169  for (i = 0; i < ARRAY_SIZE(s_wrappers); i++) {
170    ns_start_thread(wrapper_thread_func, &s_wrappers[i]);
171  }
172
173  // Start websocket servers in separate threads
174  mg_start_thread(serve_thread_func, ws1_server);
175  mg_start_thread(serve_thread_func, ws2_server);
176
177  // Finally, start proxy server in this thread: this call blocks
178  serve_thread_func(proxy_server);
179
180  printf("Existing on signal %d\n", s_received_signal);
181  return EXIT_SUCCESS;
182}
trunk/3rdparty/mongoose/examples/websocket_ssl_proxy/ws_ssl.html
r0r250110
1<html>
2<head>
3  <title>Websocket Proxy SSL Test</title>
4  <meta charset="utf-8">
5  <script>
6  window.onload = function() {
7    var protocols = ['ws://', 'wss://'];
8    var websocketServers = ['ws1', 'ws2'];
9    //protocols = ['wss://'];
10    //websocketServers = ['ws1']
11
12    var createWebsocketConnection = function(proto, server) {
13      var conn = new WebSocket(proto + server);
14
15      var div = document.createElement('div');
16      var h2 = document.createElement('h2');
17      h2.innerHTML = 'Connection to ' + proto + server;
18      document.body.appendChild(h2);
19      document.body.appendChild(div);
20
21      conn.onmessage = function(ev) {
22        var el = document.createElement('div');
23        el.innerHTML = 'websocket message: ' + ev.data;
24        div.appendChild(el);
25        // Keep only last 5 messages in the list
26        while (div.childNodes.length > 5) div.removeChild(div.firstChild);
27      };
28
29      // Send some string to the websocket connection periodically.
30      // websocket server much echo it back.
31      window.setInterval(function() { conn.send(Math.random()); }, 1000);
32    };
33
34    for (var i = 0; i < protocols.length; i++) {
35      for (var j = 0; j < websocketServers.length; j++) {
36        createWebsocketConnection(protocols[i], websocketServers[j]);
37      }
38    }
39  };
40  </script>
41  <style>
42    body > div {
43      border: 1px solid #ccc; background: #f0f0f0; padding: 0 1em;
44      margin: 0 2em; min-height: 4em; max-width: 40em;
45    }
46  </style>
47</head>
48<body>
49</body>
50</html>
No newline at end of file
trunk/3rdparty/mongoose/jni/Android.mk
r0r250110
1LOCAL_PATH := $(call my-dir)/..
2include $(CLEAR_VARS)
3
4LOCAL_CFLAGS    := -std=c99 -O2 -W -Wall -pthread -pipe $(COPT)
5LOCAL_MODULE    := mongoose
6LOCAL_SRC_FILES := examples/web_server/web_server.c mongoose.c
7
8include $(BUILD_EXECUTABLE)
trunk/3rdparty/mongoose/mongoose.c
r0r250110
1// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
2// Copyright (c) 2013-2014 Cesanta Software Limited
3// All rights reserved
4//
5// This library is dual-licensed: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License version 2 as
7// published by the Free Software Foundation. For the terms of this
8// license, see <http://www.gnu.org/licenses/>.
9//
10// You are free to use this library under the terms of the GNU General
11// Public License, but WITHOUT ANY WARRANTY; without even the implied
12// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13// See the GNU General Public License for more details.
14//
15// Alternatively, you can license this library under a commercial
16// license, as set out in <http://cesanta.com/>.
17
18#ifdef NOEMBED_NET_SKELETON
19#include "net_skeleton.h"
20#else
21// net_skeleton start
22// Copyright (c) 2014 Cesanta Software Limited
23// All rights reserved
24//
25// This software is dual-licensed: you can redistribute it and/or modify
26// it under the terms of the GNU General Public License version 2 as
27// published by the Free Software Foundation. For the terms of this
28// license, see <http://www.gnu.org/licenses/>.
29//
30// You are free to use this software under the terms of the GNU General
31// Public License, but WITHOUT ANY WARRANTY; without even the implied
32// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
33// See the GNU General Public License for more details.
34//
35// Alternatively, you can license this software under a commercial
36// license, as set out in <http://cesanta.com/>.
37
38#ifndef NS_SKELETON_HEADER_INCLUDED
39#define NS_SKELETON_HEADER_INCLUDED
40
41#define NS_SKELETON_VERSION "2.1.0"
42
43#undef UNICODE                  // Use ANSI WinAPI functions
44#undef _UNICODE                 // Use multibyte encoding on Windows
45#define _MBCS                   // Use multibyte encoding on Windows
46#define _INTEGRAL_MAX_BITS 64   // Enable _stati64() on Windows
47#ifndef _CRT_SECURE_NO_WARNINGS
48#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005+
49#endif
50#undef WIN32_LEAN_AND_MEAN      // Let windows.h always include winsock2.h
51#ifdef __Linux__
52#define _XOPEN_SOURCE 600       // For flockfile() on Linux
53#endif
54#define __STDC_FORMAT_MACROS    // <inttypes.h> wants this for C++
55#define __STDC_LIMIT_MACROS     // C++ wants that for INT64_MAX
56#ifndef _LARGEFILE_SOURCE
57#define _LARGEFILE_SOURCE       // Enable fseeko() and ftello() functions
58#endif
59#define _FILE_OFFSET_BITS 64    // Enable 64-bit file offsets
60
61#ifdef _MSC_VER
62#pragma warning (disable : 4127)  // FD_SET() emits warning, disable it
63#pragma warning (disable : 4204)  // missing c99 support
64#endif
65
66#if defined(_WIN32) && !defined(MONGOOSE_NO_CGI) && !defined(MONGOOSE_ENABLE_THREADS)
67#define MONGOOSE_ENABLE_THREADS   /* Windows uses stdio threads for CGI */
68#endif
69
70#ifndef MONGOOSE_ENABLE_THREADS
71#define NS_DISABLE_THREADS
72#endif
73
74#ifdef __OS2__
75#define _MMAP_DECLARED          // Prevent dummy mmap() declaration in stdio.h
76#endif
77
78#include <sys/types.h>
79#include <sys/stat.h>
80#include <assert.h>
81#include <ctype.h>
82#include <errno.h>
83#include <fcntl.h>
84#include <stdarg.h>
85#include <stddef.h>
86#include <stdio.h>
87#include <stdlib.h>
88#include <string.h>
89#include <time.h>
90#include <signal.h>
91
92#ifdef _WIN32
93#ifdef _MSC_VER
94#pragma comment(lib, "ws2_32.lib")    // Linking with winsock library
95#include <BaseTsd.h>
96typedef SSIZE_T ssize_t;
97#endif
98#ifndef FD_SETSIZE
99#define FD_SETSIZE 1024
100#endif
101#include <winsock2.h>
102#include <ws2tcpip.h>
103#include <windows.h>
104#include <process.h>
105#ifndef EINPROGRESS
106#define EINPROGRESS WSAEINPROGRESS
107#endif
108#ifndef EWOULDBLOCK
109#define EWOULDBLOCK WSAEWOULDBLOCK
110#endif
111#ifndef __func__
112#define STRX(x) #x
113#define STR(x) STRX(x)
114#define __func__ __FILE__ ":" STR(__LINE__)
115#endif
116#ifndef va_copy
117#define va_copy(x,y) x = y
118#endif // MINGW #defines va_copy
119#define snprintf _snprintf
120#define vsnprintf _vsnprintf
121#define sleep(x) Sleep((x) * 1000)
122#define to64(x) _atoi64(x)
123typedef int socklen_t;
124typedef unsigned char uint8_t;
125typedef unsigned int uint32_t;
126typedef unsigned short uint16_t;
127typedef unsigned __int64 uint64_t;
128typedef __int64   int64_t;
129typedef SOCKET sock_t;
130typedef struct _stati64 ns_stat_t;
131#ifndef S_ISDIR
132#define S_ISDIR(x) ((x) & _S_IFDIR)
133#endif
134#else
135#include <errno.h>
136#include <fcntl.h>
137#include <netdb.h>
138#include <pthread.h>
139#include <stdarg.h>
140#include <unistd.h>
141#include <arpa/inet.h>  // For inet_pton() when NS_ENABLE_IPV6 is defined
142#include <netinet/in.h>
143#include <sys/socket.h>
144#include <sys/select.h>
145#define closesocket(x) close(x)
146#ifndef __OS2__
147#define __cdecl
148#else
149#include <sys/time.h>
150typedef int socklen_t;
151#endif
152#define INVALID_SOCKET (-1)
153#define to64(x) strtoll(x, NULL, 10)
154typedef int sock_t;
155typedef struct stat ns_stat_t;
156#endif
157
158#ifdef NS_ENABLE_DEBUG
159#define DBG(x) do { printf("%-20s ", __func__); printf x; putchar('\n'); \
160  fflush(stdout); } while(0)
161#else
162#define DBG(x)
163#endif
164
165#ifndef ARRAY_SIZE
166#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
167#endif
168
169#ifdef NS_ENABLE_SSL
170#ifdef __APPLE__
171#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
172#endif
173#include <openssl/ssl.h>
174#else
175typedef void *SSL;
176typedef void *SSL_CTX;
177#endif
178
179#ifdef __cplusplus
180extern "C" {
181#endif // __cplusplus
182
183union socket_address {
184  struct sockaddr sa;
185  struct sockaddr_in sin;
186#ifdef NS_ENABLE_IPV6
187  struct sockaddr_in6 sin6;
188#else
189  struct sockaddr sin6;
190#endif
191};
192
193// Describes chunk of memory
194struct ns_str {
195  const char *p;
196  size_t len;
197};
198
199// IO buffers interface
200struct iobuf {
201  char *buf;
202  size_t len;
203  size_t size;
204};
205
206void iobuf_init(struct iobuf *, size_t initial_size);
207void iobuf_free(struct iobuf *);
208size_t iobuf_append(struct iobuf *, const void *data, size_t data_size);
209void iobuf_remove(struct iobuf *, size_t data_size);
210void iobuf_resize(struct iobuf *, size_t new_size);
211
212// Callback function (event handler) prototype, must be defined by user.
213// Net skeleton will call event handler, passing events defined above.
214struct ns_connection;
215typedef void (*ns_callback_t)(struct ns_connection *, int event_num, void *evp);
216
217// Events. Meaning of event parameter (evp) is given in the comment.
218#define NS_POLL    0  // Sent to each connection on each call to ns_mgr_poll()
219#define NS_ACCEPT  1  // New connection accept()-ed. union socket_address *addr
220#define NS_CONNECT 2  // connect() succeeded or failed. int *success_status
221#define NS_RECV    3  // Data has benn received. int *num_bytes
222#define NS_SEND    4  // Data has been written to a socket. int *num_bytes
223#define NS_CLOSE   5  // Connection is closed. NULL
224
225
226struct ns_mgr {
227  struct ns_connection *active_connections;
228  const char *hexdump_file;         // Debug hexdump file path
229  sock_t ctl[2];                    // Socketpair for mg_wakeup()
230  void *user_data;                  // User data
231};
232
233
234struct ns_connection {
235  struct ns_connection *next, *prev;  // ns_mgr::active_connections linkage
236  struct ns_connection *listener;     // Set only for accept()-ed connections
237  struct ns_mgr *mgr;
238
239  sock_t sock;                // Socket
240  union socket_address sa;    // Peer address
241  size_t recv_iobuf_limit; /* Max size of recv buffer */
242  struct iobuf recv_iobuf;    // Received data
243  struct iobuf send_iobuf;    // Data scheduled for sending
244  SSL *ssl;
245  SSL_CTX *ssl_ctx;
246  void *user_data;            // User-specific data
247  void *proto_data;           // Application protocol-specific data
248  time_t last_io_time;        // Timestamp of the last socket IO
249  ns_callback_t callback;     // Event handler function
250
251  unsigned int flags;
252#define NSF_FINISHED_SENDING_DATA   (1 << 0)
253#define NSF_BUFFER_BUT_DONT_SEND    (1 << 1)
254#define NSF_SSL_HANDSHAKE_DONE      (1 << 2)
255#define NSF_CONNECTING              (1 << 3)
256#define NSF_CLOSE_IMMEDIATELY       (1 << 4)
257#define NSF_WANT_READ               (1 << 5)
258#define NSF_WANT_WRITE              (1 << 6)
259#define NSF_LISTENING               (1 << 7)
260#define NSF_UDP                     (1 << 8)
261#define NSF_DISCARD                 (1 << 9)
262
263#define NSF_USER_1                  (1 << 20)
264#define NSF_USER_2                  (1 << 21)
265#define NSF_USER_3                  (1 << 22)
266#define NSF_USER_4                  (1 << 23)
267#define NSF_USER_5                  (1 << 24)
268#define NSF_USER_6                  (1 << 25)
269};
270
271void ns_mgr_init(struct ns_mgr *, void *user_data);
272void ns_mgr_free(struct ns_mgr *);
273time_t ns_mgr_poll(struct ns_mgr *, int milli);
274void ns_broadcast(struct ns_mgr *, ns_callback_t, void *, size_t);
275
276struct ns_connection *ns_next(struct ns_mgr *, struct ns_connection *);
277struct ns_connection *ns_add_sock(struct ns_mgr *, sock_t,
278                                  ns_callback_t, void *);
279struct ns_connection *ns_bind(struct ns_mgr *, const char *,
280                              ns_callback_t, void *);
281struct ns_connection *ns_connect(struct ns_mgr *, const char *,
282                                 ns_callback_t, void *);
283
284int ns_send(struct ns_connection *, const void *buf, size_t len);
285int ns_printf(struct ns_connection *, const char *fmt, ...);
286int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap);
287
288// Utility functions
289void *ns_start_thread(void *(*f)(void *), void *p);
290int ns_socketpair(sock_t [2]);
291int ns_socketpair2(sock_t [2], int sock_type);  // SOCK_STREAM or SOCK_DGRAM
292void ns_set_close_on_exec(sock_t);
293void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags);
294int ns_hexdump(const void *buf, int len, char *dst, int dst_len);
295int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap);
296int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len);
297
298#ifdef __cplusplus
299}
300#endif // __cplusplus
301
302#endif // NS_SKELETON_HEADER_INCLUDED
303// Copyright (c) 2014 Cesanta Software Limited
304// All rights reserved
305//
306// This software is dual-licensed: you can redistribute it and/or modify
307// it under the terms of the GNU General Public License version 2 as
308// published by the Free Software Foundation. For the terms of this
309// license, see <http://www.gnu.org/licenses/>.
310//
311// You are free to use this software under the terms of the GNU General
312// Public License, but WITHOUT ANY WARRANTY; without even the implied
313// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
314// See the GNU General Public License for more details.
315//
316// Alternatively, you can license this software under a commercial
317// license, as set out in <http://cesanta.com/>.
318//
319// $Date: 2014-09-28 05:04:41 UTC $
320
321
322#ifndef NS_MALLOC
323#define NS_MALLOC malloc
324#endif
325
326#ifndef NS_REALLOC
327#define NS_REALLOC realloc
328#endif
329
330#ifndef NS_FREE
331#define NS_FREE free
332#endif
333
334#ifndef NS_CALLOC
335#define NS_CALLOC calloc
336#endif
337
338#define NS_MAX_SOCKETPAIR_ATTEMPTS  10
339#define NS_CTL_MSG_MESSAGE_SIZE     (8 * 1024)
340#define NS_READ_BUFFER_SIZE         2048
341#define NS_UDP_RECEIVE_BUFFER_SIZE  2000
342#define NS_VPRINTF_BUFFER_SIZE      500
343
344struct ctl_msg {
345  ns_callback_t callback;
346  char message[NS_CTL_MSG_MESSAGE_SIZE];
347};
348
349void iobuf_resize(struct iobuf *io, size_t new_size) {
350  char *p;
351  if ((new_size > io->size || (new_size < io->size && new_size >= io->len)) &&
352      (p = (char *) NS_REALLOC(io->buf, new_size)) != NULL) {
353    io->size = new_size;
354    io->buf = p;
355  }
356}
357
358void iobuf_init(struct iobuf *iobuf, size_t initial_size) {
359  iobuf->len = iobuf->size = 0;
360  iobuf->buf = NULL;
361  iobuf_resize(iobuf, initial_size);
362}
363
364void iobuf_free(struct iobuf *iobuf) {
365  if (iobuf != NULL) {
366    if (iobuf->buf != NULL) NS_FREE(iobuf->buf);
367    iobuf_init(iobuf, 0);
368  }
369}
370
371size_t iobuf_append(struct iobuf *io, const void *buf, size_t len) {
372  char *p = NULL;
373
374  assert(io != NULL);
375  assert(io->len <= io->size);
376
377  /* check overflow */
378  if (len > ~(size_t)0 - (size_t)(io->buf + io->len)) {
379    return 0;
380  }
381
382  if (len <= 0) {
383  } else if (io->len + len <= io->size) {
384    memcpy(io->buf + io->len, buf, len);
385    io->len += len;
386  } else if ((p = (char *) NS_REALLOC(io->buf, io->len + len)) != NULL) {
387    io->buf = p;
388    memcpy(io->buf + io->len, buf, len);
389    io->len += len;
390    io->size = io->len;
391  } else {
392    len = 0;
393  }
394
395  return len;
396}
397
398void iobuf_remove(struct iobuf *io, size_t n) {
399  if (n > 0 && n <= io->len) {
400    memmove(io->buf, io->buf + n, io->len - n);
401    io->len -= n;
402  }
403}
404
405static size_t ns_out(struct ns_connection *nc, const void *buf, size_t len) {
406  if (nc->flags & NSF_UDP) {
407    long n = sendto(nc->sock, (const char *) buf, len, 0, &nc->sa.sa,
408                    sizeof(nc->sa.sin));
409    DBG(("%p %d send %ld (%d %s)", nc, nc->sock, n, errno, strerror(errno)));
410    return n < 0 ? 0 : n;
411  } else {
412    return iobuf_append(&nc->send_iobuf, buf, len);
413  }
414}
415
416#ifndef NS_DISABLE_THREADS
417void *ns_start_thread(void *(*f)(void *), void *p) {
418#ifdef _WIN32
419  return (void *) _beginthread((void (__cdecl *)(void *)) f, 0, p);
420#else
421  pthread_t thread_id = (pthread_t) 0;
422  pthread_attr_t attr;
423
424  (void) pthread_attr_init(&attr);
425  (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
426
427#if defined(NS_STACK_SIZE) && NS_STACK_SIZE > 1
428  (void) pthread_attr_setstacksize(&attr, NS_STACK_SIZE);
429#endif
430
431  pthread_create(&thread_id, &attr, f, p);
432  pthread_attr_destroy(&attr);
433
434  return (void *) thread_id;
435#endif
436}
437#endif  // NS_DISABLE_THREADS
438
439static void ns_add_conn(struct ns_mgr *mgr, struct ns_connection *c) {
440  c->next = mgr->active_connections;
441  mgr->active_connections = c;
442  c->prev = NULL;
443  if (c->next != NULL) c->next->prev = c;
444}
445
446static void ns_remove_conn(struct ns_connection *conn) {
447  if (conn->prev == NULL) conn->mgr->active_connections = conn->next;
448  if (conn->prev) conn->prev->next = conn->next;
449  if (conn->next) conn->next->prev = conn->prev;
450}
451
452// Print message to buffer. If buffer is large enough to hold the message,
453// return buffer. If buffer is to small, allocate large enough buffer on heap,
454// and return allocated buffer.
455int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
456  va_list ap_copy;
457  int len;
458
459  va_copy(ap_copy, ap);
460  len = vsnprintf(*buf, size, fmt, ap_copy);
461  va_end(ap_copy);
462
463  if (len < 0) {
464    // eCos and Windows are not standard-compliant and return -1 when
465    // the buffer is too small. Keep allocating larger buffers until we
466    // succeed or out of memory.
467    *buf = NULL;
468    while (len < 0) {
469      if (*buf) NS_FREE(*buf);
470      size *= 2;
471      if ((*buf = (char *) NS_MALLOC(size)) == NULL) break;
472      va_copy(ap_copy, ap);
473      len = vsnprintf(*buf, size, fmt, ap_copy);
474      va_end(ap_copy);
475    }
476  } else if (len > (int) size) {
477    // Standard-compliant code path. Allocate a buffer that is large enough.
478    if ((*buf = (char *) NS_MALLOC(len + 1)) == NULL) {
479      len = -1;
480    } else {
481      va_copy(ap_copy, ap);
482      len = vsnprintf(*buf, len + 1, fmt, ap_copy);
483      va_end(ap_copy);
484    }
485  }
486
487  return len;
488}
489
490int ns_vprintf(struct ns_connection *nc, const char *fmt, va_list ap) {
491  char mem[NS_VPRINTF_BUFFER_SIZE], *buf = mem;
492  int len;
493
494  if ((len = ns_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
495    ns_out(nc, buf, len);
496  }
497  if (buf != mem && buf != NULL) {
498    NS_FREE(buf);
499  }
500
501  return len;
502}
503
504int ns_printf(struct ns_connection *conn, const char *fmt, ...) {
505  int len;
506  va_list ap;
507  va_start(ap, fmt);
508  len = ns_vprintf(conn, fmt, ap);
509  va_end(ap);
510  return len;
511}
512
513static void hexdump(struct ns_connection *nc, const char *path,
514                    int num_bytes, int ev) {
515  const struct iobuf *io = ev == NS_SEND ? &nc->send_iobuf : &nc->recv_iobuf;
516  FILE *fp;
517  char *buf, src[60], dst[60];
518  int buf_size = num_bytes * 5 + 100;
519
520  if ((fp = fopen(path, "a")) != NULL) {
521    ns_sock_to_str(nc->sock, src, sizeof(src), 3);
522    ns_sock_to_str(nc->sock, dst, sizeof(dst), 7);
523    fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) time(NULL),
524            nc->user_data, src,
525            ev == NS_RECV ? "<-" : ev == NS_SEND ? "->" :
526            ev == NS_ACCEPT ? "<A" : ev == NS_CONNECT ? "C>" : "XX",
527            dst, num_bytes);
528    if (num_bytes > 0 && (buf = (char *) NS_MALLOC(buf_size)) != NULL) {
529      ns_hexdump(io->buf + (ev == NS_SEND ? 0 : io->len) -
530        (ev == NS_SEND ? 0 : num_bytes), num_bytes, buf, buf_size);
531      fprintf(fp, "%s", buf);
532      NS_FREE(buf);
533    }
534    fclose(fp);
535  }
536}
537
538static void ns_call(struct ns_connection *nc, int ev, void *p) {
539  if (nc->mgr->hexdump_file != NULL && ev != NS_POLL) {
540    int len = (ev == NS_RECV || ev == NS_SEND) ? * (int *) p : 0;
541    hexdump(nc, nc->mgr->hexdump_file, len, ev);
542  }
543
544  nc->callback(nc, ev, p);
545}
546
547static void ns_destroy_conn(struct ns_connection *conn) {
548  closesocket(conn->sock);
549  iobuf_free(&conn->recv_iobuf);
550  iobuf_free(&conn->send_iobuf);
551#ifdef NS_ENABLE_SSL
552  if (conn->ssl != NULL) {
553    SSL_free(conn->ssl);
554  }
555  if (conn->ssl_ctx != NULL) {
556    SSL_CTX_free(conn->ssl_ctx);
557  }
558#endif
559  NS_FREE(conn);
560}
561
562static void ns_close_conn(struct ns_connection *conn) {
563  DBG(("%p %d", conn, conn->flags));
564  ns_call(conn, NS_CLOSE, NULL);
565  ns_remove_conn(conn);
566  ns_destroy_conn(conn);
567}
568
569void ns_set_close_on_exec(sock_t sock) {
570#ifdef _WIN32
571  (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
572#else
573  fcntl(sock, F_SETFD, FD_CLOEXEC);
574#endif
575}
576
577static void ns_set_non_blocking_mode(sock_t sock) {
578#ifdef _WIN32
579  unsigned long on = 1;
580  ioctlsocket(sock, FIONBIO, &on);
581#else
582  int flags = fcntl(sock, F_GETFL, 0);
583  fcntl(sock, F_SETFL, flags | O_NONBLOCK);
584#endif
585}
586
587#ifndef NS_DISABLE_SOCKETPAIR
588int ns_socketpair2(sock_t sp[2], int sock_type) {
589  union socket_address sa;
590  sock_t sock;
591  socklen_t len = sizeof(sa.sin);
592  int ret = 0;
593
594  sp[0] = sp[1] = INVALID_SOCKET;
595
596  (void) memset(&sa, 0, sizeof(sa));
597  sa.sin.sin_family = AF_INET;
598  sa.sin.sin_port = htons(0);
599  sa.sin.sin_addr.s_addr = htonl(0x7f000001);
600
601  if ((sock = socket(AF_INET, sock_type, 0)) != INVALID_SOCKET &&
602      !bind(sock, &sa.sa, len) &&
603      (sock_type == SOCK_DGRAM || !listen(sock, 1)) &&
604      !getsockname(sock, &sa.sa, &len) &&
605      (sp[0] = socket(AF_INET, sock_type, 0)) != INVALID_SOCKET &&
606      !connect(sp[0], &sa.sa, len) &&
607      (sock_type == SOCK_STREAM ||
608       (!getsockname(sp[0], &sa.sa, &len) && !connect(sock, &sa.sa, len))) &&
609      (sp[1] = (sock_type == SOCK_DGRAM ? sock :
610                accept(sock, &sa.sa, &len))) != INVALID_SOCKET) {
611    ns_set_close_on_exec(sp[0]);
612    ns_set_close_on_exec(sp[1]);
613    ret = 1;
614  } else {
615    if (sp[0] != INVALID_SOCKET) closesocket(sp[0]);
616    if (sp[1] != INVALID_SOCKET) closesocket(sp[1]);
617    sp[0] = sp[1] = INVALID_SOCKET;
618  }
619  if (sock_type != SOCK_DGRAM) closesocket(sock);
620
621  return ret;
622}
623
624int ns_socketpair(sock_t sp[2]) {
625  return ns_socketpair2(sp, SOCK_STREAM);
626}
627#endif  // NS_DISABLE_SOCKETPAIR
628
629// TODO(lsm): use non-blocking resolver
630static int ns_resolve2(const char *host, struct in_addr *ina) {
631#ifdef NS_ENABLE_GETADDRINFO
632  int rv = 0;
633  struct addrinfo hints, *servinfo, *p;
634  struct sockaddr_in *h = NULL;
635
636  memset(&hints, 0, sizeof hints);
637  hints.ai_family = AF_INET;
638  hints.ai_socktype = SOCK_STREAM;
639
640  if((rv = getaddrinfo(host, NULL , NULL, &servinfo)) != 0) {
641    DBG(("getaddrinfo(%s) failed: %s", host, strerror(errno)));
642    return 0;
643  }
644
645  for(p = servinfo; p != NULL; p = p->ai_next) {
646    memcpy(&h, &p->ai_addr, sizeof(struct sockaddr_in *));
647    memcpy(ina, &h->sin_addr, sizeof(ina));
648  }
649
650  freeaddrinfo(servinfo);
651  return 1;
652#else
653  struct hostent *he;
654  if ((he = gethostbyname(host)) == NULL) {
655    DBG(("gethostbyname(%s) failed: %s", host, strerror(errno)));
656  } else {
657    memcpy(ina, he->h_addr_list[0], sizeof(*ina));
658    return 1;
659  }
660  return 0;
661#endif
662}
663
664// Resolve FDQN "host", store IP address in the "ip".
665// Return > 0 (IP address length) on success.
666int ns_resolve(const char *host, char *buf, size_t n) {
667  struct in_addr ad;
668  return ns_resolve2(host, &ad) ? snprintf(buf, n, "%s", inet_ntoa(ad)) : 0;
669}
670
671// Address format: [PROTO://][IP_ADDRESS:]PORT[:CERT][:CA_CERT]
672static int ns_parse_address(const char *str, union socket_address *sa,
673                            int *proto, int *use_ssl, char *cert, char *ca) {
674  unsigned int a, b, c, d, port;
675  int n = 0, len = 0;
676  char host[200];
677#ifdef NS_ENABLE_IPV6
678  char buf[100];
679#endif
680
681  // MacOS needs that. If we do not zero it, subsequent bind() will fail.
682  // Also, all-zeroes in the socket address means binding to all addresses
683  // for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
684  memset(sa, 0, sizeof(*sa));
685  sa->sin.sin_family = AF_INET;
686
687  *proto = SOCK_STREAM;
688  *use_ssl = 0;
689  cert[0] = ca[0] = '\0';
690
691  if (memcmp(str, "ssl://", 6) == 0) {
692    str += 6;
693    *use_ssl = 1;
694  } else if (memcmp(str, "udp://", 6) == 0) {
695    str += 6;
696    *proto = SOCK_DGRAM;
697  } else if (memcmp(str, "tcp://", 6) == 0) {
698    str += 6;
699  }
700
701  if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
702    // Bind to a specific IPv4 address, e.g. 192.168.1.5:8080
703    sa->sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
704    sa->sin.sin_port = htons((uint16_t) port);
705#ifdef NS_ENABLE_IPV6
706  } else if (sscanf(str, "[%99[^]]]:%u%n", buf, &port, &len) == 2 &&
707             inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) {
708    // IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080
709    sa->sin6.sin6_family = AF_INET6;
710    sa->sin6.sin6_port = htons((uint16_t) port);
711#endif
712  } else if (sscanf(str, "%199[^ :]:%u%n", host, &port, &len) == 2) {
713    sa->sin.sin_port = htons((uint16_t) port);
714    ns_resolve2(host, &sa->sin.sin_addr);
715  } else if (sscanf(str, "%u%n", &port, &len) == 1) {
716    // If only port is specified, bind to IPv4, INADDR_ANY
717    sa->sin.sin_port = htons((uint16_t) port);
718  }
719
720  if (*use_ssl && (sscanf(str + len, ":%99[^:,]:%99[^:,]%n", cert, ca, &n) == 2 ||
721                   sscanf(str + len, ":%99[^:,]%n", cert, &n) == 1)) {
722    len += n;
723  }
724
725  return port < 0xffff && str[len] == '\0' ? len : 0;
726}
727
728// 'sa' must be an initialized address to bind to
729static sock_t ns_open_listening_socket(union socket_address *sa, int proto) {
730  socklen_t sa_len = (sa->sa.sa_family == AF_INET) ?
731    sizeof(sa->sin) : sizeof(sa->sin6);
732  sock_t sock = INVALID_SOCKET;
733#ifndef _WIN32
734  int on = 1;
735#endif
736
737  if ((sock = socket(sa->sa.sa_family, proto, 0)) != INVALID_SOCKET &&
738#ifndef _WIN32
739      // SO_RESUSEADDR is not enabled on Windows because the semantics of
740      // SO_REUSEADDR on UNIX and Windows is different. On Windows,
741      // SO_REUSEADDR allows to bind a socket to a port without error even if
742      // the port is already open by another program. This is not the behavior
743      // SO_REUSEADDR was designed for, and leads to hard-to-track failure
744      // scenarios. Therefore, SO_REUSEADDR was disabled on Windows.
745      !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
746#endif
747      !bind(sock, &sa->sa, sa_len) &&
748      (proto == SOCK_DGRAM || listen(sock, SOMAXCONN) == 0)) {
749    ns_set_non_blocking_mode(sock);
750    // In case port was set to 0, get the real port number
751    (void) getsockname(sock, &sa->sa, &sa_len);
752  } else if (sock != INVALID_SOCKET) {
753    closesocket(sock);
754    sock = INVALID_SOCKET;
755  }
756
757  return sock;
758}
759
760#ifdef NS_ENABLE_SSL
761// Certificate generation script is at
762// https://github.com/cesanta/net_skeleton/blob/master/scripts/gen_certs.sh
763
764static int ns_use_ca_cert(SSL_CTX *ctx, const char *cert) {
765  if (ctx == NULL) {
766    return -1;
767  } else if (cert == NULL || cert[0] == '\0') {
768    return 0;
769  }
770  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
771  return SSL_CTX_load_verify_locations(ctx, cert, NULL) == 1 ? 0 : -2;
772}
773
774static int ns_use_cert(SSL_CTX *ctx, const char *pem_file) {
775  if (ctx == NULL) {
776    return -1;
777  } else if (pem_file == NULL || pem_file[0] == '\0') {
778    return 0;
779  } else if (SSL_CTX_use_certificate_file(ctx, pem_file, 1) == 0 ||
780             SSL_CTX_use_PrivateKey_file(ctx, pem_file, 1) == 0) {
781    return -2;
782  } else {
783    SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
784    SSL_CTX_use_certificate_chain_file(ctx, pem_file);
785    return 0;
786  }
787}
788#endif  // NS_ENABLE_SSL
789
790struct ns_connection *ns_bind(struct ns_mgr *srv, const char *str,
791                              ns_callback_t callback, void *user_data) {
792  union socket_address sa;
793  struct ns_connection *nc = NULL;
794  int use_ssl, proto;
795  char cert[100], ca_cert[100];
796  sock_t sock;
797
798  ns_parse_address(str, &sa, &proto, &use_ssl, cert, ca_cert);
799  if (use_ssl && cert[0] == '\0') return NULL;
800
801  if ((sock = ns_open_listening_socket(&sa, proto)) == INVALID_SOCKET) {
802  } else if ((nc = ns_add_sock(srv, sock, callback, NULL)) == NULL) {
803    closesocket(sock);
804  } else {
805    nc->sa = sa;
806    nc->flags |= NSF_LISTENING;
807    nc->user_data = user_data;
808    nc->callback = callback;
809
810    if (proto == SOCK_DGRAM) {
811      nc->flags |= NSF_UDP;
812    }
813
814#ifdef NS_ENABLE_SSL
815    if (use_ssl) {
816      nc->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
817      if (ns_use_cert(nc->ssl_ctx, cert) != 0 ||
818          ns_use_ca_cert(nc->ssl_ctx, ca_cert) != 0) {
819        ns_close_conn(nc);
820        nc = NULL;
821      }
822    }
823#endif
824
825    DBG(("%p sock %d/%d ssl %p %p", nc, sock, proto, nc->ssl_ctx, nc->ssl));
826  }
827
828  return nc;
829}
830
831static struct ns_connection *accept_conn(struct ns_connection *ls) {
832  struct ns_connection *c = NULL;
833  union socket_address sa;
834  socklen_t len = sizeof(sa);
835  sock_t sock = INVALID_SOCKET;
836
837  // NOTE(lsm): on Windows, sock is always > FD_SETSIZE
838  if ((sock = accept(ls->sock, &sa.sa, &len)) == INVALID_SOCKET) {
839  } else if ((c = ns_add_sock(ls->mgr, sock, ls->callback,
840              ls->user_data)) == NULL) {
841    closesocket(sock);
842#ifdef NS_ENABLE_SSL
843  } else if (ls->ssl_ctx != NULL &&
844             ((c->ssl = SSL_new(ls->ssl_ctx)) == NULL ||
845              SSL_set_fd(c->ssl, sock) != 1)) {
846    DBG(("SSL error"));
847    ns_close_conn(c);
848    c = NULL;
849#endif
850  } else {
851    c->listener = ls;
852    c->proto_data = ls->proto_data;
853    ns_call(c, NS_ACCEPT, &sa);
854    DBG(("%p %d %p %p", c, c->sock, c->ssl_ctx, c->ssl));
855  }
856
857  return c;
858}
859
860static int ns_is_error(int n) {
861  return n == 0 ||
862    (n < 0 && errno != EINTR && errno != EINPROGRESS &&
863     errno != EAGAIN && errno != EWOULDBLOCK
864#ifdef _WIN32
865     && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK
866#endif
867    )
868#ifdef NS_ENABLE_SSL
869    /*
870     * OpenSSL can return an error when the peer is closing the socket.
871     * We don't encounter this error with openssl actually, but it's returned
872     * by our polarssl <-> openssl wrapper who tries to speak the openssl API
873     * as we understood it.
874     */
875    || n == SSL_AD_CLOSE_NOTIFY
876#endif
877    ;
878}
879
880void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags) {
881  union socket_address sa;
882  socklen_t slen = sizeof(sa);
883
884  if (buf != NULL && len > 0) {
885    buf[0] = '\0';
886    memset(&sa, 0, sizeof(sa));
887    if (flags & 4) {
888      getpeername(sock, &sa.sa, &slen);
889    } else {
890      getsockname(sock, &sa.sa, &slen);
891    }
892    if (flags & 1) {
893#if defined(NS_ENABLE_IPV6)
894      inet_ntop(sa.sa.sa_family, sa.sa.sa_family == AF_INET ?
895                (void *) &sa.sin.sin_addr :
896                (void *) &sa.sin6.sin6_addr, buf, len);
897#elif defined(_WIN32)
898      // Only Windoze Vista (and newer) have inet_ntop()
899      strncpy(buf, inet_ntoa(sa.sin.sin_addr), len);
900#else
901      inet_ntop(sa.sa.sa_family, (void *) &sa.sin.sin_addr, buf,(socklen_t)len);
902#endif
903    }
904    if (flags & 2) {
905      snprintf(buf + strlen(buf), len - (strlen(buf) + 1), "%s%d",
906               flags & 1 ? ":" : "", (int) ntohs(sa.sin.sin_port));
907    }
908  }
909}
910
911int ns_hexdump(const void *buf, int len, char *dst, int dst_len) {
912  const unsigned char *p = (const unsigned char *) buf;
913  char ascii[17] = "";
914  int i, idx, n = 0;
915
916  for (i = 0; i < len; i++) {
917    idx = i % 16;
918    if (idx == 0) {
919      if (i > 0) n += snprintf(dst + n, dst_len - n, "  %s\n", ascii);
920      n += snprintf(dst + n, dst_len - n, "%04x ", i);
921    }
922    n += snprintf(dst + n, dst_len - n, " %02x", p[i]);
923    ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i];
924    ascii[idx + 1] = '\0';
925  }
926
927  while (i++ % 16) n += snprintf(dst + n, dst_len - n, "%s", "   ");
928  n += snprintf(dst + n, dst_len - n, "  %s\n\n", ascii);
929
930  return n;
931}
932
933#ifdef NS_ENABLE_SSL
934static int ns_ssl_err(struct ns_connection *conn, int res) {
935  int ssl_err = SSL_get_error(conn->ssl, res);
936  if (ssl_err == SSL_ERROR_WANT_READ) conn->flags |= NSF_WANT_READ;
937  if (ssl_err == SSL_ERROR_WANT_WRITE) conn->flags |= NSF_WANT_WRITE;
938  return ssl_err;
939}
940#endif
941
942static void ns_read_from_socket(struct ns_connection *conn) {
943  char buf[NS_READ_BUFFER_SIZE];
944  int n = 0;
945
946  if (conn->flags & NSF_CONNECTING) {
947    int ok = 1, ret;
948    socklen_t len = sizeof(ok);
949
950    ret = getsockopt(conn->sock, SOL_SOCKET, SO_ERROR, (char *) &ok, &len);
951    (void) ret;
952#ifdef NS_ENABLE_SSL
953    if (ret == 0 && ok == 0 && conn->ssl != NULL) {
954      int res = SSL_connect(conn->ssl);
955      int ssl_err = ns_ssl_err(conn, res);
956      if (res == 1) {
957        conn->flags |= NSF_SSL_HANDSHAKE_DONE;
958      } else if (ssl_err == SSL_ERROR_WANT_READ ||
959                 ssl_err == SSL_ERROR_WANT_WRITE) {
960        return; // Call us again
961      } else {
962        ok = 1;
963      }
964      conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
965    }
966#endif
967    conn->flags &= ~NSF_CONNECTING;
968    DBG(("%p ok=%d", conn, ok));
969    if (ok != 0) {
970      conn->flags |= NSF_CLOSE_IMMEDIATELY;
971    }
972    ns_call(conn, NS_CONNECT, &ok);
973    return;
974  }
975
976#ifdef NS_ENABLE_SSL
977  if (conn->ssl != NULL) {
978    if (conn->flags & NSF_SSL_HANDSHAKE_DONE) {
979      // SSL library may have more bytes ready to read then we ask to read.
980      // Therefore, read in a loop until we read everything. Without the loop,
981      // we skip to the next select() cycle which can just timeout.
982      while ((n = SSL_read(conn->ssl, buf, sizeof(buf))) > 0) {
983        DBG(("%p %d <- %d bytes (SSL)", conn, conn->flags, n));
984        iobuf_append(&conn->recv_iobuf, buf, n);
985        ns_call(conn, NS_RECV, &n);
986      }
987      ns_ssl_err(conn, n);
988    } else {
989      int res = SSL_accept(conn->ssl);
990      int ssl_err = ns_ssl_err(conn, res);
991      if (res == 1) {
992        conn->flags |= NSF_SSL_HANDSHAKE_DONE;
993        conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
994      } else if (ssl_err == SSL_ERROR_WANT_READ ||
995                 ssl_err == SSL_ERROR_WANT_WRITE) {
996        return; // Call us again
997      } else {
998        conn->flags |= NSF_CLOSE_IMMEDIATELY;
999      }
1000      return;
1001    }
1002  } else
1003#endif
1004  {
1005    while ((n = (int) recv(conn->sock, buf, sizeof(buf), 0)) > 0) {
1006      DBG(("%p %d <- %d bytes (PLAIN)", conn, conn->flags, n));
1007      iobuf_append(&conn->recv_iobuf, buf, n);
1008      ns_call(conn, NS_RECV, &n);
1009    }
1010  }
1011
1012  if (ns_is_error(n)) {
1013    conn->flags |= NSF_CLOSE_IMMEDIATELY;
1014  }
1015}
1016
1017static void ns_write_to_socket(struct ns_connection *conn) {
1018  struct iobuf *io = &conn->send_iobuf;
1019  int n = 0;
1020
1021#ifdef NS_ENABLE_SSL
1022  if (conn->ssl != NULL) {
1023    n = SSL_write(conn->ssl, io->buf, io->len);
1024    if (n <= 0) {
1025      int ssl_err = ns_ssl_err(conn, n);
1026      if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
1027        return; // Call us again
1028      } else {
1029        conn->flags |= NSF_CLOSE_IMMEDIATELY;
1030      }
1031    } else {
1032      conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
1033    }
1034  } else
1035#endif
1036  { n = (int) send(conn->sock, io->buf, io->len, 0); }
1037
1038  DBG(("%p %d -> %d bytes", conn, conn->flags, n));
1039
1040  ns_call(conn, NS_SEND, &n);
1041  if (ns_is_error(n)) {
1042    conn->flags |= NSF_CLOSE_IMMEDIATELY;
1043  } else if (n > 0) {
1044    iobuf_remove(io, n);
1045  }
1046}
1047
1048int ns_send(struct ns_connection *conn, const void *buf, size_t len) {
1049  return (int) ns_out(conn, buf, len);
1050}
1051
1052static void ns_handle_udp(struct ns_connection *ls) {
1053  struct ns_connection nc;
1054  char buf[NS_UDP_RECEIVE_BUFFER_SIZE];
1055  ssize_t n;
1056  socklen_t s_len = sizeof(nc.sa);
1057
1058  memset(&nc, 0, sizeof(nc));
1059  n = recvfrom(ls->sock, buf, sizeof(buf), 0, &nc.sa.sa, &s_len);
1060  if (n <= 0) {
1061    DBG(("%p recvfrom: %s", ls, strerror(errno)));
1062  } else {
1063    nc.mgr = ls->mgr;
1064    nc.recv_iobuf.buf = buf;
1065    nc.recv_iobuf.len = nc.recv_iobuf.size = n;
1066    nc.sock = ls->sock;
1067    nc.callback = ls->callback;
1068    nc.user_data = ls->user_data;
1069    nc.proto_data = ls->proto_data;
1070    nc.mgr = ls->mgr;
1071    nc.listener = ls;
1072    nc.flags = NSF_UDP;
1073    DBG(("%p %d bytes received", ls, n));
1074    ns_call(&nc, NS_RECV, &n);
1075  }
1076}
1077
1078static void ns_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
1079  if ( (sock != INVALID_SOCKET) && (sock < FD_SETSIZE) ) {
1080    FD_SET(sock, set);
1081    if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
1082      *max_fd = sock;
1083    }
1084  }
1085}
1086
1087time_t ns_mgr_poll(struct ns_mgr *mgr, int milli) {
1088  struct ns_connection *conn, *tmp_conn;
1089  struct timeval tv;
1090  fd_set read_set, write_set;
1091  sock_t max_fd = INVALID_SOCKET;
1092  time_t current_time = time(NULL);
1093
1094  FD_ZERO(&read_set);
1095  FD_ZERO(&write_set);
1096  ns_add_to_set(mgr->ctl[1], &read_set, &max_fd);
1097
1098  for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) {
1099    tmp_conn = conn->next;
1100    if (!(conn->flags & (NSF_LISTENING | NSF_CONNECTING))) {
1101      ns_call(conn, NS_POLL, &current_time);
1102    }
1103    if (conn->flags & NSF_CLOSE_IMMEDIATELY) {
1104      ns_close_conn(conn);
1105    } else {
1106      if (!(conn->flags & NSF_WANT_WRITE)) {
1107        //DBG(("%p read_set", conn));
1108        ns_add_to_set(conn->sock, &read_set, &max_fd);
1109      }
1110      if (((conn->flags & NSF_CONNECTING) && !(conn->flags & NSF_WANT_READ)) ||
1111          (conn->send_iobuf.len > 0 && !(conn->flags & NSF_CONNECTING) &&
1112           !(conn->flags & NSF_BUFFER_BUT_DONT_SEND))) {
1113        //DBG(("%p write_set", conn));
1114        ns_add_to_set(conn->sock, &write_set, &max_fd);
1115      }
1116    }
1117  }
1118
1119  tv.tv_sec = milli / 1000;
1120  tv.tv_usec = (milli % 1000) * 1000;
1121
1122  if (select((int) max_fd + 1, &read_set, &write_set, NULL, &tv) < 0) {
1123    return 0;
1124  } else {
1125    // select() might have been waiting for a long time, reset current_time
1126    // now to prevent last_io_time being set to the past.
1127    current_time = time(NULL);
1128
1129    // Read wakeup messages
1130    if (mgr->ctl[1] != INVALID_SOCKET &&
1131        FD_ISSET(mgr->ctl[1], &read_set)) {
1132      struct ctl_msg ctl_msg;
1133      int len = (int) recv(mgr->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0);
1134      send(mgr->ctl[1], ctl_msg.message, 1, 0);
1135      if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) {
1136        struct ns_connection *c;
1137        for (c = ns_next(mgr, NULL); c != NULL; c = ns_next(mgr, c)) {
1138          ctl_msg.callback(c, NS_POLL, ctl_msg.message);
1139        }
1140      }
1141    }
1142
1143    for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) {
1144      tmp_conn = conn->next;
1145      if (FD_ISSET(conn->sock, &read_set)) {
1146        if (conn->flags & NSF_LISTENING) {
1147          if (conn->flags & NSF_UDP) {
1148            ns_handle_udp(conn);
1149          } else {
1150            // We're not looping here, and accepting just one connection at
1151            // a time. The reason is that eCos does not respect non-blocking
1152            // flag on a listening socket and hangs in a loop.
1153            accept_conn(conn);
1154          }
1155        } else {
1156          conn->last_io_time = current_time;
1157          ns_read_from_socket(conn);
1158        }
1159      }
1160
1161      if (FD_ISSET(conn->sock, &write_set)) {
1162        if (conn->flags & NSF_CONNECTING) {
1163          ns_read_from_socket(conn);
1164        } else if (!(conn->flags & NSF_BUFFER_BUT_DONT_SEND)) {
1165          conn->last_io_time = current_time;
1166          ns_write_to_socket(conn);
1167        }
1168      }
1169    }
1170  }
1171
1172  for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) {
1173    tmp_conn = conn->next;
1174    if ((conn->flags & NSF_CLOSE_IMMEDIATELY) ||
1175        (conn->send_iobuf.len == 0 &&
1176          (conn->flags & NSF_FINISHED_SENDING_DATA))) {
1177      ns_close_conn(conn);
1178    }
1179  }
1180
1181  return current_time;
1182}
1183
1184struct ns_connection *ns_connect(struct ns_mgr *mgr, const char *address,
1185                                 ns_callback_t callback, void *user_data) {
1186  sock_t sock = INVALID_SOCKET;
1187  struct ns_connection *nc = NULL;
1188  union socket_address sa;
1189  char cert[100], ca_cert[100];
1190  int rc, use_ssl, proto;
1191
1192  ns_parse_address(address, &sa, &proto, &use_ssl, cert, ca_cert);
1193  if ((sock = socket(AF_INET, proto, 0)) == INVALID_SOCKET) {
1194    return NULL;
1195  }
1196  ns_set_non_blocking_mode(sock);
1197  rc = (proto == SOCK_DGRAM) ? 0 : connect(sock, &sa.sa, sizeof(sa.sin));
1198
1199  if (rc != 0 && ns_is_error(rc)) {
1200    closesocket(sock);
1201    return NULL;
1202  } else if ((nc = ns_add_sock(mgr, sock, callback, user_data)) == NULL) {
1203    closesocket(sock);
1204    return NULL;
1205  }
1206
1207  nc->sa = sa;   // Important, cause UDP conns will use sendto()
1208  nc->flags = (proto == SOCK_DGRAM) ? NSF_UDP : NSF_CONNECTING;
1209
1210#ifdef NS_ENABLE_SSL
1211  if (use_ssl) {
1212    if ((nc->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL ||
1213        ns_use_cert(nc->ssl_ctx, cert) != 0 ||
1214        ns_use_ca_cert(nc->ssl_ctx, ca_cert) != 0 ||
1215        (nc->ssl = SSL_new(nc->ssl_ctx)) == NULL) {
1216      ns_close_conn(nc);
1217      return NULL;
1218    } else {
1219      SSL_set_fd(nc->ssl, sock);
1220    }
1221  }
1222#endif
1223
1224  return nc;
1225}
1226
1227struct ns_connection *ns_add_sock(struct ns_mgr *s, sock_t sock,
1228                                  ns_callback_t callback, void *user_data) {
1229  struct ns_connection *conn;
1230  if ((conn = (struct ns_connection *) NS_MALLOC(sizeof(*conn))) != NULL) {
1231    memset(conn, 0, sizeof(*conn));
1232    ns_set_non_blocking_mode(sock);
1233    ns_set_close_on_exec(sock);
1234    conn->sock = sock;
1235    conn->user_data = user_data;
1236    conn->callback = callback;
1237    conn->mgr = s;
1238    conn->last_io_time = time(NULL);
1239    ns_add_conn(s, conn);
1240    DBG(("%p %d", conn, sock));
1241  }
1242  return conn;
1243}
1244
1245struct ns_connection *ns_next(struct ns_mgr *s, struct ns_connection *conn) {
1246  return conn == NULL ? s->active_connections : conn->next;
1247}
1248
1249void ns_broadcast(struct ns_mgr *mgr, ns_callback_t cb,void *data, size_t len) {
1250  struct ctl_msg ctl_msg;
1251  if (mgr->ctl[0] != INVALID_SOCKET && data != NULL &&
1252      len < sizeof(ctl_msg.message)) {
1253    ctl_msg.callback = cb;
1254    memcpy(ctl_msg.message, data, len);
1255    send(mgr->ctl[0], (char *) &ctl_msg,
1256         offsetof(struct ctl_msg, message) + len, 0);
1257    recv(mgr->ctl[0], (char *) &len, 1, 0);
1258  }
1259}
1260
1261void ns_mgr_init(struct ns_mgr *s, void *user_data) {
1262  memset(s, 0, sizeof(*s));
1263  s->ctl[0] = s->ctl[1] = INVALID_SOCKET;
1264  s->user_data = user_data;
1265
1266#ifdef _WIN32
1267  { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); }
1268#else
1269  // Ignore SIGPIPE signal, so if client cancels the request, it
1270  // won't kill the whole process.
1271  signal(SIGPIPE, SIG_IGN);
1272#endif
1273
1274#ifndef NS_DISABLE_SOCKETPAIR
1275  {
1276    int attempts = 0, max_attempts = NS_MAX_SOCKETPAIR_ATTEMPTS;
1277    do {
1278      ns_socketpair2(s->ctl, SOCK_DGRAM);
1279    } while (s->ctl[0] == INVALID_SOCKET && ++attempts < max_attempts);
1280  }
1281#endif
1282
1283#ifdef NS_ENABLE_SSL
1284  {static int init_done; if (!init_done) { SSL_library_init(); init_done++; }}
1285#endif
1286}
1287
1288void ns_mgr_free(struct ns_mgr *s) {
1289  struct ns_connection *conn, *tmp_conn;
1290
1291  DBG(("%p", s));
1292  if (s == NULL) return;
1293  // Do one last poll, see https://github.com/cesanta/mongoose/issues/286
1294  ns_mgr_poll(s, 0);
1295
1296  if (s->ctl[0] != INVALID_SOCKET) closesocket(s->ctl[0]);
1297  if (s->ctl[1] != INVALID_SOCKET) closesocket(s->ctl[1]);
1298  s->ctl[0] = s->ctl[1] = INVALID_SOCKET;
1299
1300  for (conn = s->active_connections; conn != NULL; conn = tmp_conn) {
1301    tmp_conn = conn->next;
1302    ns_close_conn(conn);
1303  }
1304}
1305// net_skeleton end
1306#endif  // NOEMBED_NET_SKELETON
1307
1308#include <ctype.h>
1309
1310#ifdef _WIN32         //////////////// Windows specific defines and includes
1311#include <io.h>       // For _lseeki64
1312#include <direct.h>   // For _mkdir
1313#ifndef S_ISDIR
1314#define S_ISDIR(x) ((x) & _S_IFDIR)
1315#endif
1316#ifdef stat
1317#undef stat
1318#endif
1319#ifdef lseek
1320#undef lseek
1321#endif
1322#ifdef popen
1323#undef popen
1324#endif
1325#ifdef pclose
1326#undef pclose
1327#endif
1328#define stat(x, y) mg_stat((x), (y))
1329#define fopen(x, y) mg_fopen((x), (y))
1330#define open(x, y, z) mg_open((x), (y), (z))
1331#define close(x) _close(x)
1332#define fileno(x) _fileno(x)
1333#define lseek(x, y, z) _lseeki64((x), (y), (z))
1334#define read(x, y, z) _read((x), (y), (z))
1335#define write(x, y, z) _write((x), (y), (z))
1336#define popen(x, y) _popen((x), (y))
1337#define pclose(x) _pclose(x)
1338#define mkdir(x, y) _mkdir(x)
1339#define rmdir(x) _rmdir(x)
1340#define strdup(x) _strdup(x)
1341#ifndef __func__
1342#define STRX(x) #x
1343#define STR(x) STRX(x)
1344#define __func__ __FILE__ ":" STR(__LINE__)
1345#endif
1346// find proper defines for this for VS and other compilers
1347#if defined(__USE_MINGW_ANSI_STDIO)
1348#define INT64_FMT   "lld"
1349#else
1350#define INT64_FMT   "I64d"
1351#endif
1352#define flockfile(x)      ((void) (x))
1353#define funlockfile(x)    ((void) (x))
1354typedef struct _stati64 file_stat_t;
1355typedef HANDLE process_id_t;
1356
1357#else                    ////////////// UNIX specific defines and includes
1358
1359#if !defined(MONGOOSE_NO_FILESYSTEM) &&\
1360    (!defined(MONGOOSE_NO_DAV) || !defined(MONGOOSE_NO_DIRECTORY_LISTING))
1361#include <dirent.h>
1362#endif
1363#if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_DL)
1364#include <dlfcn.h>
1365#endif
1366#include <inttypes.h>
1367#include <pwd.h>
1368#if !defined(O_BINARY)
1369#define O_BINARY 0
1370#endif
1371#define INT64_FMT PRId64
1372typedef struct stat file_stat_t;
1373typedef pid_t process_id_t;
1374#endif                  //////// End of platform-specific defines and includes
1375
1376#include "mongoose.h"
1377
1378#define MAX_REQUEST_SIZE 16384
1379#define IOBUF_SIZE 8192
1380#define MAX_PATH_SIZE 8192
1381#define DEFAULT_CGI_PATTERN "**.cgi$|**.pl$|**.php$"
1382#define CGI_ENVIRONMENT_SIZE 8192
1383#define MAX_CGI_ENVIR_VARS 64
1384#define ENV_EXPORT_TO_CGI "MONGOOSE_CGI"
1385#define PASSWORDS_FILE_NAME ".htpasswd"
1386
1387#ifndef MONGOOSE_USE_WEBSOCKET_PING_INTERVAL
1388#define MONGOOSE_USE_WEBSOCKET_PING_INTERVAL 5
1389#endif
1390
1391// Extra HTTP headers to send in every static file reply
1392#if !defined(MONGOOSE_USE_EXTRA_HTTP_HEADERS)
1393#define MONGOOSE_USE_EXTRA_HTTP_HEADERS ""
1394#endif
1395
1396#ifndef MONGOOSE_POST_SIZE_LIMIT
1397#define MONGOOSE_POST_SIZE_LIMIT 0
1398#endif
1399
1400#ifndef MONGOOSE_IDLE_TIMEOUT_SECONDS
1401#define MONGOOSE_IDLE_TIMEOUT_SECONDS 300
1402#endif
1403
1404#if defined(NS_DISABLE_SOCKETPAIR) && !defined(MONGOOSE_NO_CGI)
1405#define MONGOOSE_NO_CGI
1406#endif
1407
1408#ifdef MONGOOSE_NO_FILESYSTEM
1409#define MONGOOSE_NO_AUTH
1410#if !defined(MONGOOSE_NO_CGI)
1411#define MONGOOSE_NO_CGI
1412#endif
1413#define MONGOOSE_NO_DAV
1414#define MONGOOSE_NO_DIRECTORY_LISTING
1415#define MONGOOSE_NO_LOGGING
1416#define MONGOOSE_NO_SSI
1417#define MONGOOSE_NO_DL
1418#endif
1419
1420struct vec {
1421  const char *ptr;
1422  size_t len;
1423};
1424
1425// For directory listing and WevDAV support
1426struct dir_entry {
1427  struct connection *conn;
1428  char *file_name;
1429  file_stat_t st;
1430};
1431
1432// NOTE(lsm): this enum should be in sync with the config_options.
1433enum {
1434  ACCESS_CONTROL_LIST,
1435#ifndef MONGOOSE_NO_FILESYSTEM
1436  ACCESS_LOG_FILE,
1437#ifndef MONGOOSE_NO_AUTH
1438  AUTH_DOMAIN,
1439#endif
1440#ifndef MONGOOSE_NO_CGI
1441  CGI_INTERPRETER,
1442  CGI_PATTERN,
1443#endif
1444  DAV_AUTH_FILE,
1445  DAV_ROOT,
1446  DOCUMENT_ROOT,
1447#ifndef MONGOOSE_NO_DIRECTORY_LISTING
1448  ENABLE_DIRECTORY_LISTING,
1449#endif
1450#endif
1451  ENABLE_PROXY,
1452  EXTRA_MIME_TYPES,
1453#if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_AUTH)
1454  GLOBAL_AUTH_FILE,
1455#endif
1456#ifndef MONGOOSE_NO_FILESYSTEM
1457  HIDE_FILES_PATTERN,
1458  HEXDUMP_FILE,
1459  INDEX_FILES,
1460#endif
1461  LISTENING_PORT,
1462#ifndef _WIN32
1463  RUN_AS_USER,
1464#endif
1465#ifndef MONGOOSE_NO_SSI
1466  SSI_PATTERN,
1467#endif
1468  URL_REWRITES,
1469  NUM_OPTIONS
1470};
1471
1472static const char *static_config_options[] = {
1473  "access_control_list", NULL,
1474#ifndef MONGOOSE_NO_FILESYSTEM
1475  "access_log_file", NULL,
1476#ifndef MONGOOSE_NO_AUTH
1477  "auth_domain", "mydomain.com",
1478#endif
1479#ifndef MONGOOSE_NO_CGI
1480  "cgi_interpreter", NULL,
1481  "cgi_pattern", DEFAULT_CGI_PATTERN,
1482#endif
1483  "dav_auth_file", NULL,
1484  "dav_root", NULL,
1485  "document_root",  NULL,
1486#ifndef MONGOOSE_NO_DIRECTORY_LISTING
1487  "enable_directory_listing", "yes",
1488#endif
1489#endif
1490  "enable_proxy", NULL,
1491  "extra_mime_types", NULL,
1492#if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_AUTH)
1493  "global_auth_file", NULL,
1494#endif
1495#ifndef MONGOOSE_NO_FILESYSTEM
1496  "hide_files_patterns", NULL,
1497  "hexdump_file", NULL,
1498  "index_files","index.html,index.htm,index.shtml,index.cgi,index.php",
1499#endif
1500  "listening_port", NULL,
1501#ifndef _WIN32
1502  "run_as_user", NULL,
1503#endif
1504#ifndef MONGOOSE_NO_SSI
1505  "ssi_pattern", "**.shtml$|**.shtm$",
1506#endif
1507  "url_rewrites", NULL,
1508  NULL
1509};
1510
1511struct mg_server {
1512  struct ns_mgr ns_mgr;
1513  union socket_address lsa;   // Listening socket address
1514  mg_handler_t event_handler;
1515  char *config_options[NUM_OPTIONS];
1516};
1517
1518// Local endpoint representation
1519union endpoint {
1520  int fd;                     // Opened regular local file
1521  struct ns_connection *nc;   // CGI or proxy->target connection
1522};
1523
1524enum endpoint_type {
1525 EP_NONE, EP_FILE, EP_CGI, EP_USER, EP_PUT, EP_CLIENT, EP_PROXY
1526};
1527
1528#define MG_HEADERS_SENT NSF_USER_1
1529#define MG_USING_CHUNKED_API NSF_USER_2
1530#define MG_CGI_CONN NSF_USER_3
1531#define MG_PROXY_CONN NSF_USER_4
1532#define MG_PROXY_DONT_PARSE NSF_USER_5
1533
1534struct connection {
1535  struct ns_connection *ns_conn;  // NOTE(lsm): main.c depends on this order
1536  struct mg_connection mg_conn;
1537  struct mg_server *server;
1538  union endpoint endpoint;
1539  enum endpoint_type endpoint_type;
1540  char *path_info;
1541  char *request;
1542  int64_t num_bytes_recv; // Total number of bytes received
1543  int64_t cl;             // Reply content length, for Range support
1544  ssize_t request_len;  // Request length, including last \r\n after last header
1545};
1546
1547#define MG_CONN_2_CONN(c) ((struct connection *) ((char *) (c) - \
1548  offsetof(struct connection, mg_conn)))
1549
1550static void open_local_endpoint(struct connection *conn, int skip_user);
1551static void close_local_endpoint(struct connection *conn);
1552static void mg_ev_handler(struct ns_connection *nc, int ev, void *p);
1553
1554static const struct {
1555  const char *extension;
1556  size_t ext_len;
1557  const char *mime_type;
1558} static_builtin_mime_types[] = {
1559  {".html", 5, "text/html"},
1560  {".htm", 4, "text/html"},
1561  {".shtm", 5, "text/html"},
1562  {".shtml", 6, "text/html"},
1563  {".css", 4, "text/css"},
1564  {".js",  3, "application/javascript"},
1565  {".ico", 4, "image/x-icon"},
1566  {".gif", 4, "image/gif"},
1567  {".jpg", 4, "image/jpeg"},
1568  {".jpeg", 5, "image/jpeg"},
1569  {".png", 4, "image/png"},
1570  {".svg", 4, "image/svg+xml"},
1571  {".txt", 4, "text/plain"},
1572  {".torrent", 8, "application/x-bittorrent"},
1573  {".wav", 4, "audio/x-wav"},
1574  {".mp3", 4, "audio/x-mp3"},
1575  {".mid", 4, "audio/mid"},
1576  {".m3u", 4, "audio/x-mpegurl"},
1577  {".ogg", 4, "application/ogg"},
1578  {".ram", 4, "audio/x-pn-realaudio"},
1579  {".xml", 4, "text/xml"},
1580  {".json",  5, "application/json"},
1581  {".xslt", 5, "application/xml"},
1582  {".xsl", 4, "application/xml"},
1583  {".ra",  3, "audio/x-pn-realaudio"},
1584  {".doc", 4, "application/msword"},
1585  {".exe", 4, "application/octet-stream"},
1586  {".zip", 4, "application/x-zip-compressed"},
1587  {".xls", 4, "application/excel"},
1588  {".tgz", 4, "application/x-tar-gz"},
1589  {".tar", 4, "application/x-tar"},
1590  {".gz",  3, "application/x-gunzip"},
1591  {".arj", 4, "application/x-arj-compressed"},
1592  {".rar", 4, "application/x-rar-compressed"},
1593  {".rtf", 4, "application/rtf"},
1594  {".pdf", 4, "application/pdf"},
1595  {".swf", 4, "application/x-shockwave-flash"},
1596  {".mpg", 4, "video/mpeg"},
1597  {".webm", 5, "video/webm"},
1598  {".mpeg", 5, "video/mpeg"},
1599  {".mov", 4, "video/quicktime"},
1600  {".mp4", 4, "video/mp4"},
1601  {".m4v", 4, "video/x-m4v"},
1602  {".asf", 4, "video/x-ms-asf"},
1603  {".avi", 4, "video/x-msvideo"},
1604  {".bmp", 4, "image/bmp"},
1605  {".ttf", 4, "application/x-font-ttf"},
1606  {NULL,  0, NULL}
1607};
1608
1609#ifdef MONGOOSE_ENABLE_THREADS
1610void *mg_start_thread(void *(*f)(void *), void *p) {
1611  return ns_start_thread(f, p);
1612}
1613#endif  // MONGOOSE_ENABLE_THREADS
1614
1615#ifndef MONGOOSE_NO_MMAP
1616#ifdef _WIN32
1617static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
1618                  int offset) {
1619  HANDLE fh = (HANDLE) _get_osfhandle(fd);
1620  HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
1621  void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t) len);
1622  CloseHandle(mh);
1623  return p;
1624}
1625#define munmap(x, y)  UnmapViewOfFile(x)
1626#define MAP_FAILED NULL
1627#define MAP_PRIVATE 0
1628#define PROT_READ 0
1629#elif defined(__OS2__)
1630static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
1631                  int offset) {
1632  void *p;
1633
1634  int pos = lseek( fd, 0, SEEK_CUR ); /* Get a current position */
1635
1636  if (pos == -1)
1637    return NULL;
1638
1639  /* Seek to offset offset */
1640  if (lseek( fd, offset, SEEK_SET) == -1)
1641    return NULL;
1642
1643  p = malloc(len);
1644
1645  /* Read in a file */
1646  if (!p || read(fd, p, len) == -1) {
1647    free(p);
1648    p = NULL;
1649  }
1650
1651  /* Restore the position */
1652  lseek(fd, pos, SEEK_SET);
1653
1654  return p;
1655}
1656#define munmap(x, y)  free(x)
1657#define MAP_FAILED NULL
1658#define MAP_PRIVATE 0
1659#define PROT_READ 0
1660#else
1661#include <sys/mman.h>
1662#endif
1663
1664void *mg_mmap(FILE *fp, size_t size) {
1665  void *p = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
1666  return p == MAP_FAILED ? NULL : p;
1667}
1668
1669void mg_munmap(void *p, size_t size) {
1670  munmap(p, size);
1671}
1672#endif  // MONGOOSE_NO_MMAP
1673
1674#if defined(_WIN32) && !defined(MONGOOSE_NO_FILESYSTEM)
1675// Encode 'path' which is assumed UTF-8 string, into UNICODE string.
1676// wbuf and wbuf_len is a target buffer and its length.
1677static void to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
1678  char buf[MAX_PATH_SIZE * 2], buf2[MAX_PATH_SIZE * 2], *p;
1679
1680  strncpy(buf, path, sizeof(buf));
1681  buf[sizeof(buf) - 1] = '\0';
1682
1683  // Trim trailing slashes. Leave backslash for paths like "X:\"
1684  p = buf + strlen(buf) - 1;
1685  while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
1686
1687  // Convert to Unicode and back. If doubly-converted string does not
1688  // match the original, something is fishy, reject.
1689  memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
1690  MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
1691  WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
1692                      NULL, NULL);
1693  if (strcmp(buf, buf2) != 0) {
1694    wbuf[0] = L'\0';
1695  }
1696}
1697
1698static int mg_stat(const char *path, file_stat_t *st) {
1699  wchar_t wpath[MAX_PATH_SIZE];
1700  to_wchar(path, wpath, ARRAY_SIZE(wpath));
1701  DBG(("[%ls] -> %d", wpath, _wstati64(wpath, st)));
1702  return _wstati64(wpath, st);
1703}
1704
1705static FILE *mg_fopen(const char *path, const char *mode) {
1706  wchar_t wpath[MAX_PATH_SIZE], wmode[10];
1707  to_wchar(path, wpath, ARRAY_SIZE(wpath));
1708  to_wchar(mode, wmode, ARRAY_SIZE(wmode));
1709  return _wfopen(wpath, wmode);
1710}
1711
1712static int mg_open(const char *path, int flag, int mode) {
1713  wchar_t wpath[MAX_PATH_SIZE];
1714  to_wchar(path, wpath, ARRAY_SIZE(wpath));
1715  return _wopen(wpath, flag, mode);
1716}
1717#endif // _WIN32 && !MONGOOSE_NO_FILESYSTEM
1718
1719// A helper function for traversing a comma separated list of values.
1720// It returns a list pointer shifted to the next value, or NULL if the end
1721// of the list found.
1722// Value is stored in val vector. If value has form "x=y", then eq_val
1723// vector is initialized to point to the "y" part, and val vector length
1724// is adjusted to point only to "x".
1725static const char *next_option(const char *list, struct vec *val,
1726                               struct vec *eq_val) {
1727  if (list == NULL || *list == '\0') {
1728    // End of the list
1729    list = NULL;
1730  } else {
1731    val->ptr = list;
1732    if ((list = strchr(val->ptr, ',')) != NULL) {
1733      // Comma found. Store length and shift the list ptr
1734      val->len = list - val->ptr;
1735      list++;
1736    } else {
1737      // This value is the last one
1738      list = val->ptr + strlen(val->ptr);
1739      val->len = list - val->ptr;
1740    }
1741
1742    if (eq_val != NULL) {
1743      // Value has form "x=y", adjust pointers and lengths
1744      // so that val points to "x", and eq_val points to "y".
1745      eq_val->len = 0;
1746      eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
1747      if (eq_val->ptr != NULL) {
1748        eq_val->ptr++;  // Skip over '=' character
1749        eq_val->len = val->ptr + val->len - eq_val->ptr;
1750        val->len = (eq_val->ptr - val->ptr) - 1;
1751      }
1752    }
1753  }
1754
1755  return list;
1756}
1757
1758// Like snprintf(), but never returns negative value, or a value
1759// that is larger than a supplied buffer.
1760static int mg_vsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap) {
1761  int n;
1762  if (buflen < 1) return 0;
1763  n = vsnprintf(buf, buflen, fmt, ap);
1764  if (n < 0) {
1765    n = 0;
1766  } else if (n >= (int) buflen) {
1767    n = (int) buflen - 1;
1768  }
1769  buf[n] = '\0';
1770  return n;
1771}
1772
1773static int mg_snprintf(char *buf, size_t buflen, const char *fmt, ...) {
1774  va_list ap;
1775  int n;
1776  va_start(ap, fmt);
1777  n = mg_vsnprintf(buf, buflen, fmt, ap);
1778  va_end(ap);
1779  return n;
1780}
1781
1782// Check whether full request is buffered. Return:
1783//   -1  if request is malformed
1784//    0  if request is not yet fully buffered
1785//   >0  actual request length, including last \r\n\r\n
1786static int get_request_len(const char *s, size_t buf_len) {
1787  const unsigned char *buf = (unsigned char *) s;
1788  size_t i;
1789
1790  for (i = 0; i < buf_len; i++) {
1791    // Control characters are not allowed but >=128 are.
1792    // Abort scan as soon as one malformed character is found.
1793    if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128) {
1794      return -1;
1795    } else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') {
1796      return i + 2;
1797    } else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' &&
1798               buf[i + 2] == '\n') {
1799      return i + 3;
1800    }
1801  }
1802
1803  return 0;
1804}
1805
1806// Skip the characters until one of the delimiters characters found.
1807// 0-terminate resulting word. Skip the rest of the delimiters if any.
1808// Advance pointer to buffer to the next word. Return found 0-terminated word.
1809static char *skip(char **buf, const char *delimiters) {
1810  char *p, *begin_word, *end_word, *end_delimiters;
1811
1812  begin_word = *buf;
1813  end_word = begin_word + strcspn(begin_word, delimiters);
1814  end_delimiters = end_word + strspn(end_word, delimiters);
1815
1816  for (p = end_word; p < end_delimiters; p++) {
1817    *p = '\0';
1818  }
1819
1820  *buf = end_delimiters;
1821
1822  return begin_word;
1823}
1824
1825// Parse HTTP headers from the given buffer, advance buffer to the point
1826// where parsing stopped.
1827static void parse_http_headers(char **buf, struct mg_connection *ri) {
1828  size_t i;
1829
1830  for (i = 0; i < ARRAY_SIZE(ri->http_headers); i++) {
1831    ri->http_headers[i].name = skip(buf, ": ");
1832    ri->http_headers[i].value = skip(buf, "\r\n");
1833    if (ri->http_headers[i].name[0] == '\0')
1834      break;
1835    ri->num_headers = i + 1;
1836  }
1837}
1838
1839static const char *status_code_to_str(int status_code) {
1840  switch (status_code) {
1841
1842    case 100: return "Continue";
1843    case 101: return "Switching Protocols";
1844    case 102: return "Processing";
1845
1846    case 200: return "OK";
1847    case 201: return "Created";
1848    case 202: return "Accepted";
1849    case 203: return "Non-Authoritative Information";
1850    case 204: return "No Content";
1851    case 205: return "Reset Content";
1852    case 206: return "Partial Content";
1853    case 207: return "Multi-Status";
1854    case 208: return "Already Reported";
1855    case 226: return "IM Used";
1856
1857    case 300: return "Multiple Choices";
1858    case 301: return "Moved Permanently";
1859    case 302: return "Found";
1860    case 303: return "See Other";
1861    case 304: return "Not Modified";
1862    case 305: return "Use Proxy";
1863    case 306: return "Switch Proxy";
1864    case 307: return "Temporary Redirect";
1865    case 308: return "Permanent Redirect";
1866
1867    case 400: return "Bad Request";
1868    case 401: return "Unauthorized";
1869    case 402: return "Payment Required";
1870    case 403: return "Forbidden";
1871    case 404: return "Not Found";
1872    case 405: return "Method Not Allowed";
1873    case 406: return "Not Acceptable";
1874    case 407: return "Proxy Authentication Required";
1875    case 408: return "Request Timeout";
1876    case 409: return "Conflict";
1877    case 410: return "Gone";
1878    case 411: return "Length Required";
1879    case 412: return "Precondition Failed";
1880    case 413: return "Payload Too Large";
1881    case 414: return "URI Too Long";
1882    case 415: return "Unsupported Media Type";
1883    case 416: return "Requested Range Not Satisfiable";
1884    case 417: return "Expectation Failed";
1885    case 418: return "I\'m a teapot";
1886    case 422: return "Unprocessable Entity";
1887    case 423: return "Locked";
1888    case 424: return "Failed Dependency";
1889    case 426: return "Upgrade Required";
1890    case 428: return "Precondition Required";
1891    case 429: return "Too Many Requests";
1892    case 431: return "Request Header Fields Too Large";
1893    case 451: return "Unavailable For Legal Reasons";
1894
1895    case 500: return "Internal Server Error";
1896    case 501: return "Not Implemented";
1897    case 502: return "Bad Gateway";
1898    case 503: return "Service Unavailable";
1899    case 504: return "Gateway Timeout";
1900    case 505: return "HTTP Version Not Supported";
1901    case 506: return "Variant Also Negotiates";
1902    case 507: return "Insufficient Storage";
1903    case 508: return "Loop Detected";
1904    case 510: return "Not Extended";
1905    case 511: return "Network Authentication Required";
1906
1907    default:  return "Server Error";
1908  }
1909}
1910
1911static int call_user(struct connection *conn, enum mg_event ev) {
1912  return conn != NULL && conn->server != NULL &&
1913    conn->server->event_handler != NULL ?
1914    conn->server->event_handler(&conn->mg_conn, ev) : MG_FALSE;
1915}
1916
1917static void send_http_error(struct connection *conn, int code,
1918                            const char *fmt, ...) {
1919  const char *message = status_code_to_str(code);
1920  const char *rewrites = conn->server->config_options[URL_REWRITES];
1921  char headers[200], body[200];
1922  struct vec a, b;
1923  va_list ap;
1924  int body_len, headers_len, match_code;
1925
1926  conn->mg_conn.status_code = code;
1927
1928  // Invoke error handler if it is set
1929  if (call_user(conn, MG_HTTP_ERROR) == MG_TRUE) {
1930    close_local_endpoint(conn);
1931    return;
1932  }
1933
1934  // Handle error code rewrites
1935  while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
1936    if ((match_code = atoi(a.ptr)) > 0 && match_code == code) {
1937      struct mg_connection *c = &conn->mg_conn;
1938      c->status_code = 302;
1939      mg_printf(c, "HTTP/1.1 %d Moved\r\n"
1940                "Location: %.*s?code=%d&orig_uri=%s&query_string=%s\r\n\r\n",
1941                c->status_code, b.len, b.ptr, code, c->uri,
1942                c->query_string == NULL ? "" : c->query_string);
1943      close_local_endpoint(conn);
1944      return;
1945    }
1946  }
1947
1948  body_len = mg_snprintf(body, sizeof(body), "%d %s\n", code, message);
1949  if (fmt != NULL) {
1950    va_start(ap, fmt);
1951    body_len += mg_vsnprintf(body + body_len, sizeof(body) - body_len, fmt, ap);
1952    va_end(ap);
1953  }
1954  if ((code >= 300 && code <= 399) || code == 204) {
1955    // 3xx errors do not have body
1956    body_len = 0;
1957  }
1958  headers_len = mg_snprintf(headers, sizeof(headers),
1959                            "HTTP/1.1 %d %s\r\nContent-Length: %d\r\n"
1960                            "Content-Type: text/plain\r\n\r\n",
1961                            code, message, body_len);
1962  ns_send(conn->ns_conn, headers, headers_len);
1963  ns_send(conn->ns_conn, body, body_len);
1964  close_local_endpoint(conn);  // This will write to the log file
1965}
1966
1967static void write_chunk(struct connection *conn, const char *buf, int len) {
1968  char chunk_size[50];
1969  int n = mg_snprintf(chunk_size, sizeof(chunk_size), "%X\r\n", len);
1970  ns_send(conn->ns_conn, chunk_size, n);
1971  ns_send(conn->ns_conn, buf, len);
1972  ns_send(conn->ns_conn, "\r\n", 2);
1973}
1974
1975size_t mg_printf(struct mg_connection *conn, const char *fmt, ...) {
1976  va_list ap;
1977  int ret;
1978
1979  va_start(ap, fmt);
1980  ret = mg_vprintf(conn, fmt, ap);
1981  va_end(ap);
1982
1983  return ret;
1984}
1985
1986size_t mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) {
1987  struct connection *c = MG_CONN_2_CONN(conn);
1988
1989  ns_vprintf(c->ns_conn, fmt, ap);
1990
1991  return c->ns_conn->send_iobuf.len;
1992}
1993
1994static void ns_forward(struct ns_connection *from, struct ns_connection *to) {
1995  DBG(("%p -> %p %lu bytes", from, to, (unsigned long)from->recv_iobuf.len));
1996  ns_send(to, from->recv_iobuf.buf, from->recv_iobuf.len);
1997  iobuf_remove(&from->recv_iobuf, from->recv_iobuf.len);
1998}
1999
2000#ifndef MONGOOSE_NO_CGI
2001#ifdef _WIN32
2002struct threadparam {
2003  sock_t s;
2004  HANDLE hPipe;
2005};
2006
2007static int wait_until_ready(sock_t sock, int for_read) {
2008  fd_set set;
2009  if ( (sock == INVALID_SOCKET) || (sock >= FD_SETSIZE) )
2010    return 0;
2011  FD_ZERO(&set);
2012  FD_SET(sock, &set);
2013  select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0);
2014  return 1;
2015}
2016
2017static void *push_to_stdin(void *arg) {
2018  struct threadparam *tp = (struct threadparam *)arg;
2019  int n, sent, stop = 0;
2020  DWORD k;
2021  char buf[IOBUF_SIZE];
2022
2023  while (!stop && wait_until_ready(tp->s, 1) &&
2024         (n = recv(tp->s, buf, sizeof(buf), 0)) > 0) {
2025    if (n == -1 && GetLastError() == WSAEWOULDBLOCK) continue;
2026    for (sent = 0; !stop && sent < n; sent += k) {
2027      if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1;
2028    }
2029  }
2030  DBG(("%s", "FORWARDED EVERYTHING TO CGI"));
2031  CloseHandle(tp->hPipe);
2032  NS_FREE(tp);
2033  _endthread();
2034  return NULL;
2035}
2036
2037static void *pull_from_stdout(void *arg) {
2038  struct threadparam *tp = (struct threadparam *)arg;
2039  int k = 0, stop = 0;
2040  DWORD n, sent;
2041  char buf[IOBUF_SIZE];
2042
2043  while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
2044    for (sent = 0; !stop && sent < n; sent += k) {
2045      if (wait_until_ready(tp->s, 0) &&
2046          (k = send(tp->s, buf + sent, n - sent, 0)) <= 0) stop = 1;
2047    }
2048  }
2049  DBG(("%s", "EOF FROM CGI"));
2050  CloseHandle(tp->hPipe);
2051  shutdown(tp->s, 2);  // Without this, IO thread may get truncated data
2052  closesocket(tp->s);
2053  NS_FREE(tp);
2054  _endthread();
2055  return NULL;
2056}
2057
2058static void spawn_stdio_thread(sock_t sock, HANDLE hPipe,
2059                               void *(*func)(void *)) {
2060  struct threadparam *tp = (struct threadparam *)NS_MALLOC(sizeof(*tp));
2061  if (tp != NULL) {
2062    tp->s = sock;
2063    tp->hPipe = hPipe;
2064    mg_start_thread(func, tp);
2065  }
2066}
2067
2068static void abs_path(const char *utf8_path, char *abs_path, size_t len) {
2069  wchar_t buf[MAX_PATH_SIZE], buf2[MAX_PATH_SIZE];
2070  to_wchar(utf8_path, buf, ARRAY_SIZE(buf));
2071  GetFullPathNameW(buf, ARRAY_SIZE(buf2), buf2, NULL);
2072  WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0);
2073}
2074
2075static process_id_t start_process(char *interp, const char *cmd,
2076                                  const char *env, const char *envp[],
2077                                  const char *dir, sock_t sock) {
2078  STARTUPINFOW si;
2079  PROCESS_INFORMATION pi;
2080  HANDLE a[2], b[2], me = GetCurrentProcess();
2081  wchar_t wcmd[MAX_PATH_SIZE], full_dir[MAX_PATH_SIZE];
2082  char buf[MAX_PATH_SIZE], buf4[MAX_PATH_SIZE], buf5[MAX_PATH_SIZE],
2083       cmdline[MAX_PATH_SIZE], *p;
2084  DWORD flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
2085  FILE *fp;
2086
2087  memset(&si, 0, sizeof(si));
2088  memset(&pi, 0, sizeof(pi));
2089
2090  si.cb = sizeof(si);
2091  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
2092  si.wShowWindow = SW_HIDE;
2093  si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
2094
2095  CreatePipe(&a[0], &a[1], NULL, 0);
2096  CreatePipe(&b[0], &b[1], NULL, 0);
2097  DuplicateHandle(me, a[0], me, &si.hStdInput, 0, TRUE, flags);
2098  DuplicateHandle(me, b[1], me, &si.hStdOutput, 0, TRUE, flags);
2099
2100  if (interp == NULL && (fp = fopen(cmd, "r")) != NULL) {
2101    buf[0] = buf[1] = '\0';
2102    fgets(buf, sizeof(buf), fp);
2103    buf[sizeof(buf) - 1] = '\0';
2104    if (buf[0] == '#' && buf[1] == '!') {
2105      interp = buf + 2;
2106      for (p = interp + strlen(interp) - 1;
2107           isspace(* (uint8_t *) p) && p > interp; p--) *p = '\0';
2108    }
2109    fclose(fp);
2110  }
2111
2112  if (interp != NULL) {
2113    abs_path(interp, buf4, ARRAY_SIZE(buf4));
2114    interp = buf4;
2115  }
2116  abs_path(dir, buf5, ARRAY_SIZE(buf5));
2117  to_wchar(dir, full_dir, ARRAY_SIZE(full_dir));
2118  mg_snprintf(cmdline, sizeof(cmdline), "%s%s\"%s\"",
2119              interp ? interp : "", interp ? " " : "", cmd);
2120  to_wchar(cmdline, wcmd, ARRAY_SIZE(wcmd));
2121
2122  if (CreateProcessW(NULL, wcmd, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP,
2123                     (void *) env, full_dir, &si, &pi) != 0) {
2124    spawn_stdio_thread(sock, a[1], push_to_stdin);
2125    spawn_stdio_thread(sock, b[0], pull_from_stdout);
2126  } else {
2127    CloseHandle(a[1]);
2128    CloseHandle(b[0]);
2129    closesocket(sock);
2130  }
2131  DBG(("CGI command: [%ls] -> %p", wcmd, pi.hProcess));
2132
2133  // Not closing a[0] and b[1] because we've used DUPLICATE_CLOSE_SOURCE
2134  CloseHandle(si.hStdOutput);
2135  CloseHandle(si.hStdInput);
2136  //CloseHandle(pi.hThread);
2137  //CloseHandle(pi.hProcess);
2138
2139  return pi.hProcess;
2140}
2141#else
2142static process_id_t start_process(const char *interp, const char *cmd,
2143                                  const char *env, const char *envp[],
2144                                  const char *dir, sock_t sock) {
2145  char buf[500];
2146  process_id_t pid = fork();
2147  (void) env;
2148
2149  if (pid == 0) {
2150    (void) chdir(dir);
2151    (void) dup2(sock, 0);
2152    (void) dup2(sock, 1);
2153    closesocket(sock);
2154
2155    // After exec, all signal handlers are restored to their default values,
2156    // with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
2157    // implementation, SIGCHLD's handler will leave unchanged after exec
2158    // if it was set to be ignored. Restore it to default action.
2159    signal(SIGCHLD, SIG_DFL);
2160
2161    if (interp == NULL) {
2162      execle(cmd, cmd, (char *) 0, envp); // Using (char *) 0 to avoid warning
2163    } else {
2164      execle(interp, interp, cmd, (char *) 0, envp);
2165    }
2166    snprintf(buf, sizeof(buf), "Status: 500\r\n\r\n"
2167             "500 Server Error: %s%s%s: %s", interp == NULL ? "" : interp,
2168             interp == NULL ? "" : " ", cmd, strerror(errno));
2169    send(1, buf, strlen(buf), 0);
2170    exit(EXIT_FAILURE);  // exec call failed
2171  }
2172
2173  return pid;
2174}
2175#endif  // _WIN32
2176
2177// This structure helps to create an environment for the spawned CGI program.
2178// Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
2179// last element must be NULL.
2180// However, on Windows there is a requirement that all these VARIABLE=VALUE\0
2181// strings must reside in a contiguous buffer. The end of the buffer is
2182// marked by two '\0' characters.
2183// We satisfy both worlds: we create an envp array (which is vars), all
2184// entries are actually pointers inside buf.
2185struct cgi_env_block {
2186  struct mg_connection *conn;
2187  char buf[CGI_ENVIRONMENT_SIZE];       // Environment buffer
2188  const char *vars[MAX_CGI_ENVIR_VARS]; // char *envp[]
2189  int len;                              // Space taken
2190  int nvars;                            // Number of variables in envp[]
2191};
2192
2193// Append VARIABLE=VALUE\0 string to the buffer, and add a respective
2194// pointer into the vars array.
2195static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
2196  int n, space;
2197  char *added;
2198  va_list ap;
2199
2200  // Calculate how much space is left in the buffer
2201  space = sizeof(block->buf) - block->len - 2;
2202  assert(space >= 0);
2203
2204  // Make a pointer to the free space int the buffer
2205  added = block->buf + block->len;
2206
2207  // Copy VARIABLE=VALUE\0 string into the free space
2208  va_start(ap, fmt);
2209  n = mg_vsnprintf(added, (size_t) space, fmt, ap);
2210  va_end(ap);
2211
2212  // Make sure we do not overflow buffer and the envp array
2213  if (n > 0 && n + 1 < space &&
2214      block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
2215    // Append a pointer to the added string into the envp array
2216    block->vars[block->nvars++] = added;
2217    // Bump up used length counter. Include \0 terminator
2218    block->len += n + 1;
2219  }
2220
2221  return added;
2222}
2223
2224static void addenv2(struct cgi_env_block *blk, const char *name) {
2225  const char *s;
2226  if ((s = getenv(name)) != NULL) addenv(blk, "%s=%s", name, s);
2227}
2228
2229static void prepare_cgi_environment(struct connection *conn,
2230                                    const char *prog,
2231                                    struct cgi_env_block *blk) {
2232  struct mg_connection *ri = &conn->mg_conn;
2233  const char *s, *slash;
2234  char *p, **opts = conn->server->config_options;
2235  int  i;
2236
2237  blk->len = blk->nvars = 0;
2238  blk->conn = ri;
2239
2240  if ((s = getenv("SERVER_NAME")) != NULL) {
2241    addenv(blk, "SERVER_NAME=%s", s);
2242  } else {
2243    addenv(blk, "SERVER_NAME=%s", ri->local_ip);
2244  }
2245  addenv(blk, "SERVER_ROOT=%s", opts[DOCUMENT_ROOT]);
2246  addenv(blk, "DOCUMENT_ROOT=%s", opts[DOCUMENT_ROOT]);
2247  addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", MONGOOSE_VERSION);
2248
2249  // Prepare the environment block
2250  addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
2251  addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
2252  addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP
2253
2254  // TODO(lsm): fix this for IPv6 case
2255  //addenv(blk, "SERVER_PORT=%d", ri->remote_port);
2256
2257  addenv(blk, "REQUEST_METHOD=%s", ri->request_method);
2258  addenv(blk, "REMOTE_ADDR=%s", ri->remote_ip);
2259  addenv(blk, "REMOTE_PORT=%d", ri->remote_port);
2260  addenv(blk, "REQUEST_URI=%s%s%s", ri->uri,
2261         ri->query_string == NULL ? "" : "?",
2262         ri->query_string == NULL ? "" : ri->query_string);
2263
2264  // SCRIPT_NAME
2265  if (conn->path_info != NULL) {
2266    addenv(blk, "SCRIPT_NAME=%.*s",
2267           (int) (strlen(ri->uri) - strlen(conn->path_info)), ri->uri);
2268    addenv(blk, "PATH_INFO=%s", conn->path_info);
2269  } else {
2270    s = strrchr(prog, '/');
2271    slash = strrchr(ri->uri, '/');
2272    addenv(blk, "SCRIPT_NAME=%.*s%s",
2273           slash == NULL ? 0 : (int) (slash - ri->uri), ri->uri,
2274           s == NULL ? prog : s);
2275  }
2276
2277  addenv(blk, "SCRIPT_FILENAME=%s", prog);
2278  addenv(blk, "PATH_TRANSLATED=%s", prog);
2279  addenv(blk, "HTTPS=%s", conn->ns_conn->ssl != NULL ? "on" : "off");
2280
2281  if ((s = mg_get_header(ri, "Content-Type")) != NULL)
2282    addenv(blk, "CONTENT_TYPE=%s", s);
2283
2284  if (ri->query_string != NULL)
2285    addenv(blk, "QUERY_STRING=%s", ri->query_string);
2286
2287  if ((s = mg_get_header(ri, "Content-Length")) != NULL)
2288    addenv(blk, "CONTENT_LENGTH=%s", s);
2289
2290  addenv2(blk, "PATH");
2291  addenv2(blk, "TMP");
2292  addenv2(blk, "TEMP");
2293  addenv2(blk, "TMPDIR");
2294  addenv2(blk, "PERLLIB");
2295  addenv2(blk, ENV_EXPORT_TO_CGI);
2296
2297#if defined(_WIN32)
2298  addenv2(blk, "COMSPEC");
2299  addenv2(blk, "SYSTEMROOT");
2300  addenv2(blk, "SystemDrive");
2301  addenv2(blk, "ProgramFiles");
2302  addenv2(blk, "ProgramFiles(x86)");
2303  addenv2(blk, "CommonProgramFiles(x86)");
2304#else
2305  addenv2(blk, "LD_LIBRARY_PATH");
2306#endif // _WIN32
2307
2308  // Add all headers as HTTP_* variables
2309  for (i = 0; i < ri->num_headers; i++) {
2310    p = addenv(blk, "HTTP_%s=%s",
2311        ri->http_headers[i].name, ri->http_headers[i].value);
2312
2313    // Convert variable name into uppercase, and change - to _
2314    for (; *p != '=' && *p != '\0'; p++) {
2315      if (*p == '-')
2316        *p = '_';
2317      *p = (char) toupper(* (unsigned char *) p);
2318    }
2319  }
2320
2321  blk->vars[blk->nvars++] = NULL;
2322  blk->buf[blk->len++] = '\0';
2323
2324  assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
2325  assert(blk->len > 0);
2326  assert(blk->len < (int) sizeof(blk->buf));
2327}
2328
2329static const char cgi_status[] = "HTTP/1.1 200 OK\r\n";
2330
2331static void open_cgi_endpoint(struct connection *conn, const char *prog) {
2332  struct cgi_env_block blk;
2333  char dir[MAX_PATH_SIZE];
2334  const char *p;
2335  sock_t fds[2];
2336
2337  prepare_cgi_environment(conn, prog, &blk);
2338  // CGI must be executed in its own directory. 'dir' must point to the
2339  // directory containing executable program, 'p' must point to the
2340  // executable program name relative to 'dir'.
2341  if ((p = strrchr(prog, '/')) == NULL) {
2342    mg_snprintf(dir, sizeof(dir), "%s", ".");
2343  } else {
2344    mg_snprintf(dir, sizeof(dir), "%.*s", (int) (p - prog), prog);
2345  }
2346
2347  // Try to create socketpair in a loop until success. ns_socketpair()
2348  // can be interrupted by a signal and fail.
2349  // TODO(lsm): use sigaction to restart interrupted syscall
2350  {
2351    int attempts = 0, max_attempts = NS_MAX_SOCKETPAIR_ATTEMPTS;
2352    do {
2353      ns_socketpair(fds);
2354    } while (fds[0] == INVALID_SOCKET && ++attempts < max_attempts);
2355
2356    if (fds[0] == INVALID_SOCKET) {
2357      closesocket(fds[0]);
2358      send_http_error(conn, 500, "ns_socketpair() failed");
2359    }
2360  }
2361
2362  if (start_process(conn->server->config_options[CGI_INTERPRETER],
2363                    prog, blk.buf, blk.vars, dir, fds[1]) != 0) {
2364    conn->endpoint_type = EP_CGI;
2365    conn->endpoint.nc = ns_add_sock(&conn->server->ns_mgr, fds[0],
2366                                    mg_ev_handler, conn);
2367    conn->endpoint.nc->flags |= MG_CGI_CONN;
2368    ns_send(conn->ns_conn, cgi_status, sizeof(cgi_status) - 1);
2369    conn->mg_conn.status_code = 200;
2370    conn->ns_conn->flags |= NSF_BUFFER_BUT_DONT_SEND;
2371    // Pass POST data to the CGI process
2372    conn->endpoint.nc->send_iobuf = conn->ns_conn->recv_iobuf;
2373    iobuf_init(&conn->ns_conn->recv_iobuf, 0);
2374  } else {
2375    closesocket(fds[0]);
2376    send_http_error(conn, 500, "start_process(%s) failed", prog);
2377  }
2378
2379#ifndef _WIN32
2380  closesocket(fds[1]);  // On Windows, CGI stdio thread closes that socket
2381#endif
2382}
2383
2384static void on_cgi_data(struct ns_connection *nc) {
2385  struct connection *conn = (struct connection *) nc->user_data;
2386  const char *status = "500";
2387  struct mg_connection c;
2388
2389  if (!conn) return;
2390
2391  // Copy CGI data from CGI socket to the client send buffer
2392  ns_forward(nc, conn->ns_conn);
2393
2394  // If reply has not been parsed yet, parse it
2395  if (conn->ns_conn->flags & NSF_BUFFER_BUT_DONT_SEND) {
2396    struct iobuf *io = &conn->ns_conn->send_iobuf;
2397    size_t s_len = sizeof(cgi_status) - 1;
2398    int len = get_request_len(io->buf + s_len, io->len - s_len);
2399    char buf[MAX_REQUEST_SIZE], *s = buf;
2400
2401    if (len == 0) return;
2402
2403    if (len < 0 || len > (int) sizeof(buf)) {
2404      len = io->len;
2405      iobuf_remove(io, io->len);
2406      send_http_error(conn, 500, "CGI program sent malformed headers: [%.*s]",
2407        len, io->buf);
2408    } else {
2409      memset(&c, 0, sizeof(c));
2410      memcpy(buf, io->buf + s_len, len);
2411      buf[len - 1] = '\0';
2412      parse_http_headers(&s, &c);
2413      if (mg_get_header(&c, "Location") != NULL) {
2414        status = "302";
2415      } else if ((status = (char *) mg_get_header(&c, "Status")) == NULL) {
2416        status = "200";
2417      }
2418      memcpy(io->buf + 9, status, 3);
2419      conn->mg_conn.status_code = atoi(status);
2420    }
2421    conn->ns_conn->flags &= ~NSF_BUFFER_BUT_DONT_SEND;
2422  }
2423}
2424#endif  // !MONGOOSE_NO_CGI
2425
2426static char *mg_strdup(const char *str) {
2427  char *copy = (char *) NS_MALLOC(strlen(str) + 1);
2428  if (copy != NULL) {
2429    strcpy(copy, str);
2430  }
2431  return copy;
2432}
2433
2434static int isbyte(int n) {
2435  return n >= 0 && n <= 255;
2436}
2437
2438static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
2439  int n, a, b, c, d, slash = 32, len = 0;
2440
2441  if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
2442      sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
2443      isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) &&
2444      slash >= 0 && slash < 33) {
2445    len = n;
2446    *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | d;
2447    *mask = slash ? 0xffffffffU << (32 - slash) : 0;
2448  }
2449
2450  return len;
2451}
2452
2453// Verify given socket address against the ACL.
2454// Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
2455static int check_acl(const char *acl, uint32_t remote_ip) {
2456  int allowed, flag;
2457  uint32_t net, mask;
2458  struct vec vec;
2459
2460  // If any ACL is set, deny by default
2461  allowed = acl == NULL ? '+' : '-';
2462
2463  while ((acl = next_option(acl, &vec, NULL)) != NULL) {
2464    flag = vec.ptr[0];
2465    if ((flag != '+' && flag != '-') ||
2466        parse_net(&vec.ptr[1], &net, &mask) == 0) {
2467      return -1;
2468    }
2469
2470    if (net == (remote_ip & mask)) {
2471      allowed = flag;
2472    }
2473  }
2474
2475  return allowed == '+';
2476}
2477
2478// Protect against directory disclosure attack by removing '..',
2479// excessive '/' and '\' characters
2480static void remove_double_dots_and_double_slashes(char *s) {
2481  char *p = s;
2482
2483  while (*s != '\0') {
2484    *p++ = *s++;
2485    if (s[-1] == '/' || s[-1] == '\\') {
2486      // Skip all following slashes, backslashes and double-dots
2487      while (s[0] != '\0') {
2488        if (s[0] == '/' || s[0] == '\\') { s++; }
2489        else if (s[0] == '.' && (s[1] == '/' || s[1] == '\\')) { s += 2; }
2490        else if (s[0] == '.' && s[1] == '.' && s[2] == '\0') { s += 2; }
2491        else if (s[0] == '.' && s[1] == '.' && (s[2] == '/' || s[2] == '\\')) { s += 3; }
2492        else { break; }
2493      }
2494    }
2495  }
2496  *p = '\0';
2497}
2498
2499int mg_url_decode(const char *src, size_t src_len, char *dst,
2500                  size_t dst_len, int is_form_url_encoded) {
2501  size_t i, j = 0;
2502  int a, b;
2503#define HEXTOI(x) (isdigit(x) ? (x) - '0' : (x) - 'W')
2504
2505  for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
2506    if (src[i] == '%' && i + 2 < src_len &&
2507        isxdigit(* (const unsigned char *) (src + i + 1)) &&
2508        isxdigit(* (const unsigned char *) (src + i + 2))) {
2509      a = tolower(* (const unsigned char *) (src + i + 1));
2510      b = tolower(* (const unsigned char *) (src + i + 2));
2511      dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
2512      i += 2;
2513    } else if (is_form_url_encoded && src[i] == '+') {
2514      dst[j] = ' ';
2515    } else {
2516      dst[j] = src[i];
2517    }
2518  }
2519
2520  dst[j] = '\0'; // Null-terminate the destination
2521
2522  return i >= src_len ? j : -1;
2523}
2524
2525static int is_valid_http_method(const char *s) {
2526  return !strcmp(s, "GET") || !strcmp(s, "POST") || !strcmp(s, "HEAD") ||
2527    !strcmp(s, "CONNECT") || !strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
2528    !strcmp(s, "OPTIONS") || !strcmp(s, "PROPFIND") || !strcmp(s, "MKCOL") ||
2529    !strcmp(s, "PATCH");
2530}
2531
2532// Parse HTTP request, fill in mg_request structure.
2533// This function modifies the buffer by NUL-terminating
2534// HTTP request components, header names and header values.
2535// Note that len must point to the last \n of HTTP headers.
2536static size_t parse_http_message(char *buf, size_t len,
2537                                 struct mg_connection *ri) {
2538  int is_request, n;
2539
2540  // Reset the connection. Make sure that we don't touch fields that are
2541  // set elsewhere: remote_ip, remote_port, server_param
2542  ri->request_method = ri->uri = ri->http_version = ri->query_string = NULL;
2543  ri->num_headers = ri->status_code = ri->is_websocket = ri->content_len = 0;
2544
2545  if (len < 1) return ~0;
2546
2547  buf[len - 1] = '\0';
2548
2549  // RFC says that all initial whitespaces should be ignored
2550  while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
2551    buf++;
2552  }
2553  ri->request_method = skip(&buf, " ");
2554  ri->uri = skip(&buf, " ");
2555  ri->http_version = skip(&buf, "\r\n");
2556
2557  // HTTP message could be either HTTP request or HTTP response, e.g.
2558  // "GET / HTTP/1.0 ...." or  "HTTP/1.0 200 OK ..."
2559  is_request = is_valid_http_method(ri->request_method);
2560  if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) ||
2561      (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
2562    len = ~0;
2563  } else {
2564    if (is_request) {
2565      ri->http_version += 5;
2566    } else {
2567      ri->status_code = atoi(ri->uri);
2568    }
2569    parse_http_headers(&buf, ri);
2570
2571    if ((ri->query_string = strchr(ri->uri, '?')) != NULL) {
2572      *(char *) ri->query_string++ = '\0';
2573    }
2574    n = (int) strlen(ri->uri);
2575    mg_url_decode(ri->uri, n, (char *) ri->uri, n + 1, 0);
2576    if (*ri->uri == '/' || *ri->uri == '.') {
2577      remove_double_dots_and_double_slashes((char *) ri->uri);
2578    }
2579  }
2580
2581  return len;
2582}
2583
2584static int lowercase(const char *s) {
2585  return tolower(* (const unsigned char *) s);
2586}
2587
2588static int mg_strcasecmp(const char *s1, const char *s2) {
2589  int diff;
2590
2591  do {
2592    diff = lowercase(s1++) - lowercase(s2++);
2593  } while (diff == 0 && s1[-1] != '\0');
2594
2595  return diff;
2596}
2597
2598static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
2599  int diff = 0;
2600
2601  if (len > 0)
2602    do {
2603      diff = lowercase(s1++) - lowercase(s2++);
2604    } while (diff == 0 && s1[-1] != '\0' && --len > 0);
2605
2606  return diff;
2607}
2608
2609// Return HTTP header value, or NULL if not found.
2610const char *mg_get_header(const struct mg_connection *ri, const char *s) {
2611  int i;
2612
2613  for (i = 0; i < ri->num_headers; i++)
2614    if (!mg_strcasecmp(s, ri->http_headers[i].name))
2615      return ri->http_headers[i].value;
2616
2617  return NULL;
2618}
2619
2620// Perform case-insensitive match of string against pattern
2621int mg_match_prefix(const char *pattern, ssize_t pattern_len, const char *str) {
2622  const char *or_str;
2623  int len, res, i = 0, j = 0;
2624
2625  if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
2626    res = mg_match_prefix(pattern, or_str - pattern, str);
2627    return res > 0 ? res : mg_match_prefix(or_str + 1,
2628      (pattern + pattern_len) - (or_str + 1), str);
2629  }
2630
2631  for (; i < pattern_len; i++, j++) {
2632    if (pattern[i] == '?' && str[j] != '\0') {
2633      continue;
2634    } else if (pattern[i] == '$') {
2635      return str[j] == '\0' ? j : -1;
2636    } else if (pattern[i] == '*') {
2637      i++;
2638      if (pattern[i] == '*') {
2639        i++;
2640        len = (int) strlen(str + j);
2641      } else {
2642        len = (int) strcspn(str + j, "/");
2643      }
2644      if (i == pattern_len) {
2645        return j + len;
2646      }
2647      do {
2648        res = mg_match_prefix(pattern + i, pattern_len - i, str + j + len);
2649      } while (res == -1 && len-- > 0);
2650      return res == -1 ? -1 : j + res + len;
2651    } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
2652      return -1;
2653    }
2654  }
2655  return j;
2656}
2657
2658// This function prints HTML pages, and expands "{{something}}" blocks
2659// inside HTML by calling appropriate callback functions.
2660// Note that {{@path/to/file}} construct outputs embedded file's contents,
2661// which provides SSI-like functionality.
2662void mg_template(struct mg_connection *conn, const char *s,
2663                 struct mg_expansion *expansions) {
2664  int i, j, pos = 0, inside_marker = 0;
2665
2666  for (i = 0; s[i] != '\0'; i++) {
2667    if (inside_marker == 0 && !memcmp(&s[i], "{{", 2)) {
2668      if (i > pos) {
2669        mg_send_data(conn, &s[pos], i - pos);
2670      }
2671      pos = i;
2672      inside_marker = 1;
2673    }
2674    if (inside_marker == 1 && !memcmp(&s[i], "}}", 2)) {
2675      for (j = 0; expansions[j].keyword != NULL; j++) {
2676        const char *kw = expansions[j].keyword;
2677        if ((int) strlen(kw) == i - (pos + 2) &&
2678            memcmp(kw, &s[pos + 2], i - (pos + 2)) == 0) {
2679          expansions[j].handler(conn);
2680          pos = i + 2;
2681          break;
2682        }
2683      }
2684      inside_marker = 0;
2685    }
2686  }
2687  if (i > pos) {
2688    mg_send_data(conn, &s[pos], i - pos);
2689  }
2690}
2691
2692#ifndef MONGOOSE_NO_FILESYSTEM
2693static int is_dav_request(const struct connection *conn) {
2694  const char *s = conn->mg_conn.request_method;
2695  return !strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
2696    !strcmp(s, "MKCOL") || !strcmp(s, "PROPFIND");
2697}
2698
2699static int must_hide_file(struct connection *conn, const char *path) {
2700  const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
2701  const char *pattern = conn->server->config_options[HIDE_FILES_PATTERN];
2702  return mg_match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 ||
2703    (pattern != NULL && mg_match_prefix(pattern, strlen(pattern), path) > 0);
2704}
2705
2706// Return 1 if real file has been found, 0 otherwise
2707static int convert_uri_to_file_name(struct connection *conn, char *buf,
2708                                    size_t buf_len, file_stat_t *st) {
2709  struct vec a, b;
2710  const char *rewrites = conn->server->config_options[URL_REWRITES];
2711  const char *root =
2712#ifndef MONGOOSE_NO_DAV
2713    is_dav_request(conn) && conn->server->config_options[DAV_ROOT] != NULL ?
2714    conn->server->config_options[DAV_ROOT] :
2715#endif
2716    conn->server->config_options[DOCUMENT_ROOT];
2717#ifndef MONGOOSE_NO_CGI
2718  const char *cgi_pat = conn->server->config_options[CGI_PATTERN];
2719  char *p;
2720#endif
2721  const char *uri = conn->mg_conn.uri;
2722  const char *domain = mg_get_header(&conn->mg_conn, "Host");
2723  // Important: match_len has to be declared as int, unless rewrites break.
2724  int match_len, root_len = root == NULL ? 0 : strlen(root);
2725
2726  // Perform virtual hosting rewrites
2727  if (rewrites != NULL && domain != NULL) {
2728    const char *colon = strchr(domain, ':');
2729    size_t domain_len = colon == NULL ? strlen(domain) : colon - domain;
2730
2731    while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
2732      if (a.len > 1 && a.ptr[0] == '@' && a.len == domain_len + 1 &&
2733          mg_strncasecmp(a.ptr + 1, domain, domain_len) == 0) {
2734        root = b.ptr;
2735        root_len = b.len;
2736        break;
2737      }
2738    }
2739  }
2740
2741  // No filesystem access
2742  if (root == NULL || root_len == 0) return 0;
2743
2744  // Handle URL rewrites
2745  mg_snprintf(buf, buf_len, "%.*s%s", root_len, root, uri);
2746  rewrites = conn->server->config_options[URL_REWRITES];  // Re-initialize!
2747  while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
2748    if ((match_len = mg_match_prefix(a.ptr, a.len, uri)) > 0) {
2749      mg_snprintf(buf, buf_len, "%.*s%s", (int) b.len, b.ptr, uri + match_len);
2750      break;
2751    }
2752  }
2753
2754  if (stat(buf, st) == 0) return 1;
2755
2756#ifndef MONGOOSE_NO_CGI
2757  // Support PATH_INFO for CGI scripts.
2758  for (p = buf + strlen(root) + 2; *p != '\0'; p++) {
2759    if (*p == '/') {
2760      *p = '\0';
2761      if (mg_match_prefix(cgi_pat, strlen(cgi_pat), buf) > 0 &&
2762          !stat(buf, st)) {
2763      DBG(("!!!! [%s]", buf));
2764        *p = '/';
2765        conn->path_info = mg_strdup(p);
2766        *p = '\0';
2767        return 1;
2768      }
2769      *p = '/';
2770    }
2771  }
2772#endif
2773
2774  return 0;
2775}
2776#endif  // MONGOOSE_NO_FILESYSTEM
2777
2778static int should_keep_alive(const struct mg_connection *conn) {
2779  struct connection *c = MG_CONN_2_CONN(conn);
2780  const char *method = conn->request_method;
2781  const char *http_version = conn->http_version;
2782  const char *header = mg_get_header(conn, "Connection");
2783  return method != NULL &&
2784    (!strcmp(method, "GET") || c->endpoint_type == EP_USER) &&
2785    ((header != NULL && !mg_strcasecmp(header, "keep-alive")) ||
2786     (header == NULL && http_version && !strcmp(http_version, "1.1")));
2787}
2788
2789size_t mg_write(struct mg_connection *c, const void *buf, size_t len) {
2790  struct connection *conn = MG_CONN_2_CONN(c);
2791  ns_send(conn->ns_conn, buf, len);
2792  return conn->ns_conn->send_iobuf.len;
2793}
2794
2795void mg_send_status(struct mg_connection *c, int status) {
2796  struct connection *conn = MG_CONN_2_CONN(c);
2797  if (c->status_code == 0) {
2798    c->status_code = status;
2799    mg_printf(c, "HTTP/1.1 %d %s\r\n", status, status_code_to_str(status));
2800  }
2801  conn->ns_conn->flags |= MG_USING_CHUNKED_API;
2802}
2803
2804void mg_send_header(struct mg_connection *c, const char *name, const char *v) {
2805  struct connection *conn = MG_CONN_2_CONN(c);
2806  if (c->status_code == 0) {
2807    c->status_code = 200;
2808    mg_printf(c, "HTTP/1.1 %d %s\r\n", 200, status_code_to_str(200));
2809  }
2810  mg_printf(c, "%s: %s\r\n", name, v);
2811  conn->ns_conn->flags |= MG_USING_CHUNKED_API;
2812}
2813
2814static void terminate_headers(struct mg_connection *c) {
2815  struct connection *conn = MG_CONN_2_CONN(c);
2816  if (!(conn->ns_conn->flags & MG_HEADERS_SENT)) {
2817    mg_send_header(c, "Transfer-Encoding", "chunked");
2818    mg_write(c, "\r\n", 2);
2819    conn->ns_conn->flags |= MG_HEADERS_SENT;
2820  }
2821}
2822
2823size_t mg_send_data(struct mg_connection *c, const void *data, int data_len) {
2824  struct connection *conn = MG_CONN_2_CONN(c);
2825  terminate_headers(c);
2826  write_chunk(MG_CONN_2_CONN(c), (const char *) data, data_len);
2827  return conn->ns_conn->send_iobuf.len;
2828}
2829
2830size_t mg_printf_data(struct mg_connection *c, const char *fmt, ...) {
2831  va_list ap;
2832  int ret;
2833
2834  va_start(ap, fmt);
2835  ret = mg_vprintf_data(c, fmt, ap);
2836  va_end(ap);
2837
2838  return ret;
2839}
2840
2841size_t mg_vprintf_data(struct mg_connection *c, const char *fmt, va_list ap) {
2842  struct connection *conn = MG_CONN_2_CONN(c);
2843  int len;
2844  char mem[IOBUF_SIZE], *buf = mem;
2845
2846  terminate_headers(c);
2847
2848  len = ns_avprintf(&buf, sizeof(mem), fmt, ap);
2849
2850  if (len >= 0) {
2851    write_chunk((struct connection *) conn, buf, len);
2852  }
2853  if (buf != mem && buf != NULL) {
2854    NS_FREE(buf);
2855  }
2856  return conn->ns_conn->send_iobuf.len;
2857}
2858
2859#if !defined(MONGOOSE_NO_WEBSOCKET) || !defined(MONGOOSE_NO_AUTH)
2860static int is_big_endian(void) {
2861  static const int n = 1;
2862  return ((char *) &n)[0] == 0;
2863}
2864#endif
2865
2866#ifndef MONGOOSE_NO_WEBSOCKET
2867// START OF SHA-1 code
2868// Copyright(c) By Steve Reid <steve@edmweb.com>
2869#define SHA1HANDSOFF
2870#if defined(__sun)
2871#include "solarisfixes.h"
2872#endif
2873
2874union char64long16 { unsigned char c[64]; uint32_t l[16]; };
2875
2876#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
2877
2878static uint32_t blk0(union char64long16 *block, int i) {
2879  // Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN
2880  if (!is_big_endian()) {
2881    block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
2882      (rol(block->l[i], 8) & 0x00FF00FF);
2883  }
2884  return block->l[i];
2885}
2886
2887/* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
2888#undef blk
2889#undef R0
2890#undef R1
2891#undef R2
2892#undef R3
2893#undef R4
2894
2895#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
2896    ^block->l[(i+2)&15]^block->l[i&15],1))
2897#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
2898#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
2899#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
2900#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
2901#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
2902
2903typedef struct {
2904    uint32_t state[5];
2905    uint32_t count[2];
2906    unsigned char buffer[64];
2907} SHA1_CTX;
2908
2909static void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) {
2910  uint32_t a, b, c, d, e;
2911  union char64long16 block[1];
2912
2913  memcpy(block, buffer, 64);
2914  a = state[0];
2915  b = state[1];
2916  c = state[2];
2917  d = state[3];
2918  e = state[4];
2919  R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
2920  R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
2921  R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
2922  R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
2923  R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
2924  R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
2925  R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
2926  R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
2927  R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
2928  R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
2929  R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
2930  R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
2931  R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
2932  R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
2933  R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
2934  R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
2935  R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
2936  R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
2937  R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
2938  R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
2939  state[0] += a;
2940  state[1] += b;
2941  state[2] += c;
2942  state[3] += d;
2943  state[4] += e;
2944  // Erase working structures. The order of operations is important,
2945  // used to ensure that compiler doesn't optimize those out.
2946  memset(block, 0, sizeof(block));
2947  a = b = c = d = e = 0;
2948  (void) a; (void) b; (void) c; (void) d; (void) e;
2949}
2950
2951static void SHA1Init(SHA1_CTX *context) {
2952  context->state[0] = 0x67452301;
2953  context->state[1] = 0xEFCDAB89;
2954  context->state[2] = 0x98BADCFE;
2955  context->state[3] = 0x10325476;
2956  context->state[4] = 0xC3D2E1F0;
2957  context->count[0] = context->count[1] = 0;
2958}
2959
2960static void SHA1Update(SHA1_CTX *context, const unsigned char *data,
2961                       size_t len) {
2962  size_t i, j;
2963
2964  j = context->count[0];
2965  if ((context->count[0] += len << 3) < j)
2966    context->count[1]++;
2967  context->count[1] += (len>>29);
2968  j = (j >> 3) & 63;
2969  if ((j + len) > 63) {
2970    memcpy(&context->buffer[j], data, (i = 64-j));
2971    SHA1Transform(context->state, context->buffer);
2972    for ( ; i + 63 < len; i += 64) {
2973      SHA1Transform(context->state, &data[i]);
2974    }
2975    j = 0;
2976  }
2977  else i = 0;
2978  memcpy(&context->buffer[j], &data[i], len - i);
2979}
2980
2981static void SHA1Final(unsigned char digest[20], SHA1_CTX *context) {
2982  unsigned i;
2983  unsigned char finalcount[8], c;
2984
2985  for (i = 0; i < 8; i++) {
2986    finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
2987                                     >> ((3-(i & 3)) * 8) ) & 255);
2988  }
2989  c = 0200;
2990  SHA1Update(context, &c, 1);
2991  while ((context->count[0] & 504) != 448) {
2992    c = 0000;
2993    SHA1Update(context, &c, 1);
2994  }
2995  SHA1Update(context, finalcount, 8);
2996  for (i = 0; i < 20; i++) {
2997    digest[i] = (unsigned char)
2998      ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
2999  }
3000  memset(context, '\0', sizeof(*context));
3001  memset(&finalcount, '\0', sizeof(finalcount));
3002}
3003// END OF SHA1 CODE
3004
3005static void base64_encode(const unsigned char *src, int src_len, char *dst) {
3006  static const char *b64 =
3007    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3008  int i, j, a, b, c;
3009
3010  for (i = j = 0; i < src_len; i += 3) {
3011    a = src[i];
3012    b = i + 1 >= src_len ? 0 : src[i + 1];
3013    c = i + 2 >= src_len ? 0 : src[i + 2];
3014
3015    dst[j++] = b64[a >> 2];
3016    dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
3017    if (i + 1 < src_len) {
3018      dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
3019    }
3020    if (i + 2 < src_len) {
3021      dst[j++] = b64[c & 63];
3022    }
3023  }
3024  while (j % 4 != 0) {
3025    dst[j++] = '=';
3026  }
3027  dst[j++] = '\0';
3028}
3029
3030static void send_websocket_handshake(struct mg_connection *conn,
3031                                     const char *key) {
3032  static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
3033  char buf[500], sha[20], b64_sha[sizeof(sha) * 2];
3034  SHA1_CTX sha_ctx;
3035
3036  mg_snprintf(buf, sizeof(buf), "%s%s", key, magic);
3037  SHA1Init(&sha_ctx);
3038  SHA1Update(&sha_ctx, (unsigned char *) buf, strlen(buf));
3039  SHA1Final((unsigned char *) sha, &sha_ctx);
3040  base64_encode((unsigned char *) sha, sizeof(sha), b64_sha);
3041  mg_snprintf(buf, sizeof(buf), "%s%s%s",
3042              "HTTP/1.1 101 Switching Protocols\r\n"
3043              "Upgrade: websocket\r\n"
3044              "Connection: Upgrade\r\n"
3045              "Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
3046
3047  mg_write(conn, buf, strlen(buf));
3048}
3049
3050static size_t deliver_websocket_frame(struct connection *conn) {
3051  // Having buf unsigned char * is important, as it is used below in arithmetic
3052  unsigned char *buf = (unsigned char *) conn->ns_conn->recv_iobuf.buf;
3053  size_t i, len, buf_len = conn->ns_conn->recv_iobuf.len, frame_len = 0,
3054      mask_len = 0, header_len = 0, data_len = 0, buffered = 0;
3055
3056  if (buf_len >= 2) {
3057    len = buf[1] & 127;
3058    mask_len = buf[1] & 128 ? 4 : 0;
3059    if (len < 126 && buf_len >= mask_len) {
3060      data_len = len;
3061      header_len = 2 + mask_len;
3062    } else if (len == 126 && buf_len >= 4 + mask_len) {
3063      header_len = 4 + mask_len;
3064      data_len = ((((size_t) buf[2]) << 8) + buf[3]);
3065    } else if (buf_len >= 10 + mask_len) {
3066      header_len = 10 + mask_len;
3067      data_len = (size_t) (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
3068        htonl(* (uint32_t *) &buf[6]);
3069    }
3070  }
3071
3072  frame_len = header_len + data_len;
3073  buffered = frame_len > 0 && frame_len <= buf_len;
3074
3075  if (buffered) {
3076    conn->mg_conn.content_len = data_len;
3077    conn->mg_conn.content = (char *) buf + header_len;
3078    conn->mg_conn.wsbits = buf[0];
3079
3080    // Apply mask if necessary
3081    if (mask_len > 0) {
3082      for (i = 0; i < data_len; i++) {
3083        buf[i + header_len] ^= (buf + header_len - mask_len)[i % 4];
3084      }
3085    }
3086
3087    // Call the handler and remove frame from the iobuf
3088    if (call_user(conn, MG_REQUEST) == MG_FALSE ||
3089        (buf[0] & 0x0f) == WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
3090      conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
3091    }
3092    iobuf_remove(&conn->ns_conn->recv_iobuf, frame_len);
3093  }
3094
3095  return buffered;
3096}
3097
3098size_t mg_websocket_write(struct mg_connection *conn, int opcode,
3099                          const char *data, size_t data_len) {
3100    unsigned char mem[4192], *copy = mem;
3101    size_t copy_len = 0;
3102
3103    /* Check overflow */
3104    if (data_len > ~(size_t)0 - (size_t)10) {
3105      return 0;
3106    }
3107
3108    if (data_len + 10 > sizeof(mem) &&
3109        (copy = (unsigned char *) NS_MALLOC(data_len + 10)) == NULL) {
3110      return 0;
3111    }
3112
3113    copy[0] = 0x80 + (opcode & 0x0f);
3114
3115    // Frame format: http://tools.ietf.org/html/rfc6455#section-5.2
3116    if (data_len < 126) {
3117      // Inline 7-bit length field
3118      copy[1] = data_len;
3119      memcpy(copy + 2, data, data_len);
3120      copy_len = 2 + data_len;
3121    } else if (data_len <= 0xFFFF) {
3122      // 16-bit length field
3123      copy[1] = 126;
3124      * (uint16_t *) (copy + 2) = (uint16_t) htons((uint16_t) data_len);
3125      memcpy(copy + 4, data, data_len);
3126      copy_len = 4 + data_len;
3127    } else {
3128      // 64-bit length field
3129      const uint32_t hi = htonl((uint32_t) ((uint64_t) data_len >> 32));
3130      const uint32_t lo = htonl(data_len & 0xffffffff);
3131      copy[1] = 127;
3132      memcpy(copy+2,&hi,sizeof(hi));
3133      memcpy(copy+6,&lo,sizeof(lo));
3134      memcpy(copy + 10, data, data_len);
3135      copy_len = 10 + data_len;
3136    }
3137
3138    if (copy_len > 0) {
3139      mg_write(conn, copy, copy_len);
3140    }
3141    if (copy != mem) {
3142      NS_FREE(copy);
3143    }
3144
3145    // If we send closing frame, schedule a connection to be closed after
3146    // data is drained to the client.
3147    if (opcode == WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
3148      MG_CONN_2_CONN(conn)->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
3149    }
3150
3151    return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len;
3152}
3153
3154size_t mg_websocket_printf(struct mg_connection *conn, int opcode,
3155                           const char *fmt, ...) {
3156  char mem[4192], *buf = mem;
3157  va_list ap;
3158  int len;
3159
3160  va_start(ap, fmt);
3161  if ((len = ns_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
3162    mg_websocket_write(conn, opcode, buf, len);
3163  }
3164  va_end(ap);
3165
3166  if (buf != mem && buf != NULL) {
3167    NS_FREE(buf);
3168  }
3169
3170  return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len;
3171}
3172
3173static void send_websocket_handshake_if_requested(struct mg_connection *conn) {
3174  const char *ver = mg_get_header(conn, "Sec-WebSocket-Version"),
3175        *key = mg_get_header(conn, "Sec-WebSocket-Key");
3176  if (ver != NULL && key != NULL) {
3177    conn->is_websocket = 1;
3178    if (call_user(MG_CONN_2_CONN(conn), MG_WS_HANDSHAKE) == MG_FALSE) {
3179      send_websocket_handshake(conn, key);
3180    }
3181    call_user(MG_CONN_2_CONN(conn), MG_WS_CONNECT);
3182  }
3183}
3184
3185static void ping_idle_websocket_connection(struct connection *conn, time_t t) {
3186  if (t - conn->ns_conn->last_io_time > MONGOOSE_USE_WEBSOCKET_PING_INTERVAL) {
3187    mg_websocket_write(&conn->mg_conn, WEBSOCKET_OPCODE_PING, "", 0);
3188  }
3189}
3190#else
3191#define ping_idle_websocket_connection(conn, t)
3192#endif // !MONGOOSE_NO_WEBSOCKET
3193
3194static void write_terminating_chunk(struct connection *conn) {
3195  mg_write(&conn->mg_conn, "0\r\n\r\n", 5);
3196}
3197
3198static int call_request_handler(struct connection *conn) {
3199  int result;
3200  conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
3201  if ((result = call_user(conn, MG_REQUEST)) == MG_TRUE) {
3202    if (conn->ns_conn->flags & MG_USING_CHUNKED_API) {
3203      terminate_headers(&conn->mg_conn);
3204      write_terminating_chunk(conn);
3205    }
3206    close_local_endpoint(conn);
3207  }
3208  return result;
3209}
3210
3211const char *mg_get_mime_type(const char *path, const char *default_mime_type) {
3212  const char *ext;
3213  size_t i, path_len;
3214
3215  path_len = strlen(path);
3216
3217  for (i = 0; static_builtin_mime_types[i].extension != NULL; i++) {
3218    ext = path + (path_len - static_builtin_mime_types[i].ext_len);
3219    if (path_len > static_builtin_mime_types[i].ext_len &&
3220        mg_strcasecmp(ext, static_builtin_mime_types[i].extension) == 0) {
3221      return static_builtin_mime_types[i].mime_type;
3222    }
3223  }
3224
3225  return default_mime_type;
3226}
3227
3228#ifndef MONGOOSE_NO_FILESYSTEM
3229// Convert month to the month number. Return -1 on error, or month number
3230static int get_month_index(const char *s) {
3231  static const char *month_names[] = {
3232    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3233    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
3234  };
3235  int i;
3236
3237  for (i = 0; i < (int) ARRAY_SIZE(month_names); i++)
3238    if (!strcmp(s, month_names[i]))
3239      return i;
3240
3241  return -1;
3242}
3243
3244static int num_leap_years(int year) {
3245  return year / 4 - year / 100 + year / 400;
3246}
3247
3248// Parse UTC date-time string, and return the corresponding time_t value.
3249static time_t parse_date_string(const char *datetime) {
3250  static const unsigned short days_before_month[] = {
3251    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
3252  };
3253  char month_str[32];
3254  int second, minute, hour, day, month, year, leap_days, days;
3255  time_t result = (time_t) 0;
3256
3257  if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d",
3258               &day, month_str, &year, &hour, &minute, &second) == 6) ||
3259       (sscanf(datetime, "%d %3s %d %d:%d:%d",
3260               &day, month_str, &year, &hour, &minute, &second) == 6) ||
3261       (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d",
3262               &day, month_str, &year, &hour, &minute, &second) == 6) ||
3263       (sscanf(datetime, "%d-%3s-%d %d:%d:%d",
3264               &day, month_str, &year, &hour, &minute, &second) == 6)) &&
3265      year > 1970 &&
3266      (month = get_month_index(month_str)) != -1) {
3267    leap_days = num_leap_years(year) - num_leap_years(1970);
3268    year -= 1970;
3269    days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
3270    result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
3271  }
3272
3273  return result;
3274}
3275
3276// Look at the "path" extension and figure what mime type it has.
3277// Store mime type in the vector.
3278static void get_mime_type(const struct mg_server *server, const char *path,
3279                          struct vec *vec) {
3280  struct vec ext_vec, mime_vec;
3281  const char *list, *ext;
3282  size_t path_len;
3283
3284  path_len = strlen(path);
3285
3286  // Scan user-defined mime types first, in case user wants to
3287  // override default mime types.
3288  list = server->config_options[EXTRA_MIME_TYPES];
3289  while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
3290    // ext now points to the path suffix
3291    ext = path + path_len - ext_vec.len;
3292    if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
3293      *vec = mime_vec;
3294      return;
3295    }
3296  }
3297
3298  vec->ptr = mg_get_mime_type(path, "text/plain");
3299  vec->len = strlen(vec->ptr);
3300}
3301
3302static const char *suggest_connection_header(const struct mg_connection *conn) {
3303  return should_keep_alive(conn) ? "keep-alive" : "close";
3304}
3305
3306static void construct_etag(char *buf, size_t buf_len, const file_stat_t *st) {
3307  mg_snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"",
3308              (unsigned long) st->st_mtime, (int64_t) st->st_size);
3309}
3310
3311// Return True if we should reply 304 Not Modified.
3312static int is_not_modified(const struct connection *conn,
3313                           const file_stat_t *stp) {
3314  char etag[64];
3315  const char *ims = mg_get_header(&conn->mg_conn, "If-Modified-Since");
3316  const char *inm = mg_get_header(&conn->mg_conn, "If-None-Match");
3317  construct_etag(etag, sizeof(etag), stp);
3318  return (inm != NULL && !mg_strcasecmp(etag, inm)) ||
3319    (ims != NULL && stp->st_mtime <= parse_date_string(ims));
3320}
3321
3322// For given directory path, substitute it to valid index file.
3323// Return 0 if index file has been found, -1 if not found.
3324// If the file is found, it's stats is returned in stp.
3325static int find_index_file(struct connection *conn, char *path,
3326                           size_t path_len, file_stat_t *stp) {
3327  const char *list = conn->server->config_options[INDEX_FILES];
3328  file_stat_t st;
3329  struct vec filename_vec;
3330  size_t n = strlen(path);
3331  int found = 0;
3332
3333  // The 'path' given to us points to the directory. Remove all trailing
3334  // directory separator characters from the end of the path, and
3335  // then append single directory separator character.
3336  while (n > 0 && path[n - 1] == '/') {
3337    n--;
3338  }
3339  path[n] = '/';
3340
3341  // Traverse index files list. For each entry, append it to the given
3342  // path and see if the file exists. If it exists, break the loop
3343  while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
3344
3345    if (path_len <= n + 2) {
3346      continue;
3347    }
3348
3349    // Ignore too long entries that may overflow path buffer
3350    if (filename_vec.len > (path_len - (n + 2)))
3351      continue;
3352
3353    // Prepare full path to the index file
3354    strncpy(path + n + 1, filename_vec.ptr, filename_vec.len);
3355    path[n + 1 + filename_vec.len] = '\0';
3356
3357    //DBG(("[%s]", path));
3358
3359    // Does it exist?
3360    if (!stat(path, &st)) {
3361      // Yes it does, break the loop
3362      *stp = st;
3363      found = 1;
3364      break;
3365    }
3366  }
3367
3368  // If no index file exists, restore directory path
3369  if (!found) {
3370    path[n] = '/';
3371    path[n + 1] = '\0';
3372  }
3373
3374  return found;
3375}
3376
3377static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
3378//  return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
3379//  return sscanf(header, "bytes=%ld-%ld" INT64_FMT, a, b);
3380   return 0;
3381}
3382
3383static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
3384  strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
3385}
3386
3387static void open_file_endpoint(struct connection *conn, const char *path,
3388                               file_stat_t *st, const char *extra_headers) {
3389  char date[64], lm[64], etag[64], range[64], headers[1000];
3390  const char *msg = "OK", *hdr;
3391  time_t t, curtime = time(NULL);
3392  int64_t r1, r2;
3393  struct vec mime_vec;
3394  int n;
3395
3396  conn->endpoint_type = EP_FILE;
3397  ns_set_close_on_exec(conn->endpoint.fd);
3398  conn->mg_conn.status_code = 200;
3399
3400  get_mime_type(conn->server, path, &mime_vec);
3401  conn->cl = st->st_size;
3402  range[0] = '\0';
3403
3404  // If Range: header specified, act accordingly
3405  r1 = r2 = 0;
3406  hdr = mg_get_header(&conn->mg_conn, "Range");
3407  if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
3408      r1 >= 0 && r2 >= 0) {
3409    conn->mg_conn.status_code = 206;
3410    conn->cl = n == 2 ? (r2 > conn->cl ? conn->cl : r2) - r1 + 1: conn->cl - r1;
3411    mg_snprintf(range, sizeof(range), "Content-Range: bytes "
3412                "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n",
3413                r1, r1 + conn->cl - 1, (int64_t) st->st_size);
3414    msg = "Partial Content";
3415    lseek(conn->endpoint.fd, r1, SEEK_SET);
3416  }
3417
3418  // Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
3419  // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
3420  gmt_time_string(date, sizeof(date), &curtime);
3421  t = st->st_mtime; // store in local variable for NDK compile
3422  gmt_time_string(lm, sizeof(lm), &t);
3423  construct_etag(etag, sizeof(etag), st);
3424
3425  n = mg_snprintf(headers, sizeof(headers),
3426                  "HTTP/1.1 %d %s\r\n"
3427                  "Date: %s\r\n"
3428                  "Last-Modified: %s\r\n"
3429                  "Etag: %s\r\n"
3430                  "Content-Type: %.*s\r\n"
3431                  "Content-Length: %" INT64_FMT "\r\n"
3432                  "Connection: %s\r\n"
3433                  "Accept-Ranges: bytes\r\n"
3434                  "%s%s%s\r\n",
3435                  conn->mg_conn.status_code, msg, date, lm, etag,
3436                  (int) mime_vec.len, mime_vec.ptr, conn->cl,
3437                  suggest_connection_header(&conn->mg_conn),
3438                  range, extra_headers == NULL ? "" : extra_headers,
3439                  MONGOOSE_USE_EXTRA_HTTP_HEADERS);
3440  ns_send(conn->ns_conn, headers, n);
3441
3442  if (!strcmp(conn->mg_conn.request_method, "HEAD")) {
3443    conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
3444    close(conn->endpoint.fd);
3445    conn->endpoint_type = EP_NONE;
3446  }
3447}
3448
3449void mg_send_file_data(struct mg_connection *c, int fd) {
3450  struct connection *conn = MG_CONN_2_CONN(c);
3451  conn->endpoint_type = EP_FILE;
3452  conn->endpoint.fd = fd;
3453  ns_set_close_on_exec(conn->endpoint.fd);
3454}
3455#endif  // MONGOOSE_NO_FILESYSTEM
3456
3457static void call_request_handler_if_data_is_buffered(struct connection *conn) {
3458#ifndef MONGOOSE_NO_WEBSOCKET
3459  if (conn->mg_conn.is_websocket) {
3460    do { } while (deliver_websocket_frame(conn));
3461  } else
3462#endif
3463  if (conn->num_bytes_recv >= (conn->cl + conn->request_len) &&
3464      call_request_handler(conn) == MG_FALSE) {
3465    open_local_endpoint(conn, 1);
3466  }
3467}
3468
3469#if !defined(MONGOOSE_NO_DIRECTORY_LISTING) || !defined(MONGOOSE_NO_DAV)
3470
3471#ifdef _WIN32
3472struct dirent {
3473  char d_name[MAX_PATH_SIZE];
3474};
3475
3476typedef struct DIR {
3477  HANDLE   handle;
3478  WIN32_FIND_DATAW info;
3479  struct dirent result;
3480} DIR;
3481
3482// Implementation of POSIX opendir/closedir/readdir for Windows.
3483static DIR *opendir(const char *name) {
3484  DIR *dir = NULL;
3485  wchar_t wpath[MAX_PATH_SIZE];
3486  DWORD attrs;
3487
3488  if (name == NULL) {
3489    SetLastError(ERROR_BAD_ARGUMENTS);
3490  } else if ((dir = (DIR *) NS_MALLOC(sizeof(*dir))) == NULL) {
3491    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3492  } else {
3493    to_wchar(name, wpath, ARRAY_SIZE(wpath));
3494    attrs = GetFileAttributesW(wpath);
3495    if (attrs != 0xFFFFFFFF &&
3496        ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
3497      (void) wcscat(wpath, L"\\*");
3498      dir->handle = FindFirstFileW(wpath, &dir->info);
3499      dir->result.d_name[0] = '\0';
3500    } else {
3501      NS_FREE(dir);
3502      dir = NULL;
3503    }
3504  }
3505
3506  return dir;
3507}
3508
3509static int closedir(DIR *dir) {
3510  int result = 0;
3511
3512  if (dir != NULL) {
3513    if (dir->handle != INVALID_HANDLE_VALUE)
3514      result = FindClose(dir->handle) ? 0 : -1;
3515
3516    NS_FREE(dir);
3517  } else {
3518    result = -1;
3519    SetLastError(ERROR_BAD_ARGUMENTS);
3520  }
3521
3522  return result;
3523}
3524
3525static struct dirent *readdir(DIR *dir) {
3526  struct dirent *result = 0;
3527
3528  if (dir) {
3529    if (dir->handle != INVALID_HANDLE_VALUE) {
3530      result = &dir->result;
3531      (void) WideCharToMultiByte(CP_UTF8, 0,
3532          dir->info.cFileName, -1, result->d_name,
3533          sizeof(result->d_name), NULL, NULL);
3534
3535      if (!FindNextFileW(dir->handle, &dir->info)) {
3536        (void) FindClose(dir->handle);
3537        dir->handle = INVALID_HANDLE_VALUE;
3538      }
3539
3540    } else {
3541      SetLastError(ERROR_FILE_NOT_FOUND);
3542    }
3543  } else {
3544    SetLastError(ERROR_BAD_ARGUMENTS);
3545  }
3546
3547  return result;
3548}
3549#endif // _WIN32  POSIX opendir/closedir/readdir implementation
3550
3551static int scan_directory(struct connection *conn, const char *dir,
3552                          struct dir_entry **arr) {
3553  char path[MAX_PATH_SIZE];
3554  struct dir_entry *p;
3555  struct dirent *dp;
3556  int arr_size = 0, arr_ind = 0, inc = 100;
3557  DIR *dirp;
3558
3559  *arr = NULL;
3560  if ((dirp = (opendir(dir))) == NULL) return 0;
3561
3562  while ((dp = readdir(dirp)) != NULL) {
3563    // Do not show current dir and hidden files
3564    if (!strcmp(dp->d_name, ".") ||
3565        !strcmp(dp->d_name, "..") ||
3566        must_hide_file(conn, dp->d_name)) {
3567      continue;
3568    }
3569    mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
3570
3571    // Resize the array if necessary
3572    if (arr_ind >= arr_size) {
3573      if ((p = (struct dir_entry *)
3574           NS_REALLOC(*arr, (inc + arr_size) * sizeof(**arr))) != NULL) {
3575        // Memset new chunk to zero, otherwise st_mtime will have garbage which
3576        // can make strftime() segfault, see
3577        // http://code.google.com/p/mongoose/issues/detail?id=79
3578        memset(p + arr_size, 0, sizeof(**arr) * inc);
3579
3580        *arr = p;
3581        arr_size += inc;
3582      }
3583    }
3584
3585    if (arr_ind < arr_size) {
3586      (*arr)[arr_ind].conn = conn;
3587      (*arr)[arr_ind].file_name = strdup(dp->d_name);
3588      stat(path, &(*arr)[arr_ind].st);
3589      arr_ind++;
3590    }
3591  }
3592  closedir(dirp);
3593
3594  return arr_ind;
3595}
3596
3597size_t mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len) {
3598  static const char *dont_escape = "._-$,;~()";
3599  static const char *hex = "0123456789abcdef";
3600  size_t i = 0, j = 0;
3601
3602  for (i = j = 0; dst_len > 0 && i < s_len && j + 2 < dst_len - 1; i++, j++) {
3603    if (isalnum(* (const unsigned char *) (src + i)) ||
3604        strchr(dont_escape, * (const unsigned char *) (src + i)) != NULL) {
3605      dst[j] = src[i];
3606    } else if (j + 3 < dst_len) {
3607      dst[j] = '%';
3608      dst[j + 1] = hex[(* (const unsigned char *) (src + i)) >> 4];
3609      dst[j + 2] = hex[(* (const unsigned char *) (src + i)) & 0xf];
3610      j += 2;
3611    }
3612  }
3613
3614  dst[j] = '\0';
3615  return j;
3616}
3617#endif  // !NO_DIRECTORY_LISTING || !MONGOOSE_NO_DAV
3618
3619#ifndef MONGOOSE_NO_DIRECTORY_LISTING
3620
3621static void print_dir_entry(const struct dir_entry *de) {
3622  char size[64], mod[64], href[MAX_PATH_SIZE * 3];
3623  int64_t fsize = de->st.st_size;
3624  int is_dir = S_ISDIR(de->st.st_mode);
3625  const char *slash = is_dir ? "/" : "";
3626  time_t t;
3627
3628  if (is_dir) {
3629    mg_snprintf(size, sizeof(size), "%s", "[DIRECTORY]");
3630  } else {
3631     // We use (signed) cast below because MSVC 6 compiler cannot
3632     // convert unsigned __int64 to double.
3633    if (fsize < 1024) {
3634      mg_snprintf(size, sizeof(size), "%d", (int) fsize);
3635    } else if (fsize < 0x100000) {
3636      mg_snprintf(size, sizeof(size), "%.1fk", (double) fsize / 1024.0);
3637    } else if (fsize < 0x40000000) {
3638      mg_snprintf(size, sizeof(size), "%.1fM", (double) fsize / 1048576);
3639    } else {
3640      mg_snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824);
3641    }
3642  }
3643  t = de->st.st_mtime;  // store in local variable for NDK compile
3644  strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&t));
3645  mg_url_encode(de->file_name, strlen(de->file_name), href, sizeof(href));
3646  mg_printf_data(&de->conn->mg_conn,
3647                  "<tr><td><a href=\"%s%s\">%s%s</a></td>"
3648                  "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
3649                  href, slash, de->file_name, slash, mod, size);
3650}
3651
3652// Sort directory entries by size, or name, or modification time.
3653// On windows, __cdecl specification is needed in case if project is built
3654// with __stdcall convention. qsort always requires __cdels callback.
3655static int __cdecl compare_dir_entries(const void *p1, const void *p2) {
3656  const struct dir_entry *a = (const struct dir_entry *) p1,
3657        *b = (const struct dir_entry *) p2;
3658  const char *qs = a->conn->mg_conn.query_string ?
3659    a->conn->mg_conn.query_string : "na";
3660  int cmp_result = 0;
3661
3662  if (S_ISDIR(a->st.st_mode) && !S_ISDIR(b->st.st_mode)) {
3663    return -1;  // Always put directories on top
3664  } else if (!S_ISDIR(a->st.st_mode) && S_ISDIR(b->st.st_mode)) {
3665    return 1;   // Always put directories on top
3666  } else if (*qs == 'n') {
3667    cmp_result = strcmp(a->file_name, b->file_name);
3668  } else if (*qs == 's') {
3669    cmp_result = a->st.st_size == b->st.st_size ? 0 :
3670      a->st.st_size > b->st.st_size ? 1 : -1;
3671  } else if (*qs == 'd') {
3672    cmp_result = a->st.st_mtime == b->st.st_mtime ? 0 :
3673      a->st.st_mtime > b->st.st_mtime ? 1 : -1;
3674  }
3675
3676  return qs[1] == 'd' ? -cmp_result : cmp_result;
3677}
3678
3679static void send_directory_listing(struct connection *conn, const char *dir) {
3680  struct dir_entry *arr = NULL;
3681  int i, num_entries, sort_direction = conn->mg_conn.query_string != NULL &&
3682    conn->mg_conn.query_string[1] == 'd' ? 'a' : 'd';
3683
3684  mg_send_header(&conn->mg_conn, "Transfer-Encoding", "chunked");
3685  mg_send_header(&conn->mg_conn, "Content-Type", "text/html; charset=utf-8");
3686
3687  mg_printf_data(&conn->mg_conn,
3688              "<html><head><title>Index of %s</title>"
3689              "<style>th {text-align: left;}</style></head>"
3690              "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
3691              "<tr><th><a href=\"?n%c\">Name</a></th>"
3692              "<th><a href=\"?d%c\">Modified</a></th>"
3693              "<th><a href=\"?s%c\">Size</a></th></tr>"
3694              "<tr><td colspan=\"3\"><hr></td></tr>",
3695              conn->mg_conn.uri, conn->mg_conn.uri,
3696              sort_direction, sort_direction, sort_direction);
3697
3698  num_entries = scan_directory(conn, dir, &arr);
3699  if (arr) {
3700      qsort(arr, num_entries, sizeof(arr[0]), compare_dir_entries);
3701      for (i = 0; i < num_entries; i++) {
3702        print_dir_entry(&arr[i]);
3703        NS_FREE(arr[i].file_name);
3704      }
3705      NS_FREE(arr);
3706  }
3707
3708  write_terminating_chunk(conn);
3709  close_local_endpoint(conn);
3710}
3711#endif  // MONGOOSE_NO_DIRECTORY_LISTING
3712
3713#ifndef MONGOOSE_NO_DAV
3714static void print_props(struct connection *conn, const char *uri,
3715                        file_stat_t *stp) {
3716  char mtime[64];
3717  time_t t = stp->st_mtime;  // store in local variable for NDK compile
3718  gmt_time_string(mtime, sizeof(mtime), &t);
3719  mg_printf(&conn->mg_conn,
3720      "<d:response>"
3721       "<d:href>%s</d:href>"
3722       "<d:propstat>"
3723        "<d:prop>"
3724         "<d:resourcetype>%s</d:resourcetype>"
3725         "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
3726         "<d:getlastmodified>%s</d:getlastmodified>"
3727        "</d:prop>"
3728        "<d:status>HTTP/1.1 200 OK</d:status>"
3729       "</d:propstat>"
3730      "</d:response>\n",
3731      uri, S_ISDIR(stp->st_mode) ? "<d:collection/>" : "",
3732      (int64_t) stp->st_size, mtime);
3733}
3734
3735static void handle_propfind(struct connection *conn, const char *path,
3736                            file_stat_t *stp, int exists) {
3737  static const char header[] = "HTTP/1.1 207 Multi-Status\r\n"
3738    "Connection: close\r\n"
3739    "Content-Type: text/xml; charset=utf-8\r\n\r\n"
3740    "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
3741    "<d:multistatus xmlns:d='DAV:'>\n";
3742  static const char footer[] = "</d:multistatus>";
3743  const char *depth = mg_get_header(&conn->mg_conn, "Depth");
3744#ifdef MONGOOSE_NO_DIRECTORY_LISTING
3745  const char *list_dir = "no";
3746#else
3747  const char *list_dir = conn->server->config_options[ENABLE_DIRECTORY_LISTING];
3748#endif
3749
3750  conn->mg_conn.status_code = 207;
3751
3752  // Print properties for the requested resource itself
3753  if (!exists) {
3754    conn->mg_conn.status_code = 404;
3755    mg_printf(&conn->mg_conn, "%s", "HTTP/1.1 404 Not Found\r\n\r\n");
3756  } else if (S_ISDIR(stp->st_mode) && mg_strcasecmp(list_dir, "yes") != 0) {
3757    conn->mg_conn.status_code = 403;
3758    mg_printf(&conn->mg_conn, "%s",
3759              "HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
3760  } else {
3761    ns_send(conn->ns_conn, header, sizeof(header) - 1);
3762    print_props(conn, conn->mg_conn.uri, stp);
3763
3764    if (S_ISDIR(stp->st_mode) &&
3765             (depth == NULL || strcmp(depth, "0") != 0)) {
3766      struct dir_entry *arr = NULL;
3767      int i, num_entries = scan_directory(conn, path, &arr);
3768
3769      for (i = 0; i < num_entries; i++) {
3770        char buf[MAX_PATH_SIZE * 3];
3771        struct dir_entry *de = &arr[i];
3772        mg_url_encode(de->file_name, strlen(de->file_name), buf, sizeof(buf));
3773        print_props(conn, buf, &de->st);
3774        NS_FREE(de->file_name);
3775      }
3776      NS_FREE(arr);
3777    }
3778    ns_send(conn->ns_conn, footer, sizeof(footer) - 1);
3779  }
3780
3781  close_local_endpoint(conn);
3782}
3783
3784static void handle_mkcol(struct connection *conn, const char *path) {
3785  int status_code = 500;
3786
3787  if (conn->mg_conn.content_len > 0) {
3788    status_code = 415;
3789  } else if (!mkdir(path, 0755)) {
3790    status_code = 201;
3791  } else if (errno == EEXIST) {
3792    status_code = 405;
3793  } else if (errno == EACCES) {
3794    status_code = 403;
3795  } else if (errno == ENOENT) {
3796    status_code = 409;
3797  }
3798  send_http_error(conn, status_code, NULL);
3799}
3800
3801static int remove_directory(const char *dir) {
3802  char path[MAX_PATH_SIZE];
3803  struct dirent *dp;
3804  file_stat_t st;
3805  DIR *dirp;
3806
3807  if ((dirp = opendir(dir)) == NULL) return 0;
3808
3809  while ((dp = readdir(dirp)) != NULL) {
3810    if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
3811    mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
3812    stat(path, &st);
3813    if (S_ISDIR(st.st_mode)) {
3814      remove_directory(path);
3815    } else {
3816      remove(path);
3817    }
3818  }
3819  closedir(dirp);
3820  rmdir(dir);
3821
3822  return 1;
3823}
3824
3825static void handle_delete(struct connection *conn, const char *path) {
3826  file_stat_t st;
3827
3828  if (stat(path, &st) != 0) {
3829    send_http_error(conn, 404, NULL);
3830  } else if (S_ISDIR(st.st_mode)) {
3831    remove_directory(path);
3832    send_http_error(conn, 204, NULL);
3833  } else if (remove(path) == 0) {
3834    send_http_error(conn, 204, NULL);
3835  } else {
3836    send_http_error(conn, 423, NULL);
3837  }
3838}
3839
3840// For a given PUT path, create all intermediate subdirectories
3841// for given path. Return 0 if the path itself is a directory,
3842// or -1 on error, 1 if OK.
3843static int put_dir(const char *path) {
3844  char buf[MAX_PATH_SIZE];
3845  const char *s, *p;
3846  file_stat_t st;
3847
3848  // Create intermediate directories if they do not exist
3849  for (s = p = path + 1; (p = strchr(s, '/')) != NULL; s = ++p) {
3850    if (p - path >= (int) sizeof(buf)) return -1; // Buffer overflow
3851    memcpy(buf, path, p - path);
3852    buf[p - path] = '\0';
3853    if (stat(buf, &st) != 0 && mkdir(buf, 0755) != 0) return -1;
3854    if (p[1] == '\0') return 0;  // Path is a directory itself
3855  }
3856
3857  return 1;
3858}
3859
3860static void handle_put(struct connection *conn, const char *path) {
3861  file_stat_t st;
3862  const char *range, *cl_hdr = mg_get_header(&conn->mg_conn, "Content-Length");
3863  int64_t r1, r2;
3864  int rc;
3865
3866  conn->mg_conn.status_code = !stat(path, &st) ? 200 : 201;
3867  if ((rc = put_dir(path)) == 0) {
3868    mg_printf(&conn->mg_conn, "HTTP/1.1 %d OK\r\n\r\n",
3869              conn->mg_conn.status_code);
3870    close_local_endpoint(conn);
3871  } else if (rc == -1) {
3872    send_http_error(conn, 500, "put_dir: %s", strerror(errno));
3873  } else if (cl_hdr == NULL) {
3874    send_http_error(conn, 411, NULL);
3875  } else if ((conn->endpoint.fd =
3876              open(path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644)) < 0) {
3877    send_http_error(conn, 500, "open(%s): %s", path, strerror(errno));
3878  } else {
3879    DBG(("PUT [%s] %lu", path, (unsigned long) conn->ns_conn->recv_iobuf.len));
3880    conn->endpoint_type = EP_PUT;
3881    ns_set_close_on_exec(conn->endpoint.fd);
3882    range = mg_get_header(&conn->mg_conn, "Content-Range");
3883    conn->cl = to64(cl_hdr);
3884    r1 = r2 = 0;
3885    if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
3886      conn->mg_conn.status_code = 206;
3887      lseek(conn->endpoint.fd, r1, SEEK_SET);
3888      conn->cl = r2 > r1 ? r2 - r1 + 1: conn->cl - r1;
3889    }
3890    mg_printf(&conn->mg_conn, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n",
3891              conn->mg_conn.status_code);
3892  }
3893}
3894
3895static void forward_put_data(struct connection *conn) {
3896  struct iobuf *io = &conn->ns_conn->recv_iobuf;
3897  size_t k = conn->cl < (int64_t) io->len ? conn->cl : (int64_t) io->len;   // To write
3898  size_t n = write(conn->endpoint.fd, io->buf, k);   // Write them!
3899  if (n > 0) {
3900    iobuf_remove(io, n);
3901    conn->cl -= n;
3902  }
3903  if (conn->cl <= 0) {
3904    close_local_endpoint(conn);
3905  }
3906}
3907#endif //  MONGOOSE_NO_DAV
3908
3909static void send_options(struct connection *conn) {
3910  conn->mg_conn.status_code = 200;
3911  mg_printf(&conn->mg_conn, "%s",
3912            "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, PUT, "
3913            "DELETE, OPTIONS, PROPFIND, MKCOL\r\nDAV: 1\r\n\r\n");
3914  close_local_endpoint(conn);
3915}
3916
3917#ifndef MONGOOSE_NO_AUTH
3918void mg_send_digest_auth_request(struct mg_connection *c) {
3919  struct connection *conn = MG_CONN_2_CONN(c);
3920  c->status_code = 401;
3921  mg_printf(c,
3922            "HTTP/1.1 401 Unauthorized\r\n"
3923            "Content-Length: 0\r\n"
3924            "WWW-Authenticate: Digest qop=\"auth\", "
3925            "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
3926            conn->server->config_options[AUTH_DOMAIN],
3927            (unsigned long) time(NULL));
3928  if (conn->cl > 0) {
3929    conn->ns_conn->flags |= NSF_DISCARD;
3930  } else {
3931    close_local_endpoint(conn);
3932  }
3933}
3934
3935// Use the global passwords file, if specified by auth_gpass option,
3936// or search for .htpasswd in the requested directory.
3937static FILE *open_auth_file(struct connection *conn, const char *path,
3938                            int is_directory) {
3939  char name[MAX_PATH_SIZE];
3940  const char *p, *gpass = conn->server->config_options[GLOBAL_AUTH_FILE];
3941  FILE *fp = NULL;
3942
3943  if (gpass != NULL) {
3944    // Use global passwords file
3945    fp = fopen(gpass, "r");
3946  } else if (is_directory) {
3947    mg_snprintf(name, sizeof(name), "%s%c%s", path, '/', PASSWORDS_FILE_NAME);
3948    fp = fopen(name, "r");
3949  } else {
3950    // Try to find .htpasswd in requested directory.
3951    if ((p = strrchr(path, '/')) == NULL) p = path;
3952    mg_snprintf(name, sizeof(name), "%.*s%c%s",
3953                (int) (p - path), path, '/', PASSWORDS_FILE_NAME);
3954    fp = fopen(name, "r");
3955  }
3956
3957  return fp;
3958}
3959
3960#if !defined(HAVE_MD5) && !defined(MONGOOSE_NO_AUTH)
3961/*
3962 * This code implements the MD5 message-digest algorithm.
3963 * The algorithm is due to Ron Rivest.   This code was
3964 * written by Colin Plumb in 1993, no copyright is claimed.
3965 * This code is in the public domain; do with it what you wish.
3966 *
3967 * Equivalent code is available from RSA Data Security, Inc.
3968 * This code has been tested against that, and is equivalent,
3969 * except that you don't need to include two pages of legalese
3970 * with every copy.
3971 *
3972 * To compute the message digest of a chunk of bytes, declare an
3973 * MD5Context structure, pass it to MD5Init, call MD5Update as
3974 * needed on buffers full of bytes, and then call MD5Final, which
3975 * will fill a supplied 16-byte array with the digest.
3976 */
3977
3978typedef struct MD5Context {
3979  uint32_t buf[4];
3980  uint32_t bits[2];
3981  unsigned char in[64];
3982} MD5_CTX;
3983
3984static void byteReverse(unsigned char *buf, unsigned longs) {
3985  uint32_t t;
3986
3987  // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN
3988  if (is_big_endian()) {
3989    do {
3990      t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
3991        ((unsigned) buf[1] << 8 | buf[0]);
3992      * (uint32_t *) buf = t;
3993      buf += 4;
3994    } while (--longs);
3995  }
3996}
3997
3998#define F1(x, y, z) (z ^ (x & (y ^ z)))
3999#define F2(x, y, z) F1(z, x, y)
4000#define F3(x, y, z) (x ^ y ^ z)
4001#define F4(x, y, z) (y ^ (x | ~z))
4002
4003#define MD5STEP(f, w, x, y, z, data, s) \
4004  ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
4005
4006// Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
4007// initialization constants.
4008static void MD5Init(MD5_CTX *ctx) {
4009  ctx->buf[0] = 0x67452301;
4010  ctx->buf[1] = 0xefcdab89;
4011  ctx->buf[2] = 0x98badcfe;
4012  ctx->buf[3] = 0x10325476;
4013
4014  ctx->bits[0] = 0;
4015  ctx->bits[1] = 0;
4016}
4017
4018static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
4019  register uint32_t a, b, c, d;
4020
4021  a = buf[0];
4022  b = buf[1];
4023  c = buf[2];
4024  d = buf[3];
4025
4026  MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
4027  MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
4028  MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
4029  MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
4030  MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
4031  MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
4032  MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
4033  MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
4034  MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
4035  MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
4036  MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
4037  MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
4038  MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
4039  MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
4040  MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
4041  MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
4042
4043  MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
4044  MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
4045  MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
4046  MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
4047  MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
4048  MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
4049  MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
4050  MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
4051  MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
4052  MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
4053  MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
4054  MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
4055  MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
4056  MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
4057  MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
4058  MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
4059
4060  MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
4061  MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
4062  MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
4063  MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
4064  MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
4065  MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
4066  MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
4067  MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
4068  MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
4069  MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
4070  MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
4071  MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
4072  MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
4073  MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
4074  MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
4075  MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
4076
4077  MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
4078  MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
4079  MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
4080  MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
4081  MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
4082  MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
4083  MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
4084  MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
4085  MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
4086  MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
4087  MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
4088  MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
4089  MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
4090  MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
4091  MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
4092  MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
4093
4094  buf[0] += a;
4095  buf[1] += b;
4096  buf[2] += c;
4097  buf[3] += d;
4098}
4099
4100static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
4101  uint32_t t;
4102
4103  t = ctx->bits[0];
4104  if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
4105    ctx->bits[1]++;
4106  ctx->bits[1] += len >> 29;
4107
4108  t = (t >> 3) & 0x3f;
4109
4110  if (t) {
4111    unsigned char *p = (unsigned char *) ctx->in + t;
4112
4113    t = 64 - t;
4114    if (len < t) {
4115      memcpy(p, buf, len);
4116      return;
4117    }
4118    memcpy(p, buf, t);
4119    byteReverse(ctx->in, 16);
4120    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
4121    buf += t;
4122    len -= t;
4123  }
4124
4125  while (len >= 64) {
4126    memcpy(ctx->in, buf, 64);
4127    byteReverse(ctx->in, 16);
4128    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
4129    buf += 64;
4130    len -= 64;
4131  }
4132
4133  memcpy(ctx->in, buf, len);
4134}
4135
4136static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
4137  unsigned count;
4138  unsigned char *p;
4139  uint32_t *a;
4140
4141  count = (ctx->bits[0] >> 3) & 0x3F;
4142
4143  p = ctx->in + count;
4144  *p++ = 0x80;
4145  count = 64 - 1 - count;
4146  if (count < 8) {
4147    memset(p, 0, count);
4148    byteReverse(ctx->in, 16);
4149    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
4150    memset(ctx->in, 0, 56);
4151  } else {
4152    memset(p, 0, count - 8);
4153  }
4154  byteReverse(ctx->in, 14);
4155
4156  a = (uint32_t *)ctx->in;
4157  a[14] = ctx->bits[0];
4158  a[15] = ctx->bits[1];
4159
4160  MD5Transform(ctx->buf, (uint32_t *) ctx->in);
4161  byteReverse((unsigned char *) ctx->buf, 4);
4162  memcpy(digest, ctx->buf, 16);
4163  memset((char *) ctx, 0, sizeof(*ctx));
4164}
4165#endif // !HAVE_MD5
4166
4167
4168
4169// Stringify binary data. Output buffer must be twice as big as input,
4170// because each byte takes 2 bytes in string representation
4171static void bin2str(char *to, const unsigned char *p, size_t len) {
4172  static const char *hex = "0123456789abcdef";
4173
4174  for (; len--; p++) {
4175    *to++ = hex[p[0] >> 4];
4176    *to++ = hex[p[0] & 0x0f];
4177  }
4178  *to = '\0';
4179}
4180
4181// Return stringified MD5 hash for list of strings. Buffer must be 33 bytes.
4182char *mg_md5(char buf[33], ...) {
4183  unsigned char hash[16];
4184  const char *p;
4185  va_list ap;
4186  MD5_CTX ctx;
4187
4188  MD5Init(&ctx);
4189
4190  va_start(ap, buf);
4191  while ((p = va_arg(ap, const char *)) != NULL) {
4192    MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p));
4193  }
4194  va_end(ap);
4195
4196  MD5Final(hash, &ctx);
4197  bin2str(buf, hash, sizeof(hash));
4198  return buf;
4199}
4200
4201// Check the user's password, return 1 if OK
4202static int check_password(const char *method, const char *ha1, const char *uri,
4203                          const char *nonce, const char *nc, const char *cnonce,
4204                          const char *qop, const char *response) {
4205  char ha2[32 + 1], expected_response[32 + 1];
4206
4207#if 0
4208  // Check for authentication timeout
4209  if ((unsigned long) time(NULL) - (unsigned long) to64(nonce) > 3600 * 2) {
4210    return 0;
4211  }
4212#endif
4213
4214  mg_md5(ha2, method, ":", uri, NULL);
4215  mg_md5(expected_response, ha1, ":", nonce, ":", nc,
4216      ":", cnonce, ":", qop, ":", ha2, NULL);
4217
4218  return mg_strcasecmp(response, expected_response) == 0 ? MG_TRUE : MG_FALSE;
4219}
4220
4221
4222// Authorize against the opened passwords file. Return 1 if authorized.
4223int mg_authorize_digest(struct mg_connection *c, FILE *fp) {
4224  struct connection *conn = MG_CONN_2_CONN(c);
4225  const char *hdr;
4226  char line[256], f_user[256], ha1[256], f_domain[256], user[100], nonce[100],
4227       uri[MAX_REQUEST_SIZE], cnonce[100], resp[100], qop[100], nc[100];
4228
4229  if (c == NULL || fp == NULL) return 0;
4230  if ((hdr = mg_get_header(c, "Authorization")) == NULL ||
4231      mg_strncasecmp(hdr, "Digest ", 7) != 0) return 0;
4232  if (!mg_parse_header(hdr, "username", user, sizeof(user))) return 0;
4233  if (!mg_parse_header(hdr, "cnonce", cnonce, sizeof(cnonce))) return 0;
4234  if (!mg_parse_header(hdr, "response", resp, sizeof(resp))) return 0;
4235  if (!mg_parse_header(hdr, "uri", uri, sizeof(uri))) return 0;
4236  if (!mg_parse_header(hdr, "qop", qop, sizeof(qop))) return 0;
4237  if (!mg_parse_header(hdr, "nc", nc, sizeof(nc))) return 0;
4238  if (!mg_parse_header(hdr, "nonce", nonce, sizeof(nonce))) return 0;
4239
4240  while (fgets(line, sizeof(line), fp) != NULL) {
4241    if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) == 3 &&
4242        !strcmp(user, f_user) &&
4243        // NOTE(lsm): due to a bug in MSIE, we do not compare URIs
4244        !strcmp(conn->server->config_options[AUTH_DOMAIN], f_domain))
4245      return check_password(c->request_method, ha1, uri,
4246                            nonce, nc, cnonce, qop, resp);
4247  }
4248  return MG_FALSE;
4249}
4250
4251
4252// Return 1 if request is authorised, 0 otherwise.
4253static int is_authorized(struct connection *conn, const char *path,
4254                         int is_directory) {
4255  FILE *fp;
4256  int authorized = MG_TRUE;
4257
4258  if ((fp = open_auth_file(conn, path, is_directory)) != NULL) {
4259    authorized = mg_authorize_digest(&conn->mg_conn, fp);
4260    fclose(fp);
4261  }
4262
4263  return authorized;
4264}
4265
4266static int is_authorized_for_dav(struct connection *conn) {
4267  const char *auth_file = conn->server->config_options[DAV_AUTH_FILE];
4268  const char *method = conn->mg_conn.request_method;
4269  FILE *fp;
4270  int authorized = MG_FALSE;
4271
4272  // If dav_auth_file is not set, allow non-authorized PROPFIND
4273  if (method != NULL && !strcmp(method, "PROPFIND") && auth_file == NULL) {
4274    authorized = MG_TRUE;
4275  } else if (auth_file != NULL && (fp = fopen(auth_file, "r")) != NULL) {
4276    authorized = mg_authorize_digest(&conn->mg_conn, fp);
4277    fclose(fp);
4278  }
4279
4280  return authorized;
4281}
4282#endif // MONGOOSE_NO_AUTH
4283
4284static int parse_header(const char *str, size_t str_len, const char *var_name,
4285                        char *buf, size_t buf_size) {
4286  int ch = ' ', ch1 = ',', len = 0;
4287  size_t n = strlen(var_name);
4288  const char *p, *end = str + str_len, *s = NULL;
4289
4290  if (buf != NULL && buf_size > 0) buf[0] = '\0';
4291
4292  // Find where variable starts
4293  for (s = str; s != NULL && s + n < end; s++) {
4294    if ((s == str || s[-1] == ch || s[-1] == ch1) && s[n] == '=' &&
4295        !memcmp(s, var_name, n)) break;
4296  }
4297
4298  if (s != NULL && &s[n + 1] < end) {
4299    s += n + 1;
4300    if (*s == '"' || *s == '\'') ch = ch1 = *s++;
4301    p = s;
4302    while (p < end && p[0] != ch && p[0] != ch1 && len < (int) buf_size) {
4303      if (ch == ch1 && p[0] == '\\' && p[1] == ch) p++;
4304      buf[len++] = *p++;
4305    }
4306    if (len >= (int) buf_size || (ch != ' ' && *p != ch)) {
4307      len = 0;
4308    } else {
4309      if (len > 0 && s[len - 1] == ',') len--;
4310      if (len > 0 && s[len - 1] == ';') len--;
4311      buf[len] = '\0';
4312    }
4313  }
4314
4315  return len;
4316}
4317
4318int mg_parse_header(const char *s, const char *var_name, char *buf,
4319                    size_t buf_size) {
4320  return parse_header(s, s == NULL ? 0 : strlen(s), var_name, buf, buf_size);
4321}
4322
4323#ifndef MONGOOSE_NO_SSI
4324static void send_ssi_file(struct mg_connection *, const char *, FILE *, int);
4325
4326static void send_file_data(struct mg_connection *conn, FILE *fp) {
4327  char buf[IOBUF_SIZE];
4328  size_t n;
4329  while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
4330    mg_write(conn, buf, n);
4331  }
4332}
4333
4334static void do_ssi_include(struct mg_connection *conn, const char *ssi,
4335                           char *tag, int include_level) {
4336  char file_name[IOBUF_SIZE], path[MAX_PATH_SIZE], *p;
4337  char **opts = (MG_CONN_2_CONN(conn))->server->config_options;
4338  FILE *fp;
4339
4340  // sscanf() is safe here, since send_ssi_file() also uses buffer
4341  // of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
4342  if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
4343    // File name is relative to the webserver root
4344    mg_snprintf(path, sizeof(path), "%s%c%s",
4345                opts[DOCUMENT_ROOT], '/', file_name);
4346  } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
4347    // File name is relative to the webserver working directory
4348    // or it is absolute system path
4349    mg_snprintf(path, sizeof(path), "%s", file_name);
4350  } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
4351             sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
4352    // File name is relative to the current document
4353    mg_snprintf(path, sizeof(path), "%s", ssi);
4354    if ((p = strrchr(path, '/')) != NULL) {
4355      p[1] = '\0';
4356    }
4357    mg_snprintf(path + strlen(path), sizeof(path) - strlen(path), "%s",
4358                file_name);
4359  } else {
4360    mg_printf(conn, "Bad SSI #include: [%s]", tag);
4361    return;
4362  }
4363
4364  if ((fp = fopen(path, "rb")) == NULL) {
4365    mg_printf(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s",
4366              tag, path, strerror(errno));
4367  } else {
4368    ns_set_close_on_exec(fileno(fp));
4369    if (mg_match_prefix(opts[SSI_PATTERN], strlen(opts[SSI_PATTERN]),
4370        path) > 0) {
4371      send_ssi_file(conn, path, fp, include_level + 1);
4372    } else {
4373      send_file_data(conn, fp);
4374    }
4375    fclose(fp);
4376  }
4377}
4378
4379#ifndef MONGOOSE_NO_POPEN
4380static void do_ssi_exec(struct mg_connection *conn, char *tag) {
4381  char cmd[IOBUF_SIZE];
4382  FILE *fp;
4383
4384  if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
4385    mg_printf(conn, "Bad SSI #exec: [%s]", tag);
4386  } else if ((fp = popen(cmd, "r")) == NULL) {
4387    mg_printf(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(errno));
4388  } else {
4389    send_file_data(conn, fp);
4390    pclose(fp);
4391  }
4392}
4393#endif // !MONGOOSE_NO_POPEN
4394
4395static void send_ssi_file(struct mg_connection *conn, const char *path,
4396                          FILE *fp, int include_level) {
4397  char buf[IOBUF_SIZE];
4398  int ch, offset, len, in_ssi_tag;
4399
4400  if (include_level > 10) {
4401    mg_printf(conn, "SSI #include level is too deep (%s)", path);
4402    return;
4403  }
4404
4405  in_ssi_tag = len = offset = 0;
4406  while ((ch = fgetc(fp)) != EOF) {
4407    if (in_ssi_tag && ch == '>') {
4408      in_ssi_tag = 0;
4409      buf[len++] = (char) ch;
4410      buf[len] = '\0';
4411      assert(len <= (int) sizeof(buf));
4412      if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
4413        // Not an SSI tag, pass it
4414        (void) mg_write(conn, buf, (size_t) len);
4415      } else {
4416        if (!memcmp(buf + 5, "include", 7)) {
4417          do_ssi_include(conn, path, buf + 12, include_level);
4418#if !defined(MONGOOSE_NO_POPEN)
4419        } else if (!memcmp(buf + 5, "exec", 4)) {
4420          do_ssi_exec(conn, buf + 9);
4421#endif // !NO_POPEN
4422        } else {
4423          mg_printf(conn, "%s: unknown SSI " "command: \"%s\"", path, buf);
4424        }
4425      }
4426      len = 0;
4427    } else if (in_ssi_tag) {
4428      if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
4429        // Not an SSI tag
4430        in_ssi_tag = 0;
4431      } else if (len == (int) sizeof(buf) - 2) {
4432        mg_printf(conn, "%s: SSI tag is too large", path);
4433        len = 0;
4434      }
4435      buf[len++] = ch & 0xff;
4436    } else if (ch == '<') {
4437      in_ssi_tag = 1;
4438      if (len > 0) {
4439        mg_write(conn, buf, (size_t) len);
4440      }
4441      len = 0;
4442      buf[len++] = ch & 0xff;
4443    } else {
4444      buf[len++] = ch & 0xff;
4445      if (len == (int) sizeof(buf)) {
4446        mg_write(conn, buf, (size_t) len);
4447        len = 0;
4448      }
4449    }
4450  }
4451
4452  // Send the rest of buffered data
4453  if (len > 0) {
4454    mg_write(conn, buf, (size_t) len);
4455  }
4456}
4457
4458static void handle_ssi_request(struct connection *conn, const char *path) {
4459  FILE *fp;
4460  struct vec mime_vec;
4461
4462  if ((fp = fopen(path, "rb")) == NULL) {
4463    send_http_error(conn, 500, "fopen(%s): %s", path, strerror(errno));
4464  } else {
4465    ns_set_close_on_exec(fileno(fp));
4466    get_mime_type(conn->server, path, &mime_vec);
4467    conn->mg_conn.status_code = 200;
4468    mg_printf(&conn->mg_conn,
4469              "HTTP/1.1 %d OK\r\n"
4470              "Content-Type: %.*s\r\n"
4471              "Connection: close\r\n\r\n",
4472              conn->mg_conn.status_code, (int) mime_vec.len, mime_vec.ptr);
4473    send_ssi_file(&conn->mg_conn, path, fp, 0);
4474    fclose(fp);
4475    close_local_endpoint(conn);
4476  }
4477}
4478#endif
4479
4480static void proxy_request(struct ns_connection *pc, struct mg_connection *c) {
4481  int i, sent_close_header = 0;
4482
4483  ns_printf(pc, "%s %s%s%s HTTP/%s\r\n", c->request_method, c->uri,
4484            c->query_string ? "?" : "",
4485            c->query_string ? c->query_string : "",
4486            c->http_version);
4487  for (i = 0; i < c->num_headers; i++) {
4488    if (mg_strcasecmp(c->http_headers[i].name, "Connection") == 0) {
4489      // Force connection close, cause we don't parse proxy replies
4490      // therefore we don't know message boundaries
4491      ns_printf(pc, "%s: %s\r\n", "Connection", "close");
4492      sent_close_header = 1;
4493    } else {
4494      ns_printf(pc, "%s: %s\r\n", c->http_headers[i].name,
4495                c->http_headers[i].value);
4496    }
4497  }
4498  if (!sent_close_header) {
4499    ns_printf(pc, "%s: %s\r\n", "Connection", "close");
4500  }
4501  ns_printf(pc, "%s", "\r\n");
4502  ns_send(pc, c->content, c->content_len);
4503
4504}
4505
4506#ifdef NS_ENABLE_SSL
4507int mg_terminate_ssl(struct mg_connection *c, const char *cert) {
4508  static const char ok[] = "HTTP/1.0 200 OK\r\n\r\n";
4509  struct connection *conn = MG_CONN_2_CONN(c);
4510  SSL_CTX *ctx;
4511
4512  DBG(("%p MITM", conn));
4513  if ((ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) return 0;
4514
4515  SSL_CTX_use_certificate_file(ctx, cert, 1);
4516  SSL_CTX_use_PrivateKey_file(ctx, cert, 1);
4517  SSL_CTX_use_certificate_chain_file(ctx, cert);
4518
4519  // When clear-text reply is pushed to client, switch to SSL mode.
4520  // TODO(lsm): check for send() failure
4521  send(conn->ns_conn->sock, ok, sizeof(ok) - 1, 0);
4522  //DBG(("%p %lu %d SEND", c, (unsigned long) sizeof(ok) - 1, n));
4523  conn->ns_conn->send_iobuf.len = 0;
4524  conn->endpoint_type = EP_USER;  // To keep-alive in close_local_endpoint()
4525  close_local_endpoint(conn);     // Clean up current CONNECT request
4526  if ((conn->ns_conn->ssl = SSL_new(ctx)) != NULL) {
4527    SSL_set_fd(conn->ns_conn->ssl, conn->ns_conn->sock);
4528  }
4529  SSL_CTX_free(ctx);
4530  return 1;
4531}
4532#endif
4533
4534int mg_forward(struct mg_connection *c, const char *addr) {
4535  static const char ok[] = "HTTP/1.1 200 OK\r\n\r\n";
4536  struct connection *conn = MG_CONN_2_CONN(c);
4537  struct ns_connection *pc;
4538
4539  if ((pc = ns_connect(&conn->server->ns_mgr, addr,
4540      mg_ev_handler, conn)) == NULL) {
4541    conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
4542    return 0;
4543  }
4544
4545  // Interlink two connections
4546  pc->flags |= MG_PROXY_CONN;
4547  conn->endpoint_type = EP_PROXY;
4548  conn->endpoint.nc = pc;
4549  DBG(("%p [%s] [%s] -> %p %p", conn, c->uri, addr, pc, conn->ns_conn->ssl));
4550
4551  if (strcmp(c->request_method, "CONNECT") == 0) {
4552    // For CONNECT request, reply with 200 OK. Tunnel is established.
4553    // TODO(lsm): check for send() failure
4554    (void) send(conn->ns_conn->sock, ok, sizeof(ok) - 1, 0);
4555  } else {
4556    // Strip "http://host:port" part from the URI
4557    if (memcmp(c->uri, "http://", 7) == 0) c->uri += 7;
4558    while (*c->uri != '\0' && *c->uri != '/') c->uri++;
4559    proxy_request(pc, c);
4560  }
4561  return 1;
4562}
4563
4564static void proxify_connection(struct connection *conn) {
4565  char proto[10], host[500], cert[500], addr[1000];
4566  unsigned short port = 80;
4567  struct mg_connection *c = &conn->mg_conn;
4568  int n = 0;
4569  const char *url = c->uri;
4570
4571  proto[0] = host[0] = cert[0] = '\0';
4572  if (sscanf(url, "%499[^: ]:%hu%n", host, &port, &n) != 2 &&
4573      sscanf(url, "%9[a-z]://%499[^: ]:%hu%n", proto, host, &port, &n) != 3 &&
4574      sscanf(url, "%9[a-z]://%499[^/ ]%n", proto, host, &n) != 2) {
4575    n = 0;
4576  }
4577
4578  snprintf(addr, sizeof(addr), "%s://%s:%hu",
4579           conn->ns_conn->ssl != NULL ? "ssl" : "tcp", host, port);
4580  if (n <= 0 || !mg_forward(c, addr)) {
4581    conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
4582  }
4583}
4584
4585#ifndef MONGOOSE_NO_FILESYSTEM
4586void mg_send_file_internal(struct mg_connection *c, const char *file_name,
4587                           file_stat_t *st, int exists,
4588                           const char *extra_headers) {
4589  struct connection *conn = MG_CONN_2_CONN(c);
4590  char path[MAX_PATH_SIZE];
4591  const int is_directory = S_ISDIR(st->st_mode);
4592#ifndef MONGOOSE_NO_CGI
4593  const char *cgi_pat = conn->server->config_options[CGI_PATTERN];
4594#else
4595  const char *cgi_pat = DEFAULT_CGI_PATTERN;
4596#endif
4597#ifndef MONGOOSE_NO_DIRECTORY_LISTING
4598  const char *dir_lst = conn->server->config_options[ENABLE_DIRECTORY_LISTING];
4599#else
4600  const char *dir_lst = "yes";
4601#endif
4602
4603  mg_snprintf(path, sizeof(path), "%s", file_name);
4604
4605  if (!exists || must_hide_file(conn, path)) {
4606    send_http_error(conn, 404, NULL);
4607  } else if (is_directory &&
4608             conn->mg_conn.uri[strlen(conn->mg_conn.uri) - 1] != '/') {
4609    conn->mg_conn.status_code = 301;
4610    mg_printf(&conn->mg_conn, "HTTP/1.1 301 Moved Permanently\r\n"
4611              "Location: %s/\r\n\r\n", conn->mg_conn.uri);
4612    close_local_endpoint(conn);
4613  } else if (is_directory && !find_index_file(conn, path, sizeof(path), st)) {
4614    if (!mg_strcasecmp(dir_lst, "yes")) {
4615#ifndef MONGOOSE_NO_DIRECTORY_LISTING
4616      send_directory_listing(conn, path);
4617#else
4618      send_http_error(conn, 501, NULL);
4619#endif
4620    } else {
4621      send_http_error(conn, 403, NULL);
4622    }
4623  } else if (mg_match_prefix(cgi_pat, strlen(cgi_pat), path) > 0) {
4624#if !defined(MONGOOSE_NO_CGI)
4625    open_cgi_endpoint(conn, path);
4626#else
4627    send_http_error(conn, 501, NULL);
4628#endif // !MONGOOSE_NO_CGI
4629#ifndef MONGOOSE_NO_SSI
4630  } else if (mg_match_prefix(conn->server->config_options[SSI_PATTERN],
4631                             strlen(conn->server->config_options[SSI_PATTERN]),
4632                             path) > 0) {
4633    handle_ssi_request(conn, path);
4634#endif
4635  } else if (is_not_modified(conn, st)) {
4636    send_http_error(conn, 304, NULL);
4637  } else if ((conn->endpoint.fd = open(path, O_RDONLY | O_BINARY, 0)) != -1) {
4638    // O_BINARY is required for Windows, otherwise in default text mode
4639    // two bytes \r\n will be read as one.
4640    open_file_endpoint(conn, path, st, extra_headers);
4641  } else {
4642    send_http_error(conn, 404, NULL);
4643  }
4644}
4645void mg_send_file(struct mg_connection *c, const char *file_name,
4646                  const char *extra_headers) {
4647  file_stat_t st;
4648  const int exists = stat(file_name, &st) == 0;
4649  mg_send_file_internal(c, file_name, &st, exists, extra_headers);
4650}
4651#endif  // !MONGOOSE_NO_FILESYSTEM
4652
4653static void open_local_endpoint(struct connection *conn, int skip_user) {
4654#ifndef MONGOOSE_NO_FILESYSTEM
4655  char path[MAX_PATH_SIZE];
4656  file_stat_t st;
4657  int exists = 0;
4658#endif
4659
4660  // If EP_USER was set in a prev call, reset it
4661  conn->endpoint_type = EP_NONE;
4662
4663#ifndef MONGOOSE_NO_AUTH
4664  if (conn->server->event_handler && call_user(conn, MG_AUTH) == MG_FALSE) {
4665    mg_send_digest_auth_request(&conn->mg_conn);
4666    return;
4667  }
4668#endif
4669
4670  // Call URI handler if one is registered for this URI
4671  if (skip_user == 0 && conn->server->event_handler != NULL) {
4672    conn->endpoint_type = EP_USER;
4673#if MONGOOSE_POST_SIZE_LIMIT > 1
4674    {
4675      const char *cl = mg_get_header(&conn->mg_conn, "Content-Length");
4676      if ((strcmp(conn->mg_conn.request_method, "POST") == 0 ||
4677           strcmp(conn->mg_conn.request_method, "PUT") == 0) &&
4678          (cl == NULL || to64(cl) > MONGOOSE_POST_SIZE_LIMIT)) {
4679        send_http_error(conn, 500, "POST size > %lu",
4680                        (unsigned long) MONGOOSE_POST_SIZE_LIMIT);
4681      }
4682    }
4683#endif
4684    return;
4685  }
4686
4687  if (strcmp(conn->mg_conn.request_method, "CONNECT") == 0 ||
4688      mg_strncasecmp(conn->mg_conn.uri, "http", 4) == 0) {
4689    const char *enp = conn->server->config_options[ENABLE_PROXY];
4690    if (enp == NULL || strcmp(enp, "yes") != 0) {
4691      send_http_error(conn, 405, NULL);
4692    } else {
4693      proxify_connection(conn);
4694    }
4695    return;
4696  }
4697
4698  if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) {
4699    send_options(conn);
4700    return;
4701  }
4702
4703#ifdef MONGOOSE_NO_FILESYSTEM
4704  send_http_error(conn, 404, NULL);
4705#else
4706  exists = convert_uri_to_file_name(conn, path, sizeof(path), &st);
4707
4708  if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) {
4709    send_options(conn);
4710  } else if (conn->server->config_options[DOCUMENT_ROOT] == NULL) {
4711    send_http_error(conn, 404, NULL);
4712#ifndef MONGOOSE_NO_AUTH
4713  } else if ((!is_dav_request(conn) && !is_authorized(conn, path,
4714               exists && S_ISDIR(st.st_mode))) ||
4715             (is_dav_request(conn) && !is_authorized_for_dav(conn))) {
4716    mg_send_digest_auth_request(&conn->mg_conn);
4717    close_local_endpoint(conn);
4718#endif
4719#ifndef MONGOOSE_NO_DAV
4720  } else if (must_hide_file(conn, path)) {
4721    send_http_error(conn, 404, NULL);
4722  } else if (!strcmp(conn->mg_conn.request_method, "PROPFIND")) {
4723    handle_propfind(conn, path, &st, exists);
4724  } else if (!strcmp(conn->mg_conn.request_method, "MKCOL")) {
4725    handle_mkcol(conn, path);
4726  } else if (!strcmp(conn->mg_conn.request_method, "DELETE")) {
4727    handle_delete(conn, path);
4728  } else if (!strcmp(conn->mg_conn.request_method, "PUT")) {
4729    handle_put(conn, path);
4730#endif
4731  } else {
4732    mg_send_file_internal(&conn->mg_conn, path, &st, exists, NULL);
4733  }
4734#endif  // MONGOOSE_NO_FILESYSTEM
4735}
4736
4737static void send_continue_if_expected(struct connection *conn) {
4738  static const char expect_response[] = "HTTP/1.1 100 Continue\r\n\r\n";
4739  const char *expect_hdr = mg_get_header(&conn->mg_conn, "Expect");
4740
4741  if (expect_hdr != NULL && !mg_strcasecmp(expect_hdr, "100-continue")) {
4742    ns_send(conn->ns_conn, expect_response, sizeof(expect_response) - 1);
4743  }
4744}
4745
4746// Conform to http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
4747static int is_valid_uri(const char *uri) {
4748  unsigned short n;
4749  return uri[0] == '/' ||
4750    strcmp(uri, "*") == 0 ||            // OPTIONS method can use asterisk URI
4751    mg_strncasecmp(uri, "http", 4) == 0 || // Naive check for the absolute URI
4752    sscanf(uri, "%*[^ :]:%hu", &n) > 0; // CONNECT method can use host:port
4753}
4754
4755static void try_parse(struct connection *conn) {
4756  struct iobuf *io = &conn->ns_conn->recv_iobuf;
4757
4758  if (conn->request_len == 0 &&
4759      (conn->request_len = get_request_len(io->buf, io->len)) > 0) {
4760    // If request is buffered in, remove it from the iobuf. This is because
4761    // iobuf could be reallocated, and pointers in parsed request could
4762    // become invalid.
4763    conn->request = (char *) NS_MALLOC(conn->request_len);
4764    if (conn->request == NULL) {
4765      conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
4766      return;
4767    }
4768    memcpy(conn->request, io->buf, conn->request_len);
4769    //DBG(("%p [%.*s]", conn, conn->request_len, conn->request));
4770    iobuf_remove(io, conn->request_len);
4771    conn->request_len = parse_http_message(conn->request, conn->request_len,
4772                                           &conn->mg_conn);
4773    if (conn->request_len > 0) {
4774      const char *cl_hdr = mg_get_header(&conn->mg_conn, "Content-Length");
4775      conn->cl = cl_hdr == NULL ? 0 : to64(cl_hdr);
4776      conn->mg_conn.content_len = (size_t) conn->cl;
4777    }
4778  }
4779}
4780
4781static void do_proxy(struct connection *conn) {
4782  if (0 && conn->request_len == 0) {
4783    try_parse(conn);
4784    DBG(("%p parsing -> %d", conn, conn->request_len));
4785    if (conn->request_len > 0 && call_user(conn, MG_REQUEST) == MG_FALSE) {
4786      proxy_request(conn->endpoint.nc, &conn->mg_conn);
4787    } else if (conn->request_len < 0) {
4788      ns_forward(conn->ns_conn, conn->endpoint.nc);
4789    }
4790  } else {
4791    DBG(("%p forwarding", conn));
4792    ns_forward(conn->ns_conn, conn->endpoint.nc);
4793  }
4794}
4795
4796static void on_recv_data(struct connection *conn) {
4797  struct iobuf *io = &conn->ns_conn->recv_iobuf;
4798  int n;
4799
4800  if (conn->endpoint_type == EP_PROXY) {
4801    if (conn->endpoint.nc != NULL) do_proxy(conn);
4802    return;
4803  }
4804
4805  if (conn->ns_conn->flags & NSF_DISCARD) {
4806    size_t n = conn->cl;
4807    if (n > io->len) {
4808      n = io->len;
4809    }
4810    iobuf_remove(io, n);
4811    conn->cl -= n;
4812    if (conn->cl == 0) {
4813      close_local_endpoint(conn);
4814    }
4815    return;
4816  }
4817
4818  try_parse(conn);
4819  DBG(("%p %d %lu %d", conn, conn->request_len, (unsigned long)io->len,
4820       conn->ns_conn->flags));
4821  if (conn->request_len < 0 ||
4822      (conn->request_len > 0 && !is_valid_uri(conn->mg_conn.uri))) {
4823    send_http_error(conn, 400, NULL);
4824  } else if (conn->request_len == 0 && io->len > MAX_REQUEST_SIZE) {
4825    send_http_error(conn, 413, NULL);
4826  } else if (conn->request_len > 0 &&
4827             strcmp(conn->mg_conn.http_version, "1.0") != 0 &&
4828             strcmp(conn->mg_conn.http_version, "1.1") != 0) {
4829    send_http_error(conn, 505, NULL);
4830  } else if (conn->request_len > 0 && conn->endpoint_type == EP_NONE) {
4831#ifndef MONGOOSE_NO_WEBSOCKET
4832    send_websocket_handshake_if_requested(&conn->mg_conn);
4833#endif
4834    send_continue_if_expected(conn);
4835    open_local_endpoint(conn, 0);
4836  }
4837
4838#ifndef MONGOOSE_NO_CGI
4839  if (conn->endpoint_type == EP_CGI && conn->endpoint.nc != NULL) {
4840    ns_forward(conn->ns_conn, conn->endpoint.nc);
4841  }
4842#endif
4843  if (conn->endpoint_type == EP_USER) {
4844    conn->mg_conn.content = io->buf;
4845    conn->mg_conn.content_len = io->len;
4846    n = call_user(conn, MG_RECV);
4847    if (n < 0) {
4848      conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
4849    } else if ((size_t) n <= io->len) {
4850      iobuf_remove(io, n);
4851    }
4852    call_request_handler_if_data_is_buffered(conn);
4853  }
4854#ifndef MONGOOSE_NO_DAV
4855  if (conn->endpoint_type == EP_PUT && io->len > 0) {
4856    forward_put_data(conn);
4857  }
4858#endif
4859}
4860
4861static void call_http_client_handler(struct connection *conn) {
4862  //conn->mg_conn.status_code = code;
4863  // For responses without Content-Lengh, use the whole buffer
4864  if (conn->cl == 0) {
4865    conn->mg_conn.content_len = conn->ns_conn->recv_iobuf.len;
4866  }
4867  conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
4868  if (call_user(conn, MG_REPLY) == MG_FALSE) {
4869    conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
4870  }
4871  iobuf_remove(&conn->ns_conn->recv_iobuf, conn->mg_conn.content_len);
4872  conn->mg_conn.status_code = 0;
4873  conn->cl = conn->num_bytes_recv = conn->request_len = 0;
4874  NS_FREE(conn->request);
4875  conn->request = NULL;
4876}
4877
4878static void process_response(struct connection *conn) {
4879  struct iobuf *io = &conn->ns_conn->recv_iobuf;
4880
4881  try_parse(conn);
4882  DBG(("%p %d %lu", conn, conn->request_len, (unsigned long)io->len));
4883  if (conn->request_len < 0 ||
4884      (conn->request_len == 0 && io->len > MAX_REQUEST_SIZE)) {
4885    call_http_client_handler(conn);
4886  } else if ((int64_t) io->len >= conn->cl) {
4887    call_http_client_handler(conn);
4888  }
4889}
4890
4891struct mg_connection *mg_connect(struct mg_server *server, const char *addr) {
4892  struct ns_connection *nsconn;
4893  struct connection *conn;
4894
4895  nsconn = ns_connect(&server->ns_mgr, addr, mg_ev_handler, NULL);
4896  if (nsconn == NULL) return 0;
4897
4898  if ((conn = (struct connection *) NS_CALLOC(1, sizeof(*conn))) == NULL) {
4899    nsconn->flags |= NSF_CLOSE_IMMEDIATELY;
4900    return 0;
4901  }
4902
4903  // Interlink two structs
4904  conn->ns_conn = nsconn;
4905  nsconn->user_data = conn;
4906
4907  conn->server = server;
4908  conn->endpoint_type = EP_CLIENT;
4909  //conn->handler = handler;
4910  conn->mg_conn.server_param = server->ns_mgr.user_data;
4911  conn->ns_conn->flags = NSF_CONNECTING;
4912
4913  return &conn->mg_conn;
4914}
4915
4916#ifndef MONGOOSE_NO_LOGGING
4917static void log_header(const struct mg_connection *conn, const char *header,
4918                       FILE *fp) {
4919  const char *header_value;
4920
4921  if ((header_value = mg_get_header(conn, header)) == NULL) {
4922    (void) fprintf(fp, "%s", " -");
4923  } else {
4924    (void) fprintf(fp, " \"%s\"", header_value);
4925  }
4926}
4927
4928static void log_access(const struct connection *conn, const char *path) {
4929  const struct mg_connection *c = &conn->mg_conn;
4930  FILE *fp = (path == NULL) ?  NULL : fopen(path, "a+");
4931  char date[64], user[100];
4932  time_t now;
4933
4934  if (fp == NULL) return;
4935  now = time(NULL);
4936  strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", localtime(&now));
4937
4938  flockfile(fp);
4939  mg_parse_header(mg_get_header(&conn->mg_conn, "Authorization"), "username",
4940                  user, sizeof(user));
4941  fprintf(fp, "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d 0",
4942          c->remote_ip, user[0] == '\0' ? "-" : user, date,
4943          c->request_method ? c->request_method : "-",
4944          c->uri ? c->uri : "-", c->query_string ? "?" : "",
4945          c->query_string ? c->query_string : "",
4946          c->http_version, c->status_code);
4947  log_header(c, "Referer", fp);
4948  log_header(c, "User-Agent", fp);
4949  fputc('\n', fp);
4950  fflush(fp);
4951
4952  funlockfile(fp);
4953  fclose(fp);
4954}
4955#endif
4956
4957static void close_local_endpoint(struct connection *conn) {
4958  struct mg_connection *c = &conn->mg_conn;
4959  // Must be done before free()
4960  int keep_alive = should_keep_alive(&conn->mg_conn) &&
4961    (conn->endpoint_type == EP_FILE || conn->endpoint_type == EP_USER);
4962  DBG(("%p %d %d %d", conn, conn->endpoint_type, keep_alive,
4963       conn->ns_conn->flags));
4964
4965  switch (conn->endpoint_type) {
4966    case EP_PUT:
4967    case EP_FILE:
4968      close(conn->endpoint.fd);
4969      break;
4970    case EP_CGI:
4971    case EP_PROXY:
4972      if (conn->endpoint.nc != NULL) {
4973        DBG(("%p %p %p :-)", conn, conn->ns_conn, conn->endpoint.nc));
4974        conn->endpoint.nc->flags |= NSF_CLOSE_IMMEDIATELY;
4975        conn->endpoint.nc->user_data = NULL;
4976      }
4977      break;
4978    default: break;
4979  }
4980
4981#ifndef MONGOOSE_NO_LOGGING
4982  if (c->status_code > 0 && conn->endpoint_type != EP_CLIENT &&
4983      c->status_code != 400) {
4984    log_access(conn, conn->server->config_options[ACCESS_LOG_FILE]);
4985  }
4986#endif
4987
4988  // Gobble possible POST data sent to the URI handler
4989  iobuf_free(&conn->ns_conn->recv_iobuf);
4990  NS_FREE(conn->request);
4991  NS_FREE(conn->path_info);
4992  conn->endpoint.nc = NULL;
4993  conn->request = conn->path_info = NULL;
4994
4995  conn->endpoint_type = EP_NONE;
4996  conn->cl = conn->num_bytes_recv = conn->request_len = 0;
4997  conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA | NSF_DISCARD |
4998                            NSF_BUFFER_BUT_DONT_SEND | NSF_CLOSE_IMMEDIATELY |
4999                            MG_HEADERS_SENT | MG_USING_CHUNKED_API);
5000
5001  // Do not memset() the whole structure, as some of the fields
5002  // (IP addresses & ports, server_param) must survive. Nullify the rest.
5003  c->request_method = c->uri = c->http_version = c->query_string = NULL;
5004  c->num_headers = c->status_code = c->is_websocket = c->content_len = 0;
5005  c->callback_param = NULL;
5006
5007  if (keep_alive) {
5008    on_recv_data(conn);  // Can call us recursively if pipelining is used
5009  } else {
5010    conn->ns_conn->flags |= conn->ns_conn->send_iobuf.len == 0 ?
5011      NSF_CLOSE_IMMEDIATELY : NSF_FINISHED_SENDING_DATA;
5012  }
5013}
5014
5015static void transfer_file_data(struct connection *conn) {
5016  char buf[IOBUF_SIZE];
5017  size_t n;
5018
5019  // If output buffer is too big, don't send anything. Wait until
5020  // mongoose drains already buffered data to the client.
5021  if (conn->ns_conn->send_iobuf.len > sizeof(buf) * 2) return;
5022
5023  // Do not send anyt
5024  n = read(conn->endpoint.fd, buf, conn->cl < (int64_t) sizeof(buf) ?
5025           (int) conn->cl : (int) sizeof(buf));
5026
5027  if (n <= 0) {
5028    close_local_endpoint(conn);
5029  } else if (n > 0) {
5030    conn->cl -= n;
5031    ns_send(conn->ns_conn, buf, n);
5032    if (conn->cl <= 0) {
5033      close_local_endpoint(conn);
5034    }
5035  }
5036}
5037
5038time_t mg_poll_server(struct mg_server *server, int milliseconds) {
5039  return ns_mgr_poll(&server->ns_mgr, milliseconds);
5040}
5041
5042void mg_destroy_server(struct mg_server **server) {
5043  if (server != NULL && *server != NULL) {
5044    struct mg_server *s = *server;
5045    int i;
5046
5047    ns_mgr_free(&s->ns_mgr);
5048    for (i = 0; i < (int) ARRAY_SIZE(s->config_options); i++) {
5049      NS_FREE(s->config_options[i]);  // It is OK to free(NULL)
5050    }
5051    NS_FREE(s);
5052    *server = NULL;
5053  }
5054}
5055
5056struct mg_connection *mg_next(struct mg_server *s, struct mg_connection *c) {
5057  struct ns_connection *nc = ns_next(&s->ns_mgr, c == NULL ? NULL :
5058                                     MG_CONN_2_CONN(c)->ns_conn);
5059  if (nc != NULL && nc->user_data != NULL) {
5060    return & ((struct connection *) nc->user_data)->mg_conn;
5061  } else {
5062    return NULL;
5063  }
5064}
5065
5066static int get_var(const char *data, size_t data_len, const char *name,
5067                   char *dst, size_t dst_len, int n) {
5068  const char *p, *e = data + data_len, *s;
5069  size_t name_len;
5070  int i = 0, len = -1;
5071
5072  if (dst == NULL || dst_len == 0) {
5073    len = -2;
5074  } else if (data == NULL || name == NULL || data_len == 0) {
5075    dst[0] = '\0';
5076  } else {
5077    name_len = strlen(name);
5078    dst[0] = '\0';
5079
5080    // data is "var1=val1&var2=val2...". Find variable first
5081    for (p = data; p + name_len < e; p++) {
5082      if ((p == data || p[-1] == '&') && p[name_len] == '=' &&
5083          !mg_strncasecmp(name, p, name_len)) {
5084
5085        if (n != i++) continue;
5086
5087        // Point p to variable value
5088        p += name_len + 1;
5089
5090        // Point s to the end of the value
5091        s = (const char *) memchr(p, '&', (size_t)(e - p));
5092        if (s == NULL) {
5093          s = e;
5094        }
5095        assert(s >= p);
5096
5097        // Decode variable into destination buffer
5098        len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
5099
5100        // Redirect error code from -1 to -2 (destination buffer too small).
5101        if (len == -1) {
5102          len = -2;
5103        }
5104        break;
5105      }
5106    }
5107  }
5108
5109  return len;
5110}
5111
5112int mg_get_var_n(const struct mg_connection *conn, const char *name,
5113               char *dst, size_t dst_len, int n) {
5114  int len = get_var(conn->query_string, conn->query_string == NULL ? 0 :
5115                    strlen(conn->query_string), name, dst, dst_len, n);
5116  if (len == -1) {
5117    len = get_var(conn->content, conn->content_len, name, dst, dst_len, n);
5118  }
5119  return len;
5120}
5121
5122int mg_get_var(const struct mg_connection *conn, const char *name,
5123               char *dst, size_t dst_len) {
5124  return mg_get_var_n(conn, name, dst, dst_len, 0);
5125}
5126
5127static int get_line_len(const char *buf, int buf_len) {
5128  int len = 0;
5129  while (len < buf_len && buf[len] != '\n') len++;
5130  return buf[len] == '\n' ? len + 1: -1;
5131}
5132
5133int mg_parse_multipart(const char *buf, int buf_len,
5134                       char *var_name, int var_name_len,
5135                       char *file_name, int file_name_len,
5136                       const char **data, int *data_len) {
5137  static const char cd[] = "Content-Disposition: ";
5138  //struct mg_connection c;
5139  int hl, bl, n, ll, pos, cdl = sizeof(cd) - 1;
5140  //char *p;
5141
5142  if (buf == NULL || buf_len <= 0) return 0;
5143  if ((hl = get_request_len(buf, buf_len)) <= 0) return 0;
5144  if (buf[0] != '-' || buf[1] != '-' || buf[2] == '\n') return 0;
5145
5146  // Get boundary length
5147  bl = get_line_len(buf, buf_len);
5148
5149  // Loop through headers, fetch variable name and file name
5150  var_name[0] = file_name[0] = '\0';
5151  for (n = bl; (ll = get_line_len(buf + n, hl - n)) > 0; n += ll) {
5152    if (mg_strncasecmp(cd, buf + n, cdl) == 0) {
5153      parse_header(buf + n + cdl, ll - (cdl + 2), "name",
5154                   var_name, var_name_len);
5155      parse_header(buf + n + cdl, ll - (cdl + 2), "filename",
5156                   file_name, file_name_len);
5157    }
5158  }
5159
5160  // Scan body, search for terminating boundary
5161  for (pos = hl; pos + (bl - 2) < buf_len; pos++) {
5162    if (buf[pos] == '-' && !memcmp(buf, &buf[pos], bl - 2)) {
5163      if (data_len != NULL) *data_len = (pos - 2) - hl;
5164      if (data != NULL) *data = buf + hl;
5165      return pos;
5166    }
5167  }
5168
5169  return 0;
5170}
5171
5172const char **mg_get_valid_option_names(void) {
5173  return static_config_options;
5174}
5175
5176void mg_copy_listeners(struct mg_server *s, struct mg_server *to) {
5177  struct ns_connection *c;
5178  for (c = ns_next(&s->ns_mgr, NULL); c != NULL; c = ns_next(&s->ns_mgr, c)) {
5179    struct ns_connection *tmp;
5180    if ((c->flags & NSF_LISTENING) &&
5181        (tmp = (struct ns_connection *) NS_MALLOC(sizeof(*tmp))) != NULL) {
5182      memcpy(tmp, c, sizeof(*tmp));
5183
5184#if defined(NS_ENABLE_SSL) && defined(HEADER_SSL_H)
5185      /* OpenSSL only. See https://github.com/cesanta/mongoose/issues/441 */
5186      if (tmp->ssl_ctx != NULL) {
5187        tmp->ssl_ctx->references++;
5188      }
5189#endif
5190
5191      tmp->mgr = &to->ns_mgr;
5192      ns_add_conn(tmp->mgr, tmp);
5193    }
5194  }
5195}
5196
5197static int get_option_index(const char *name) {
5198  int i;
5199
5200  for (i = 0; static_config_options[i * 2] != NULL; i++) {
5201    if (strcmp(static_config_options[i * 2], name) == 0) {
5202      return i;
5203    }
5204  }
5205  return -1;
5206}
5207
5208static void set_default_option_values(char **opts) {
5209  const char *value, **all_opts = mg_get_valid_option_names();
5210  int i;
5211
5212  for (i = 0; all_opts[i * 2] != NULL; i++) {
5213    value = all_opts[i * 2 + 1];
5214    if (opts[i] == NULL && value != NULL) {
5215      opts[i] = mg_strdup(value);
5216    }
5217  }
5218}
5219
5220const char *mg_set_option(struct mg_server *server, const char *name,
5221                          const char *value) {
5222  int ind = get_option_index(name);
5223  const char *error_msg = NULL;
5224  char **v = NULL;
5225
5226  if (ind < 0) return  "No such option";
5227  v = &server->config_options[ind];
5228
5229  // Return success immediately if setting to the same value
5230  if ((*v == NULL && value == NULL) ||
5231      (value != NULL && *v != NULL && !strcmp(value, *v))) {
5232    return NULL;
5233  }
5234
5235  if (*v != NULL) {
5236    NS_FREE(*v);
5237    *v = NULL;
5238  }
5239
5240  if (value == NULL || value[0] == '\0') return NULL;
5241
5242  *v = mg_strdup(value);
5243  DBG(("%s [%s]", name, *v));
5244
5245  if (ind == LISTENING_PORT) {
5246    char buf[500] = "";
5247    size_t n = 0;
5248    struct vec vec;
5249
5250    /*
5251     * Ports can be specified as 0, meaning that OS has to choose any
5252     * free port that is available. In order to pass chosen port number to
5253     * the user, we rewrite all 0 port to chosen values.
5254     */
5255    while ((value = next_option(value, &vec, NULL)) != NULL) {
5256      struct ns_connection *c = ns_bind(&server->ns_mgr, vec.ptr,
5257                                        mg_ev_handler, NULL);
5258      if (c == NULL) {
5259        error_msg = "Cannot bind to port";
5260        break;
5261      } else {
5262        char buf2[50], cert[100], ca[100];
5263        union socket_address sa;
5264        int proto, use_ssl;
5265
5266        ns_parse_address(vec.ptr, &sa, &proto, &use_ssl, cert, ca);
5267        ns_sock_to_str(c->sock, buf2, sizeof(buf2),
5268                       memchr(vec.ptr, ':', vec.len) == NULL ? 2 : 3);
5269
5270        n += snprintf(buf + n, sizeof(buf) - n, "%s%s%s%s%s%s%s",
5271                      n > 0 ? "," : "",
5272                      use_ssl ? "ssl://" : "",
5273                      buf2, cert[0] ? ":" : "", cert, ca[0] ? ":" : "", ca);
5274      }
5275    }
5276    buf[sizeof(buf) - 1] = '\0';
5277    NS_FREE(*v);
5278    *v = mg_strdup(buf);
5279#ifndef MONGOOSE_NO_FILESYSTEM
5280  } else if (ind == HEXDUMP_FILE) {
5281    server->ns_mgr.hexdump_file = *v;
5282#endif
5283#if !defined(_WIN32) && !defined(MONGOOSE_NO_USER)
5284  } else if (ind == RUN_AS_USER) {
5285    struct passwd *pw;
5286    if ((pw = getpwnam(value)) == NULL) {
5287      error_msg = "Unknown user";
5288    } else if (setgid(pw->pw_gid) != 0) {
5289      error_msg = "setgid() failed";
5290    } else if (setuid(pw->pw_uid) != 0) {
5291      error_msg = "setuid() failed";
5292    }
5293#endif
5294  }
5295
5296  return error_msg;
5297}
5298
5299static void set_ips(struct ns_connection *nc, int is_rem) {
5300  struct connection *conn = (struct connection *) nc->user_data;
5301  struct mg_connection *c = &conn->mg_conn;
5302  char buf[100];
5303
5304  ns_sock_to_str(nc->sock, buf, sizeof(buf), is_rem ? 7 : 3);
5305  sscanf(buf, "%47[^:]:%hu",
5306         is_rem ? c->remote_ip : c->local_ip,
5307         is_rem ? &c->remote_port : &c->local_port);
5308  //DBG(("%p %s %s", conn, is_rem ? "rem" : "loc", buf));
5309}
5310
5311static void on_accept(struct ns_connection *nc, union socket_address *sa) {
5312  struct mg_server *server = (struct mg_server *) nc->mgr;
5313  struct connection *conn;
5314
5315  if (!check_acl(server->config_options[ACCESS_CONTROL_LIST],
5316                 ntohl(* (uint32_t *) &sa->sin.sin_addr)) ||
5317      (conn = (struct connection *) NS_CALLOC(1, sizeof(*conn))) == NULL) {
5318    nc->flags |= NSF_CLOSE_IMMEDIATELY;
5319  } else {
5320    // Circularly link two connection structures
5321    nc->user_data = conn;
5322    conn->ns_conn = nc;
5323
5324    // Initialize the rest of connection attributes
5325    conn->server = server;
5326    conn->mg_conn.server_param = nc->mgr->user_data;
5327    set_ips(nc, 1);
5328    set_ips(nc, 0);
5329  }
5330}
5331
5332static void process_udp(struct ns_connection *nc) {
5333  struct iobuf *io = &nc->recv_iobuf;
5334  struct connection conn;
5335
5336  memset(&conn, 0, sizeof(conn));
5337  conn.ns_conn = nc;
5338  conn.server = (struct mg_server *) nc->mgr;
5339  conn.request_len = parse_http_message(io->buf, io->len, &conn.mg_conn);
5340  on_recv_data(&conn);
5341  //ns_printf(nc, "%s", "HTTP/1.0 200 OK\r\n\r\n");
5342}
5343
5344#ifdef MONGOOSE_SEND_NS_EVENTS
5345static void send_ns_event(struct ns_connection *nc, int ev, void *p) {
5346  struct connection *conn = (struct connection *) nc->user_data;
5347  if (conn != NULL) {
5348    void *param[2] = { nc, p };
5349    conn->mg_conn.callback_param = param;
5350    call_user(conn, (enum mg_event) ev);
5351  }
5352}
5353#else
5354static void send_ns_event(struct ns_connection *nc, int ev, void *p) {
5355  (void) nc; (void) p; (void) ev;
5356}
5357#endif
5358
5359static void mg_ev_handler(struct ns_connection *nc, int ev, void *p) {
5360  struct connection *conn = (struct connection *) nc->user_data;
5361
5362  // Send NS event to the handler. Note that call_user won't send an event
5363  // if conn == NULL. Therefore, repeat this for NS_ACCEPT event as well.
5364  send_ns_event(nc, ev, p);
5365
5366  switch (ev) {
5367    case NS_ACCEPT:
5368      on_accept(nc, (union socket_address *) p);
5369      send_ns_event(nc, ev, p);
5370      break;
5371
5372    case NS_CONNECT:
5373      if (nc->user_data != NULL) {
5374        set_ips(nc, 1);
5375        set_ips(nc, 0);
5376      }
5377      conn->mg_conn.status_code = * (int *) p;
5378      if (conn->mg_conn.status_code != 0 ||
5379          (!(nc->flags & MG_PROXY_CONN) &&
5380           call_user(conn, MG_CONNECT) == MG_FALSE)) {
5381        nc->flags |= NSF_CLOSE_IMMEDIATELY;
5382      }
5383      break;
5384
5385    case NS_RECV:
5386      if (conn != NULL) {
5387        conn->num_bytes_recv += * (int *) p;
5388      }
5389
5390      if (nc->flags & NSF_UDP) {
5391        process_udp(nc);
5392      } else if (nc->listener != NULL) {
5393        on_recv_data(conn);
5394#ifndef MONGOOSE_NO_CGI
5395      } else if (nc->flags & MG_CGI_CONN) {
5396        on_cgi_data(nc);
5397#endif
5398      } else if (nc->flags & MG_PROXY_CONN) {
5399        if (conn != NULL) {
5400          ns_forward(nc, conn->ns_conn);
5401        }
5402      } else {
5403        process_response(conn);
5404      }
5405      break;
5406
5407    case NS_SEND:
5408      break;
5409
5410    case NS_CLOSE:
5411      nc->user_data = NULL;
5412      if (nc->flags & (MG_CGI_CONN | MG_PROXY_CONN)) {
5413        DBG(("%p %p closing cgi/proxy conn", conn, nc));
5414        if (conn && conn->ns_conn) {
5415          conn->ns_conn->flags &= ~NSF_BUFFER_BUT_DONT_SEND;
5416          conn->ns_conn->flags |= conn->ns_conn->send_iobuf.len > 0 ?
5417            NSF_FINISHED_SENDING_DATA : NSF_CLOSE_IMMEDIATELY;
5418          conn->endpoint.nc = NULL;
5419        }
5420      } else if (conn != NULL) {
5421        DBG(("%p %p %d closing", conn, nc, conn->endpoint_type));
5422
5423        if (conn->endpoint_type == EP_CLIENT && nc->recv_iobuf.len > 0) {
5424          call_http_client_handler(conn);
5425        }
5426
5427        call_user(conn, MG_CLOSE);
5428        close_local_endpoint(conn);
5429        conn->ns_conn = NULL;
5430        NS_FREE(conn);
5431      }
5432      break;
5433
5434    case NS_POLL:
5435      if (conn != NULL) {
5436        if (call_user(conn, MG_POLL) == MG_TRUE) {
5437          if (conn->ns_conn->flags & MG_HEADERS_SENT) {
5438            write_terminating_chunk(conn);
5439          }
5440          close_local_endpoint(conn);
5441          /*
5442           * MG_POLL callback returned MG_TRUE,
5443           * i.e. data is sent, set corresponding flag
5444           */
5445          conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
5446        }
5447
5448        if (conn->endpoint_type == EP_FILE) {
5449          transfer_file_data(conn);
5450        }
5451      }
5452
5453      // Expire idle connections
5454      {
5455        time_t current_time = * (time_t *) p;
5456
5457        if (conn != NULL && conn->mg_conn.is_websocket) {
5458          ping_idle_websocket_connection(conn, current_time);
5459        }
5460
5461        if (nc->listener != NULL &&
5462            nc->last_io_time + MONGOOSE_IDLE_TIMEOUT_SECONDS < current_time) {
5463          mg_ev_handler(nc, NS_CLOSE, NULL);
5464          nc->flags |= NSF_CLOSE_IMMEDIATELY;
5465        }
5466      }
5467      break;
5468
5469    default:
5470      break;
5471  }
5472}
5473
5474static void iter2(struct ns_connection *nc, int ev, void *param) {
5475  mg_handler_t func = NULL;
5476  struct connection *conn = (struct connection *) nc->user_data;
5477  const char *msg = (const char *) param;
5478  int n;
5479  (void) ev;
5480
5481  //DBG(("%p [%s]", conn, msg));
5482  if (sscanf(msg, "%p %n", (void **) &func, &n) && func != NULL && conn != NULL) {
5483    conn->mg_conn.callback_param = (void *) (msg + n);
5484    func(&conn->mg_conn, MG_POLL);
5485  }
5486}
5487
5488void mg_wakeup_server_ex(struct mg_server *server, mg_handler_t cb,
5489                         const char *fmt, ...) {
5490  va_list ap;
5491  char buf[8 * 1024];
5492  int len;
5493
5494  // Encode callback (cb) into a buffer
5495  len = snprintf(buf, sizeof(buf), "%p ", cb);
5496  va_start(ap, fmt);
5497  len += vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
5498  va_end(ap);
5499
5500  // "len + 1" is to include terminating \0 in the message
5501  ns_broadcast(&server->ns_mgr, iter2, buf, len + 1);
5502}
5503
5504void mg_wakeup_server(struct mg_server *server) {
5505  ns_broadcast(&server->ns_mgr, NULL, (void *) "", 0);
5506}
5507
5508const char *mg_get_option(const struct mg_server *server, const char *name) {
5509  const char **opts = (const char **) server->config_options;
5510  int i = get_option_index(name);
5511  return i == -1 ? NULL : opts[i] == NULL ? "" : opts[i];
5512}
5513
5514struct mg_server *mg_create_server(void *server_data, mg_handler_t handler) {
5515  struct mg_server *server = (struct mg_server *) NS_CALLOC(1, sizeof(*server));
5516  ns_mgr_init(&server->ns_mgr, server_data);
5517  set_default_option_values(server->config_options);
5518  server->event_handler = handler;
5519  return server;
5520}
trunk/3rdparty/mongoose/mongoose.h
r0r250110
1// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
2// Copyright (c) 2013-2014 Cesanta Software Limited
3// All rights reserved
4//
5// This software is dual-licensed: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License version 2 as
7// published by the Free Software Foundation. For the terms of this
8// license, see <http://www.gnu.org/licenses/>.
9//
10// You are free to use this software under the terms of the GNU General
11// Public License, but WITHOUT ANY WARRANTY; without even the implied
12// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13// See the GNU General Public License for more details.
14//
15// Alternatively, you can license this software under a commercial
16// license, as set out in <http://cesanta.com/>.
17
18#ifndef MONGOOSE_HEADER_INCLUDED
19#define  MONGOOSE_HEADER_INCLUDED
20
21#define MONGOOSE_VERSION "5.6"
22
23#include <stdarg.h>     // required for va_list
24#include <stdio.h>      // required for FILE
25#include <stddef.h>     // required for size_t
26#include <sys/types.h>  // required for time_t
27
28#ifdef __cplusplus
29extern "C" {
30#endif // __cplusplus
31
32// This structure contains information about HTTP request.
33struct mg_connection {
34  const char *request_method; // "GET", "POST", etc
35  const char *uri;            // URL-decoded URI
36  const char *http_version;   // E.g. "1.0", "1.1"
37  const char *query_string;   // URL part after '?', not including '?', or NULL
38
39  char remote_ip[48];         // Max IPv6 string length is 45 characters
40  char local_ip[48];          // Local IP address
41  unsigned short remote_port; // Client's port
42  unsigned short local_port;  // Local port number
43
44  int num_headers;            // Number of HTTP headers
45  struct mg_header {
46    const char *name;         // HTTP header name
47    const char *value;        // HTTP header value
48  } http_headers[30];
49
50  char *content;              // POST (or websocket message) data, or NULL
51  size_t content_len;         // Data length
52
53  int is_websocket;           // Connection is a websocket connection
54  int status_code;            // HTTP status code for HTTP error handler
55  int wsbits;                 // First byte of the websocket frame
56  void *server_param;         // Parameter passed to mg_create_server()
57  void *connection_param;     // Placeholder for connection-specific data
58  void *callback_param;
59};
60
61struct mg_server; // Opaque structure describing server instance
62enum mg_result { MG_FALSE, MG_TRUE, MG_MORE };
63enum mg_event {
64  MG_POLL = 100,  // If callback returns MG_TRUE connection closes
65                  // after all of data is sent
66  MG_CONNECT,     // If callback returns MG_FALSE, connect fails
67  MG_AUTH,        // If callback returns MG_FALSE, authentication fails
68  MG_REQUEST,     // If callback returns MG_FALSE, Mongoose continues with req
69  MG_REPLY,       // If callback returns MG_FALSE, Mongoose closes connection
70  MG_RECV,        // Mongoose has received POST data chunk.
71                  // Callback should return a number of bytes to discard from
72                  // the receive buffer, or -1 to close the connection.
73  MG_CLOSE,       // Connection is closed, callback return value is ignored
74  MG_WS_HANDSHAKE,  // New websocket connection, handshake request
75  MG_WS_CONNECT,  // New websocket connection established
76  MG_HTTP_ERROR   // If callback returns MG_FALSE, Mongoose continues with err
77};
78typedef int (*mg_handler_t)(struct mg_connection *, enum mg_event);
79
80// Websocket opcodes, from http://tools.ietf.org/html/rfc6455
81enum {
82  WEBSOCKET_OPCODE_CONTINUATION = 0x0,
83  WEBSOCKET_OPCODE_TEXT = 0x1,
84  WEBSOCKET_OPCODE_BINARY = 0x2,
85  WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
86  WEBSOCKET_OPCODE_PING = 0x9,
87  WEBSOCKET_OPCODE_PONG = 0xa
88};
89
90// Server management functions
91struct mg_server *mg_create_server(void *server_param, mg_handler_t handler);
92void mg_destroy_server(struct mg_server **);
93const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
94time_t mg_poll_server(struct mg_server *, int milliseconds);
95const char **mg_get_valid_option_names(void);
96const char *mg_get_option(const struct mg_server *server, const char *name);
97void mg_copy_listeners(struct mg_server *from, struct mg_server *to);
98struct mg_connection *mg_next(struct mg_server *, struct mg_connection *);
99void mg_wakeup_server(struct mg_server *);
100void mg_wakeup_server_ex(struct mg_server *, mg_handler_t, const char *, ...);
101struct mg_connection *mg_connect(struct mg_server *, const char *);
102
103// Connection management functions
104void mg_send_status(struct mg_connection *, int status_code);
105void mg_send_header(struct mg_connection *, const char *name, const char *val);
106size_t mg_send_data(struct mg_connection *, const void *data, int data_len);
107size_t mg_printf_data(struct mg_connection *, const char *format, ...);
108size_t mg_vprintf_data(struct mg_connection *, const char *format, va_list ap);
109size_t mg_write(struct mg_connection *, const void *buf, size_t len);
110size_t mg_printf(struct mg_connection *conn, const char *fmt, ...);
111size_t mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap);
112
113size_t mg_websocket_write(struct mg_connection *, int opcode,
114                          const char *data, size_t data_len);
115size_t mg_websocket_printf(struct mg_connection* conn, int opcode,
116                           const char *fmt, ...);
117
118void mg_send_file(struct mg_connection *, const char *path, const char *);
119void mg_send_file_data(struct mg_connection *, int fd);
120
121const char *mg_get_header(const struct mg_connection *, const char *name);
122const char *mg_get_mime_type(const char *name, const char *default_mime_type);
123int mg_get_var(const struct mg_connection *conn, const char *var_name,
124               char *buf, size_t buf_len);
125int mg_get_var_n(const struct mg_connection *conn, const char *var_name,
126                 char *buf, size_t buf_len, int n);
127int mg_parse_header(const char *hdr, const char *var_name, char *buf, size_t);
128int mg_parse_multipart(const char *buf, int buf_len,
129                       char *var_name, int var_name_len,
130                       char *file_name, int file_name_len,
131                       const char **data, int *data_len);
132
133
134// Utility functions
135void *mg_start_thread(void *(*func)(void *), void *param);
136char *mg_md5(char buf[33], ...);
137int mg_authorize_digest(struct mg_connection *c, FILE *fp);
138size_t mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len);
139int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, int);
140int mg_terminate_ssl(struct mg_connection *c, const char *cert);
141int mg_forward(struct mg_connection *c, const char *addr);
142void *mg_mmap(FILE *fp, size_t size);
143void mg_munmap(void *p, size_t size);
144
145
146// Templates support
147struct mg_expansion {
148  const char *keyword;
149  void (*handler)(struct mg_connection *);
150};
151void mg_template(struct mg_connection *, const char *text,
152                 struct mg_expansion *expansions);
153
154#ifdef __cplusplus
155}
156#endif // __cplusplus
157
158#endif // MONGOOSE_HEADER_INCLUDED
trunk/3rdparty/mongoose/scripts/embed_binary_files.pl
r0r250110
1# This program is used to embed arbitrary data into a C binary. It takes
2# a list of files as an input, and produces a .c data file that contains
3# contents of all these files as collection of char arrays.
4#
5# Usage: perl <this_file> <file1> [file2, ...] > embedded_data.c
6
7foreach my $i (0 .. $#ARGV) {
8  open FD, '<:raw', $ARGV[$i] or die "Cannot open $ARGV[$i]: $!\n";
9  printf("static const unsigned char v%d[] = {", $i);
10  my $byte;
11  my $j = 0;
12  while (read(FD, $byte, 1)) {
13    if (($j % 12) == 0) {
14      print "\n";
15    }
16    printf ' %#04x,', ord($byte);
17    $j++;
18  }
19  print " 0x00\n};\n";
20  close FD;
21}
22
23print <<EOS;
24
25#include <stddef.h>
26#include <string.h>
27
28static const struct embedded_file {
29  const char *name;
30  const unsigned char *data;
31  size_t size;
32} embedded_files[] = {
33EOS
34
35foreach my $i (0 .. $#ARGV) {
36  print "  {\"$ARGV[$i]\", v$i, sizeof(v$i) - 1},\n";
37}
38
39print <<EOS;
40  {NULL, NULL, 0}
41};
42
43const char *find_embedded_file(const char *name, size_t *size) {
44  const struct embedded_file *p;
45  for (p = embedded_files; p->name != NULL; p++) {
46    if (!strcmp(p->name, name)) {
47      if (size != NULL) { *size = p->size; }
48      return (const char *) p->data;
49    }
50  }
51  return NULL;
52}
53EOS
trunk/3rdparty/mongoose/test/Makefile
r0r250110
1# Copyright (c) 2014 Cesanta Software
2# All rights reserved
3
4PROG = unit_test
5PROF_FLAGS = -fprofile-arcs -ftest-coverage -g -O0 -DGUI
6CFLAGS = -W -Wall -pthread -I.. $(PROF_FLAGS) $(CFLAGS_EXTRA)
7SOURCES = $(PROG).c
8
9all: $(PROG)
10   ./$(PROG)
11   gcov -b $(PROG).c | egrep '^(File|Lines)'
12
13$(PROG): $(SOURCES) Makefile ../mongoose.c clean
14   $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) -ldl -lssl
15
16win:
17   wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /Fe$(PROG).exe
18   wine $(PROG).exe
19
20clean:
21   rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc*
trunk/3rdparty/mongoose/test/unit_test.c
r0r250110
1// Unit test for the mongoose web server.
2// g++ -W -Wall -pedantic -g unit_test.c -lssl && ./a.out
3// cl unit_test.c /MD
4
5#ifndef _WIN32
6#define NS_ENABLE_IPV6
7#define NS_ENABLE_SSL
8#endif
9#define MONGOOSE_POST_SIZE_LIMIT 999
10
11// USE_* definitions must be made before #include "mongoose.c" !
12#include "../mongoose.c"
13
14#define FAIL(str, line) do {                    \
15  printf("Fail on line %d: [%s]\n", line, str); \
16  return str;                                   \
17} while (0)
18
19#define ASSERT(expr) do {             \
20  static_num_tests++;               \
21  if (!(expr)) FAIL(#expr, __LINE__); \
22} while (0)
23
24#define RUN_TEST(test) do { const char *msg = test(); \
25  if (msg) return msg; } while (0)
26
27#define HTTP_PORT "45772"
28#define LISTENING_ADDR "127.0.0.1:" HTTP_PORT
29
30static int static_num_tests = 0;
31
32#if 0
33// Connects to host:port, and sends formatted request to it. Returns
34// malloc-ed reply and reply length, or NULL on error. Reply contains
35// everything including headers, not just the message body.
36static char *wget(const char *host, int port, int *len, const char *fmt, ...) {
37  char buf[2000], *reply = NULL;
38  int request_len, reply_size = 0, n, sock = -1;
39  struct sockaddr_in sin;
40  struct hostent *he = NULL;
41  va_list ap;
42
43  if (host != NULL &&
44      (he = gethostbyname(host)) != NULL &&
45      (sock = socket(PF_INET, SOCK_STREAM, 0)) != -1) {
46    sin.sin_family = AF_INET;
47    sin.sin_port = htons((uint16_t) port);
48    sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
49    if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) == 0) {
50
51      // Format and send the request.
52      va_start(ap, fmt);
53      request_len = vsnprintf(buf, sizeof(buf), fmt, ap);
54      va_end(ap);
55      while (request_len > 0 && (n = send(sock, buf, request_len, 0)) > 0) {
56        request_len -= n;
57      }
58      if (request_len == 0) {
59        *len = 0;
60        while ((n = recv(sock, buf, sizeof(buf), 0)) > 0) {
61          if (*len + n > reply_size) {
62            // Leak possible
63            reply = (char *) realloc(reply, reply_size + sizeof(buf));
64            reply_size += sizeof(buf);
65          }
66          if (reply != NULL) {
67            memcpy(reply + *len, buf, n);
68            *len += n;
69          }
70        }
71      }
72      closesocket(sock);
73    }
74  }
75
76  return reply;
77}
78#endif
79
80static char *read_file(const char *path, int *size) {
81  FILE *fp;
82  struct stat st;
83  char *data = NULL;
84  if ((fp = fopen(path, "rb")) != NULL && !fstat(fileno(fp), &st)) {
85    *size = (int) st.st_size;
86    data = (char *) malloc(*size);
87    fread(data, 1, *size, fp);
88    fclose(fp);
89  }
90  return data;
91}
92
93static const char *test_parse_http_message() {
94  struct mg_connection ri;
95  char req1[] = "GET / HTTP/1.1\r\n\r\n";
96  char req2[] = "BLAH / HTTP/1.1\r\n\r\n";
97  char req3[] = "GET / HTTP/1.1\r\nBah\r\n";
98  char req4[] = "GET / HTTP/1.1\r\nA: foo bar\r\nB: bar\r\nbaz\r\n\r\n";
99  char req5[] = "GET / HTTP/1.1\r\n\r\n";
100  char req6[] = "G";
101  char req7[] = " blah ";
102  char req8[] = " HTTP/1.1 200 OK \n\n";
103  char req9[] = "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n";
104
105  ASSERT(get_request_len("\r\n", 3) == -1);
106  ASSERT(get_request_len("\r\n", 2) == 0);
107  ASSERT(get_request_len("GET", 3) == 0);
108  ASSERT(get_request_len("\n\n", 2) == 2);
109  ASSERT(get_request_len("\n\r\n", 3) == 3);
110  ASSERT(get_request_len("\xdd\xdd", 2) == 0);
111  ASSERT(get_request_len("\xdd\x03", 2) == -1);
112  ASSERT(get_request_len(req3, sizeof(req3) - 1) == 0);
113  ASSERT(get_request_len(req6, sizeof(req6) - 1) == 0);
114  ASSERT(get_request_len(req7, sizeof(req7) - 1) == 0);
115
116  ASSERT(parse_http_message(req9, sizeof(req9) - 1, &ri) == sizeof(req9) - 1);
117  ASSERT(ri.num_headers == 1);
118
119  ASSERT(parse_http_message(req1, sizeof(req1) - 1, &ri) == sizeof(req1) - 1);
120  ASSERT(strcmp(ri.http_version, "1.1") == 0);
121  ASSERT(ri.num_headers == 0);
122
123  ASSERT(parse_http_message(req2, sizeof(req2) - 1, &ri) == (size_t) ~0);
124  ASSERT(parse_http_message(req6, 0, &ri) == (size_t) ~0);
125  ASSERT(parse_http_message(req8, sizeof(req8) - 1, &ri) == sizeof(req8) - 1);
126
127  // TODO(lsm): Fix this. Header value may span multiple lines.
128  ASSERT(parse_http_message(req4, sizeof(req4) - 1, &ri) == sizeof(req4) - 1);
129  ASSERT(strcmp(ri.http_version, "1.1") == 0);
130  ASSERT(ri.num_headers == 3);
131  ASSERT(strcmp(ri.http_headers[0].name, "A") == 0);
132  ASSERT(strcmp(ri.http_headers[0].value, "foo bar") == 0);
133  ASSERT(strcmp(ri.http_headers[1].name, "B") == 0);
134  ASSERT(strcmp(ri.http_headers[1].value, "bar") == 0);
135  ASSERT(strcmp(ri.http_headers[2].name, "baz\r\n\r") == 0);
136  ASSERT(strcmp(ri.http_headers[2].value, "") == 0);
137
138  ASSERT(parse_http_message(req5, sizeof(req5) - 1, &ri) == sizeof(req5) - 1);
139  ASSERT(strcmp(ri.request_method, "GET") == 0);
140  ASSERT(strcmp(ri.http_version, "1.1") == 0);
141
142  return NULL;
143}
144
145static const char *test_should_keep_alive(void) {
146  struct mg_connection conn;
147  char req1[] = "GET / HTTP/1.1\r\n\r\n";
148  char req2[] = "GET / HTTP/1.0\r\n\r\n";
149  char req3[] = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n";
150  char req4[] = "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n";
151
152  memset(&conn, 0, sizeof(conn));
153  ASSERT(parse_http_message(req1, sizeof(req1) - 1, &conn) == sizeof(req1) - 1);
154  ASSERT(should_keep_alive(&conn) != 0);
155
156  parse_http_message(req2, sizeof(req2) - 1, &conn);
157  ASSERT(should_keep_alive(&conn) == 0);
158
159  parse_http_message(req3, sizeof(req3) - 1, &conn);
160  ASSERT(should_keep_alive(&conn) == 0);
161
162  parse_http_message(req4, sizeof(req4) - 1, &conn);
163  ASSERT(should_keep_alive(&conn) != 0);
164
165  return NULL;
166}
167
168static const char *test_match_prefix(void) {
169  ASSERT(mg_match_prefix("/api", 4, "/api") == 4);
170  ASSERT(mg_match_prefix("/a/", 3, "/a/b/c") == 3);
171  ASSERT(mg_match_prefix("/a/", 3, "/ab/c") == -1);
172  ASSERT(mg_match_prefix("/blog/", 6, "/") == -1);
173  ASSERT(mg_match_prefix("/*/", 3, "/ab/c") == 4);
174  ASSERT(mg_match_prefix("**", 2, "/a/b/c") == 6);
175  ASSERT(mg_match_prefix("/*", 2, "/a/b/c") == 2);
176  ASSERT(mg_match_prefix("*/*", 3, "/a/b/c") == 2);
177  ASSERT(mg_match_prefix("**/", 3, "/a/b/c") == 5);
178  ASSERT(mg_match_prefix("**.foo|**.bar", 13, "a.bar") == 5);
179  ASSERT(mg_match_prefix("a|b|cd", 6, "cdef") == 2);
180  ASSERT(mg_match_prefix("a|b|c?", 6, "cdef") == 2);
181  ASSERT(mg_match_prefix("a|?|cd", 6, "cdef") == 1);
182  ASSERT(mg_match_prefix("/a/**.cgi", 9, "/foo/bar/x.cgi") == -1);
183  ASSERT(mg_match_prefix("/a/**.cgi", 9, "/a/bar/x.cgi") == 12);
184  ASSERT(mg_match_prefix("**/", 3, "/a/b/c") == 5);
185  ASSERT(mg_match_prefix("**/$", 4, "/a/b/c") == -1);
186  ASSERT(mg_match_prefix("**/$", 4, "/a/b/") == 5);
187  ASSERT(mg_match_prefix("$", 1, "") == 0);
188  ASSERT(mg_match_prefix("$", 1, "x") == -1);
189  ASSERT(mg_match_prefix("*$", 2, "x") == 1);
190  ASSERT(mg_match_prefix("/$", 2, "/") == 1);
191  ASSERT(mg_match_prefix("**/$", 4, "/a/b/c") == -1);
192  ASSERT(mg_match_prefix("**/$", 4, "/a/b/") == 5);
193  ASSERT(mg_match_prefix("*", 1, "/hello/") == 0);
194  ASSERT(mg_match_prefix("**.a$|**.b$", 11, "/a/b.b/") == -1);
195  ASSERT(mg_match_prefix("**.a$|**.b$", 11, "/a/b.b") == 6);
196  ASSERT(mg_match_prefix("**.a$|**.b$", 11, "/a/B.A") == 6);
197  ASSERT(mg_match_prefix("**o$", 4, "HELLO") == 5);
198  return NULL;
199}
200
201static const char *test_remove_double_dots() {
202  struct { char before[30], after[30]; } data[] = {
203    {"////a", "/a"},
204    {"/.....", "/....."},
205    {"/......", "/......"},
206    {"...", "..."},
207    {"/...///", "/.../"},
208    {"/a...///", "/a.../"},
209    {"/.x", "/.x"},
210    {"/\\", "/"},
211    {"/a\\", "/a\\"},
212    {"/a\\\\...", "/a\\..."},
213    {"foo/x..y/././y/../../..", "foo/x..y/y/"},
214    {"foo/..x", "foo/..x"},
215  };
216  size_t i;
217
218  for (i = 0; i < ARRAY_SIZE(data); i++) {
219    remove_double_dots_and_double_slashes(data[i].before);
220    ASSERT(strcmp(data[i].before, data[i].after) == 0);
221  }
222
223  return NULL;
224}
225
226static const char *test_get_var(void) {
227  static const char *data = "a=1&&b=2&d&=&c=3%20&e=&k=aa&a=23";
228  static const char *data2 = "q=&st=2012%2F11%2F13+17%3A05&et=&team_id=";
229  char buf[20];
230
231  ASSERT(get_var(data, strlen(data), "a", buf, sizeof(buf), 0) == 1);
232  ASSERT(buf[0] == '1' && buf[1] == '\0');
233  ASSERT(get_var(data, strlen(data), "a", buf, sizeof(buf), 1) == 2);
234  ASSERT(strcmp(buf, "23") == 0);
235  ASSERT(get_var(data, strlen(data), "b", buf, sizeof(buf), 0) == 1);
236  ASSERT(buf[0] == '2' && buf[1] == '\0');
237  ASSERT(get_var(data, strlen(data), "c", buf, sizeof(buf), 0) == 2);
238  ASSERT(buf[0] == '3' && buf[1] == ' ' && buf[2] == '\0');
239  ASSERT(get_var(data, strlen(data), "e", buf, sizeof(buf), 0) == 0);
240  ASSERT(buf[0] == '\0');
241
242  ASSERT(get_var(data, strlen(data), "d", buf, sizeof(buf), 0) == -1);
243  ASSERT(get_var(data, strlen(data), "c", buf, 2, 0) == -2);
244
245  ASSERT(get_var(data, strlen(data), "x", NULL, 10, 0) == -2);
246  ASSERT(get_var(data, strlen(data), "x", buf, 0, 0) == -2);
247  ASSERT(get_var(data2, strlen(data2), "st", buf, 16, 0) == -2);
248  ASSERT(get_var(data2, strlen(data2), "st", buf, 17, 0) == 16);
249  return NULL;
250}
251
252static const char *test_url_decode(void) {
253  char buf[100];
254
255  ASSERT(mg_url_decode("foo", 3, buf, 3, 0) == -1);  // No space for \0
256  ASSERT(mg_url_decode("foo", 3, buf, 4, 0) == 3);
257  ASSERT(strcmp(buf, "foo") == 0);
258
259  ASSERT(mg_url_decode("a+", 2, buf, sizeof(buf), 0) == 2);
260  ASSERT(strcmp(buf, "a+") == 0);
261
262  ASSERT(mg_url_decode("a+", 2, buf, sizeof(buf), 1) == 2);
263  ASSERT(strcmp(buf, "a ") == 0);
264
265  ASSERT(mg_url_decode("%61", 1, buf, sizeof(buf), 1) == 1);
266  printf("[%s]\n", buf);
267  ASSERT(strcmp(buf, "%") == 0);
268
269  ASSERT(mg_url_decode("%61", 2, buf, sizeof(buf), 1) == 2);
270  ASSERT(strcmp(buf, "%6") == 0);
271
272  ASSERT(mg_url_decode("%61", 3, buf, sizeof(buf), 1) == 1);
273  ASSERT(strcmp(buf, "a") == 0);
274  return NULL;
275}
276
277static const char *test_url_encode(void) {
278  char buf[100];
279  ASSERT(mg_url_encode("", 0, buf, sizeof(buf)) == 0);
280  ASSERT(buf[0] == '\0');
281  ASSERT(mg_url_encode("foo", 3, buf, sizeof(buf)) == 3);
282  ASSERT(strcmp(buf, "foo") == 0);
283  ASSERT(mg_url_encode("f o", 3, buf, sizeof(buf)) == 5);
284  ASSERT(strcmp(buf, "f%20o") == 0);
285  return NULL;
286}
287
288static const char *test_to64(void) {
289  ASSERT(to64("0") == 0);
290  ASSERT(to64("") == 0);
291  ASSERT(to64("123") == 123);
292  ASSERT(to64("-34") == -34);
293  ASSERT(to64("3566626116") == 3566626116);
294  return NULL;
295}
296
297static const char *test_base64_encode(void) {
298  const char *in[] = {"a", "ab", "abc", "abcd", NULL};
299  const char *out[] = {"YQ==", "YWI=", "YWJj", "YWJjZA=="};
300  char buf[100];
301  int i;
302
303  for (i = 0; in[i] != NULL; i++) {
304    base64_encode((unsigned char *) in[i], strlen(in[i]), buf);
305    ASSERT(!strcmp(buf, out[i]));
306  }
307
308  return NULL;
309}
310
311static const char *test_mg_parse_header(void) {
312  const char *str = "xx=1 kl yy, ert=234 kl=123, uri=\"/?name=x,y\", "
313    "ii=\"12\\\"34\" zz='aa bb',tt=2,gf=\"xx d=1234";
314  char buf[20];
315  ASSERT(mg_parse_header(str, "yy", buf, sizeof(buf)) == 0);
316  ASSERT(mg_parse_header(str, "ert", buf, sizeof(buf)) == 3);
317  ASSERT(strcmp(buf, "234") == 0);
318  ASSERT(mg_parse_header(str, "ert", buf, 2) == 0);
319  ASSERT(mg_parse_header(str, "ert", buf, 3) == 0);
320  ASSERT(mg_parse_header(str, "ert", buf, 4) == 3);
321  ASSERT(mg_parse_header(str, "gf", buf, sizeof(buf)) == 0);
322  ASSERT(mg_parse_header(str, "zz", buf, sizeof(buf)) == 5);
323  ASSERT(strcmp(buf, "aa bb") == 0);
324  ASSERT(mg_parse_header(str, "d", buf, sizeof(buf)) == 4);
325  ASSERT(strcmp(buf, "1234") == 0);
326  buf[0] = 'x';
327  ASSERT(mg_parse_header(str, "MMM", buf, sizeof(buf)) == 0);
328  ASSERT(buf[0] == '\0');
329  ASSERT(mg_parse_header(str, "kl", buf, sizeof(buf)) == 3);
330  ASSERT(strcmp(buf, "123") == 0);
331  ASSERT(mg_parse_header(str, "xx", buf, sizeof(buf)) == 1);
332  ASSERT(strcmp(buf, "1") == 0);
333  ASSERT(mg_parse_header(str, "ii", buf, sizeof(buf)) == 5);
334  ASSERT(strcmp(buf, "12\"34") == 0);
335  ASSERT(mg_parse_header(str, "tt", buf, sizeof(buf)) == 1);
336  ASSERT(strcmp(buf, "2") == 0);
337  ASSERT(mg_parse_header(str, "uri", buf, sizeof(buf)) == 10);
338  return NULL;
339}
340
341static const char *test_next_option(void) {
342  const char *p, *list = "x/8,/y**=1;2k,z";
343  struct vec a, b;
344  int i;
345
346  ASSERT(next_option(NULL, &a, &b) == NULL);
347  for (i = 0, p = list; (p = next_option(p, &a, &b)) != NULL; i++) {
348    ASSERT(i != 0 || (a.ptr == list && a.len == 3 && b.len == 0));
349    ASSERT(i != 1 || (a.ptr == list + 4 && a.len == 4 && b.ptr == list + 9 &&
350                      b.len == 4));
351
352    ASSERT(i != 2 || (a.ptr == list + 14 && a.len == 1 && b.len == 0));
353  }
354  return NULL;
355}
356
357static int evh1(struct mg_connection *conn, enum mg_event ev) {
358  char *buf = (char *) conn->connection_param;
359  int result = MG_FALSE;
360
361  switch (ev) {
362    case MG_CONNECT:
363      mg_printf(conn,  "GET %s HTTP/1.0\r\n\r\n",
364                buf[0] == '1' ? "/cb1" : "/non_exist");
365      result = MG_TRUE;
366      break;
367    case MG_HTTP_ERROR:
368      mg_printf(conn, "HTTP/1.0 404 NF\r\n\r\nERR: %d", conn->status_code);
369      result = MG_TRUE;
370      break;
371    case MG_REQUEST:
372      if (!strcmp(conn->uri, "/cb1")) {
373        mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\n%s %s %s",
374                  (char *) conn->server_param,
375                  buf == NULL ? "?" : "!", conn->remote_ip);
376        result = MG_TRUE;
377      }
378      break;
379    case MG_REPLY:
380      if (buf != NULL) {
381        sprintf(buf + 1, "%.*s", (int) conn->content_len, conn->content);
382      }
383      break;
384    case MG_AUTH:
385      result = MG_TRUE;
386      break;
387    default:
388      break;
389  }
390
391  return result;
392}
393
394static const char *test_server(void) {
395  char buf1[100] = "1", buf2[100] = "2";
396  struct mg_server *server = mg_create_server((void *) "foo", evh1);
397  struct mg_connection *conn;
398
399  ASSERT(server != NULL);
400  ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
401  ASSERT(mg_set_option(server, "document_root", ".") == NULL);
402
403  ASSERT((conn = mg_connect(server, "127.0.0.1:" HTTP_PORT)) != NULL);
404  conn->connection_param = buf1;
405  ASSERT((conn = mg_connect(server, "127.0.0.1:" HTTP_PORT)) != NULL);
406  conn->connection_param = buf2;
407
408  { int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
409  ASSERT(strcmp(buf1, "1foo ? 127.0.0.1") == 0);
410  ASSERT(strcmp(buf2, "2ERR: 404") == 0);
411
412  ASSERT(strcmp(static_config_options[URL_REWRITES * 2], "url_rewrites") == 0);
413  mg_destroy_server(&server);
414  ASSERT(server == NULL);
415  return NULL;
416}
417
418#define DISP "Content-Disposition: form/data; "
419#define CRLF "\r\n"
420#define BOUNDARY "--xyz"
421static const char *test_parse_multipart(void) {
422  char a[100], b[100];
423  const char *p;
424  static const char f1[] = BOUNDARY CRLF DISP "name=f1" CRLF CRLF
425    "some_content" CRLF BOUNDARY CRLF
426    BOUNDARY CRLF DISP "name=f2; filename=\"foo bar.txt\"" CRLF CRLF
427    "another_content" CRLF BOUNDARY CRLF
428    "--" CRLF;
429  int n, n2, len, f1_len = sizeof(f1) - 1;
430
431  ASSERT(mg_parse_multipart("", 0, a, sizeof(a), b, sizeof(b), &p, &len) == 0);
432  ASSERT(mg_parse_multipart("a", 1, a, sizeof(a), b, sizeof(b), &p, &len) == 0);
433  ASSERT((n = mg_parse_multipart(f1, f1_len, a, sizeof(a),
434                                 b, sizeof(b), &p, &len)) > 0);
435  ASSERT(len == 12);
436  ASSERT(memcmp(p, "some_content", len) == 0);
437  ASSERT(strcmp(a, "f1") == 0);
438  ASSERT(b[0] == '\0');
439
440  ASSERT((n2 = mg_parse_multipart(f1 + n, f1_len - n, a, sizeof(a),
441                                  b, sizeof(b), &p, &len)) > 0);
442  ASSERT(len == 15);
443  ASSERT(memcmp(p, "another_content", len) == 0);
444  ASSERT(strcmp(a, "f2") == 0);
445  ASSERT(strcmp(b, "foo bar.txt") == 0);
446
447  ASSERT((n2 = mg_parse_multipart(f1 + n + n2, f1_len - (n + n2), a, sizeof(a),
448                                  b, sizeof(b), &p, &len)) == 0);
449
450  return NULL;
451}
452
453static int evh2(struct mg_connection *conn, enum mg_event ev) {
454  char *file_data, *cp = (char *) conn->connection_param;
455  int file_size, result = MG_FALSE;
456
457  switch (ev) {
458    case MG_AUTH:
459      result = MG_TRUE;
460      break;
461    case MG_CONNECT:
462      mg_printf(conn, "GET /%s HTTP/1.0\r\n\r\n", cp);
463      result = MG_TRUE;
464      break;
465    case MG_REQUEST:
466      break;
467    case MG_REPLY:
468      file_data = read_file("unit_test.c", &file_size);
469      sprintf(cp, "%d %s", (size_t) file_size == conn->content_len &&
470              memcmp(file_data, conn->content, file_size) == 0 ? 1 : 0,
471              conn->query_string == NULL ? "?" : conn->query_string);
472      free(file_data);
473      break;
474    default:
475      break;
476  }
477
478  return result;
479}
480
481static const char *test_mg_set_option(void) {
482  struct mg_server *server = mg_create_server(NULL, NULL);
483  ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
484  ASSERT(mg_get_option(server, "listening_port")[0] != '\0');
485  mg_destroy_server(&server);
486  return NULL;
487}
488
489static const char *test_rewrites(void) {
490  char buf1[100] = "xx", addr[50];
491  struct mg_server *server = mg_create_server(NULL, evh2);
492  struct mg_connection *conn;
493  const char *port;
494
495  ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
496  ASSERT(mg_set_option(server, "document_root", ".") == NULL);
497  ASSERT(mg_set_option(server, "url_rewrites", "/xx=unit_test.c") == NULL);
498  ASSERT((port = mg_get_option(server, "listening_port")) != NULL);
499  snprintf(addr, sizeof(addr), "127.0.0.1:%s", port);
500  ASSERT((conn = mg_connect(server, addr)) != NULL);
501  conn->connection_param = buf1;
502
503  { int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
504
505  ASSERT(strcmp(buf1, "1 ?") == 0);
506  mg_destroy_server(&server);
507  return NULL;
508}
509
510static const char *run_all_tests(void) {
511  RUN_TEST(test_should_keep_alive);
512  RUN_TEST(test_match_prefix);
513  RUN_TEST(test_remove_double_dots);
514  RUN_TEST(test_parse_http_message);
515  RUN_TEST(test_to64);
516  RUN_TEST(test_url_decode);
517  RUN_TEST(test_url_encode);
518  RUN_TEST(test_base64_encode);
519  RUN_TEST(test_mg_parse_header);
520  RUN_TEST(test_get_var);
521  RUN_TEST(test_next_option);
522  RUN_TEST(test_parse_multipart);
523  RUN_TEST(test_mg_set_option);
524  RUN_TEST(test_server);
525  RUN_TEST(test_rewrites);
526  return NULL;
527}
528
529int __cdecl main(void) {
530  const char *fail_msg = run_all_tests();
531  printf("%s, tests run: %d\n", fail_msg ? "FAIL" : "PASS", static_num_tests);
532  return fail_msg == NULL ? EXIT_SUCCESS : EXIT_FAILURE;
533}
trunk/scripts/src/3rdparty.lua
r250109r250110
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--------------------------------------------------
464504-- jsoncpp library objects
465505--------------------------------------------------
466506
trunk/scripts/src/emu.lua
r250109r250110
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",
248250   MAME_DIR .. "src/emu/sound/filter.c",
249251   MAME_DIR .. "src/emu/sound/filter.h",
250252   MAME_DIR .. "src/devices/sound/flt_vol.c",
trunk/scripts/src/main.lua
r250109r250110
116116      "lua",
117117      "lsqlite3",
118118      "jsoncpp",
119      "mongoose",
119120   }
120121
121122   if _OPTIONS["with-bundled-zlib"] then
trunk/src/devices/bus/snes_ctrl/joypad.c
r250109r250110
2020   PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("B")
2121   PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Y")
2222   PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("Select")
23   PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("Start")
23   PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_START ) PORT_NAME("Start")
2424   PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP )
2525   PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN )
2626   PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT )
trunk/src/devices/cpu/am29000/am29ops.h
r250109r250110
956956
957957   if (!FREEZE_MODE)
958958   {
959      m_chc = ((m_exec_ir << 8) & 0xff) | CHC_LS | RA << CHC_TR_SHIFT | CHC_CV;
959      m_chc = ((m_exec_ir << 8) & 0xff) |
960                  CHC_LS |
961                  RA << CHC_TR_SHIFT |
962                  CHC_CV;
963
960964      m_cha = addr;
961965      m_chd = r;
962966
963      if (!(m_cfg & CFG_DW) && INST_SB_BIT)
964      {
965         SET_ALU_BP(addr);
966      }
967      if (!(m_cfg & CFG_DW) && (m_exec_ir & INST_SB_BIT))
968         SET_ALU_BP(addr & 3);
967969   }
968970
969971   m_r[RA] = r;
970972
971973   if (m_cfg & CFG_DW)
972   {
973974      logerror("DW ON A STORE");
974   }
975975}
976976
977977void am29000_cpu_device::LOADL()
r250109r250110
987987void am29000_cpu_device::LOADM()
988988{
989989   UINT32 addr = INST_M_BIT ? I8: GET_RB_VAL;
990   UINT32 r;
990991
991992   if (INST_UA_BIT)
992   {
993993      fatalerror("Am29000: UA bit set on LOAD\n");
994   }
995994
996   UINT32 r;
997995   if (INST_CE_BIT)
998996   {
999997      logerror("Am29000: Attempting a co-processor LOAD!\n");
r250109r250110
10211019   {
10221020      // TODO
10231021      m_chc &= (CHC_CR_MASK << CHC_CR_SHIFT);
1024      m_chc |= ((m_exec_ir << 8) & 0xff) | RA << CHC_TR_SHIFT | CHC_CV;
1022      m_chc |= ((m_exec_ir << 8) & 0xff) |
1023                  RA << CHC_TR_SHIFT |
1024                  CHC_CV;
1025
10251026      m_cha = addr;
10261027      m_chd = r; // ?????
10271028
1028      if (!(m_cfg & CFG_DW) && INST_SB_BIT)
1029      {
1030         SET_ALU_BP(addr);
1031      }
1029      if (!(m_cfg & CFG_DW) && (m_exec_ir & INST_SB_BIT))
1030         SET_ALU_BP(addr & 3);
10321031   }
10331032
10341033   r = RA;
10351034
1036   for (INT32 cnt = 0; cnt <= GET_CHC_CR; ++cnt)
10371035   {
1038      m_r[r] = m_data->read_dword(addr);
1036      int cnt;
1037      for (cnt = 0; cnt <= GET_CHC_CR; ++cnt)
1038      {
1039         m_r[r] = m_data->read_dword(addr);
10391040
10401041//          SET_CHC_CR(cnt - 1);
1041      addr += 4;
1042         addr += 4;
10421043
1043      if (++r == 256)
1044      {
1045         r = 128;
1044         if (++r == 256)
1045            r = 128;
10461046      }
10471047   }
10481048}
r250109r250110
10501050void am29000_cpu_device::STORE()
10511051{
10521052   UINT32 addr = INST_M_BIT ? I8: GET_RB_VAL;
1053//  UINT32 r;
10531054
10541055   if (INST_UA_BIT)
1055   {
10561056      fatalerror("Am29000: UA bit set on LOAD\n");
1057   }
10581057
10591058   if (INST_CE_BIT)
10601059   {
10611060      logerror("Am29000: Attempting a co-processor LOAD!\n");
1061//      r = 0;
10621062   }
10631063   else
10641064   {
r250109r250110
10731073            SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
10741074            return;
10751075         }
1076
10761077      }
10771078   }
10781079
r250109r250110
10801081
10811082   if (!FREEZE_MODE)
10821083   {
1083      m_chc = ((m_exec_ir << 8) & 0xff) | RA << CHC_TR_SHIFT | CHC_CV;
1084      m_chc = ((m_exec_ir << 8) & 0xff) |
1085                  RA << CHC_TR_SHIFT |
1086                  CHC_CV;
1087
10841088      m_cha = addr;
10851089
1086      if (!(m_cfg & CFG_DW) && INST_SB_BIT)
1087      {
1088         SET_ALU_BP(addr);
1089      }
1090      if (!(m_cfg & CFG_DW) && (m_exec_ir & INST_SB_BIT))
1091         SET_ALU_BP(addr & 3);
10901092   }
10911093
10921094   if (m_cfg & CFG_DW)
1093   {
10941095      logerror("DW ON A STORE");
1095   }
10961096}
10971097
10981098void am29000_cpu_device::STOREL()
r250109r250110
11031103void am29000_cpu_device::STOREM()
11041104{
11051105   UINT32 addr = INST_M_BIT ? I8: GET_RB_VAL;
1106   UINT32 r;
11061107
11071108   if (INST_UA_BIT)
1108   {
11091109      fatalerror("Am29000: UA bit set on LOAD\n");
1110   }
11111110
1112   UINT32 r;
11131111   if (INST_CE_BIT)
11141112   {
11151113      logerror("Am29000: Attempting a co-processor LOAD!\n");
r250109r250110
11281126            SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
11291127            return;
11301128         }
1129
11311130      }
11321131   }
11331132
r250109r250110
11351134   {
11361135      // TODO
11371136      m_chc &= (CHC_CR_MASK << CHC_CR_SHIFT);
1138      m_chc |= ((m_exec_ir << 8) & 0xff) | RA << CHC_TR_SHIFT | CHC_CV;
1137      m_chc |= ((m_exec_ir << 8) & 0xff) |
1138                  RA << CHC_TR_SHIFT |
1139                  CHC_CV;
1140
11391141      m_cha = addr;
11401142
1141      if (!(m_cfg & CFG_DW) && INST_SB_BIT)
1142      {
1143         SET_ALU_BP(addr);
1144      }
1143      if (!(m_cfg & CFG_DW) && (m_exec_ir & INST_SB_BIT))
1144         SET_ALU_BP(addr & 3);
11451145   }
11461146
11471147   r = RA;
11481148
1149   for (INT32 cnt = 0; cnt <= GET_CHC_CR; ++cnt)
11501149   {
1151      m_data->write_dword(addr, m_r[r]);
1150      int cnt;
1151      for (cnt = 0; cnt <= GET_CHC_CR; ++cnt)
1152      {
1153         m_data->write_dword(addr, m_r[r]);
11521154
1153      addr += 4;
1155//          SET_CHC_CR(cnt - 1);
1156         addr += 4;
11541157
1155      if (++r == 256)
1156      {
1157         r = 128;
1158         if (++r == 256)
1159            r = 128;
11581160      }
11591161   }
11601162}
trunk/src/devices/cpu/avr8/avr8dasm.c
r250109r250110
592592               switch(op & 0x0007)
593593               {
594594                  case 0x0000:
595                     output += sprintf( output, "BRLO    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
595                     output += sprintf( output, "BRLO    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
596596                     break;
597597                  case 0x0001:
598                     output += sprintf( output, "BREQ    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
598                     output += sprintf( output, "BREQ    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
599599                     break;
600600                  case 0x0002:
601                     output += sprintf( output, "BRMI    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
601                     output += sprintf( output, "BRMI    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
602602                     break;
603603                  case 0x0003:
604                     output += sprintf( output, "BRVS    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
604                     output += sprintf( output, "BRVS    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
605605                     break;
606606                  case 0x0004:
607                     output += sprintf( output, "BRLT    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
607                     output += sprintf( output, "BRLT    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
608608                     break;
609609                  case 0x0005:
610                     output += sprintf( output, "BRHS    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
610                     output += sprintf( output, "BRHS    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
611611                     break;
612612                  case 0x0006:
613                     output += sprintf( output, "BRTS    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
613                     output += sprintf( output, "BRTS    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
614614                     break;
615615                  case 0x0007:
616                     output += sprintf( output, "BRIE    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
616                     output += sprintf( output, "BRIE    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
617617                     break;
618618               }
619619               break;
r250109r250110
621621               switch(op & 0x0007)
622622               {
623623                  case 0x0000:
624                     output += sprintf( output, "BRSH    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
624                     output += sprintf( output, "BRSH    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
625625                     break;
626626                  case 0x0001:
627                     output += sprintf( output, "BRNE    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
627                     output += sprintf( output, "BRNE    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
628628                     break;
629629                  case 0x0002:
630                     output += sprintf( output, "BRPL    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
630                     output += sprintf( output, "BRPL    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
631631                     break;
632632                  case 0x0003:
633                     output += sprintf( output, "BRVC    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
633                     output += sprintf( output, "BRVC    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
634634                     break;
635635                  case 0x0004:
636                     output += sprintf( output, "BRGE    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
636                     output += sprintf( output, "BRGE    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
637637                     break;
638638                  case 0x0005:
639                     output += sprintf( output, "BRHC    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
639                     output += sprintf( output, "BRHC    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
640640                     break;
641641                  case 0x0006:
642                     output += sprintf( output, "BRTC    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
642                     output += sprintf( output, "BRTC    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
643643                     break;
644644                  case 0x0007:
645                     output += sprintf( output, "BRID    %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1) );
645                     output += sprintf( output, "BRID    %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) );
646646                     break;
647647               }
648648               break;
trunk/src/devices/cpu/e132xs/e132xs.c
r250109r250110
31413141
31423142         case 2:
31433143
3144            load = READ_HW(EXTRA_S);
3144            load = READ_HW(EXTRA_S & ~1);
31453145
31463146            if( EXTRA_S & 1 ) // LDHS.A
31473147            {
r250109r250110
34173417
34183418         case 2:
34193419
3420            WRITE_HW(EXTRA_S, SREG & 0xffff);
3420            WRITE_HW(EXTRA_S & ~1, SREG & 0xffff);
34213421
34223422            /*
34233423            if( EXTRA_S & 1 ) // STHS.A
trunk/src/devices/cpu/hd61700/hd61700.c
r250109r250110
508508            case 0x15:  //psr
509509               {
510510                  UINT8 arg = read_op();
511                  WRITE_SREG(arg, READ_REG(arg));
511                  WRITE_SREG(arg, READ_REG(arg)&0x1f);
512512
513513                  check_optional_jr(arg);
514514                  m_icount -= 3;
r250109r250110
10381038            case 0x55:  //psr
10391039               {
10401040                  UINT8 arg = read_op();
1041                  WRITE_SREG(arg, arg);
1041                  WRITE_SREG(arg, arg&0x1f);
10421042
10431043                  m_icount -= 3;
10441044               }
r250109r250110
28932893   }
28942894   else
28952895   {
2896      return READ_SREG(arg);
2896      return READ_SREG(arg)&0x1f;
28972897   }
28982898}
28992899
r250109r250110
29052905   }
29062906   else
29072907   {
2908      return READ_SREG(arg);
2908      return READ_SREG(arg)&0x1f;
29092909   }
29102910}
29112911
trunk/src/devices/cpu/score/scoredsm.c
r250109r250110
224224         buffer += sprintf(buffer, "j%s! 0x%08x", GET_J_LK(opcode) ? "l": "", (pc & 0xfffff000) | (GET_J_DISP11(opcode) << 1));
225225         break;
226226      case 0x04:
227         buffer += sprintf(buffer, "b%s! 0x%08x", m_cond[GET_BX_EC(opcode)], pc + sign_extend(GET_BX_DISP8(opcode) << 1, 9));
227         buffer += sprintf(buffer, "b%s! 0x%08x", m_cond[GET_BX_EC(opcode) & 0x0f], pc + sign_extend(GET_BX_DISP8(opcode) << 1, 9));
228228         break;
229229      case 0x05:
230230         buffer += sprintf(buffer, "ldiu! r%d, 0x%02x", GET_I2_RD(opcode), GET_I2_IMM8(opcode));
trunk/src/devices/cpu/tms7000/tms70op.inc
r250109r250110
252252{
253253   m_icount -= 39;
254254   UINT16 t = param1 * param2;
255   SET_CNZ(t >> 8);
255   SET_CNZ(t >> 8 & 0xff);
256256   write_mem16(0, t); // always writes result to regs A-B
257257   return WB_NO;
258258}
r250109r250110
502502   m_icount -= 15;
503503   UINT16 t = imm16();
504504   write_r16(imm8(), t);
505   SET_CNZ(t >> 8);
505   SET_CNZ(t >> 8 & 0xff);
506506}
507507
508508void tms7000_device::movd_inx()
r250109r250110
510510   m_icount -= 17;
511511   UINT16 t = imm16() + read_r8(1);
512512   write_r16(imm8(), t);
513   SET_CNZ(t >> 8);
513   SET_CNZ(t >> 8 & 0xff);
514514}
515515
516516void tms7000_device::movd_ind()
r250109r250110
518518   m_icount -= 14;
519519   UINT16 t = read_r16(imm8());
520520   write_r16(imm8(), t);
521   SET_CNZ(t >> 8);
521   SET_CNZ(t >> 8 & 0xff);
522522}
523523
524524// long branch
trunk/src/devices/machine/mos6530n.c
r250109r250110
5858
5959DEVICE_ADDRESS_MAP_START( io_map, 8, mos6532_t )
6060   ADDRESS_MAP_GLOBAL_MASK(0x1f)
61   AM_RANGE(0x00, 0x00) AM_MIRROR(0x18) AM_READWRITE(pa_data_r, pa_data_w)  // SWCHA
62   AM_RANGE(0x01, 0x01) AM_MIRROR(0x18) AM_READWRITE(pa_ddr_r, pa_ddr_w)    // SWACNT
63   AM_RANGE(0x02, 0x02) AM_MIRROR(0x18) AM_READWRITE(pb_data_r, pb_data_w)  // SWCHB
64   AM_RANGE(0x03, 0x03) AM_MIRROR(0x18) AM_READWRITE(pb_ddr_r, pb_ddr_w)    // SWBCNT
61   AM_RANGE(0x00, 0x00) AM_MIRROR(0x18) AM_READWRITE(pa_data_r, pa_data_w)
62   AM_RANGE(0x01, 0x01) AM_MIRROR(0x18) AM_READWRITE(pa_ddr_r, pa_ddr_w)
63   AM_RANGE(0x02, 0x02) AM_MIRROR(0x18) AM_READWRITE(pb_data_r, pb_data_w)
64   AM_RANGE(0x03, 0x03) AM_MIRROR(0x18) AM_READWRITE(pb_ddr_r, pb_ddr_w)
6565   AM_RANGE(0x14, 0x17) AM_WRITE(timer_off_w)
6666   AM_RANGE(0x1c, 0x1f) AM_WRITE(timer_on_w)
6767   AM_RANGE(0x04, 0x04) AM_MIRROR(0x12) AM_READ(timer_off_r)
r250109r250110
276276
277277void mos6530_base_t::device_reset()
278278{
279   m_pa_out = 0xff;
279   m_pa_out = 0;
280280   m_pa_ddr = 0;
281   m_pb_out = 0xff; // a7800 One-On-One Basketball (1on1u) needs this or you can't start a game, it doesn't initialize it.  (see MT6060)
281   m_pb_out = 0;
282282   m_pb_ddr = 0;
283283
284284   m_ie_timer = false;
trunk/src/devices/video/315_5313.c
r250109r250110
14521452
14531453                     xxx = (xpos+xtile*8)&0x1ff;
14541454
1455                     gfxdata = MEGADRIV_VDP_VRAM(base_addr+1) | (MEGADRIV_VDP_VRAM(base_addr)<<16);
1455                     gfxdata = MEGADRIV_VDP_VRAM((base_addr+1)&0x7fff) | (MEGADRIV_VDP_VRAM((base_addr+0)&0x7fff)<<16);
14561456
14571457                     for(loopcount=0;loopcount<8;loopcount++)
14581458                     {
trunk/src/devices/video/mc6845.c
r250109r250110
10321032   m_max_ras_addr = 0x1f;
10331033   m_vert_char_total = 0x7f;
10341034
1035   m_supports_disp_start_addr_r = false;  // MC6845 can not read Display Start (double checked on datasheet)
1035   m_supports_disp_start_addr_r = true;
10361036   m_supports_vert_sync_width = false;
10371037   m_supports_status_reg_d5 = false;
10381038   m_supports_status_reg_d6 = false;
r250109r250110
11681168{
11691169   mc6845_device::device_start();
11701170
1171   m_supports_disp_start_addr_r = true;  // HD6845S can definitely read Display Start (double checked on datasheet)
1171   m_supports_disp_start_addr_r = false;
11721172   m_supports_vert_sync_width = true;
11731173   m_supports_status_reg_d5 = false;
11741174   m_supports_status_reg_d6 = false;
trunk/src/emu/debug/debugcpu.c
r250109r250110
19311931         // flush any pending updates before waiting again
19321932         machine.debug_view().flush_osd_updates();
19331933
1934         machine.manager().web()->serve();
1935
19341936         // clear the memory modified flag and wait
19351937         global->memory_modified = false;
19361938         if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED)
trunk/src/emu/emuopts.c
r250109r250110
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" },
188192   { NULL }
189193};
190194
trunk/src/emu/emuopts.h
r250109r250110
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
192197//**************************************************************************
193198//  TYPE DEFINITIONS
194199//**************************************************************************
r250109r250110
361366   int autoboot_delay() const { return int_value(OPTION_AUTOBOOT_DELAY); }
362367   const char *autoboot_script() const { return value(OPTION_AUTOBOOT_SCRIPT); }
363368
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
364374   // FIXME: Couriersud: This should be in image_device_exit
365375   void remove_device_options();
366376
trunk/src/emu/luaengine.c
r250109r250110
1717#include "osdepend.h"
1818#include "drivenum.h"
1919#include "ui/ui.h"
20#include "mongoose/mongoose.h"
2021
2122//**************************************************************************
2223//  LUA ENGINE
r250109r250110
861862   } while (1);
862863}
863864
864/*
865865static void *serve_lua(void *param)
866866{
867867   lua_engine *engine = (lua_engine *)param;
868868   engine->serve_lua();
869869   return NULL;
870870}
871*/
872871
872
873873//-------------------------------------------------
874874//  lua_engine - constructor
875875//-------------------------------------------------
r250109r250110
10251025
10261026void lua_engine::start_console()
10271027{
1028   mg_start_thread(::serve_lua, this);
10281029}
10291030
10301031//-------------------------------------------------
trunk/src/emu/machine.c
r250109r250110
393393         js_set_main_loop(this);
394394#endif
395395
396         manager().web()->serve();
397
396398         // execute CPUs if not paused
397399         if (!m_paused)
398400            m_scheduler.timeslice();
trunk/src/emu/mame.c
r250109r250110
117117machine_manager::machine_manager(emu_options &options,osd_interface &osd)
118118      : m_osd(osd),
119119      m_options(options),
120      m_web(options),
120121      m_new_driver_pending(NULL),
121122      m_machine(NULL)
122123{
r250109r250110
154155void machine_manager::update_machine()
155156{
156157   m_lua.set_machine(m_machine);
158   m_web.set_machine(m_machine);
159   if (m_machine!=NULL) m_web.push_message("update_machine");
157160}
158161
159162/*-------------------------------------------------
r250109r250110
172175   int error = MAMERR_NONE;
173176
174177   m_lua.initialize();
178   if (m_options.console()) {
179      m_lua.start_console();
180   }
175181   while (error == MAMERR_NONE && !exit_pending)
176182   {
177183      m_new_driver_pending = NULL;
trunk/src/emu/mame.h
r250109r250110
1818
1919#include <time.h>
2020
21#include "webengine.h"
22
2123class osd_interface;
2224
2325//**************************************************************************
r250109r250110
8789
8890   osd_interface &osd() const;
8991   emu_options &options() const { return m_options; }
92   web_engine *web() { return &m_web; }
9093   lua_engine *lua() { return &m_lua; }
9194
9295   running_machine *machine() { return m_machine; }
r250109r250110
102105   osd_interface &         m_osd;                  // reference to OSD system
103106   emu_options &           m_options;              // reference to options
104107
108   web_engine              m_web;
105109   lua_engine              m_lua;
106110
107111   const game_driver *     m_new_driver_pending;   // pointer to the next pending driver
trunk/src/emu/ui/ui.c
r250109r250110
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();
377378         machine().video().frame_update();
378379      }
379380
trunk/src/emu/webengine.c
r0r250110
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
r0r250110
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__ */
trunk/src/mame/arcade.lst
r250109r250110
1210012100adonis          // (c) 1998
1210112101adonisa         // (c) 1998
1210212102swheart2        // (c) 1998
12103thgamblr        // (c) 1998
1210412103reelrock        // (c) 1998
1210512104indiandr        // (c) 1998
1210612105chariotc        // (c) 1998
r250109r250110
1211112110magicmska       // (c) 2000
1211212111margmgc         // (c) 2000
1211312112marmagic        // (c) 2000
12114prtygras        // (c) 2001
1211512113geishanz        // (c) 2001
1211612114adonise         // (c) 2001
1211712115koalamnt        // (c) 2001
r250109r250110
1323913237// Atari TTL logic games + roms
1324013238antiairc        // (c) 1975 Atari
1324113239crashnsc        // (c) 1975 Atari
13242indy4           // (c) 1976 Atari / Kee
13240indy4           // (c) 1976 Atari
1324313241indy800         // (c) 1975 Atari / Kee
1324413242jetfight        // (c) 1975 Atari
1324513243jetfighta       // (c) 1975 Atari
1324613244outlaw          // (c) 1976 Atari
13247sharkjaw        // (c) 1975 Atari / Horror Games
13245sharkjaw        // (c) 1975 Atari
1324813246steeplec        // (c) 1975 Atari
1324913247stuntcyc        // (c) 1976 Atari
13250tank            // (c) 1974 Atari / Kee
13251tankii          // (c) 1975 Atari / Kee
13248tank            // (c) 1974 Atari
1325213249
1325313250// Atari TTL Missing Rom Dumps
13254//astrotrf      // (c) 1975 Atari
13255//lemans        // (c) 1974 Atari
13256//gtrak10       // (c) 1974 Atari / Kee
13257//gtrak20       // (c) 1976 Atari / Kee
13258//qwak          // (c) 1974 Atari
13251//astrotrf
13252//lemans
13253//gtrak10
13254//gtrak20
13255//quack
1325913256
1326013257// Atari 100% TTL
1326113258pong            // (c) 1972 Atari
13259pongd           // (c) 1975 Atari
1326213260pongf           // (c) 1972 Atari
13263pongd           // (c) 1973 Atari
1326413261breakout        // (c) 1976 Atari
13265//cktpong       // (c) 1974 Atari / National Entertainment Co.
13266//coupedav      // (c) 1973 Atari France
13267//coupfran      // (c) 1974 Atari Europe
13268//drpong        // (c) 1974 Atari
13269//pupppong      // (c) 1974 Atari
13270//snoopong      // (c) 1974 Atari
13271//suprpong      // (c) 1974 Atari
13272//breakckt      // (c) 1976 Atari
13273//consolet      // (c) 1976 Atari Europe
13274//crossfir      // (c) 1975 Atari / Kee
13275//eliminat      // (c) 1973 Atari / Kee
13276//goaliv        // (c) 1975 Atari
13277//gotchaat      // (c) 1973 Atari
13278//gotchaatc     // (c) 1973 Atari
13279//hiway         // (c) 1975 Atari
13280//pinpong       // (c) 1974 Atari
13281//pursuit       // (c) 1975 Atari / Kee
13282//quadpong      // (c) 1974 Atari
13283//rebound       // (c) 1974 Atari / Kee
13284//spacrace      // (c) 1973 Atari
13285//touchme       // (c) 1974 Atari
13286//worldcup      // (c) 1974 Atari
13262//coupedem
13263//goal4
13264//gotchaat
13265//gotchaatc
13266//highway
13267//pinpong
13268//pursuit
13269//quadpong
13270//rebound
13271//spacrace
13272//touchme
1328713273
1328813274// Meadows TTL
13289bombaway      // (c) 1976 Meadows
13290ckidzo        // (c) 1976 Meadows
13291cgunship      // (c) 1976 Meadows
13292mead4in1      // (c) 197? Meadows
13275bombaway
13276ckidzo
13277cgunship
13278mead4in1
1329313279
1329413280// Misc TTL + roms
13281tv21          // (c) 197? A-1 Supply
13282tv21_3        // (c) 197? A-1 Supply
13283tvpoker       // (c) 197? A-1 Supply
1329513284sburners      // (c) 1975 Allied Leisure
1329613285fun4          // (c) 1976 Bailey
1329713286fun4a         // (c) 1976 Bailey
r250109r250110
1330313292biplane4      // (c) 1976 Fun Games
1330413293take5         // (c) 1975 Fun Games
1330513294dpatrol       // (c) 1977 PSE
13306//knightar    // (c) 1976 PSE
13307//gametree    // (c) 1978 PSE
1330813295vollyrmt      // (c) 1973 Ramtek
1330913296hockyrmt      // (c) 1973 Ramtek
1331013297soccrrmt      // (c) 1973 Ramtek
r250109r250110
1332113308ttblock       // (c) 1977 Taito
1332213309zzblock       // (c) 1979 Taito
1332313310
13324// A-1 Supply
13325tv21          // (c) 197? A-1 Supply
13326tv21_3        // (c) 197? A-1 Supply
13327tvpoker       // (c) 197? A-1 Supply
13328
1332913311// JPM System 5 + Video Expansion 2
1333013312monopoly    // Monopoly (JPM)
1333113313monopolya   // Monopoly (JPM)
trunk/src/mame/drivers/a2600.c
r250109r250110
1010
1111***************************************************************************/
1212
13// the new RIOT does not work with the SuperCharger
14// for example "mame64 a2600 scharger -cass offifrog" fails to load after playing the tape
15#define USE_NEW_RIOT 0
16
17
1813#include "emu.h"
19
14#include "machine/mos6530n.h"
2015#include "cpu/m6502/m6507.h"
2116#include "sound/tiaintf.h"
2217#include "video/tia.h"
r250109r250110
2823#include "bus/vcs/compumat.h"
2924#include "bus/vcs_ctrl/ctrl.h"
3025
31
32
33#if USE_NEW_RIOT
34#include "machine/mos6530n.h"
35#else
36#include "machine/6532riot.h"
37#endif
38
39
4026#define CONTROL1_TAG    "joyport1"
4127#define CONTROL2_TAG    "joyport2"
4228
4329
44
4530class a2600_state : public driver_device
4631{
4732public:
r250109r250110
8873   required_device<m6507_device> m_maincpu;
8974   required_device<screen_device> m_screen;
9075   required_ioport m_swb;
91#if USE_NEW_RIOT
9276   required_device<mos6532_t> m_riot;
93#else
94   required_device<riot6532_device> m_riot;
95#endif
96   
9777};
9878
9979
r250109r250110
10888static ADDRESS_MAP_START(a2600_mem, AS_PROGRAM, 8, a2600_state ) // 6507 has 13-bit address space, 0x0000 - 0x1fff
10989   AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x0f00) AM_DEVREADWRITE("tia_video", tia_video_device, read, write)
11090   AM_RANGE(0x0080, 0x00ff) AM_MIRROR(0x0d00) AM_RAM AM_SHARE("riot_ram")
111#if USE_NEW_RIOT
11291   AM_RANGE(0x0280, 0x029f) AM_MIRROR(0x0d00) AM_DEVICE("riot", mos6532_t, io_map)
113#else
114   AM_RANGE(0x0280, 0x029f) AM_MIRROR(0x0d00) AM_DEVREADWRITE("riot", riot6532_device, read, write)
115#endif
11692   // AM_RANGE(0x1000, 0x1fff) is cart data and it is configured at reset time, depending on the mounted cart!
11793ADDRESS_MAP_END
11894
r250109r250110
140116   }
141117   else if (masked_offset < 0x2a0)
142118   {
143#if USE_NEW_RIOT
144119      ret = m_riot->io_r(space, masked_offset);
145#else
146      ret = m_riot->read(space, masked_offset);
147#endif
148120   }
149121   else if (masked_offset < 0x300)
150122   {
r250109r250110
176148   }
177149   else if (masked_offset < 0x2a0)
178150   {
179#if USE_NEW_RIOT
180151      m_riot->io_w(space, masked_offset, data);
181#else
182      m_riot->write(space, masked_offset, data);
183#endif
184152   }
185153   else if (masked_offset < 0x300)
186154   {
r250109r250110
595563   MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.90)
596564
597565   /* devices */
598#if USE_NEW_RIOT
599566   MCFG_DEVICE_ADD("riot", MOS6532n, MASTER_CLOCK_NTSC / 3)
600    MCFG_MOS6530n_IN_PA_CB(READ8(a2600_state, switch_A_r))
601    MCFG_MOS6530n_OUT_PA_CB(WRITE8(a2600_state, switch_A_w))
602    MCFG_MOS6530n_IN_PB_CB(READ8(a2600_state, riot_input_port_8_r))
603    MCFG_MOS6530n_OUT_PB_CB(WRITE8(a2600_state, switch_B_w))
604    MCFG_MOS6530n_IRQ_CB(WRITELINE(a2600_state, irq_callback))
605#else
606   MCFG_DEVICE_ADD("riot", RIOT6532, MASTER_CLOCK_NTSC / 3)   
607   MCFG_RIOT6532_IN_PA_CB(READ8(a2600_state, switch_A_r))
608   MCFG_RIOT6532_OUT_PA_CB(WRITE8(a2600_state, switch_A_w))
609   MCFG_RIOT6532_IN_PB_CB(READ8(a2600_state, riot_input_port_8_r))
610   MCFG_RIOT6532_OUT_PB_CB(WRITE8(a2600_state, switch_B_w))
611   MCFG_RIOT6532_IRQ_CB(WRITELINE(a2600_state, irq_callback))
612#endif
567   MCFG_MOS6530n_IN_PA_CB(READ8(a2600_state, switch_A_r))
568   MCFG_MOS6530n_OUT_PA_CB(WRITE8(a2600_state, switch_A_w))
569   MCFG_MOS6530n_IN_PB_CB(READ8(a2600_state, riot_input_port_8_r))
570   MCFG_MOS6530n_OUT_PB_CB(WRITE8(a2600_state, switch_B_w))
571   MCFG_MOS6530n_IRQ_CB(WRITELINE(a2600_state, irq_callback))
613572
614573   MCFG_VCS_CONTROL_PORT_ADD(CONTROL1_TAG, vcs_control_port_devices, "joy")
615574   MCFG_VCS_CONTROL_PORT_ADD(CONTROL2_TAG, vcs_control_port_devices, NULL)
r250109r250110
645604   MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.90)
646605
647606   /* devices */
648#if USE_NEW_RIOT
649    MCFG_DEVICE_ADD("riot", MOS6532n, MASTER_CLOCK_PAL / 3)
650    MCFG_MOS6530n_IN_PA_CB(READ8(a2600_state, switch_A_r))
651    MCFG_MOS6530n_OUT_PA_CB(WRITE8(a2600_state, switch_A_w))
652    MCFG_MOS6530n_IN_PB_CB(READ8(a2600_state, riot_input_port_8_r))
653    MCFG_MOS6530n_OUT_PB_CB(WRITE8(a2600_state, switch_B_w))
654    MCFG_MOS6530n_IRQ_CB(WRITELINE(a2600_state, irq_callback))
655#else
656   MCFG_DEVICE_ADD("riot", RIOT6532, MASTER_CLOCK_PAL / 3)
657   MCFG_RIOT6532_IN_PA_CB(READ8(a2600_state, switch_A_r))
658   MCFG_RIOT6532_OUT_PA_CB(WRITE8(a2600_state, switch_A_w))
659   MCFG_RIOT6532_IN_PB_CB(READ8(a2600_state, riot_input_port_8_r))
660   MCFG_RIOT6532_OUT_PB_CB(WRITE8(a2600_state, switch_B_w))
661   MCFG_RIOT6532_IRQ_CB(WRITELINE(a2600_state, irq_callback))
662#endif
607   MCFG_DEVICE_ADD("riot", MOS6532n, MASTER_CLOCK_PAL / 3)
608   MCFG_MOS6530n_IN_PA_CB(READ8(a2600_state, switch_A_r))
609   MCFG_MOS6530n_OUT_PA_CB(WRITE8(a2600_state, switch_A_w))
610   MCFG_MOS6530n_IN_PB_CB(READ8(a2600_state, riot_input_port_8_r))
611   MCFG_MOS6530n_OUT_PB_CB(WRITE8(a2600_state, switch_B_w))
612   MCFG_MOS6530n_IRQ_CB(WRITELINE(a2600_state, irq_callback))
663613
664614   MCFG_VCS_CONTROL_PORT_ADD(CONTROL1_TAG, vcs_control_port_devices, "joy")
665615   MCFG_VCS_CONTROL_PORT_ADD(CONTROL2_TAG, vcs_control_port_devices, NULL)
trunk/src/mame/drivers/aristmk5.c
r250109r250110
11151115   ROM_REGION( 0x20000*4, "sram", ROMREGION_ERASE00 )
11161116ROM_END
11171117
1118// MV4084/1 - 10 Credit Multiplier / 9 Line Multiline.
1119// THE GAMBLER - Export  A - 30/10/98.
1120// Marked as EHG0916 and 92.268%.
1121// All devices are 27c4002 instead of 27c4096.
1122ROM_START( thgamblr )
1123   ARISTOCRAT_MK5_BIOS
1124   ROM_REGION( 0x400000, "game_prg", ROMREGION_ERASEFF )
1125   ROM_LOAD32_WORD( "ehg0916_the_gambler.u7",  0x000000, 0x80000, CRC(7524c954) SHA1(0a895d1e2d09a2c873bbbbeb37bc59c25f3c577c) )  // 92.268%
1126   ROM_LOAD32_WORD( "ehg0916_the_gambler.u11", 0x000002, 0x80000, CRC(f29a6932) SHA1(17761218a04d36a599c987b4e13c0e3f46b7793f) )  // 92.268%
1127   ROM_LOAD32_WORD( "ehg0916_the_gambler.u8",  0x100000, 0x80000, CRC(e2221fdf) SHA1(8a7b2d5de68ae66fe1915a6faac6277249e3fb53) )  // base
1128   ROM_LOAD32_WORD( "ehg0916_the_gambler.u12", 0x100002, 0x80000, CRC(ebe957f9) SHA1(539945ec9beafe2c83051208370588fce2334f16) )  // base
1129
1130   ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASE00 ) /* ARM Code */
1131
1132   ROM_REGION( 0x200000, "vram", ROMREGION_ERASE00 )
1133
1134   ROM_REGION( 0x20000*4, "sram", ROMREGION_ERASE00 )
1135ROM_END
1136
11371118// MV4098 - 10 Credit Multiplier / 9 Line Multiline.
11381119// BOOT SCOOTIN' - Export A - 25/08/99.
11391120// All devices are 27c4002 instead of 27c4096.
r250109r250110
12771258   ROM_REGION( 0x20000*4, "sram", ROMREGION_ERASE00 )
12781259ROM_END
12791260
1280// MV4115/3 - 20 Line Multiline / 3,5,10,20,25,50 Credit Multiplier.
1281// Party Gras - Export  B - 06/02/2001.
1282// Marked as BHG1284 and touch.
1283ROM_START( prtygras )
1284   ARISTOCRAT_MK5_BIOS
1285   ROM_REGION( 0x400000, "game_prg", ROMREGION_ERASEFF )
1286   ROM_LOAD32_WORD( "bhg1284_party_grass.u7",  0x000000, 0x80000, CRC(02ed0631) SHA1(ae2c89c876a030d325ec94490d293deba772630e) )
1287   ROM_LOAD32_WORD( "bhg1284_party_grass.u11", 0x000002, 0x80000, CRC(7ac80cd9) SHA1(70e910784a1e1ea8820005082e76223a85a3c346) )
1288   ROM_LOAD32_WORD( "bhg1284_party_grass.u8",  0x100000, 0x80000, CRC(28774b9a) SHA1(ebdd738a73ffa7c5238640f4d7956751f7bb6243) )
1289   ROM_LOAD32_WORD( "bhg1284_party_grass.u12", 0x100002, 0x80000, CRC(942835c1) SHA1(fefc509311716559ac6b836a56b2c981907d499b) )
1290
1291   ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASE00 ) /* ARM Code */
1292
1293   ROM_REGION( 0x200000, "vram", ROMREGION_ERASE00 )
1294
1295   ROM_REGION( 0x20000*4, "sram", ROMREGION_ERASE00 )
1296ROM_END
1297
12981261// MV4115/6 - 9/20 Line Multiline Multiplier.
12991262// Party Gras [Reel Game] - Export A - 10/11/2001.
13001263// All devices are 27c4002 instead of 27c4096.
r250109r250110
13441307GAME( 1998, adonisa,   adonis,   aristmk5,     aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "Adonis (0100751V, NSW/ACT)",                     MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // 602/9,    A - 25/05/98, Rev 9
13451308GAME( 1998, swheart2,  aristmk5, aristmk5_usa, aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "Sweet Hearts II (PHG0742, Export, 92.252%)",     MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // MV4061,   A - 29/06/98
13461309GAME( 1998, reelrock,  0,        aristmk5,     aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "Reelin-n-Rockin (0100779V, Local)",              MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // 628,      A - 13/07/98
1347GAME( 1998, thgamblr,  aristmk5, aristmk5_usa, aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "The Gambler (EHG0916, Export, 92.268%)",         MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // MV4084/1, A - 30/10/98
13481310GAME( 1998, indiandr,  0,        aristmk5,     aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "Indian Dreaming (0100845V, Local)",              MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // 628/1,    B - 15/12/98
13491311GAME( 1998, chariotc,  0,        aristmk5,     aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "The Chariot Challenge (04J00714, NSW/ACT)",      MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // 630,      A - 10/08/98, Rev 12
13501312GAME( 1999, wtiger,    0,        aristmk5,     aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "White Tiger Classic (0200954V, NSW/ACT)",        MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // 638/1,    B - 08/07/99
r250109r250110
13541316GAME( 2000, magicmska, magicmsk, aristmk5_usa, aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "Magic Mask (MV4115, Export, set 2)",             MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // MV4115,   A - 09/05/00
13551317GAME( 2000, margmgc,   0,        aristmk5,     aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "Margarita Magic (01J00101, NSW/ACT)",            MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // JB005,    A - 07/07/00
13561318GAME( 2000, marmagic,  aristmk5, aristmk5_usa, aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "Margarita Magic (EHG1559, NSW/ACT)",             MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // US003,    A - 07/07/00
1357GAME( 2001, prtygras,  aristmk5, aristmk5_usa, aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "Party Gras (MV4115/3, Export, touch)",           MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // MV4115/3, B - 06/02/01
13581319GAME( 2001, geishanz,  0,        aristmk5,     aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "Geisha (0101408V, New Zealand)",                 MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // MV4127,   A - 05/03/01
13591320GAME( 2001, adonise,   aristmk5, aristmk5_usa, aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "Adonis (MV4124/1, Export)",                      MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // MV4124/1, B - 31/07/01
13601321GAME( 2001, koalamnt,  aristmk5, aristmk5_usa, aristmk5, aristmk5_state, aristmk5, ROT0,  "Aristocrat", "Koala Mint (MV4137, Export)",                    MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )  // MV4137,   A - 12/09/01
trunk/src/mame/drivers/atarittl.c
r250109r250110
55 Atari / Kee Games Driver - Discrete Games made in the 1970's
66
77
8 Atari / Kee Games List (except for most Pong games) - Data based, in part from:
8 Atari / Kee Games List and Data based, in part from:
99
1010 - Andy's collection of Bronzeage Atari Video Arcade PCB's"
1111 http://www.andysarcade.net/personal/bronzeage/index.htm
r250109r250110
1919 Technical Manual #s  Game Name(s)                                               Atari Part #'s                     Data      PROM/ROM Chip Numbers
2020 -------------------+----------------------------------------------------------+----------------------------------+---------+---------------------------------------
2121 TM-025               Anti-Aircraft (1975)                                       A000951                            YES       003127
22 TM-058               Breakout/Breakout Cocktail/Consolette (1976)               A004533                            NO
23 TM-015               Cocktail Pong/Coup Franc (1974)                            ???????                            NO
2224 TM-048               Crash 'N Score/Stock Car (1975)                            A004256                            YES       003186(x2), 003187(x2), 004248, 004247
23 TM-030               Crossfire (1975)                                           ???????                            NO?
24 TM-022               Elimination! (1973)                                        A000845                            NO
25 TM-035               Goal IV (1975)                                             A000823                            NO
25 TM-030               Crossfire (1975)                                           ???????                            NO
26 TM-0??               Dr. Pong/Puppy Pong/Snoopy Pong (1974)                     ???????                            NO
27 TM-035               Goal IV/Goal/4 (1975)                                      A000823                            NO
2628 TM-016               Gotcha/Gotcha Color? (1973)                                A000816                            NO
2729 TM-003,005,011,020   Gran Trak 10/Trak 10/Formula K (1974)                      A000872,A000872 K3RT               YES       74186 Racetrack Prom (K5)
2830 TM-004,021           Gran Trak 20/Trak 20/Twin Racer (1974)                     A001791(RT20),A001793(A20-K4DRTA)  YES       74186 Racetrack prom (K5)
29 TM-028               Hi-Way/Highway (1975)                                      A003211                            NO
31 TM-028               Highway/Hi-Way (1975)                                      A003211                            NO
3032 TM-055               Indy 4 (1976)                                              A003000,A006268,A006270            YES       003186, 003187, 005502-01, 05503-01
3133 TM-026               Indy 800 (1975)                                            A003000,A003170,A003182            YES       003186-003189 (4)
3234                                                                                 A003184,A003191,A003198,A003199
3335 TM-027,052           Jet Fighter/Jet Fighter Cocktail/Launch Aircraft (1975)    A004254,A004255                    YES       004250-004252, 004253-01 to 03 (3)
34 TM-077               Le Mans (1976)                                              A005844,A005845                    YES       005837-01, 005838-01, 005839-01
36 TM-077               LeMans (1976)                                              A005844,A005845                    YES       005837-01, 005838-01, 005839-01
3537 TM-040               Outlaw (1976)                                              A003213                            YES       003323 - ROM (8205 @ J4)
3638 TM-007               Pin Pong (1974)                                            A001660                            NO
37 TM-019               Pursuit (1975)                                             K8P-B 90128                        NO
38 TM-012,034           Quadrapong (1974)                                          A000845                            NO
39 TM-013               Pong (1972)                                                A001433                            NO
40 TM-014               Pong Doubles/Coupe Davis (1974)                            A000785                            NO
41 TM-019               Pursuit (1975)                                             K8P-B 90128                        YES
42 TM-012,022,034       Quadrapong/Elimination (1974)                              A000845                            NO
3943 TM-009               Qwak!/Quack (1974)                                         A000937,A000953                    YES       72074/37-2530N (K9)
40 TM-001,023,032       Rebound/Spike/Volleyball (1974)                            A000517,A000846,SPIKE-(A or B)     NO
41 TM-047               Shark JAWS (1975)                                          A003806                            YES       004182, 004183
42 TM-008               Space Race (1973)                                          A000803                            NO
44 TM-001,032           Rebound/Volleyball (1974)                                  A000517,A000846                    NO
45 TM-047               Shark Jaws (1975)                                          A003806                            YES       004182, 004183
46 TM-008               Space Race (1974)                                          A000803                            NO
47 TM-023               Spike  (1974)                                              SPIKE-(A or B)                     NO
4348 TM-046               Steeplechase/Astroturf (1975)                              A003750                            YES       003774 ROM Bugle (C8), 003773-01 "A" Horse (C4), 003773-02 "B" Horse (D4)
4449 TM-057               Stunt Cycle (1976)                                         A004128                            YES       004275 ROM Motorcycle/Bus (1F), 004811 ROM Score Translator (D7)
45 TM-010,036           Tank/Tank Cocktail (1974)                                  A003111 (K5T-F 90124)              YES       90-2006 004800SD Tank Rom (K10)
46 TM-049               Tank II (1975)                                             K5T-F 90124                        YES       90-2006
47 TM-002               Touch-Me (1974)                                            ???????                            NO
50 422                  Superpong (1974)                                           A000423                            NO
51 TM-010,036,049       Tank/Tank Cocktail/Tank II (1974/1975)                     A003111 (K5T-F 90124)              YES       90-2006
52 TM-002               Touch Me (1974)                                            ???????                            NO
4853 TM-006,017           World Cup/World Cup Football/Coupe du Monde (1974)         A000823                            NO
4954 
5055 - Not Known to be released or produced, but at least announced.
5156
5257 TM-0??               Arcade Driver/Driver First Person (Not Produced/Released) (197?)
5358 TM-018               Dodgeball/Dodgem (Not Produced/Released) (1975)
54 TM-024               Qwakers (Not Produced/Released) (1974?) (Kee Games clone of Qwak!?)
59 TM-024               Qwakers (Not Produced/Released) (1974?)
5560
5661
5762***************************************************************************/
r250109r250110
304309   ROM_LOAD( "90-2006.k10" ,0x0000, 0x0801, CRC(c25f6014) SHA1(7bd3fca5f64c928a645ca27c643b736667cef216) )
305310ROM_END
306311
307ROM_START( tankii )
308   ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
309312
310   /* The "custom" 24-pin ROM used in Atari/Kee Games "Tank" is known as a MOSTEK MK28000P. */
311   ROM_REGION( 0x0801, "gfx", ROMREGION_ERASE00 ) // 2049 Byte Size?
312   ROM_LOAD( "90-2006.k10" ,0x0000, 0x0801, CRC(c25f6014) SHA1(7bd3fca5f64c928a645ca27c643b736667cef216) )
313ROM_END
314
315313/*  // NO DUMPED ROMS
316314
315// Astroturf (1975)
317316ROM_START( astrotrf )
318317    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
319318
r250109r250110
322321    ROM_LOAD( "003773-02.c4",  0x0100, 0x0100, NO_DUMP ) // Graphics (Astroturf - Rev.A)
323322ROM_END
324323
324// Gran Trak 10 / Trak 10 / Formula K / Race Circuit (1974)
325325ROM_START( gtrak10 )  // Unknown size, assumed 2K Bytes
326326    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
327327
r250109r250110
329329    ROM_LOAD( "74168.k5",     0x0000, 0x0800, NO_DUMP) // Racetrack
330330ROM_END
331331
332// Gran Trak 20 / Trak 20 / Twin Racer (1974)
332333ROM_START( gtrak20 )  // Unknown size, assumed 2K Bytes
333334    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
334335
r250109r250110
336337    ROM_LOAD( "74168.k5",     0x0000, 0x0800, NO_DUMP) // Racetrack
337338ROM_END
338339
340// LeMans (1976)
339341ROM_START( lemans )
340342    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
341343
r250109r250110
345347    ROM_LOAD( "005839-01.n6",  0x0200, 0x0100, NO_DUMP ) // Rom 3
346348ROM_END
347349
350// Qwak! / Quack (1974)
348351ROM_START( qwak )
349352    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
350353
r250109r250110
367370    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
368371ROM_END
369372
370ROM_START( eliminat )
373ROM_START( goal4 )
371374    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
372375ROM_END
373376
374ROM_START( goaliv )
377ROM_START( gotcha )
375378    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
376379ROM_END
377380
378ROM_START( gotchaat )
381ROM_START( gotchac )
379382    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
380383ROM_END
381384
382ROM_START( gotchaatc )
385ROM_START( highway )
383386    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
384387ROM_END
385388
386ROM_START( hiway )
387    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
388ROM_END
389
390389ROM_START( pinpong )
391390    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
392391ROM_END
r250109r250110
415414    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
416415ROM_END
417416
418ROM_START( worldcup )
419    ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
420ROM_END
421
422417*/
423418
424419
425420
426421GAME(1975,  antiairc,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Anti-Aircraft [TTL]",    MACHINE_IS_SKELETON)
427422GAME(1975,  crashnsc,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Crash 'n Score/Stock Car [TTL]",   MACHINE_IS_SKELETON)
428GAME(1976,  indy4,     0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Kee",  "Indy 4 [TTL]",           MACHINE_IS_SKELETON)
423GAME(1976,  indy4,     0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Indy 4 [TTL]",           MACHINE_IS_SKELETON)
429424GAME(1975,  indy800,   0,         atarikee,   0,  driver_device, 0,  ROT90, "Atari/Kee",  "Indy 800 [TTL]",         MACHINE_IS_SKELETON)
430425GAME(1975,  jetfight,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Jet Fighter/Jet Fighter Cocktail/Launch Aircraft (set 1) [TTL]",      MACHINE_IS_SKELETON)
431426GAME(1975,  jetfighta, jetfight,  atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Jet Fighter/Jet Fighter Cocktail/Launch Aircraft (set 2) [TTL]",      MACHINE_IS_SKELETON)
432427GAME(1976,  outlaw,    0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Outlaw [TTL]",           MACHINE_IS_SKELETON)
433GAME(1975,  sharkjaw,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Horror Games",  "Shark JAWS [TTL]",     MACHINE_IS_SKELETON)
428GAME(1975,  sharkjaw,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Horror Games",  "Shark JAWS [TTL]",MACHINE_IS_SKELETON)
434429GAME(1975,  steeplec,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Steeplechase [TTL]",     MACHINE_IS_SKELETON)
435430GAME(1976,  stuntcyc,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Stunt Cycle [TTL]",      MACHINE_IS_SKELETON)
436GAME(1974,  tank,      0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Kee",  "Tank/Tank Cocktail [TTL]",     MACHINE_IS_SKELETON)
437GAME(1975,  tankii,    0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Kee",  "Tank II [TTL]",          MACHINE_IS_SKELETON)
431GAME(1974,  tank,      0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Kee",  "Tank/Tank Cocktail/Tank II [TTL]",     MACHINE_IS_SKELETON)
438432
439433// MISSING ROM DUMPS
440434//GAME(1975,  astrotrf,  steeplec,  atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Astroturf [TTL]",        MACHINE_IS_SKELETON)
441435//GAME(1974,  gtrak10,   0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Kee",  "Gran Trak 10/Trak 10/Formula K [TTL]",     MACHINE_IS_SKELETON) //?
442//GAME(1974,  gtrak20,   0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Kee",  "Gran Trak 20/Trak 20/Twin Racer [TTL]",    MACHINE_IS_SKELETON) //?
443//GAME(1976,  lemans,    0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Le Mans [TTL]",          MACHINE_IS_SKELETON)
444//GAME(1974,  qwak,      0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Qwak!/Quack [TTL]",      MACHINE_IS_SKELETON)
436//GAME(1974,  gtrak20,   0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Kee",  "Gran Trak 20/Trak 20/Twin Racer [TTL]",     MACHINE_IS_SKELETON) //?
437//GAME(1976,  lemans,    0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "LeMans [TTL]",           MACHINE_IS_SKELETON)
438//GAME(1974,  quack,     0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Qwak!/Quack [TTL]",      MACHINE_IS_SKELETON)
445439
446440// 100% TTL
447//GAME(1975,  crossfir,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Kee",  "Crossfire [TTL]",        MACHINE_IS_SKELETON)
448//GAME(1973,  eliminat,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Kee",  "Elimination! [TTL]",     MACHINE_IS_SKELETON)
449//GAME(1975,  goaliv,    0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Goal IV [TTL]",          MACHINE_IS_SKELETON)
441//GAME(1974,  coupedem,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Coupe De Monde [TTL]",   MACHINE_IS_SKELETON)
442//GAME(1975,  crossfir,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Crossfire [TTL]",        MACHINE_IS_SKELETON)
443//GAME(1975,  goal4,     0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Goal 4/World Cup/Coupe De Monde [TTL]",     MACHINE_IS_SKELETON)
450444//GAME(1973,  gotchaat,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Gotcha [TTL]",           MACHINE_IS_SKELETON) //?
451445//GAME(1973,  gotchaatc, 0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Gotcha Color [TTL]",     MACHINE_IS_SKELETON) //?
452//GAME(1975,  hiway,     0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Hi-Way/Highway [TTL]",   MACHINE_IS_SKELETON)
446//GAME(1975,  highway,   0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Highway/Hiway [TTL]",    MACHINE_IS_SKELETON)
453447//GAME(1974,  pinpong,   0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Pin Pong [TTL]",         MACHINE_IS_SKELETON)
454448//GAME(1975,  pursuit,   0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Pursuit [TTL]",          MACHINE_IS_SKELETON)
455//GAME(1974,  quadpong,  eliminat,  atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Quadrapong [TTL]",       MACHINE_IS_SKELETON)
456//GAME(1974,  rebound,   0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Kee",  "Rebound/Spike/Volleyball [TTL]",   MACHINE_IS_SKELETON)
457//GAME(1973,  spacrace,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Space Race [TTL]",       MACHINE_IS_SKELETON)
458//GAME(1974,  touchme,   0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Touch-Me [TTL]",         MACHINE_IS_SKELETON) //?
459//GAME(1974,  worldcup,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "World Cup/World Cup Football/Coupe du Monde [TTL]",   MACHINE_IS_SKELETON)
449//GAME(1973,  quadpong,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Kee",  "Quadrapong/Elimination [TTL]",     MACHINE_IS_SKELETON)
450//GAME(1974,  rebound,   0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari/Kee",  "Rebound/Spike/Volleyball [TTL]",     MACHINE_IS_SKELETON)
451//GAME(1974,  spacrace,  0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Space Race [TTL]",       MACHINE_IS_SKELETON)
452//GAME(1974,  touchme,   0,         atarikee,   0,  driver_device, 0,  ROT0,  "Atari",      "Touch Me [TTL]",         MACHINE_IS_SKELETON) //?
trunk/src/mame/drivers/champbas.c
r250109r250110
36367000      8910 write
37377001      8910 control
38388ff0-8fff sprites
39a000      irq enable
39a000      ?
4040a006      MCU HALT control
4141a007      NOP (MCU shared RAM switch)
4242a060-a06f sprites
r250109r250110
191191
192192   AM_RANGE(0xa000, 0xa000) AM_READ_PORT("P1")
193193   AM_RANGE(0xa040, 0xa040) AM_READ_PORT("P2")
194   AM_RANGE(0xa080, 0xa080) AM_MIRROR(0x0020) AM_READ_PORT("DSW")
194   AM_RANGE(0xa080, 0xa080) AM_READ_PORT("DSW")
195195   AM_RANGE(0xa0c0, 0xa0c0) AM_READ_PORT("SYSTEM")
196196
197197   AM_RANGE(0xa000, 0xa000) AM_WRITE(irq_enable_w)
r250109r250110
218218
219219// different protection for champbasja
220220static ADDRESS_MAP_START( champbasja_map, AS_PROGRAM, 8, champbas_state )
221   AM_RANGE(0x6000, 0x63ff) AM_RAM
222221   AM_RANGE(0x6800, 0x68ff) AM_READ(champbja_protection_r)
223222   AM_IMPORT_FROM( champbas_map )
224223ADDRESS_MAP_END
r250109r250110
12001199/*    YEAR  NAME        PARENT    MACHINE     INPUT     INIT                      MONITOR, COMPANY, FULLNAME, FLAGS */
12011200GAME( 1982, talbot,     0,        talbot,     talbot,   driver_device,  0,        ROT270, "Alpha Denshi Co. (Volt Electronics license)", "Talbot", MACHINE_SUPPORTS_SAVE )
12021201
1203GAME( 1983, champbas,   0,        champbas,   champbas, champbas_state, champbas, ROT0,   "Alpha Denshi Co. (Sega license)", "Champion Base Ball", MACHINE_SUPPORTS_SAVE ) // no protection
1202GAME( 1983, champbas,   0,        champbas,   champbas, champbas_state, champbas, ROT0,   "Alpha Denshi Co. (Sega license)", "Champion Base Ball", MACHINE_SUPPORTS_SAVE )
12041203GAME( 1983, champbasj,  champbas, champbasj,  champbas, champbas_state, champbas, ROT0,   "Alpha Denshi Co.", "Champion Base Ball (Japan set 1)", MACHINE_SUPPORTS_SAVE )
1205GAME( 1983, champbasja, champbas, champbasja, champbas, champbas_state, champbas, ROT0,   "Alpha Denshi Co.", "Champion Base Ball (Japan set 2)", MACHINE_SUPPORTS_SAVE ) // simplified protection, no mcu
1204GAME( 1983, champbasja, champbas, champbasja, champbas, champbas_state, champbas, ROT0,   "Alpha Denshi Co.", "Champion Base Ball (Japan set 2)", MACHINE_SUPPORTS_SAVE )
12061205GAME( 1983, champbb2,   0,        champbb2,   champbas, champbas_state, champbas, ROT0,   "Alpha Denshi Co. (Sega license)", "Champion Base Ball Part-2 (set 1)", MACHINE_SUPPORTS_SAVE )
12071206GAME( 1983, champbb2a,  champbb2, champbb2,   champbas, champbas_state, champbas, ROT0,   "Alpha Denshi Co.", "Champion Base Ball Part-2 (set 2)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // incomplete dump
12081207GAME( 1983, champbb2j,  champbb2, champbb2,   champbas, champbas_state, champbas, ROT0,   "Alpha Denshi Co.", "Champion Base Ball Part-2 (Japan)", MACHINE_SUPPORTS_SAVE )
r250109r250110
12121211GAME( 1983, exctsccra,  exctsccr, exctsccr,   exctsccr, champbas_state, exctsccr, ROT270, "Alpha Denshi Co.", "Exciting Soccer (alternate music)", MACHINE_SUPPORTS_SAVE )
12131212GAME( 1983, exctsccrj,  exctsccr, exctsccr,   exctsccr, champbas_state, exctsccr, ROT270, "Alpha Denshi Co.", "Exciting Soccer (Japan)", MACHINE_SUPPORTS_SAVE )
12141213GAME( 1983, exctsccrjo, exctsccr, exctsccr,   exctsccr, champbas_state, exctsccr, ROT270, "Alpha Denshi Co.", "Exciting Soccer (Japan, older)", MACHINE_SUPPORTS_SAVE )
1215GAME( 1983, exctsccrb,  exctsccr, exctsccrb,  exctsccr, champbas_state, exctsccr, ROT270, "bootleg (Kazutomi)", "Exciting Soccer (bootleg)", MACHINE_SUPPORTS_SAVE ) // on champbasj hardware
1214GAME( 1983, exctsccrb,  exctsccr, exctsccrb,  exctsccr, champbas_state, exctsccr, ROT270, "bootleg (Kazutomi)", "Exciting Soccer (bootleg)", MACHINE_SUPPORTS_SAVE )
12161215GAME( 1984, exctscc2,   0,        exctsccr,   exctsccr, champbas_state, exctsccr, ROT270, "Alpha Denshi Co.", "Exciting Soccer II", MACHINE_SUPPORTS_SAVE )
trunk/src/mame/drivers/dorachan.c
r250109r250110
1919public:
2020   dorachan_state(const machine_config &mconfig, device_type type, const char *tag)
2121      : driver_device(mconfig, type, tag),
22      m_videoram(*this, "videoram"),
2223      m_maincpu(*this, "maincpu"),
2324      m_screen(*this, "screen"),
2425      m_palette(*this, "palette"),
25      m_videoram(*this, "videoram"),
26      m_colors(*this, "colors")
27   { }
26      m_colors(*this, "colors") { }
2827
29   // devices, memory pointers
28   /* memory pointers */
29   required_shared_ptr<UINT8> m_videoram;
30
31   /* video-related */
32   UINT8    m_flip_screen;
33
34   /* devices */
35   DECLARE_WRITE8_MEMBER(dorachan_ctrl_w);
36   DECLARE_CUSTOM_INPUT_MEMBER(dorachan_protection_r);
37   DECLARE_CUSTOM_INPUT_MEMBER(dorachan_v128_r);
38   virtual void machine_start();
39   virtual void machine_reset();
40   UINT32 screen_update_dorachan(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
3041   required_device<cpu_device> m_maincpu;
3142   required_device<screen_device> m_screen;
3243   required_device<palette_device> m_palette;
33
34   required_shared_ptr<UINT8> m_videoram;
3544   required_region_ptr<UINT8> m_colors;
45};
3646
37   // internal state
38   UINT8 m_flip_screen;
3947
40   DECLARE_WRITE8_MEMBER(control_w);
41   DECLARE_READ8_MEMBER(protection_r);
42   DECLARE_READ8_MEMBER(v128_r);
43   UINT32 screen_update_dorachan(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
48/*************************************
49 *
50 *  Protection handling
51 *
52 *************************************/
4453
45   virtual void machine_start();
46   virtual void machine_reset();
47};
54CUSTOM_INPUT_MEMBER(dorachan_state::dorachan_protection_r)
55{
56   UINT8 ret = 0;
4857
58   switch (m_maincpu->pcbase())
59   {
60   case 0x70ce: ret = 0xf2; break;
61   case 0x72a2: ret = 0xd5; break;
62   case 0x72b5: ret = 0xcb; break;
4963
64   default:
65      osd_printf_debug("unhandled $2400 read @ %x\n", m_maincpu->pcbase());
66      break;
67   }
5068
69   return ret;
70}
71
72
73
5174/*************************************
5275 *
5376 *  Video system
r250109r250110
87110}
88111
89112
90
91/*************************************
92 *
93 *  I/O handlers
94 *
95 *************************************/
96
97READ8_MEMBER(dorachan_state::protection_r)
113WRITE8_MEMBER(dorachan_state::dorachan_ctrl_w)
98114{
99   UINT8 ret = 0;
100
101   switch (m_maincpu->pcbase())
102   {
103   case 0x70ce: ret = 0xf2; break;
104   case 0x72a2: ret = 0xd5; break;
105   case 0x72b5: ret = 0xcb; break;
106
107   default:
108      osd_printf_debug("unhandled $2400 read @ %x\n", m_maincpu->pcbase());
109      break;
110   }
111
112   return ret;
115   m_flip_screen = (data >> 6) & 0x01;
113116}
114117
115READ8_MEMBER(dorachan_state::v128_r)
116{
117   // to avoid resetting (when player 2 starts) bit 0 need to be inverted when screen is flipped
118   return 0xfe | ((m_screen->vpos() >> 7 & 1) ^ m_flip_screen);
119}
120118
121WRITE8_MEMBER(dorachan_state::control_w)
119CUSTOM_INPUT_MEMBER(dorachan_state::dorachan_v128_r)
122120{
123   // d6: flip screen
124   // other: ?
125   m_flip_screen = data >> 6 & 1;
121   /* to avoid resetting (when player 2 starts) bit 0 need to be inverted when screen is flipped */
122   return ((m_screen->vpos() >> 7) & 0x01) ^ m_flip_screen;
126123}
127124
128125
126
127/*************************************
128 *
129 *  Memory handlers
130 *
131 *************************************/
132
129133static ADDRESS_MAP_START( dorachan_map, AS_PROGRAM, 8, dorachan_state )
130134   AM_RANGE(0x0000, 0x17ff) AM_ROM
131135   AM_RANGE(0x1800, 0x1fff) AM_RAM
132136   AM_RANGE(0x2000, 0x23ff) AM_ROM
133   AM_RANGE(0x2400, 0x2400) AM_MIRROR(0x03ff) AM_READ(protection_r)
134   AM_RANGE(0x2800, 0x2800) AM_MIRROR(0x03ff) AM_READ_PORT("IN0")
135   AM_RANGE(0x2c00, 0x2c00) AM_MIRROR(0x03ff) AM_READ_PORT("IN1")
136   AM_RANGE(0x3800, 0x3800) AM_MIRROR(0x03ff) AM_READ(v128_r)
137   AM_RANGE(0x2400, 0x2400) AM_MIRROR(0x03ff) AM_READ_PORT("PROT")
138   AM_RANGE(0x2800, 0x2800) AM_MIRROR(0x03ff) AM_READ_PORT("SYSTEM")
139   AM_RANGE(0x2c00, 0x2c00) AM_MIRROR(0x03ff) AM_READ_PORT("JOY")
140   AM_RANGE(0x3800, 0x3800) AM_MIRROR(0x03ff) AM_READ_PORT("V128")
137141   AM_RANGE(0x4000, 0x5fff) AM_RAM AM_SHARE("videoram")
138142   AM_RANGE(0x6000, 0x77ff) AM_ROM
139143ADDRESS_MAP_END
140144
145
146
147/*************************************
148 *
149 *  Port handlers
150 *
151 *************************************/
152
141153static ADDRESS_MAP_START( dorachan_io_map, AS_IO, 8, dorachan_state )
142154   ADDRESS_MAP_GLOBAL_MASK(0xff)
143155   AM_RANGE(0x01, 0x01) AM_WRITENOP
144156   AM_RANGE(0x02, 0x02) AM_WRITENOP
145   AM_RANGE(0x03, 0x03) AM_WRITE(control_w)
157   AM_RANGE(0x03, 0x03) AM_WRITE(dorachan_ctrl_w)
146158ADDRESS_MAP_END
147159
148160
r250109r250110
154166 *************************************/
155167
156168static INPUT_PORTS_START( dorachan )
157   PORT_START("IN0")
169   PORT_START("PROT")
170   PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, dorachan_state,dorachan_protection_r, NULL)
171
172   PORT_START("SYSTEM")
158173   PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
159174   PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START1 )
160175   PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_START2 )
r250109r250110
170185   PORT_DIPSETTING(    0x80, DEF_STR( Off ) )
171186   PORT_DIPSETTING(    0x00, DEF_STR( On ) )
172187
173   PORT_START("IN1")
188   PORT_START("JOY")
174189   PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_COCKTAIL
175190   PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_COCKTAIL
176191   PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_COCKTAIL
r250109r250110
179194   PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_UP )
180195   PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT )
181196   PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT )
197
198   PORT_START("V128")
199   PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, dorachan_state,dorachan_v128_r, NULL)
200   PORT_BIT( 0xfe, IP_ACTIVE_LOW, IPT_UNUSED )
182201INPUT_PORTS_END
183202
184203
r250109r250110
200219}
201220
202221static MACHINE_CONFIG_START( dorachan, dorachan_state )
203
204222   /* basic machine hardware */
205223   MCFG_CPU_ADD("maincpu", Z80, 2000000)
206224   MCFG_CPU_PROGRAM_MAP(dorachan_map)
r250109r250110
210228   /* video hardware */
211229   MCFG_SCREEN_ADD("screen", RASTER)
212230   MCFG_SCREEN_SIZE(32*8, 32*8)
213   MCFG_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 1*8, 31*8-1)
231   MCFG_SCREEN_VISIBLE_AREA(1*8, 31*8-1, 1*8, 31*8-1)
214232   MCFG_SCREEN_REFRESH_RATE(60)
215233   MCFG_SCREEN_UPDATE_DRIVER(dorachan_state, screen_update_dorachan)
216234
r250109r250110
253271 *
254272 *************************************/
255273
256GAME( 1980, dorachan, 0, dorachan, dorachan, driver_device, 0, ROT270, "Alpha Denshi Co. / Craul Denshi", "Dora-chan (Japan)", MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE )
274GAME( 1980, dorachan, 0, dorachan, dorachan, driver_device, 0, ROT270, "Craul Denshi", "Dorachan", MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE )
trunk/src/mame/drivers/equites.c
r250109r250110
22// copyright-holders:Acho A. Tang, Nicola Salmoria
33/*******************************************************************************
44
5Equites           (c) 1984 Alpha Denshi Co./Sega
6Bull Fighter      (c) 1984 Alpha Denshi Co./Sega
7Gekisou           (c) 1985 Eastern Corp.
8The Koukouyakyuh  (c) 1985 Alpha Denshi Co.
9Splendor Blast    (c) 1985 Alpha Denshi Co.
10High Voltage      (c) 1985 Alpha Denshi Co.
5Equites           (c) 1984 Alpha Denshi Co./Sega   8303
6Bull Fighter      (c) 1984 Alpha Denshi Co./Sega   8303
7Gekisou           (c) 1985 Eastern Corp.           8304
8Violent Run       (c) 1985 Eastern Corp.           8304? (probably on Equites HW)
9The Koukouyakyuh  (c) 1985 Alpha Denshi Co.        8304
10Splendor Blast    (c) 1985 Alpha Denshi Co.        8303
11High Voltage      (c) 1985 Alpha Denshi Co.        8304 (POST says 8404)
1112
12The following are not dumped yet:
13Champion Croquet  (c) 1984 Alpha Denshi Co. (sports)
14Violent Run       (c) 1985 Eastern Corp. (export version of Gekisou)
15Tune Pit(?)       (c) 1985 Alpha Denshi Co.
16Perfect Janputer  (c) 1984 Alpha Denshi Co. (4-player Mahjong)
17
18
1913Driver by Acho A. Tang, Nicola Salmoria
2014Many thanks to Corrado Tomaselli for precious hardware info.
2115
r250109r250110
182176  Yasuhiro Ogawa for the correct Equites ROM information
183177
184178
179Other unemulated Alpha Denshi and SNK games that may use similar hardware:
180-----------------------------------------------------------
181Maker        Year Genre Name             Japanese Name
182-----------------------------------------------------------
183Alpha Denshi 1984 (SPT) Champion Croquet ?`?????s?I???N???b?P?[
184Alpha Denshi 1985 (???) Tune Pit(?)      ?`?F?[???s?b?g
185Alpha Denshi 1985 (MAJ) Perfect Janputer ?p?[?t?F?N?g?W?????s???[?^?[
186
187
185188*******************************************************************************
186189
187190Bull Fighter
r250109r250110
258261-----------------------------------------------------------------------|
259262
260263
264
265
261266-----------------------------------------------------------------------------------|
262267|ALPHA DENSHI CO, LTD. MAIN CONNECTOR BOARD                                        |
263268|                                                                                  |
r250109r250110
309314|----------------------------------------------------------------------------------|
310315
311316
317
318
312319-------------------------------------------------------------------------------------|
313320|ALPHA DENSHI CO, LTD. LOWER BOARD                                                   |
314321|                                                                                    |
r250109r250110
357364
358365
359366*******************************************************************************/
367// Directives
360368
361369#include "emu.h"
362370#include "cpu/m68000/m68000.h"
r250109r250110
19011909GAME( 1984, equitess, equites,  equites,  equites,  equites_state, equites,  ROT90, "Alpha Denshi Co. (Sega license)", "Equites (Sega)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
19021910GAME( 1984, bullfgtr, 0,        equites,  bullfgtr, equites_state, bullfgtr, ROT90, "Alpha Denshi Co.", "Bull Fighter", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
19031911GAME( 1984, bullfgtrs,bullfgtr, equites,  bullfgtr, equites_state, bullfgtr, ROT90, "Alpha Denshi Co. (Sega license)", "Bull Fighter (Sega)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
1904GAME( 1985, kouyakyu, 0,        equites,  kouyakyu, equites_state, kouyakyu, ROT0,  "Alpha Denshi Co.", "The Koukou Yakyuu", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
1912GAME( 1985, kouyakyu, 0,        equites,  kouyakyu, equites_state, kouyakyu, ROT0,  "Alpha Denshi Co.", "The Koukouyakyuh", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
19051913GAME( 1985, gekisou,  0,        gekisou,  gekisou,  equites_state, gekisou,  ROT90, "Eastern Corp.", "Gekisou (Japan)", MACHINE_UNEMULATED_PROTECTION | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
19061914
19071915// Splendor Blast Hardware
trunk/src/mame/drivers/goldnpkr.c
r250109r250110
464464  the driver init till we can get more evidence about.
465465
466466
467  * Super 98
468
469  This game looks like a Golden Poker / Potten's Poker set, but could be set to play
470  2 or 3 deals per hand. It's running in a ICP-1 PCB.
471
472  Entering the service mode (key 0), you can enter to a submenu for settings pressing
473  DEAL (key 2). Use HOLD keys (keys ZXCVB) to navigate through the menu and change
474  the values. Press CANCEL to exit the settings menu.
475
476  Program is currently not working because seems to fill some zeropage registers and
477  check for existent values and changes... Maybe an external device is writting them.
478  This is NVRAM zone, so some values could be previously harcoded.
479
480  Also seems to expect some inputs combination entered to boot.
481
482  To run...
483  1) Start the game.
484  2) Break into debugger and do a pc=cfa1
485   
486  Debug notes...
487
488  From interrupts routine:
489
490  CF99: LDA $0846    ; load from PIA
491  CF9C: TSX          ; transfer stack pointer to X
492  CF9D: CPX #$C8     ; compare with 0xC8
493  CF9F: BCS $CFA4    ; not?... branch to $CFA4
494  CFA1: JMP $CEC6    ; yes?... jump to $CEC6
495  CFA4: JSR $C0E1    ; continue...
496  ...
497 
498  Forcing the first time the comparation at $CF9D --> true, the game boots and is
499  fully working.
500
501 
502467************************************************************************************
503468
504469
r250109r250110
1034999     properly. Now you can choose the program through a DIP switch.
10351000
10361001
1037  [2015-11-04]
1038
1039  - Added new sets:
1040     * Genie (ICP-1, set 2).
1041     * Super 98 (ICP-1).
1042     * Jack Potten's Poker (set 8, Australian).
1043
1044  - Derived a new machine with improved memory map for this new Genie set.
1045  - Minor fixes and clean-ups.
1046  - Added games & technical notes.
1047
1048
10491002  TODO:
10501003
10511004  - Missing PIA connections.
r250109r250110
100029955  Super 98',
100039956  running in the ICP-1 boardset.
100049957
10005  Please read the 'Games Notes' section
10006  for game and debug notes / issues...
9958  Program seems to fill some zeropage registers
9959  and check for existent values and changes...
9960  Maybe an external device is writting them.
9961  This is NVRAM zone, so some values could be
9962  previously harcoded.
9963
9964  Also seems to expect some inputs combination entered to boot.
9965
9966  To run...
9967  1) Start the game.
9968  2) Break into debugger and do a pc=cfa1
100079969*/
100089970
100099971ROM_START( super98 )
trunk/src/mame/drivers/mz700.c
r250109r250110
5959 *  D000-DFFF   videoram or RAM
6060 *  E000-FFFF   memory mapped IO or RAM
6161 *
62 *  ToDo:
63    - slows down while making sound
64    - MZ800:
65      - Had to patch the rom to load cassettes
66      - Port CF not done.
67      - Dips not connected.
68      - MZ800-mode display not working /Hi-res not coded.
69      - The CRTC is a very complex custom device, mostly unemulated.
70    - MZ1500:
71      - Various ports not done.
72      - Floppy disk and quick disk not done.
73      - F4 display is blank.
74      - Need manuals.
75
76  Note: MZ800 hardware starts in memory map (mode A), but switches to MZ700
77  compatibility mode (mode B) as soon as it starts up. We start in Mode B
78  because it helps MZ1500 get started and it doesn't break anything.
79
80*
8162 *****************************************************************************/
8263
8364#include "emu.h"
r250109r250110
11697***************************************************************************/
11798
11899static ADDRESS_MAP_START( mz700_mem, AS_PROGRAM, 8, mz_state )
119   AM_RANGE(0x0000, 0x0fff) AM_READ_BANK("bankr0") AM_WRITE_BANK("bankw0")
120   AM_RANGE(0x1000, 0xcfff) AM_RAM
121   AM_RANGE(0xd000, 0xdfff) AM_RAMBANK("bankd")
122   AM_RANGE(0xe000, 0xffff) AM_DEVICE("banke", address_map_bank_device, amap8)
123100ADDRESS_MAP_END
124101
125static ADDRESS_MAP_START( mz700_banke, AS_PROGRAM, 8, mz_state )
126   // bank 0: ram (mz700_bank1)
127   AM_RANGE(0x0000, 0x1fff) AM_RAM
128   // bank 1: devices (mz700_bank3)
129   AM_RANGE(0x2000, 0x2003) AM_MIRROR(0x1ff0) AM_DEVREADWRITE("ppi8255", i8255_device, read, write)
130   AM_RANGE(0x2004, 0x2007) AM_MIRROR(0x1ff0) AM_DEVREADWRITE("pit8253", pit8253_device, read, write)
131   AM_RANGE(0x2008, 0x200b) AM_MIRROR(0x1ff0) AM_READWRITE(mz700_e008_r,mz700_e008_w)
132   AM_RANGE(0x200c, 0x200f) AM_MIRROR(0x1ff0) AM_NOP
133   // bank 2: switched out (mz700_bank5)
134   AM_RANGE(0x4000, 0x5fff) AM_NOP
135ADDRESS_MAP_END
136
137102static ADDRESS_MAP_START( mz700_io, AS_IO, 8, mz_state )
138103   ADDRESS_MAP_GLOBAL_MASK(0xff)
139104   AM_RANGE(0xe0, 0xe0) AM_WRITE(mz700_bank_0_w)
r250109r250110
146111ADDRESS_MAP_END
147112
148113static ADDRESS_MAP_START( mz800_mem, AS_PROGRAM, 8, mz_state )
149   AM_RANGE(0x0000, 0x0fff) AM_READ_BANK("bankr0") AM_WRITE_BANK("bankw0")
150   AM_RANGE(0x1000, 0x1fff) AM_RAMBANK("bank1")
151   AM_RANGE(0x2000, 0x7fff) AM_RAM
152   AM_RANGE(0x8000, 0xbfff) AM_RAMBANK("banka")
153   AM_RANGE(0xc000, 0xcfff) AM_RAMBANK("bankc")
154   AM_RANGE(0xd000, 0xdfff) AM_RAMBANK("bankd")
155   AM_RANGE(0xe000, 0xffff) AM_DEVICE("bankf", address_map_bank_device, amap8)
156114ADDRESS_MAP_END
157115
158static ADDRESS_MAP_START( mz800_bankf, AS_PROGRAM, 8, mz_state )
159   // bank 0: ram (mz700_bank1)
160   AM_RANGE(0x0000, 0x1fff) AM_RAM
161   // bank 1: devices (mz700_bank3)
162   AM_RANGE(0x2000, 0x2003) AM_DEVREADWRITE("ppi8255", i8255_device, read, write)
163   AM_RANGE(0x2004, 0x2007) AM_DEVREADWRITE("pit8253", pit8253_device, read, write)
164   AM_RANGE(0x2008, 0x200b) AM_READWRITE(mz700_e008_r,mz700_e008_w)
165   AM_RANGE(0x200c, 0x200f) AM_NOP
166   AM_RANGE(0x2010, 0x3fff) AM_ROM AM_REGION("monitor", 0x2010)
167   // bank 2: switched out (mz700_bank5)
168   AM_RANGE(0x4000, 0x5fff) AM_NOP
169ADDRESS_MAP_END
170
171116static ADDRESS_MAP_START( mz800_io, AS_IO, 8, mz_state )
172117   ADDRESS_MAP_GLOBAL_MASK(0xff)
173118   AM_RANGE(0xcc, 0xcc) AM_WRITE(mz800_write_format_w )
r250109r250110
358303};
359304
360305static GFXDECODE_START( mz700 )
361   GFXDECODE_ENTRY("cgrom", 0, mz700_layout, 0, 4)
306   GFXDECODE_ENTRY("cgrom", 0, mz700_layout, 0, 256)
362307GFXDECODE_END
363308
364309static GFXDECODE_START( mz800 )
365   GFXDECODE_ENTRY("monitor", 0x1000, mz700_layout, 0, 4)    // for mz800 viewer only
310   GFXDECODE_ENTRY(NULL, 0, mz700_layout, 0, 256)
311   GFXDECODE_ENTRY("monitor", 0x1000, mz700_layout, 0, 256)    // for mz800 viewer only
366312GFXDECODE_END
367313
368314
r250109r250110
375321   MCFG_CPU_ADD("maincpu", Z80, XTAL_17_73447MHz/5)
376322   MCFG_CPU_PROGRAM_MAP(mz700_mem)
377323   MCFG_CPU_IO_MAP(mz700_io)
378   MCFG_DEVICE_ADD("banke", ADDRESS_MAP_BANK, 0)
379   MCFG_DEVICE_PROGRAM_MAP(mz700_banke)
380   MCFG_ADDRESS_MAP_BANK_ENDIANNESS(ENDIANNESS_LITTLE)
381   MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(8)
382   MCFG_ADDRESS_MAP_BANK_ADDRBUS_WIDTH(16)
383   MCFG_ADDRESS_MAP_BANK_STRIDE(0x2000)
384324
385   MCFG_MACHINE_RESET_OVERRIDE(mz_state, mz700)
386325
387326   /* video hardware */
388327   MCFG_SCREEN_ADD("screen", RASTER)
389328   MCFG_SCREEN_RAW_PARAMS(XTAL_17_73447MHz/2, 568, 0, 40*8, 312, 0, 25*8)
390329   MCFG_SCREEN_UPDATE_DRIVER(mz_state, screen_update_mz700)
391330   MCFG_SCREEN_PALETTE("palette")
392   MCFG_PALETTE_ADD_3BIT_RGB("palette")
393331
394332   MCFG_GFXDECODE_ADD("gfxdecode", "palette", mz700)
333   MCFG_PALETTE_ADD("palette", 256*2)
334   MCFG_PALETTE_INDIRECT_ENTRIES(8)
335   MCFG_PALETTE_INIT_OWNER(mz_state, mz)
395336
396337   /* sound hardware */
397338   MCFG_SPEAKER_STANDARD_MONO("mono")
398339   MCFG_SOUND_WAVE_ADD(WAVE_TAG, "cassette")
399   MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.05)
340   MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
400341   MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0)
401342   MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
402343
r250109r250110
435376
436377
437378static MACHINE_CONFIG_DERIVED( mz800, mz700 )
438   MCFG_DEVICE_REMOVE("banke")
439379
440380   /* basic machine hardware */
441381   MCFG_CPU_MODIFY("maincpu")
442382   MCFG_CPU_PROGRAM_MAP(mz800_mem)
443383   MCFG_CPU_IO_MAP(mz800_io)
444   MCFG_DEVICE_ADD("bankf", ADDRESS_MAP_BANK, 0)
445   MCFG_DEVICE_PROGRAM_MAP(mz800_bankf)
446   MCFG_ADDRESS_MAP_BANK_ENDIANNESS(ENDIANNESS_LITTLE)
447   MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(8)
448   MCFG_ADDRESS_MAP_BANK_ADDRBUS_WIDTH(16)
449   MCFG_ADDRESS_MAP_BANK_STRIDE(0x2000)
450384
451   MCFG_MACHINE_RESET_OVERRIDE(mz_state, mz800)
452385   MCFG_GFXDECODE_MODIFY("gfxdecode",mz800)
453386
387   MCFG_VIDEO_START_OVERRIDE(mz_state,mz800)
388
454389   MCFG_SCREEN_MODIFY("screen")
455390   MCFG_SCREEN_UPDATE_DRIVER(mz_state, screen_update_mz800)
456391
r250109r250110
500435ROM_START( mz800 )
501436   ROM_REGION( 0x4000, "monitor", 0 )
502437   ROM_LOAD( "mz800.rom", 0x0000, 0x4000, CRC(600d17e1) SHA1(950ce4b51429916f8036e41ba6130fac149b36e4) )
503   // fix cassette loading
504   ROM_FILL(0x761,1,0x13)
505   ROM_FILL(0xA4B,1,0x45)
506
507   ROM_REGION( 0x10000, "user1", ROMREGION_ERASE00 ) // ramdisk
508438ROM_END
509439
510440ROM_START( mz1500 )
511441   ROM_REGION( 0x4000, "monitor", 0 )
512   ROM_LOAD( "9z-502m.rom",  0x0000, 0x1000, CRC(643db428) SHA1(c2ad8af2ef00db32afde54d5741b07de5d4da16a))
513   ROM_CONTINUE(0x2800, 0x1800)
514
442   ROM_LOAD( "9z-502m.rom",  0x0000, 0x2800, CRC(643db428) SHA1(c2ad8af2ef00db32afde54d5741b07de5d4da16a))
515443   ROM_REGION( 0x1000, "cgrom", 0 )
516444   //ROM_LOAD( "mz700fon.jp", 0x0000, 0x1000, CRC(697ec121) SHA1(5eb1d42d273b1fd2cab120486279ab8ff6c85dc7))
517445   ROM_LOAD( "mz700fon.jpn", 0x0000, 0x1000, CRC(425eedf5) SHA1(bd2cc750f2d2f63e50a59786668509e81a276e32) )
518
519   ROM_REGION( 0x10000, "user1", ROMREGION_ERASE00 ) // ramdisk
520446ROM_END
521447
522448/***************************************************************************
trunk/src/mame/drivers/pacman.c
r250109r250110
69126912GAME( 1981, crush4,   crush,    crush4,   crush4,   driver_device, 0,        ROT90,  "Alpha Denshi Co. / Kural TWT", "Crush Roller (set 4)", MACHINE_SUPPORTS_SAVE )
69136913GAME( 1981, maketrax, crush,    pacmanp,  maketrax, pacman_state,  maketrax, ROT270, "Alpha Denshi Co. / Kural (Williams license)", "Make Trax (US set 1)", MACHINE_SUPPORTS_SAVE )
69146914GAME( 1981, maketrxb, crush,    pacmanp,  maketrax, pacman_state,  maketrax, ROT270, "Alpha Denshi Co. / Kural (Williams license)", "Make Trax (US set 2)", MACHINE_SUPPORTS_SAVE )
6915GAME( 1981, korosuke, crush,    pacmanp,  korosuke, pacman_state,  korosuke, ROT90,  "Alpha Denshi Co. / Kural Electric, Ltd.", "Korosuke Roller (Japan)", MACHINE_SUPPORTS_SAVE ) // ADK considers it a sequel?
6915GAME( 1981, korosuke, crush,    pacmanp,  korosuke, pacman_state,  korosuke, ROT90,  "Alpha Denshi Co. / Kural Electric, Ltd.", "Korosuke Roller (Japan)", MACHINE_SUPPORTS_SAVE )
69166916GAME( 1981, crushrlf, crush,    pacman,   maketrax, driver_device, 0,        ROT90,  "bootleg", "Crush Roller (Famaresa PCB)", MACHINE_SUPPORTS_SAVE )
69176917GAME( 1981, crushbl,  crush,    pacman,   maketrax, driver_device, 0,        ROT90,  "bootleg", "Crush Roller (bootleg set 1)", MACHINE_SUPPORTS_SAVE )
69186918GAME( 1981, crushbl2, crush,    pacmanp,  mbrush,   pacman_state,  maketrax, ROT90,  "bootleg", "Crush Roller (bootleg set 2)", MACHINE_SUPPORTS_SAVE )
trunk/src/mame/drivers/polyplay.c
r250109r250110
7676
7777Uniquely the Poly-Play has a light organ which totally confuses you whilst
7878playing the automaton. Bits 1-5 of PORTB control the organ but it's not
79emulated now. ;) (An external artwork file could be created that simulates
80this.)
79emulated now. ;)
8180
8281***************************************************************************/
8382
trunk/src/mame/drivers/pong.c
r250109r250110
33/***************************************************************************
44
55Pong (c) 1972 Atari
6Pong Doubles (c) 1973 Atari
7Breakout (c) 1976 Atari
86
97driver by Couriersud
108
11
12 Atari Pong Games List - Data based, in part from:
13 
14 - "Andy's collection of Bronzeage Atari Video Arcade PCBs"
15 http://www.andysarcade.net/personal/bronzeage/index.htm
16 
17 - "Atari's Technical Manual Log"
18 http://www.atarigames.com/manuals.txt
19 
20 Suspected "same games" are grouped together.  These are usually the exact same game but different cabinet/name.
21
22 Technical Manual #s  Game Name(s)                                               Atari Part #'s                     Data
23 -------------------+----------------------------------------------------------+----------------------------------+---------+
24 TM-058               Breakout/Breakout Cocktail/Consolette (1976)               A004533                            NO
25 TM-015               Cocktail Pong/Coup Franc (1974)                            A001433?                           NO
26 TM-0??               Dr. Pong/Puppy Pong/Snoopy Pong (1974)                     A001433?                           NO
27 TM-013               Pong (1972)                                                A001433                            NO
28 TM-014               Pong Doubles/Coupe Davis (1973)                            A000785                            NO
29 422                  Superpong (1974)                                           A000423                            NO
30 
319Notes:
3210
33TODO: Please see netlist include files
34TODO: Breakout Cocktail and Consolette are believed to use the Breakout PCB with different cabinet designs, this needs to be verified.
35TODO: Coupe Davis is believed to use the Pong Doubles PCB, just a different cabinet design, this needs to be verified.
36TODO: Dr. Pong, Puppy Pong, Snoopy Pong, Cocktail Pong and Coup Franc are all believed to use the Pong (Rev E) PCB, but
37      different cabinet designs; this needs to be verified.
38TODO: Superpong is believed to use the Pong (Rev E) PCB with some minor modifications, this needs to be verified.
11TODO: please see netlist include files
3912
4013***************************************************************************/
4114
r250109r250110
517490   ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
518491ROM_END
519492
520/*   // 100% TTL - NO ROMS
521
522ROM_START( coupedav ) // dummy to satisfy game entry
523   ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
524ROM_END
525
526ROM_START( coupfran ) // dummy to satisfy game entry
527   ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
528ROM_END
529
530ROM_START( cktpong ) // dummy to satisfy game entry
531   ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
532ROM_END
533
534ROM_START( drpong ) // dummy to satisfy game entry
535   ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
536ROM_END
537
538ROM_START( pupppong ) // dummy to satisfy game entry
539   ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
540ROM_END
541
542ROM_START( snoopong ) // dummy to satisfy game entry
543   ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
544ROM_END
545
546ROM_START( suprpong ) // dummy to satisfy game entry
547   ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
548ROM_END
549
550ROM_START( breakckt ) // dummy to satisfy game entry
551   ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
552ROM_END
553
554ROM_START( consolet ) // dummy to satisfy game entry
555   ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
556ROM_END
557*/
558
559493GAME( 1972, pong,      0, pong,     pong,      driver_device,  0, ROT0,  "Atari", "Pong (Rev E) external [TTL]", MACHINE_SUPPORTS_SAVE)
560GAME( 1972, pongf,     0, pongf,    pong,      driver_device,  0, ROT0,  "Atari", "Pong (Rev E) [TTL]", MACHINE_SUPPORTS_SAVE)
561GAME( 1973, pongd,     0, pongd,    pongd,     driver_device,  0, ROT0,  "Atari", "Pong Doubles [TTL]", MACHINE_SUPPORTS_SAVE)
494GAME( 1972, pongf,     0, pongf,    pong,      driver_device,  0, ROT0,  "Atari", "Pong (Rev E) [TTL]", MACHINE_SUPPORTS_SAVE )
495GAME( 1974, pongd,     0, pongd,    pongd,     driver_device,  0, ROT0,  "Atari", "Pong Doubles [TTL]", MACHINE_SUPPORTS_SAVE )
562496GAMEL( 1976, breakout,  0, breakout, breakout,  driver_device,  0, ROT90, "Atari", "Breakout [TTL]", MACHINE_SUPPORTS_SAVE, layout_breakout)
563
564// 100% TTL
565//GAME( 1973, coupedav,   pongd,    pongd,    pongd,     driver_device,  0, ROT0,  "Atari France", "Coupe Davis [TTL]", MACHINE_SUPPORTS_SAVE)
566//GAME( 1974, coupfran,   pong,     pong,     pong,      driver_device,  0, ROT0,  "Atari Europe", "Coup Franc [TTL]", MACHINE_SUPPORTS_SAVE)
567//GAME( 1974, cktpong,    pong,     pong,     pong,      driver_device,  0, ROT0,  "Atari / National Entertainment Co.", "Cocktail Pong [TTL]", MACHINE_SUPPORTS_SAVE)
568//GAME( 1974, drpong,     pong,     pong,     pong,      driver_device,  0, ROT0,  "Atari", "Dr. Pong [TTL]", MACHINE_SUPPORTS_SAVE)
569//GAME( 1974, pupppong,   pong,     pong,     pong,      driver_device,  0, ROT0,  "Atari", "Puppy Pong [TTL]", MACHINE_SUPPORTS_SAVE)
570//GAME( 1974, snoopong,   pong,     pong,     pong,      driver_device,  0, ROT0,  "Atari", "Snoopy Pong [TTL]", MACHINE_SUPPORTS_SAVE)
571//GAME( 1974, suprpong,   0,        suprpong, pong,      driver_device,  0, ROT0,  "Atari", "Superpong [TTL]", MACHINE_SUPPORTS_SAVE)
572//GAMEL( 1976, breakckt,  breakout, breakout, breakout,  driver_device,  0, ROT90, "Atari", "Breakout Cocktail [TTL]", MACHINE_SUPPORTS_SAVE, layout_breakckt)
573//GAMEL( 1976, consolet,  breakout, breakout, breakout,  driver_device,  0, ROT90, "Atari Europe", "Consolette [TTL]", MACHINE_SUPPORTS_SAVE, layout_consolet)
trunk/src/mame/includes/mz700.h
r250109r250110
1616#include "sound/speaker.h"
1717#include "imagedev/cassette.h"
1818#include "bus/centronics/ctronics.h"
19#include "machine/bankdev.h"
2019#include "machine/ram.h"
2120
2221class mz_state : public driver_device
2322{
2423public:
2524   mz_state(const machine_config &mconfig, device_type type, const char *tag)
26      : driver_device(mconfig, type, tag)
27      , m_maincpu(*this, "maincpu")
28      , m_speaker(*this, "speaker")
29      , m_pit(*this, "pit8253")
30      , m_ppi(*this, "ppi8255")
31      , m_cassette(*this, "cassette")
32      , m_centronics(*this, "centronics")
33      , m_ram(*this, RAM_TAG)
34      , m_palette(*this, "palette")
35      , m_banke(*this, "banke")
36      , m_bankf(*this, "bankf")
37      { }
25      : driver_device(mconfig, type, tag),
26      m_maincpu(*this, "maincpu"),
27      m_speaker(*this, "speaker"),
28      m_pit(*this, "pit8253"),
29      m_ppi(*this, "ppi8255"),
30      m_cassette(*this, "cassette"),
31      m_centronics(*this, "centronics"),
32      m_ram(*this, RAM_TAG),
33      m_gfxdecode(*this, "gfxdecode"),
34      m_palette(*this, "palette")  { }
3835
36   int m_mz700;                /* 1 if running on an mz700 */
37
38   int m_cursor_timer;
39   int m_other_timer;
40
41   int m_intmsk;   /* PPI8255 pin PC2 */
42
43   int m_mz700_ram_lock;       /* 1 if ram lock is active */
44   int m_mz700_ram_vram;       /* 1 if vram is banked in */
45
46   /* mz800 specific */
47   UINT8 *m_cgram;
48
49   int m_mz700_mode;           /* 1 if in mz700 mode */
50   int m_mz800_ram_lock;       /* 1 if lock is active */
51   int m_mz800_ram_monitor;    /* 1 if monitor rom banked in */
52
53   int m_hires_mode;           /* 1 if in 640x200 mode */
54   int m_screennum;           /* screen designation */
55
56   int m_centronics_busy;
57   int m_centronics_perror;
58
59   UINT8 *m_colorram;
60   UINT8 *m_videoram;
61   UINT8 m_speaker_level;
62   UINT8 m_prev_state;
63   UINT16 m_mz800_ramaddr;
64   UINT8 m_mz800_palette[4];
65   UINT8 m_mz800_palette_bank;
3966   DECLARE_READ8_MEMBER(mz700_e008_r);
4067   DECLARE_WRITE8_MEMBER(mz700_e008_w);
4168   DECLARE_READ8_MEMBER(mz800_bank_0_r);
r250109r250110
6087   DECLARE_WRITE8_MEMBER(mz800_cgram_w);
6188   DECLARE_DRIVER_INIT(mz800);
6289   DECLARE_DRIVER_INIT(mz700);
63   DECLARE_MACHINE_RESET(mz700);
64   DECLARE_MACHINE_RESET(mz800);
6590   virtual void machine_start();
91   DECLARE_PALETTE_INIT(mz);
92   DECLARE_VIDEO_START(mz800);
6693   UINT32 screen_update_mz700(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
6794   UINT32 screen_update_mz800(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
6895   TIMER_DEVICE_CALLBACK_MEMBER(ne556_cursor_callback);
r250109r250110
78105   DECLARE_WRITE8_MEMBER(mz800_z80pio_port_a_w);
79106   DECLARE_WRITE_LINE_MEMBER(write_centronics_busy);
80107   DECLARE_WRITE_LINE_MEMBER(write_centronics_perror);
81
82private:
83   int m_mz700;                /* 1 if running on an mz700 */
84
85   int m_cursor_timer;
86   int m_other_timer;
87
88   int m_intmsk;   /* PPI8255 pin PC2 */
89
90   int m_mz700_ram_lock;       /* 1 if ram lock is active */
91   int m_mz700_ram_vram;       /* 1 if vram is banked in */
92
93   /* mz800 specific */
94   UINT8 *m_cgram;
95   UINT8 *m_p_chargen;
96
97   int m_mz700_mode;           /* 1 if in mz700 mode */
98   int m_mz800_ram_lock;       /* 1 if lock is active */
99   int m_mz800_ram_monitor;    /* 1 if monitor rom banked in */
100
101   int m_hires_mode;           /* 1 if in 640x200 mode */
102   int m_screennum;           /* screen designation */
103
104   int m_centronics_busy;
105   int m_centronics_perror;
106
107   UINT8 *m_colorram;
108   UINT8 *m_videoram;
109   UINT8 m_speaker_level;
110   UINT8 m_prev_state;
111   UINT16 m_mz800_ramaddr;
112   UINT8 m_mz800_palette[4];
113   UINT8 m_mz800_palette_bank;
114
115108   required_device<cpu_device> m_maincpu;
116109   required_device<speaker_sound_device> m_speaker;
117110   required_device<pit8253_device> m_pit;
r250109r250110
119112   required_device<cassette_image_device> m_cassette;
120113   optional_device<centronics_device> m_centronics;
121114   required_device<ram_device> m_ram;
115   required_device<gfxdecode_device> m_gfxdecode;
122116   required_device<palette_device> m_palette;
123   optional_device<address_map_bank_device> m_banke;
124   optional_device<address_map_bank_device> m_bankf;
125117};
126118
127119#endif /* MZ700_H_ */
trunk/src/mame/machine/alpha8201.c
r250109r250110
2424Bull Fighter              1984   8303 (post)
2525Splendor Blast            1985   8303 (post)
2626Gekisou                   1985   8304 (post)
27The Koukou Yakyuu         1985   8304 (post)
28High Voltage              1985   8304?(post says 8404, but readme says 8304)
27The Koukouyakyuh          1985   8304 (post)
28High Voltage              1985   8404?(post says 8404, but readme says 8304)
2929
3030ALPHA-8201: "44801A75" -> HD44801, ROM code = A75
3131ALPHA-8302: "44801B35" -> HD44801, ROM code = B35
trunk/src/mame/machine/megadriv.c
r250109r250110
324324   {
325325      case 0:
326326         logerror("%06x read version register\n", space.device().safe_pc());
327         retdata = m_version_hi_nibble | 0x01; // Version number contained in bits 3-0
327         retdata = m_version_hi_nibble |
328                  0x00 | // Bit 3 of Version Number
329                  0x00 | // Bit 2 of Version Number
330                  0x00 | // Bit 1 of Version Number
331                  0x01 ; // Bit 0 of Version Number
328332         break;
329333
330334      /* Joystick Port Registers */
trunk/src/mame/machine/mz700.c
r250109r250110
4242   m_mz700 = TRUE;
4343   m_mz700_mode = TRUE;
4444
45   m_videoram = auto_alloc_array(machine(), UINT8, 0x1000);
46   memset(m_videoram, 0, sizeof(UINT8) * 0x1000);
47   m_colorram = m_videoram + 0x800;
48
49   m_p_chargen = memregion("cgrom")->base();
50   UINT8 *rom = memregion("monitor")->base();
51   UINT8 *ram = m_ram->pointer();
52   membank("bankr0")->configure_entry(0, &ram[0]); // ram
53   membank("bankr0")->configure_entry(1, &rom[0]); // rom
54   membank("bankw0")->configure_entry(0, &ram[0]); // ram
55   membank("bankd")->configure_entry(0, &ram[0xd000]); // ram
56   membank("bankd")->configure_entry(1, m_videoram); // vram
45   m_videoram = auto_alloc_array(machine(), UINT8, 0x800);
46   memset(m_videoram, 0, sizeof(UINT8) * 0x800);
47   m_colorram = auto_alloc_array(machine(), UINT8, 0x800);
48   memset(m_colorram, 0, sizeof(UINT8) * 0x800);
5749}
5850
5951DRIVER_INIT_MEMBER(mz_state,mz800)
6052{
6153   m_mz700 = FALSE;
62   m_mz700_mode = true;//FALSE;
54   m_mz700_mode = FALSE;
6355
6456   /* video ram */
6557   m_videoram = auto_alloc_array(machine(), UINT8, 0x4000);
r250109r250110
6961   /* character generator ram */
7062   m_cgram = auto_alloc_array(machine(), UINT8, 0x1000);
7163   memset(m_cgram, 0, sizeof(UINT8) * 0x1000);
72
73   m_p_chargen = memregion("cgrom")->base();
74   if (!m_p_chargen)
75      m_p_chargen = m_cgram;
76   UINT8 *rom = memregion("monitor")->base();
77   UINT8 *ram = m_ram->pointer();
78   // configure banks (0 = RAM in all cases)
79   membank("bankr0")->configure_entry(0, &ram[0]); // ram
80   membank("bankr0")->configure_entry(1, &rom[0]); // rom
81   membank("bankw0")->configure_entry(0, &ram[0]); // ram
82   membank("bank1")->configure_entry(0, &ram[0x1000]); // ram
83   membank("bank1")->configure_entry(1, &rom[0x1000]); // chargen
84   membank("banka")->configure_entry(0, &ram[0x8000]); // ram
85   membank("banka")->configure_entry(1, m_videoram); // vram in mz800 mode
86   membank("bankc")->configure_entry(0, &ram[0xc000]); // ram
87   membank("bankc")->configure_entry(1, m_cgram); // cgram in mz800 mode
88   membank("bankd")->configure_entry(0, &ram[0xd000]); // ram
89   membank("bankd")->configure_entry(1, m_videoram); // vram in mz700 mode
9064}
9165
9266void mz_state::machine_start()
9367{
9468   /* reset memory map to defaults */
95   mz700_bank_4_w(m_maincpu->space(AS_IO), 0, 0);
69   mz700_bank_4_w(m_maincpu->space(AS_PROGRAM), 0, 0);
9670}
9771
98MACHINE_RESET_MEMBER( mz_state, mz700 )
99{
100   membank("bankr0")->set_entry(1); //rom
101   membank("bankw0")->set_entry(0); //ram
102   membank("bankd")->set_entry(1); //vram
103   m_banke->set_bank(1); //devices
104}
10572
106MACHINE_RESET_MEMBER( mz_state, mz800 )
107{
108   // default to mz700 mode or mz1500 won't start.
109   membank("bankr0")->set_entry(1); //rom
110   membank("bankw0")->set_entry(0); //ram
111   membank("bank1")->set_entry(0); //ram
112   membank("banka")->set_entry(0); //ram
113   membank("bankc")->set_entry(0); //ram
114   membank("bankd")->set_entry(1); //vram
115   m_bankf->set_bank(1); //devices
116}
117
118
11973/***************************************************************************
12074    MMIO
12175***************************************************************************/
r250109r250110
14599
146100READ8_MEMBER(mz_state::mz800_bank_0_r)
147101{
148   //address_space &spc = m_maincpu->space(AS_PROGRAM);
102   UINT8 *videoram = m_videoram;
103   address_space &spc = m_maincpu->space(AS_PROGRAM);
149104
150105   /* switch in cgrom */
151   //spc.install_read_bank(0x1000, 0x1fff, "bank2");
152   //spc.nop_write(0x1000, 0x1fff);
153   //membank("bank2")->set_base(memregion("monitor")->base() + 0x1000);
154   membank("bank1")->set_entry(1);
106   spc.install_read_bank(0x1000, 0x1fff, "bank2");
107   spc.nop_write(0x1000, 0x1fff);
108   membank("bank2")->set_base(memregion("monitor")->base() + 0x1000);
155109
156110   if (m_mz700_mode)
157111   {
158112      /* cgram from 0xc000 to 0xcfff */
159      //spc.install_read_bank(0xc000, 0xcfff, "bank6");
160      //spc.install_write_handler(0xc000, 0xcfff, write8_delegate(FUNC(mz_state::mz800_cgram_w),this));
161      //membank("bank6")->set_base(m_cgram);
162      membank("bankc")->set_entry(1);
113      spc.install_read_bank(0xc000, 0xcfff, "bank6");
114      spc.install_write_handler(0xc000, 0xcfff, write8_delegate(FUNC(mz_state::mz800_cgram_w),this));
115      membank("bank6")->set_base(m_cgram);
163116   }
164117   else
165118   {
166119      if (m_hires_mode)
167120      {
168121         /* vram from 0x8000 to 0xbfff */
169         //spc.install_readwrite_bank(0x8000, 0xbfff, "bank4");
170         //membank("bank4")->set_base(m_videoram);
171         membank("banka")->set_entry(1);
122         spc.install_readwrite_bank(0x8000, 0xbfff, "bank4");
123         membank("bank4")->set_base(videoram);
172124      }
173125      else
174126      {
175127         /* vram from 0x8000 to 0x9fff */
176         //spc.install_readwrite_bank(0x8000, 0x9fff, "bank4");
177         //membank("bank4")->set_base(m_videoram);
128         spc.install_readwrite_bank(0x8000, 0x9fff, "bank4");
129         membank("bank4")->set_base(videoram);
178130
179131         /* ram from 0xa000 to 0xbfff */
180         //spc.install_readwrite_bank(0xa000, 0xbfff, "bank5");
181         //membank("bank5")->set_base(m_ram->pointer() + 0xa000);
182         membank("bank1")->set_entry(1);
132         spc.install_readwrite_bank(0xa000, 0xbfff, "bank5");
133         membank("bank5")->set_base(m_ram->pointer() + 0xa000);
183134      }
184135   }
185136
r250109r250110
188139
189140WRITE8_MEMBER(mz_state::mz700_bank_0_w)
190141{
191   //address_space &spc = m_maincpu->space(AS_PROGRAM);
142   address_space &spc = m_maincpu->space(AS_PROGRAM);
192143
193   //spc.install_readwrite_bank(0x0000, 0x0fff, "bank1a");
194   //membank("bank1a")->set_base(m_ram->pointer());
195   membank("bankr0")->set_entry(0); // ram
144   spc.install_readwrite_bank(0x0000, 0x0fff, "bank1");
145   membank("bank1")->set_base(m_ram->pointer());
196146}
197147
198148WRITE8_MEMBER(mz_state::mz800_bank_0_w)
199149{
200   //address_space &spc = m_maincpu->space(AS_PROGRAM);
150   address_space &spc = m_maincpu->space(AS_PROGRAM);
201151
202   //spc.install_readwrite_bank(0x0000, 0x7fff, "bank1a");
203   //membank("bank1a")->set_base(m_ram->pointer());
204   membank("bank1")->set_entry(0); // ram
205   membank("bankr0")->set_entry(0); // ram
152   spc.install_readwrite_bank(0x0000, 0x7fff, "bank1");
153   membank("bank1")->set_base(m_ram->pointer());
206154}
207155
208156READ8_MEMBER(mz_state::mz800_bank_1_r)
209157{
210   //address_space &spc = m_maincpu->space(AS_PROGRAM);
158   address_space &spc = m_maincpu->space(AS_PROGRAM);
211159
212160   /* switch in ram from 0x1000 to 0x1fff */
213   //spc.install_readwrite_bank(0x1000, 0x1fff, "bank2");
214   //membank("bank2")->set_base(m_ram->pointer() + 0x1000);
215   membank("bank1")->set_entry(0); // ram
161   spc.install_readwrite_bank(0x1000, 0x1fff, "bank2");
162   membank("bank2")->set_base(m_ram->pointer() + 0x1000);
216163
217164   if (m_mz700_mode)
218165   {
219166      /* ram from 0xc000 to 0xcfff */
220      //spc.install_readwrite_bank(0xc000, 0xcfff, "bank6");
221      //membank("bank6")->set_base(m_ram->pointer() + 0xc000);
222      membank("bankc")->set_entry(0); // ram
167      spc.install_readwrite_bank(0xc000, 0xcfff, "bank6");
168      membank("bank6")->set_base(m_ram->pointer() + 0xc000);
223169   }
224170   else
225171   {
226172      /* ram from 0x8000 to 0xbfff */
227      //spc.install_readwrite_bank(0x8000, 0xbfff, "bank4");
228      //membank("bank4")->set_base(m_ram->pointer() + 0x8000);
229      membank("banka")->set_entry(0); // ram
173      spc.install_readwrite_bank(0x8000, 0xbfff, "bank4");
174      membank("bank4")->set_base(m_ram->pointer() + 0x8000);
230175   }
231176
232177   return 0xff;
r250109r250110
234179
235180WRITE8_MEMBER(mz_state::mz700_bank_1_w)
236181{
237   //address_space &spc = m_maincpu->space(AS_PROGRAM);
238   membank("bankd")->set_entry(0); // ram
182   address_space &spc = m_maincpu->space(AS_PROGRAM);
239183
240184   if (m_mz700_mode)
241185   {
242186      /* switch in ram when not locked */
243187      if (!m_mz700_ram_lock)
244188      {
245         if (m_mz700)
246         {
247            //membank("bankd")->set_entry(0); // ram
248            m_banke->set_bank(0); //ram
249         }
250         else
251         {
252            //spc.install_readwrite_bank(0xd000, 0xffff, "bank7");
253            //spc.install_readwrite_bank(0xd000, 0xdfff, "bank7");
254            //membank("bank7")->set_base(m_ram->pointer() + 0xd000);
255            m_bankf->set_bank(0); //ram
256         }
189         spc.install_readwrite_bank(0xd000, 0xffff, "bank7");
190         membank("bank7")->set_base(m_ram->pointer() + 0xd000);
257191         m_mz700_ram_vram = FALSE;
258192      }
259193   }
r250109r250110
262196      /* switch in ram when not locked */
263197      if (!m_mz800_ram_lock)
264198      {
265         //spc.install_readwrite_bank(0xe000, 0xffff, "bank8");
266         //membank("bank8")->set_base(m_ram->pointer() + 0xe000);
267         m_bankf->set_bank(0); //ram
199         spc.install_readwrite_bank(0xe000, 0xffff, "bank8");
200         membank("bank8")->set_base(m_ram->pointer() + 0xe000);
268201         m_mz800_ram_monitor = FALSE;
269202      }
270203   }
r250109r250110
272205
273206WRITE8_MEMBER(mz_state::mz700_bank_2_w)
274207{
275   //address_space &spc = m_maincpu->space(AS_PROGRAM);
208   address_space &spc = m_maincpu->space(AS_PROGRAM);
276209
277   //spc.install_read_bank(0x0000, 0x0fff, "bank1a");
278   //spc.nop_write(0x0000, 0x0fff);
279   //membank("bank1a")->set_base(memregion("monitor")->base());
280   membank("bankr0")->set_entry(1); // rom
281
210   spc.install_read_bank(0x0000, 0x0fff, "bank1");
211   spc.nop_write(0x0000, 0x0fff);
212   membank("bank1")->set_base(memregion("monitor")->base());
282213}
283214
284215WRITE8_MEMBER(mz_state::mz700_bank_3_w)
285216{
286   //address_space &spc = m_maincpu->space(AS_PROGRAM);
217   UINT8 *videoram = m_videoram;
218   address_space &spc = m_maincpu->space(AS_PROGRAM);
287219
288220   if (m_mz700_mode)
289221   {
290222      if (!m_mz700_ram_lock)
291223      {
292         if (m_mz700)
293            membank("bankd")->set_entry(1);
294         else
295         {
296            /* switch in videoram */
297            //spc.install_readwrite_bank(0xd000, 0xd7ff, "bank7");
298            //membank("bank7")->set_base(m_videoram);
224         /* switch in videoram */
225         spc.install_readwrite_bank(0xd000, 0xd7ff, "bank7");
226         membank("bank7")->set_base(videoram);
299227
300            /* switch in colorram */
301            //spc.install_readwrite_bank(0xd800, 0xdfff, "bank9");
302            //membank("bank9")->set_base(m_colorram);
303            membank("bankd")->set_entry(1);
304         }
228         /* switch in colorram */
229         spc.install_readwrite_bank(0xd800, 0xdfff, "bank9");
230         membank("bank9")->set_base(m_colorram);
231
305232         m_mz700_ram_vram = TRUE;
306233
307234         /* switch in memory mapped i/o devices */
308235         if (m_mz700)
309236         {
310            m_banke->set_bank(1); //devices
237            spc.install_readwrite_handler(0xe000, 0xfff3, 0, 0x1ff0, read8_delegate(FUNC(i8255_device::read), (i8255_device*)m_ppi), write8_delegate(FUNC(i8255_device::write), (i8255_device*)m_ppi));
238            spc.install_readwrite_handler(0xe004, 0xfff7, 0, 0x1ff0, read8_delegate(FUNC(pit8253_device::read), (pit8253_device*)m_pit), write8_delegate(FUNC(pit8253_device::write), (pit8253_device*)m_pit));
239            spc.install_readwrite_handler(0xe008, 0xfff8, 0, 0x1ff0, read8_delegate(FUNC(mz_state::mz700_e008_r),this), write8_delegate(FUNC(mz_state::mz700_e008_w),this));
311240         }
312241         else
313242         {
314            m_bankf->set_bank(1); //devices
243            spc.install_readwrite_handler(0xe000, 0xe003, read8_delegate(FUNC(i8255_device::read), (i8255_device*)m_ppi), write8_delegate(FUNC(i8255_device::write), (i8255_device*)m_ppi));
244            spc.install_readwrite_handler(0xe004, 0xe007, read8_delegate(FUNC(pit8253_device::read), (pit8253_device*)m_pit), write8_delegate(FUNC(pit8253_device::write), (pit8253_device*)m_pit));
245            spc.install_readwrite_handler(0xe008, 0xe008, read8_delegate(FUNC(mz_state::mz700_e008_r),this), write8_delegate(FUNC(mz_state::mz700_e008_w),this));
315246         }
316247      }
317248   }
r250109r250110
320251      if (!m_mz800_ram_lock)
321252      {
322253         /* switch in mz800 monitor rom if not locked */
323         //spc.install_read_bank(0xe000, 0xffff, "bank8");
324         //spc.nop_write(0xe000, 0xffff);
325         //membank("bank8")->set_base(memregion("monitor")->base() + 0x2000);
326         m_bankf->set_bank(1); // devices + rom
254         spc.install_read_bank(0xe000, 0xffff, "bank8");
255         spc.nop_write(0xe000, 0xffff);
256         membank("bank8")->set_base(memregion("monitor")->base() + 0x2000);
327257         m_mz800_ram_monitor = TRUE;
328258      }
329259   }
r250109r250110
331261
332262WRITE8_MEMBER(mz_state::mz700_bank_4_w)
333263{
334   //address_space &spc = m_maincpu->space(AS_PROGRAM);
264   UINT8 *videoram = m_videoram;
265   address_space &spc = m_maincpu->space(AS_PROGRAM);
335266
336267   if (m_mz700_mode)
337268   {
r250109r250110
339270      mz700_bank_2_w(space, 0, 0);    /* switch in monitor rom */
340271      mz700_bank_3_w(space, 0, 0);    /* switch in videoram, colorram, and mmio */
341272
342      if (!m_mz700)
343      {
344         /* rest is ram is always ram in mz700 mode */
345         //spc.install_readwrite_bank(0x1000, 0xcfff, "bank2");
346         //membank("bank2")->set_base(m_ram->pointer() + 0x1000);
347         membank("bankr0")->set_entry(1); // rom
348         membank("bank1")->set_entry(0); // ram
349         membank("bankc")->set_entry(0); // ram
350      }
273      /* rest is ram is always ram in mz700 mode */
274      spc.install_readwrite_bank(0x1000, 0xcfff, "bank2");
275      membank("bank2")->set_base(m_ram->pointer() + 0x1000);
351276   }
352277   else
353278   {
354279      /* monitor rom and cgrom */
355      //spc.install_read_bank(0x0000, 0x1fff, "bank1a");
356      //spc.nop_write(0x0000, 0x1fff);
357      //membank("bank1a")->set_base(memregion("monitor")->base());
358      membank("bankr0")->set_entry(1); // rom
359      membank("bank1")->set_entry(1); // rom
280      spc.install_read_bank(0x0000, 0x1fff, "bank1");
281      spc.nop_write(0x0000, 0x1fff);
282      membank("bank1")->set_base(memregion("monitor")->base());
360283
361284      /* ram from 0x2000 to 0x7fff */
362      //spc.install_readwrite_bank(0x2000, 0x7fff, "bank3");
363      //membank("bank3")->set_base(m_ram->pointer());
285      spc.install_readwrite_bank(0x2000, 0x7fff, "bank3");
286      membank("bank3")->set_base(m_ram->pointer());
364287
365288      if (m_hires_mode)
366289      {
367290         /* vram from 0x8000 to 0xbfff */
368         //spc.install_readwrite_bank(0x8000, 0xbfff, "bank4");
369         //membank("bank4")->set_base(m_videoram);
370         membank("banka")->set_entry(1); // vram
291         spc.install_readwrite_bank(0x8000, 0xbfff, "bank4");
292         membank("bank4")->set_base(videoram);
371293      }
372294      else
373295      {
374296         /* vram from 0x8000 to 0x9fff */
375         //spc.install_readwrite_bank(0x8000, 0x9fff, "bank4");
376         //membank("bank4")->set_base(m_videoram);
377         membank("banka")->set_entry(1); // vram
297         spc.install_readwrite_bank(0x8000, 0x9fff, "bank4");
298         membank("bank4")->set_base(videoram);
378299
379300         /* ram from 0xa000 to 0xbfff */
380         //spc.install_readwrite_bank(0xa000, 0xbfff, "bank5");
381         //membank("bank5")->set_base(m_ram->pointer() + 0xa000);
301         spc.install_readwrite_bank(0xa000, 0xbfff, "bank5");
302         membank("bank5")->set_base(m_ram->pointer() + 0xa000);
382303      }
383304
384305      /* ram from 0xc000 to 0xdfff */
385      //spc.install_readwrite_bank(0xc000, 0xdfff, "bank6");
386      //membank("bank6")->set_base(m_ram->pointer() + 0xc000);
387      membank("bankd")->set_entry(0); // ram
306      spc.install_readwrite_bank(0xc000, 0xdfff, "bank6");
307      membank("bank6")->set_base(m_ram->pointer() + 0xc000);
388308
389309      /* mz800 monitor rom from 0xe000 to 0xffff */
390      //spc.install_read_bank(0xe000, 0xffff, "bank8");
391      //spc.nop_write(0xe000, 0xffff);
392      //membank("bank8")->set_base(memregion("monitor")->base() + 0x2000);
393      m_bankf->set_bank(1); // devices + rom
310      spc.install_read_bank(0xe000, 0xffff, "bank8");
311      spc.nop_write(0xe000, 0xffff);
312      membank("bank8")->set_base(memregion("monitor")->base() + 0x2000);
394313      m_mz800_ram_monitor = TRUE;
395314
396315      m_mz800_ram_lock = FALSE; /* reset lock? */
r250109r250110
399318
400319WRITE8_MEMBER(mz_state::mz700_bank_5_w)
401320{
402   //address_space &spc = m_maincpu->space(AS_PROGRAM);
321   address_space &spc = m_maincpu->space(AS_PROGRAM);
403322
404323   if (m_mz700_mode)
405324   {
406325      /* prevent access from 0xd000 to 0xffff */
407326      m_mz700_ram_lock = TRUE;
408      if (m_mz700)
409         m_banke->set_bank(2);
410      else
411         //spc.nop_readwrite(0xd000, 0xdfff);
412         //spc.nop_readwrite(0xd000, 0xffff);
413         m_bankf->set_bank(2);
327      spc.nop_readwrite(0xd000, 0xffff);
414328   }
415329   else
416330   {
417331      /* prevent access from 0xe000 to 0xffff */
418332      m_mz800_ram_lock = TRUE;
419      //spc.nop_readwrite(0xe000, 0xffff);
420      m_bankf->set_bank(2);
333      spc.nop_readwrite(0xe000, 0xffff);
421334   }
422335}
423336
r250109r250110
522435   LOG(2,"mz700_pio_port_a_w",("%02X\n", data),machine());
523436
524437   /* the ls145 is connected to PA0-PA3 */
525   dynamic_cast<ttl74145_device *>(device)->write(data & 0x0f);
438   dynamic_cast<ttl74145_device *>(device)->write(data & 0x07);
526439
527440   /* ne556 reset is connected to PA7 */
528441   timer->enable(BIT(data, 7));
trunk/src/mame/machine/namcoio.c
r250109r250110
285285
286286//popmessage("%x %x %x %x %x %x %x %x",IORAM_READ(8),IORAM_READ(9),IORAM_READ(10),IORAM_READ(11),IORAM_READ(12),IORAM_READ(13),IORAM_READ(14),IORAM_READ(15));
287287
288         m_out_0_cb((offs_t)0, IORAM_READ(9));   // output to pins 13-16 (motos, pacnpal, gaplus)
289         m_out_1_cb((offs_t)0, IORAM_READ(10));  // output to pins 17-20 (gaplus)
288         m_out_0_cb((offs_t)0, IORAM_READ(9) & 0x0f);   // output to pins 13-16 (motos, pacnpal, gaplus)
289         m_out_1_cb((offs_t)0, IORAM_READ(10) & 0x0f);  // output to pins 17-20 (gaplus)
290290         break;
291291
292292      case 2: // initialize coinage settings
r250109r250110
388388
389389//popmessage("%x %x %x %x %x %x %x %x",IORAM_READ(8),IORAM_READ(9),IORAM_READ(10),IORAM_READ(11),IORAM_READ(12),IORAM_READ(13),IORAM_READ(14),IORAM_READ(15));
390390
391         m_out_0_cb((offs_t)0, IORAM_READ(9));   // output to pins 13-16 (toypop)
392         m_out_1_cb((offs_t)0, IORAM_READ(10));  // output to pins 17-20 (toypop)
391         m_out_0_cb((offs_t)0, IORAM_READ(9) & 0x0f);   // output to pins 13-16 (toypop)
392         m_out_1_cb((offs_t)0, IORAM_READ(10) & 0x0f);  // output to pins 17-20 (toypop)
393393         break;
394394
395395      case 2: // initialize coinage settings
trunk/src/mame/video/fuukifg3.c
r250109r250110
5454{
5555   UINT16 code = (m_vram[_N_][tile_index] & 0xffff0000) >> 16;
5656   UINT16 attr = (m_vram[_N_][tile_index] & 0x0000ffff);
57   SET_TILE_INFO_MEMBER(1 + _N_, code, (attr & 0x3f) >> 4, TILE_FLIPYX(attr >> 6));
57   SET_TILE_INFO_MEMBER(1 + _N_, code, (attr & 0x3f) >> 4, TILE_FLIPYX((attr >> 6) & 3));
5858}
5959
6060TILE_GET_INFO_MEMBER(fuuki32_state::get_tile_info_0){ get_tile_info8bpp(tileinfo, tile_index, 0); }
r250109r250110
6464{
6565   UINT16 code = (m_vram[_N_][tile_index] & 0xffff0000) >> 16;
6666   UINT16 attr = (m_vram[_N_][tile_index] & 0x0000ffff);
67   SET_TILE_INFO_MEMBER(1 + _N_, code, attr & 0x3f, TILE_FLIPYX(attr >> 6));
67   SET_TILE_INFO_MEMBER(1 + _N_, code, attr & 0x3f, TILE_FLIPYX((attr >> 6) & 3));
6868}
6969
7070TILE_GET_INFO_MEMBER(fuuki32_state::get_tile_info_2){ get_tile_info4bpp(tileinfo, tile_index, 2); }
trunk/src/mame/video/mcr.c
r250109r250110
5757   int data = videoram[tile_index * 2] | (videoram[tile_index * 2 + 1] << 8);
5858   int code = data & 0x1ff;
5959   int color = (data >> 11) & 3;
60   SET_TILE_INFO_MEMBER(0, code, color, TILE_FLIPYX(data >> 9));
60   SET_TILE_INFO_MEMBER(0, code, color, TILE_FLIPYX((data >> 9) & 3));
6161
6262   /* sprite color base comes from the top 2 bits */
6363   tileinfo.category = (data >> 14) & 3;
r250109r250110
8383   int data = videoram[tile_index * 2] | (videoram[tile_index * 2 + 1] << 8);
8484   int code = data & 0x3ff;
8585   int color = (data >> 12) & 3;
86   SET_TILE_INFO_MEMBER(0, code, color, TILE_FLIPYX(data >> 10));
86   SET_TILE_INFO_MEMBER(0, code, color, TILE_FLIPYX((data >> 10) & 3));
8787
8888   /* sprite color base might come from the top 2 bits */
8989   tileinfo.category = (data >> 14) & 3;
trunk/src/mame/video/mcr3.c
r250109r250110
3636   int data = videoram[tile_index * 2] | (videoram[tile_index * 2 + 1] << 8);
3737   int code = (data & 0x3ff) | ((data >> 4) & 0x400);
3838   int color = ((data >> 12) & 3) ^ 3;
39   SET_TILE_INFO_MEMBER(0, code, color, TILE_FLIPYX(data >> 10));
39   SET_TILE_INFO_MEMBER(0, code, color, TILE_FLIPYX((data >> 10) & 3));
4040}
4141
4242
trunk/src/mame/video/mcr68.c
r250109r250110
2626   int data = LOW_BYTE(videoram[tile_index * 2]) | (LOW_BYTE(videoram[tile_index * 2 + 1]) << 8);
2727   int code = (data & 0x3ff) | ((data >> 4) & 0xc00);
2828   int color = (~data >> 12) & 3;
29   SET_TILE_INFO_MEMBER(0, code, color, TILE_FLIPYX(data >> 10));
29   SET_TILE_INFO_MEMBER(0, code, color, TILE_FLIPYX((data >> 10) & 3));
3030   if (m_gfxdecode->gfx(0)->elements() < 0x1000)
3131      tileinfo.category = (data >> 15) & 1;
3232}
r250109r250110
3737   UINT16 *videoram = m_videoram;
3838   int data = videoram[tile_index];
3939   int color = (data >> 13) & 7;
40   SET_TILE_INFO_MEMBER(0, data & 0x3ff, color, TILE_FLIPYX(data >> 11));
40   SET_TILE_INFO_MEMBER(0, data & 0x3ff, color, TILE_FLIPYX((data >> 11) & 3));
4141}
4242
4343
r250109r250110
4646   UINT16 *videoram = m_videoram;
4747   int data = videoram[tile_index];
4848   int color = (data >> 13) & 7;
49   SET_TILE_INFO_MEMBER(2, data & 0x3ff, color, TILE_FLIPYX(data >> 11));
49   SET_TILE_INFO_MEMBER(2, data & 0x3ff, color, TILE_FLIPYX((data >> 11) & 3));
5050   tileinfo.category = (color != 0);
5151}
5252
trunk/src/mame/video/mz700.c
r250109r250110
1515#include "includes/mz700.h"
1616
1717
18#ifndef VERBOSE
19#define VERBOSE 1
20#endif
21
22#define LOG(N,M,A)  \
23   do { \
24      if(VERBOSE>=N) \
25      { \
26         if( M ) \
27            logerror("%11.6f: %-24s",machine.time().as_double(),(char*)M ); \
28         logerror A; \
29      } \
30   } while (0)
31
32
33PALETTE_INIT_MEMBER(mz_state, mz)
34{
35   int i;
36
37   for (i = 0; i < 8; i++)
38      m_palette->set_indirect_color(i, rgb_t((i & 2) ? 0xff : 0x00, (i & 4) ? 0xff : 0x00, (i & 1) ? 0xff : 0x00));
39
40   for (i = 0; i < 256; i++)
41   {
42      m_palette->set_pen_indirect(i*2, i & 7);
43         m_palette->set_pen_indirect(i*2+1, (i >> 4) & 7);
44   }
45}
46
47
1848UINT32 mz_state::screen_update_mz700(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
1949{
20   UINT8 y,ra,gfx,col,bg=0,fg=0,oldcol=0x7e;
21   UINT16 sy=0,ma=0,x,chr;
50   UINT8 *videoram = m_videoram;
51   int offs;
2252
23   for (y = 0; y < 25; y++)
53   bitmap.fill(m_palette->black_pen(), cliprect);
54
55   for(offs = 0; offs < 40*25; offs++)
2456   {
25      for (ra = 0; ra < 8; ra++)
26      {
27         UINT16 *p = &bitmap.pix16(sy++);
57      int sx, sy, code, color;
2858
29         for (x = ma; x < ma + 40; x++)
30         {
31            col = m_colorram[x];
32            if (col != oldcol)
33            {
34               oldcol = col;
35               col = BITSWAP8(col, 7, 3, 4, 6, 5, 0, 2, 1); // turn BRG into RGB
36               bg = col & 7;
37               fg = (col >> 3) & 7;
38            }
39            chr = m_videoram[x] | (BIT(col, 7)<<8);
40            gfx = m_p_chargen[(chr<<3) | ra ];
59      sy = (offs / 40) * 8;
60      sx = (offs % 40) * 8;
4161
42            /* Display a scanline of a character */
43            *p++ = BIT(gfx, 0) ? fg : bg;
44            *p++ = BIT(gfx, 1) ? fg : bg;
45            *p++ = BIT(gfx, 2) ? fg : bg;
46            *p++ = BIT(gfx, 3) ? fg : bg;
47            *p++ = BIT(gfx, 4) ? fg : bg;
48            *p++ = BIT(gfx, 5) ? fg : bg;
49            *p++ = BIT(gfx, 6) ? fg : bg;
50            *p++ = BIT(gfx, 7) ? fg : bg;
51         }
52      }
53      ma+=40;
62      color = m_colorram[offs];
63      code = videoram[offs] | (color & 0x80) << 1;
64
65      m_gfxdecode->gfx(0)->opaque(bitmap,cliprect, code, color, 0, 0, sx, sy);
5466   }
67
5568   return 0;
5669}
5770
5871
5972/***************************************************************************
6073    MZ-800
61    Not working.
6274***************************************************************************/
6375
76VIDEO_START_MEMBER(mz_state,mz800)
77{
78   m_gfxdecode->gfx(0)->set_source(m_cgram);
79}
80
6481UINT32 mz_state::screen_update_mz800(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
6582{
83   UINT8 *videoram = m_videoram;
84
85   bitmap.fill(m_palette->black_pen(), cliprect);
86
6687   if (m_mz700_mode)
6788      return screen_update_mz700(screen, bitmap, cliprect);
6889   else
r250109r250110
7394      else
7495      {
7596         int x, y;
97         UINT8 *start_addr = videoram;
7698
7799         for (x = 0; x < 40; x++)
78100         {
79101            for (y = 0; y < 200; y++)
80102            {
81               bitmap.pix16(y, x * 8 + 0) = BIT(m_videoram[x * 8 + y], 0) ? 7 : 0;
82               bitmap.pix16(y, x * 8 + 1) = BIT(m_videoram[x * 8 + y], 1) ? 7 : 0;
83               bitmap.pix16(y, x * 8 + 2) = BIT(m_videoram[x * 8 + y], 2) ? 7 : 0;
84               bitmap.pix16(y, x * 8 + 3) = BIT(m_videoram[x * 8 + y], 3) ? 7 : 0;
85               bitmap.pix16(y, x * 8 + 4) = BIT(m_videoram[x * 8 + y], 4) ? 7 : 0;
86               bitmap.pix16(y, x * 8 + 5) = BIT(m_videoram[x * 8 + y], 5) ? 7 : 0;
87               bitmap.pix16(y, x * 8 + 6) = BIT(m_videoram[x * 8 + y], 6) ? 7 : 0;
88               bitmap.pix16(y, x * 8 + 7) = BIT(m_videoram[x * 8 + y], 7) ? 7 : 0;
103               bitmap.pix16(y, x * 8 + 0) = BIT(start_addr[x * 8 + y], 0);
104               bitmap.pix16(y, x * 8 + 1) = BIT(start_addr[x * 8 + y], 1);
105               bitmap.pix16(y, x * 8 + 2) = BIT(start_addr[x * 8 + y], 2);
106               bitmap.pix16(y, x * 8 + 3) = BIT(start_addr[x * 8 + y], 3);
107               bitmap.pix16(y, x * 8 + 4) = BIT(start_addr[x * 8 + y], 4);
108               bitmap.pix16(y, x * 8 + 5) = BIT(start_addr[x * 8 + y], 5);
109               bitmap.pix16(y, x * 8 + 6) = BIT(start_addr[x * 8 + y], 6);
110               bitmap.pix16(y, x * 8 + 7) = BIT(start_addr[x * 8 + y], 7);
89111            }
90112         }
91113      }
r250109r250110
101123WRITE8_MEMBER(mz_state::mz800_cgram_w)
102124{
103125   m_cgram[offset] = data;
126
127   m_gfxdecode->gfx(0)->mark_dirty(offset/8);
104128}
trunk/web/css/images/ajax-loader.gif
r0r250110
Previous 199869 Revisions Next


© 1997-2024 The MAME Team