Compare commits

..
48 Commits
Author SHA1 Message Date
Deomid Ryabkov ab650ec5c9 Merge branch 'dev' 2019-03-04 15:19:32 +00:00
Deomid Ryabkov 8f36597048 Mongoose 6.14
PUBLISHED_FROM=3e6e17d1f1cfb05efc37d76279dcbedb7f1add5d
2019-03-04 15:15:35 +00:00
Deomid Ryabkov d0213ee90a ESP32: Add support for the 3/4 key encoding scheme
* Add calculated redundancy values when writing eFuse blocks 1-3
 * Perform 192 -> 256 bit key extension when encrypting images for flashing

Fixes https://github.com/cesanta/mos-tool/issues/37

CL: mos: ESP32: Add support for the 3/4 key encoding scheme

PUBLISHED_FROM=16639fb25d5200550ad2097929239d896e188b5b
2019-03-04 09:18:28 +00:00
Deomid Ryabkov 1e9fabe1ca Fix handling of WS handshake error response
Check response code, make sure it's 101.
Pass http_message to the client to keep it appraised.
This represents a slight change in the API -
in case of an error MG_EV_WEBSOCKET_HANDSHAKE_DONE will now be delivered where previosuly connection would just hang.
Clients that do not examine the argument may for a moment think handshake has succeeded but in fact connection will be closed immediately.

CL: mg: Fix handling of WS handshake error response

PUBLISHED_FROM=645a43d9e5bee216e54411f85827c9b974e9a7d1
2019-02-14 21:19:34 +00:00
Deomid Ryabkov 148d3f0562 STM32F2 and Particle Electron board support
CL: STM32F2 and Particle Electron board support

PUBLISHED_FROM=20dede6546e9f99d2829508177924790d87e985a
2019-02-12 13:36:54 +00:00
Deomid Ryabkov c3057df3f5 Fix mongoose CI test
CL: none

PUBLISHED_FROM=9510e460251c250cb6a67a40edc0af515044f9fe
2019-02-08 17:38:56 +00:00
Deomid Ryabkov 0b2e474d52 Improve ESP flasher baud rate setting
Use old baud rate and autodetected divider to calculate new divider.

This works better with higher baud rates and drifting clocks.

CL: mos: Improve ESP flasher baud rate setting

PUBLISHED_FROM=7761e756c3ae7cc76e3b9a4fe3e40d06a779b2e8
2019-02-08 17:38:55 +00:00
Deomid Ryabkov 95a36b1759 Log file:line instead of function; add cs_log_set_file_level()
cs_log_set_filter() is removed in favor of cs_log_set_file_level() which
allows setting log verbosity of individual files and/or lines.

E.g.: `mg_=1,mjs=1,=4` - level for for everything except mjs and mongoose.

We use the fact that we are usually pretty careful with our file names and use prefixes consistently.

In mos, `debug.file_level` sets the option on boot and `Sys.SetDebug` is updated to parse `file_level` option to change it at runtime.

CL: Log file:line instead of function; add cs_log_set_file_level()

PUBLISHED_FROM=49f18d4d0d3dd224865129a4f8fe6cccd1d9bc12
2019-01-30 12:57:19 +00:00
Deomid Ryabkov 86ffa3a3ea Properly support MQTT wildcards when matching topics
CL: mg: Properly support MQTT wildcards when matching topics

PUBLISHED_FROM=aa60a71d488f4b56dff0951886c8a9a4066fd4f2
2019-01-22 12:19:04 +00:00
Deomid Ryabkov 69e2b2985d Add mg_strfree()
CL: Add mg_strfree()

PUBLISHED_FROM=b80566218986e0607a9d2758bf776a1031b27212
2019-01-16 22:48:59 +00:00
Бобби c431904b56 Send extra options with OPTIONS
CL: Send extra options with OPTIONS. Integrate https://github.com/cesanta/mongoose/pull/657

PUBLISHED_FROM=6ee609a92febd8d908f7713f94fb73657443a09a
2019-01-16 11:33:57 +00:00
Deomid Ryabkov c2a10601b9 Fix nsleep100 on STM32
CL: Fix nsleep100 on STM32

PUBLISHED_FROM=cabb98a0541bac9bb66bfa702d54bf8ff20063e7
2019-01-08 20:43:55 +00:00
Deomid Ryabkov e9a8e5468d Convert Python scripts to Python 3, delete unused ones
CL: none

PUBLISHED_FROM=4bbc2175634e20a726dd4b2dadff57f945b261d0
2018-12-25 20:38:58 +00:00
Sergey Lyubka 22e602debb Check for NULL in tcp_recved_tcpip()
CL: Check for NULL in tcp_recved_tcpip()

PUBLISHED_FROM=3f5bbc2e35b79d363eac4b99a1f0d17c9b81d4ec
2018-12-21 13:03:48 +00:00
Deomid Ryabkov 455cec67a5 CC3220: Enterprise auth support
CL: wifi: CC3220: Enterprise auth support

PUBLISHED_FROM=ce445eb5b740073c9a3f9811f1acd404ce134f2e
2018-12-18 18:19:21 +00:00
Deomid Ryabkov e2dfac946d Ensure that user sees all the data before connection is closed
If user throttles receive by setting recv_mbuf_limit,
after the net interface reports connection as closed we must wait
for data to trickle through before disposing of it.
There can still b data in the buffers (e.g. SSL).

CL: mg: Ensure that user sees all the data before connection is closed

PUBLISHED_FROM=22be0fa368950a9fdb03cfb00febc7c0a1674b01
2018-12-10 21:04:49 +00:00
Бобби c198d2e5f1 Make MG_CTL_MSG_MESSAGE_SIZE overridable
CL: Make MG_CTL_MSG_MESSAGE_SIZE overridable

Fix https://github.com/cesanta/mongoose/pull/987

PUBLISHED_FROM=b0a7c67297b98f616c9eadcd3c34b8747939c918
2018-12-07 10:04:00 +00:00
Deomid Ryabkov 9a70abef24 Add mbuf_append_and_free() and mbuf_move()
CL: Add mbuf_append_and_free() and mbuf_move()

PUBLISHED_FROM=bdf73906dd93b2ebeace160596508e15480b54b4
2018-12-05 21:49:01 +00:00
Deomid Ryabkov 53e1c469a2 Add ability for multipart data handler to provide pushback
It can specify how much data was actually processed and the rest will be re-delivered on next poll.

CL: mg: Add ability for multipart data handler to provide pushback

PUBLISHED_FROM=e0168c5064c3a32921c9209bc09f4da2079cd616
2018-12-05 16:02:56 +00:00
Deomid Ryabkov 139c2061a8 Add create-fw-bundle command
Replacement for fw_meta.py commands and also supports unbundling .hex files.

General syntax is:

```
 $ mos create-fw-bundle -o fw.zip part1:prop1=val1,prop2=val2,... part2:...
```

Example of building a mos fw bundle for ESP8266:
```
 $ mos create-fw-bundle -o fw.zip --platform esp8266 --build-info=build_info.json \
    boot:addr=0x0,src=rboot.bin,update=false \
    boot_cfg:addr=0x7000,size=0x1000,fill=0xff \
    fw:addr=0x100000,src=demo-c.bin \
    fs:src=fs.bin,type=fs,addr=0x8000,fs_size=262144,fs_block_size=4096,fs_page_size=256,fs_erase_size=4096
```

Example of converting a HEX file to a bundle:
```
 $ mos create-fw-bundle -o fw.zip host:type=host,src=hostfw.hex
```

CL: mos: Add create-fw-bundle command

PUBLISHED_FROM=35f52ea53e4b5900463415257323a4c08cf45deb
2018-11-28 20:34:06 +00:00
Deomid Ryabkov 15b361fbac Add mbuf_clear()
PUBLISHED_FROM=754b98b3000b24ad3b3d9cc0b4c480ca005a1c3f
2018-11-23 15:50:55 +00:00
Deomid Ryabkov 3130e59244 Stop reading if connection is closing
CL: none

PUBLISHED_FROM=3b74ca02e2960bbbf130f6d95aef679f2917e824
2018-11-02 18:12:34 +00:00
Deomid Ryabkov 93286836f9 Read all available data during recv poll
CL: mg: Read all available data during recv poll

PUBLISHED_FROM=b081025b9fb392c988924c7097b5333c38053f6f
2018-11-02 14:50:32 +00:00
Deomid Ryabkov 91b57aa9a8 Add MG_MK_STR_N() and mg_str_starts_with()
CL: Add MG_MK_STR_N() and mg_str_starts_with()

PUBLISHED_FROM=f01003efc6aa6ff45fa99c7ad6e5319f5002f22d
2018-10-29 15:50:31 +00:00
Deomid Ryabkov 220231e647 Fix digest auth result comparison
Should use length of the exected response, not the response sent by the user.

CL: mg: Fix digest auth result comparison

PUBLISHED_FROM=23375133b8babac0b276b51395917ad975e1bd3c
2018-10-15 16:47:18 +00:00
Deomid Ryabkov c438bb0bc5 Make mg_rpc more easily portable
CL: none

PUBLISHED_FROM=2e77d72cdf82454349a7fe29cc77bd0b90ac4369
2018-10-09 12:04:12 +00:00
Deomid Ryabkov 95afa323c0 Merge pull request #978 from cesanta/dev
Mongoose 6.13
2018-10-08 14:06:45 +01:00
Deomid Ryabkov bc56353a79 Mongoose 6.13
CL: none

PUBLISHED_FROM=32418b7da17a68193e88405547152f58a4dd877f
2018-10-08 12:20:32 +00:00
Deomid Ryabkov 1ffccdb7b2 Remove a spammy log line
PUBLISHED_FROM=b3ec2b3b43a464700a6e6d75b7336f823549cce3
2018-10-04 15:48:48 +00:00
Deomid Ryabkov e79fe4b8f0 Update mbedTLS to 2.13.1
CL: Update mbedTLS to 2.13.1

PUBLISHED_FROM=bd1216f727605a901f062a044c0c0ca762f4a6d1
2018-10-04 10:06:35 +00:00
Deomid Ryabkov aaf1fc3a4a Schedule a poll when LwIP reports TCP data sent
PUBLISHED_FROM=0cf3029d9a9b851882325e2298b878bc83fc2d33
2018-09-28 11:03:47 +00:00
Deomid Ryabkov 8b42353039 Check HTTP chunk size, ensure it's reasonable
CL: mg: Check HTTP chunk size, ensure it's reasonable

PUBLISHED_FROM=d9f6babd314c092b42ce9e7fe31d6b30a38366a2
2018-09-27 12:51:21 +00:00
Deomid Ryabkov 05c687e251 Fix handling of keepalive HTTP requests/responses
Clean the HTTP connection state when ia request/response has been fully
buffered and handler invoked.

Fixes https://github.com/cesanta/mongoose/issues/971

CL: mg: Fix handling of keepalive HTTP requests/responses

PUBLISHED_FROM=70c854aa306aacb9161f6ee48841f38dc0312e6b
2018-09-27 12:51:18 +00:00
Deomid Ryabkov 492b8f6950 CC3200: Fix boot loader regression
Go back to Ubuntu 16.04 and older gcc-arm (4.9.3).

Boot loader just won't run when compiled with newer GCC (7.x).
It's likely that it can be fixed with compile switches but I couldn't figure it out quickly, so going to just downgrade for now to get it back to workign state.

CL: CC3200: Fix boot loader regression

PUBLISHED_FROM=b70b03bd17e03c7dae02328b32b855f3ca3ad6a9
2018-09-25 20:32:35 +00:00
Deomid Ryabkov 8ccee82059 Add mgos_gpio_blink()
CL: Add mgos_gpio_blink()

PUBLISHED_FROM=a5d2e2f44413d1ab363abeeaf0fb497bd8f63d6d
2018-09-25 20:32:33 +00:00
Deomid Ryabkov b99a94a652 Fix build w/o logging
PUBLISHED_FROM=694346bd6562c55e5ab00886df47f7cbfb0a3720
2018-09-25 11:34:05 +00:00
Deomid Ryabkov 41e5d7e471 Use mbedTLS from mongoose-os-libs/mbedtls
mbedTLS is just another lib now

CL: Use mbedTLS from mongoose-os-libs/mbedtls

PUBLISHED_FROM=bae4739d22e871bd268b8a3233dbb69634770243
2018-09-20 20:38:11 +00:00
Sergey Lyubka 1adea37c45 Integrate https://github.com/cesanta/mongoose/pull/667, fix documentation
CL: Integrate https://github.com/cesanta/mongoose/pull/667, fix documentation

PUBLISHED_FROM=80a939fc3276b89c29716e7373f674dba86769ee
2018-09-20 15:34:36 +00:00
Deomid Ryabkov 98f6c8aa4f Trim recv_mbuf when we know the size of the data
CL: none

PUBLISHED_FROM=e354b67ab6f8246af50c601f5f70d36c029601ea
2018-09-17 16:04:00 +00:00
Deomid Ryabkov 341ae53e85 Update mongoose.h (amalgamation)
PUBLISHED_FROM=1fbe72f99bda5745c4b9b9def0601bdc5bf70e65
2018-09-14 21:19:15 +00:00
Sergey Lyubka 291fc024cd Docs nits
CL: Docs nits

PUBLISHED_FROM=1a2fc8080d94673acf300c6f07aba3a1e6272295
2018-09-14 08:03:58 +00:00
Deomid Ryabkov f63d833a33 Update STM32 build image
* Update CubeL4 to 1.13.0
 * Rebuild OurTLS with `-DMBEDTLS_X509_CA_CHAIN_ON_DISK`
 * Add `-Wextra` and fix build issues

CL: Update STM32 build image

PUBLISHED_FROM=a7eacff7580bab6c6e40bdaf6164df575a717c55
2018-09-11 11:49:08 +00:00
Deomid Ryabkov ab035901f8 ISM43XXX networking support (TCP, UDP client)
Listeners still TODO

CL: ISM43XXX networking support (TCP, UDP client)

PUBLISHED_FROM=b58ba88b9e6bd7b55ccb607d0b69cea98cb52fa5
2018-09-11 06:34:08 +00:00
Deomid Ryabkov 20f54059ad STM32: Make LWIP optional
CL: STM32: Make LWIP optional

PUBLISHED_FROM=eebffe7800a74d7b69aafd95e476b2e90328be98
2018-09-06 11:27:58 +00:00
Deomid Ryabkov 563c31303e Add net_if_null, a no-op net interface
Can be used for cases where device has no networking but mongoose is still needed for its event loop.

CL: mg: Add net_if_null, a no-op net interface

PUBLISHED_FROM=e79b4a8667508bbde1437dda9dad77ce3a3aa630
2018-09-06 08:34:17 +00:00
Deomid Ryabkov 421e099f2b Refactor mg polling
* Change return type of mg_mgr_poll to return number of events
 * Add mg_mgr_min_timer
 * Refactor main poll loop to remove LwIP-specific stuff

CL: Refactor mg polling

PUBLISHED_FROM=dc94618b32fa3c84a2f053bd04d134297780ec82
2018-09-06 06:34:18 +00:00
Бобби 955d4a3129 Fix file upload on windows
CL: Fix https://github.com/cesanta/mongoose/issues/962 - file upload on windows

PUBLISHED_FROM=85688eee147a1df468cca92f4ac61526ce9c02bf
2018-08-21 15:06:40 +00:00
Deomid Ryabkov b84981ad03 STM32 OTA support for L475-IOT01 and DISCO-F746
A smattering of other related changes

CL: STM32 OTA support for L475-IOT01 and DISCO-F746

PUBLISHED_FROM=e7142337086d09ba21437455b22d00db47ab33f1
2018-08-18 07:49:30 +00:00
64 changed files with 1550 additions and 678 deletions

No files matched your search

+4 -1
View File
@@ -1,12 +1,15 @@
--- ---
title: "Memory Buffers" title: "mbuf.h"
symbol_kind: "intro" symbol_kind: "intro"
decl_name: "mbuf.h" decl_name: "mbuf.h"
items: items:
- { name: mbuf_append.md } - { name: mbuf_append.md }
- { name: mbuf_append_and_free.md }
- { name: mbuf_clear.md }
- { name: mbuf_free.md } - { name: mbuf_free.md }
- { name: mbuf_init.md } - { name: mbuf_init.md }
- { name: mbuf_insert.md } - { name: mbuf_insert.md }
- { name: mbuf_move.md }
- { name: mbuf_remove.md } - { name: mbuf_remove.md }
- { name: mbuf_resize.md } - { name: mbuf_resize.md }
- { name: mbuf_trim.md } - { name: mbuf_trim.md }
+13
View File
@@ -0,0 +1,13 @@
---
title: "mbuf_append_and_free()"
decl_name: "mbuf_append_and_free"
symbol_kind: "func"
signature: |
size_t mbuf_append_and_free(struct mbuf *, void *data, size_t data_size);
---
Appends data to the Mbuf and frees it (data must be heap-allocated).
Returns the number of bytes appended or 0 if out of memory.
data is freed irrespective of return value.
+10
View File
@@ -0,0 +1,10 @@
---
title: "mbuf_clear()"
decl_name: "mbuf_clear"
symbol_kind: "func"
signature: |
void mbuf_clear(struct mbuf *);
---
Removes all the data from mbuf (if any).
+10
View File
@@ -0,0 +1,10 @@
---
title: "mbuf_move()"
decl_name: "mbuf_move"
symbol_kind: "func"
signature: |
void mbuf_move(struct mbuf *from, struct mbuf *to);
---
Moves the state from one mbuf to the other.
@@ -30,7 +30,9 @@ The user-defined event handler will receive following extra events:
- MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: server has received the WebSocket - MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: server has received the WebSocket
handshake request. `ev_data` contains parsed HTTP request. handshake request. `ev_data` contains parsed HTTP request.
- MG_EV_WEBSOCKET_HANDSHAKE_DONE: server has completed the WebSocket - MG_EV_WEBSOCKET_HANDSHAKE_DONE: server has completed the WebSocket
handshake. `ev_data` is `NULL`. handshake. `ev_data` is a `struct http_message` containing the
client's request (server mode) or server's response (client).
In client mode handler can examine `resp_code`, which should be 101.
- MG_EV_WEBSOCKET_FRAME: new WebSocket frame has arrived. `ev_data` is - MG_EV_WEBSOCKET_FRAME: new WebSocket frame has arrived. `ev_data` is
`struct websocket_message *` `struct websocket_message *`
@@ -9,6 +9,14 @@ signature: |
struct mg_str data; struct mg_str data;
int status; /* <0 on error */ int status; /* <0 on error */
void *user_data; void *user_data;
/*
* User handler can indicate how much of the data was consumed
* by setting this variable. By default, it is assumed that all
* data has been consumed by the handler.
* If not all data was consumed, user's handler will be invoked again later
* with the remainder.
*/
size_t num_data_consumed;
}; };
--- ---
+1 -1
View File
@@ -16,5 +16,5 @@ that can be, and must be, called from a different (non-IO) thread.
`func` callback function will be called by the IO thread for each `func` callback function will be called by the IO thread for each
connection. When called, the event will be `MG_EV_POLL`, and a message will connection. When called, the event will be `MG_EV_POLL`, and a message will
be passed as the `ev_data` pointer. Maximum message size is capped be passed as the `ev_data` pointer. Maximum message size is capped
by `MG_CTL_MSG_MESSAGE_SIZE` which is set to 8192 bytes. by `MG_CTL_MSG_MESSAGE_SIZE` which is set to 8192 bytes by default.
+1 -1
View File
@@ -3,7 +3,7 @@ title: "mg_mgr_free()"
decl_name: "mg_mgr_free" decl_name: "mg_mgr_free"
symbol_kind: "func" symbol_kind: "func"
signature: | signature: |
void mg_mgr_free(struct mg_mgr *); void mg_mgr_free(struct mg_mgr *mgr);
--- ---
De-initialises Mongoose manager. De-initialises Mongoose manager.
+2 -2
View File
@@ -3,11 +3,11 @@ title: "mg_mgr_poll()"
decl_name: "mg_mgr_poll" decl_name: "mg_mgr_poll"
symbol_kind: "func" symbol_kind: "func"
signature: | signature: |
time_t mg_mgr_poll(struct mg_mgr *, int milli); int mg_mgr_poll(struct mg_mgr *mgr, int milli);
--- ---
This function performs the actual IO and must be called in a loop This function performs the actual IO and must be called in a loop
(an event loop). It returns the current timestamp. (an event loop). It returns number of user events generated (except POLLs).
`milli` is the maximum number of milliseconds to sleep. `milli` is the maximum number of milliseconds to sleep.
`mg_mgr_poll()` checks all connections for IO readiness. If at least one `mg_mgr_poll()` checks all connections for IO readiness. If at least one
of the connections is IO-ready, `mg_mgr_poll()` triggers the respective of the connections is IO-ready, `mg_mgr_poll()` triggers the respective
@@ -46,6 +46,7 @@ signature: |
#define MG_F_WANT_READ (1 << 6) /* SSL specific */ #define MG_F_WANT_READ (1 << 6) /* SSL specific */
#define MG_F_WANT_WRITE (1 << 7) /* SSL specific */ #define MG_F_WANT_WRITE (1 << 7) /* SSL specific */
#define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */ #define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */
#define MG_F_RECV_AND_CLOSE (1 << 9) /* Drain rx and close the connection. */
/* Flags that are settable by user */ /* Flags that are settable by user */
#define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */ #define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */
+1
View File
@@ -13,6 +13,7 @@ signature: |
#endif #endif
void *user_data; /* User data */ void *user_data; /* User data */
int num_ifaces; int num_ifaces;
int num_calls;
struct mg_iface **ifaces; /* network interfaces */ struct mg_iface **ifaces; /* network interfaces */
const char *nameserver; /* DNS server to use */ const char *nameserver; /* DNS server to use */
}; };
+1 -1
View File
@@ -7,7 +7,7 @@ flags are meant to be set only by the user event handler to tell Mongoose how to
behave. Below is a list of connection flags that are meant to be set by event behave. Below is a list of connection flags that are meant to be set by event
handlers: handlers:
* `MG_F_FINISHED_SENDING_DATA` tells Mongoose that all data has been appended * `MG_F_SEND_AND_CLOSE` tells Mongoose that all data has been appended
to the `send_mbuf`. As soon as Mongoose sends it to the socket, the to the `send_mbuf`. As soon as Mongoose sends it to the socket, the
connection will be closed. connection will be closed.
* `MG_F_BUFFER_BUT_DONT_SEND` tells Mongoose to append data to the `send_mbuf` * `MG_F_BUFFER_BUT_DONT_SEND` tells Mongoose to append data to the `send_mbuf`
+2 -1
View File
@@ -98,7 +98,8 @@ bool bm222_get_data(struct bm222_ctx *ctx) {
s->y = v[3]; s->y = v[3];
s->z = v[5]; s->z = v[5];
if (d > max_d) max_d = d; if (d > max_d) max_d = d;
LOG(LL_VERBOSE_DEBUG, ("dx %d dy %d dz %d d %d", dx, dy, dz, d)); LOG(LL_VERBOSE_DEBUG,
("dx %d dy %d dz %d d %d", (int) dx, (int) dy, (int) dz, (int) d));
} }
} }
return (overflow ? bm222_fifo_init(ctx) : true); /* Clear the ovf flag. */ return (overflow ? bm222_fifo_init(ctx) : true); /* Clear the ovf flag. */
+84 -14
View File
@@ -1,11 +1,25 @@
/* /*
* Copyright (c) 2014-2016 Cesanta Software Limited * Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved * All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the ""License"");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an ""AS IS"" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ */
#ifndef CS_COMMON_CS_DBG_H_ #ifndef CS_COMMON_CS_DBG_H_
#define CS_COMMON_CS_DBG_H_ #define CS_COMMON_CS_DBG_H_
#include "common/platform.h"
#if CS_ENABLE_STDIO #if CS_ENABLE_STDIO
#include <stdio.h> #include <stdio.h>
#endif #endif
@@ -14,6 +28,10 @@
#define CS_ENABLE_DEBUG 0 #define CS_ENABLE_DEBUG 0
#endif #endif
#ifndef CS_LOG_PREFIX_LEN
#define CS_LOG_PREFIX_LEN 24
#endif
#ifndef CS_LOG_ENABLE_TS_DIFF #ifndef CS_LOG_ENABLE_TS_DIFF
#define CS_LOG_ENABLE_TS_DIFF 0 #define CS_LOG_ENABLE_TS_DIFF 0
#endif #endif
@@ -22,6 +40,9 @@
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
/*
* Log level; `LL_INFO` is the default. Use `cs_log_set_level()` to change it.
*/
enum cs_log_level { enum cs_log_level {
LL_NONE = -1, LL_NONE = -1,
LL_ERROR = 0, LL_ERROR = 0,
@@ -34,29 +55,78 @@ enum cs_log_level {
_LL_MAX = 5, _LL_MAX = 5,
}; };
/*
* Set max log level to print; messages with the level above the given one will
* not be printed.
*/
void cs_log_set_level(enum cs_log_level level); void cs_log_set_level(enum cs_log_level level);
/*
* A comma-separated set of prefix=level.
* prefix is matched against the log prefix exactly as printed, including line
* number, but partial match is ok. Check stops on first matching entry.
* If nothing matches, default level is used.
*
* Examples:
* main.c:=4 - everything from main C at verbose debug level.
* mongoose.c=1,mjs.c=1,=4 - everything at verbose debug except mg_* and mjs_*
*
*/
void cs_log_set_file_level(const char *file_level);
/*
* Helper function which prints message prefix with the given `level`.
* If message should be printed (according to the current log level
* and filter), prints the prefix and returns 1, otherwise returns 0.
*
* Clients should typically just use `LOG()` macro.
*/
int cs_log_print_prefix(enum cs_log_level level, const char *fname, int line);
extern enum cs_log_level cs_log_level;
#if CS_ENABLE_STDIO #if CS_ENABLE_STDIO
/*
* Set file to write logs into. If `NULL`, logs go to `stderr`.
*/
void cs_log_set_file(FILE *file); void cs_log_set_file(FILE *file);
extern enum cs_log_level cs_log_threshold; /*
void cs_log_print_prefix(const char *func); * Prints log to the current log file, appends "\n" in the end and flushes the
void cs_log_printf(const char *fmt, ...); * stream.
*/
void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2);
#define LOG(l, x) \ #if CS_ENABLE_STDIO
if (cs_log_threshold >= l) { \
cs_log_print_prefix(__func__); \ /*
cs_log_printf x; \ * Format and print message `x` with the given level `l`. Example:
} *
* ```c
* LOG(LL_INFO, ("my info message: %d", 123));
* LOG(LL_DEBUG, ("my debug message: %d", 123));
* ```
*/
#define LOG(l, x) \
do { \
if (cs_log_print_prefix(l, __FILE__, __LINE__)) { \
cs_log_printf x; \
} \
} while (0)
#else
#define LOG(l, x) ((void) l)
#endif
#ifndef CS_NDEBUG #ifndef CS_NDEBUG
#define DBG(x) \ /*
if (cs_log_threshold >= LL_VERBOSE_DEBUG) { \ * Shortcut for `LOG(LL_VERBOSE_DEBUG, (...))`
cs_log_print_prefix(__func__); \ */
cs_log_printf x; \ #define DBG(x) LOG(LL_VERBOSE_DEBUG, x)
}
#else /* NDEBUG */ #else /* NDEBUG */
+2 -2
View File
@@ -50,7 +50,7 @@
#define BM222_ADDR 0x18 #define BM222_ADDR 0x18
#define TMP006_ADDR 0x41 #define TMP006_ADDR 0x41
void fs_slfs_set_new_file_size(const char *name, size_t size); void fs_slfs_set_file_size(const char *name, size_t size);
static const char *upload_form = static const char *upload_form =
"\ "\
@@ -70,7 +70,7 @@ static struct mg_str upload_fname(struct mg_connection *nc,
if (nc->user_data != NULL) { if (nc->user_data != NULL) {
intptr_t cl = (intptr_t) nc->user_data; intptr_t cl = (intptr_t) nc->user_data;
if (cl >= 0) { if (cl >= 0) {
fs_slfs_set_new_file_size(fn + 3, cl); fs_slfs_set_file_size(fn + 3, cl);
} }
} }
lfn.len = fname.len + 4; lfn.len = fname.len + 4;
+2 -2
View File
@@ -25,7 +25,7 @@ void SimpleLinkWlanEventHandler(SlWlanEvent_t *e) {
LOG(LL_INFO, ("WiFi: station disconnected")); LOG(LL_INFO, ("WiFi: station disconnected"));
break; break;
default: default:
LOG(LL_INFO, ("WiFi: event %d", e->Event)); LOG(LL_INFO, ("WiFi: event %d", (int) e->Event));
} }
} }
@@ -39,7 +39,7 @@ void SimpleLinkNetAppEventHandler(SlNetAppEvent_t *e) {
} else if (e->Event == SL_NETAPP_IP_LEASED_EVENT) { } else if (e->Event == SL_NETAPP_IP_LEASED_EVENT) {
LOG(LL_INFO, ("IP leased")); LOG(LL_INFO, ("IP leased"));
} else { } else {
LOG(LL_INFO, ("NetApp event %d", e->Event)); LOG(LL_INFO, ("NetApp event %d", (int) e->Event));
} }
} }
@@ -14,7 +14,6 @@ static int s_done = 0;
static int s_is_connected = 0; static int s_is_connected = 0;
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct websocket_message *wm = (struct websocket_message *) ev_data;
(void) nc; (void) nc;
switch (ev) { switch (ev) {
@@ -26,8 +25,14 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
break; break;
} }
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: { case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
printf("-- Connected\n"); struct http_message *hm = (struct http_message *) ev_data;
s_is_connected = 1; if (hm->resp_code == 101) {
printf("-- Connected\n");
s_is_connected = 1;
} else {
printf("-- Connection failed! HTTP code %d\n", hm->resp_code);
/* Connection will be closed after this. */
}
break; break;
} }
case MG_EV_POLL: { case MG_EV_POLL: {
@@ -66,6 +71,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
break; break;
} }
case MG_EV_WEBSOCKET_FRAME: { case MG_EV_WEBSOCKET_FRAME: {
struct websocket_message *wm = (struct websocket_message *) ev_data;
printf("%.*s\n", (int) wm->size, wm->data); printf("%.*s\n", (int) wm->size, wm->data);
break; break;
} }
+551 -222
View File
File diff suppressed because it is too large. Load diff
+54 -12
View File
@@ -23,7 +23,7 @@
#ifndef CS_MONGOOSE_SRC_COMMON_H_ #ifndef CS_MONGOOSE_SRC_COMMON_H_
#define CS_MONGOOSE_SRC_COMMON_H_ #define CS_MONGOOSE_SRC_COMMON_H_
#define MG_VERSION "6.12" #define MG_VERSION "6.14"
/* Local tweaks, applied before any of Mongoose's own headers. */ /* Local tweaks, applied before any of Mongoose's own headers. */
#ifdef MG_LOCALS #ifdef MG_LOCALS
@@ -105,6 +105,7 @@
#define MG_NET_IF_SIMPLELINK 2 #define MG_NET_IF_SIMPLELINK 2
#define MG_NET_IF_LWIP_LOW_LEVEL 3 #define MG_NET_IF_LWIP_LOW_LEVEL 3
#define MG_NET_IF_PIC32 4 #define MG_NET_IF_PIC32 4
#define MG_NET_IF_NULL 5
#define MG_SSL_IF_OPENSSL 1 #define MG_SSL_IF_OPENSSL 1
#define MG_SSL_IF_MBEDTLS 2 #define MG_SSL_IF_MBEDTLS 2
@@ -1530,7 +1531,7 @@ int sl_set_ssl_opts(int sock, struct mg_connection *nc);
#endif /* SL_MAJOR_VERSION_NUM < 2 */ #endif /* SL_MAJOR_VERSION_NUM < 2 */
int slfs_open(const unsigned char *fname, uint32_t flags); int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token);
#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */
@@ -1944,7 +1945,7 @@ char *inet_ntoa(struct in_addr in);
#include <stm32_sdk_hal.h> #include <stm32_sdk_hal.h>
#define to64(x) strtoll(x, NULL, 10) #define to64(x) strtoll(x, NULL, 10)
#define INT64_FMT PRId64 #define INT64_FMT "lld"
#define SIZE_T_FMT "u" #define SIZE_T_FMT "u"
typedef struct stat cs_stat_t; typedef struct stat cs_stat_t;
#define DIRSEP '/' #define DIRSEP '/'
@@ -2030,7 +2031,6 @@ typedef int sock_t;
#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL #if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
struct mg_mgr; struct mg_mgr;
struct mg_connection; struct mg_connection;
uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr);
void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle, void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle,
int interval, int count); int interval, int count);
#endif #endif
@@ -2239,6 +2239,8 @@ struct mg_str mg_mk_str_n(const char *s, size_t len);
/* Macro for initializing mg_str. */ /* Macro for initializing mg_str. */
#define MG_MK_STR(str_literal) \ #define MG_MK_STR(str_literal) \
{ str_literal, sizeof(str_literal) - 1 } { str_literal, sizeof(str_literal) - 1 }
#define MG_MK_STR_N(str_literal, len) \
{ str_literal, len }
#define MG_NULL_STR \ #define MG_NULL_STR \
{ NULL, 0 } { NULL, 0 }
@@ -2278,6 +2280,11 @@ int mg_strcmp(const struct mg_str str1, const struct mg_str str2);
*/ */
int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n);
/*
* Free the string (assuming it was heap allocated).
*/
void mg_strfree(struct mg_str *s);
/* /*
* Finds the first occurrence of a substring `needle` in the `haystack`. * Finds the first occurrence of a substring `needle` in the `haystack`.
*/ */
@@ -2286,6 +2293,9 @@ const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle);
/* Strip whitespace at the start and the end of s */ /* Strip whitespace at the start and the end of s */
struct mg_str mg_strstrip(struct mg_str s); struct mg_str mg_strstrip(struct mg_str s);
/* Returns 1 if s starts with the given prefix. */
int mg_str_starts_with(struct mg_str s, struct mg_str prefix);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@@ -2312,8 +2322,6 @@ struct mg_str mg_strstrip(struct mg_str s);
*/ */
/* /*
* === Memory Buffers
*
* Mbufs are mutable/growing memory buffers, like C++ strings. * Mbufs are mutable/growing memory buffers, like C++ strings.
* Mbuf can append data to the end of a buffer or insert data into arbitrary * Mbuf can append data to the end of a buffer or insert data into arbitrary
* position in the middle of a buffer. The buffer grows automatically when * position in the middle of a buffer. The buffer grows automatically when
@@ -2365,6 +2373,14 @@ void mbuf_free(struct mbuf *);
*/ */
size_t mbuf_append(struct mbuf *, const void *data, size_t data_size); size_t mbuf_append(struct mbuf *, const void *data, size_t data_size);
/*
* Appends data to the Mbuf and frees it (data must be heap-allocated).
*
* Returns the number of bytes appended or 0 if out of memory.
* data is freed irrespective of return value.
*/
size_t mbuf_append_and_free(struct mbuf *, void *data, size_t data_size);
/* /*
* Inserts data at a specified offset in the Mbuf. * Inserts data at a specified offset in the Mbuf.
* *
@@ -2385,6 +2401,12 @@ void mbuf_remove(struct mbuf *, size_t data_size);
*/ */
void mbuf_resize(struct mbuf *, size_t new_size); void mbuf_resize(struct mbuf *, size_t new_size);
/* Moves the state from one mbuf to the other. */
void mbuf_move(struct mbuf *from, struct mbuf *to);
/* Removes all the data from mbuf (if any). */
void mbuf_clear(struct mbuf *);
/* Shrinks an Mbuf by resizing its `size` to `len`. */ /* Shrinks an Mbuf by resizing its `size` to `len`. */
void mbuf_trim(struct mbuf *); void mbuf_trim(struct mbuf *);
@@ -2625,6 +2647,8 @@ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
/* /*
* Like `mg_next_comma_list_entry()`, but takes `list` as `struct mg_str`. * Like `mg_next_comma_list_entry()`, but takes `list` as `struct mg_str`.
* NB: Test return value's .p, not .len. On last itreation that yields result
* .len will be 0 but .p will not. When finished, .p will be NULL.
*/ */
struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
struct mg_str *eq_val); struct mg_str *eq_val);
@@ -3718,6 +3742,12 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
/* Deliver a POLL event to the connection. */ /* Deliver a POLL event to the connection. */
int mg_if_poll(struct mg_connection *nc, double now); int mg_if_poll(struct mg_connection *nc, double now);
/*
* Return minimal timer value amoung connections in the manager.
* Returns 0 if there aren't any timers.
*/
double mg_mgr_min_timer(const struct mg_mgr *mgr);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
@@ -3875,6 +3905,7 @@ struct mg_mgr {
#endif #endif
void *user_data; /* User data */ void *user_data; /* User data */
int num_ifaces; int num_ifaces;
int num_calls;
struct mg_iface **ifaces; /* network interfaces */ struct mg_iface **ifaces; /* network interfaces */
const char *nameserver; /* DNS server to use */ const char *nameserver; /* DNS server to use */
}; };
@@ -3925,6 +3956,7 @@ struct mg_connection {
#define MG_F_WANT_READ (1 << 6) /* SSL specific */ #define MG_F_WANT_READ (1 << 6) /* SSL specific */
#define MG_F_WANT_WRITE (1 << 7) /* SSL specific */ #define MG_F_WANT_WRITE (1 << 7) /* SSL specific */
#define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */ #define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */
#define MG_F_RECV_AND_CLOSE (1 << 9) /* Drain rx and close the connection. */
/* Flags that are settable by user */ /* Flags that are settable by user */
#define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */ #define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */
@@ -3987,17 +4019,17 @@ void mg_mgr_init_opt(struct mg_mgr *mgr, void *user_data,
* *
* Closes and deallocates all active connections. * Closes and deallocates all active connections.
*/ */
void mg_mgr_free(struct mg_mgr *); void mg_mgr_free(struct mg_mgr *mgr);
/* /*
* This function performs the actual IO and must be called in a loop * This function performs the actual IO and must be called in a loop
* (an event loop). It returns the current timestamp. * (an event loop). It returns number of user events generated (except POLLs).
* `milli` is the maximum number of milliseconds to sleep. * `milli` is the maximum number of milliseconds to sleep.
* `mg_mgr_poll()` checks all connections for IO readiness. If at least one * `mg_mgr_poll()` checks all connections for IO readiness. If at least one
* of the connections is IO-ready, `mg_mgr_poll()` triggers the respective * of the connections is IO-ready, `mg_mgr_poll()` triggers the respective
* event handlers and returns. * event handlers and returns.
*/ */
time_t mg_mgr_poll(struct mg_mgr *, int milli); int mg_mgr_poll(struct mg_mgr *mgr, int milli);
#if MG_ENABLE_BROADCAST #if MG_ENABLE_BROADCAST
/* /*
@@ -4010,7 +4042,7 @@ time_t mg_mgr_poll(struct mg_mgr *, int milli);
* `func` callback function will be called by the IO thread for each * `func` callback function will be called by the IO thread for each
* connection. When called, the event will be `MG_EV_POLL`, and a message will * connection. When called, the event will be `MG_EV_POLL`, and a message will
* be passed as the `ev_data` pointer. Maximum message size is capped * be passed as the `ev_data` pointer. Maximum message size is capped
* by `MG_CTL_MSG_MESSAGE_SIZE` which is set to 8192 bytes. * by `MG_CTL_MSG_MESSAGE_SIZE` which is set to 8192 bytes by default.
*/ */
void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data, void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data,
size_t len); size_t len);
@@ -4748,6 +4780,14 @@ struct mg_http_multipart_part {
struct mg_str data; struct mg_str data;
int status; /* <0 on error */ int status; /* <0 on error */
void *user_data; void *user_data;
/*
* User handler can indicate how much of the data was consumed
* by setting this variable. By default, it is assumed that all
* data has been consumed by the handler.
* If not all data was consumed, user's handler will be invoked again later
* with the remainder.
*/
size_t num_data_consumed;
}; };
/* SSI call context */ /* SSI call context */
@@ -4766,7 +4806,7 @@ struct mg_ssi_call_ctx {
#if MG_ENABLE_HTTP_WEBSOCKET #if MG_ENABLE_HTTP_WEBSOCKET
#define MG_EV_WEBSOCKET_HANDSHAKE_REQUEST 111 /* struct http_message * */ #define MG_EV_WEBSOCKET_HANDSHAKE_REQUEST 111 /* struct http_message * */
#define MG_EV_WEBSOCKET_HANDSHAKE_DONE 112 /* NULL */ #define MG_EV_WEBSOCKET_HANDSHAKE_DONE 112 /* struct http_message * */
#define MG_EV_WEBSOCKET_FRAME 113 /* struct websocket_message * */ #define MG_EV_WEBSOCKET_FRAME 113 /* struct websocket_message * */
#define MG_EV_WEBSOCKET_CONTROL_FRAME 114 /* struct websocket_message * */ #define MG_EV_WEBSOCKET_CONTROL_FRAME 114 /* struct websocket_message * */
#endif #endif
@@ -4805,7 +4845,9 @@ struct mg_ssi_call_ctx {
* - MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: server has received the WebSocket * - MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: server has received the WebSocket
* handshake request. `ev_data` contains parsed HTTP request. * handshake request. `ev_data` contains parsed HTTP request.
* - MG_EV_WEBSOCKET_HANDSHAKE_DONE: server has completed the WebSocket * - MG_EV_WEBSOCKET_HANDSHAKE_DONE: server has completed the WebSocket
* handshake. `ev_data` is `NULL`. * handshake. `ev_data` is a `struct http_message` containing the
* client's request (server mode) or server's response (client).
* In client mode handler can examine `resp_code`, which should be 101.
* - MG_EV_WEBSOCKET_FRAME: new WebSocket frame has arrived. `ev_data` is * - MG_EV_WEBSOCKET_FRAME: new WebSocket frame has arrived. `ev_data` is
* `struct websocket_message *` * `struct websocket_message *`
* *
+53 -26
View File
@@ -24,7 +24,7 @@
#include "common/cs_time.h" #include "common/cs_time.h"
#include "common/str_util.h" #include "common/str_util.h"
enum cs_log_level cs_log_threshold WEAK = enum cs_log_level cs_log_level WEAK =
#if CS_ENABLE_DEBUG #if CS_ENABLE_DEBUG
LL_VERBOSE_DEBUG; LL_VERBOSE_DEBUG;
#else #else
@@ -32,10 +32,9 @@ enum cs_log_level cs_log_threshold WEAK =
#endif #endif
#if CS_ENABLE_STDIO #if CS_ENABLE_STDIO
static char *s_filter_pattern = NULL; static char *s_file_level = NULL;
static size_t s_filter_pattern_len;
void cs_log_set_filter(const char *pattern) WEAK; void cs_log_set_file_level(const char *file_level) WEAK;
FILE *cs_log_file WEAK = NULL; FILE *cs_log_file WEAK = NULL;
@@ -45,34 +44,62 @@ double cs_log_ts WEAK;
enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE; enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE;
void cs_log_set_filter(const char *pattern) { void cs_log_set_file_level(const char *file_level) {
free(s_filter_pattern); char *fl = s_file_level;
if (pattern != NULL) { if (file_level != NULL) {
s_filter_pattern = strdup(pattern); s_file_level = strdup(file_level);
s_filter_pattern_len = strlen(pattern);
} else { } else {
s_filter_pattern = NULL; s_file_level = NULL;
s_filter_pattern_len = 0;
} }
free(fl);
} }
int cs_log_print_prefix(enum cs_log_level, const char *, const char *) WEAK; int cs_log_print_prefix(enum cs_log_level level, const char *file, int ln) WEAK;
int cs_log_print_prefix(enum cs_log_level level, const char *func, int cs_log_print_prefix(enum cs_log_level level, const char *file, int ln) {
const char *filename) { char prefix[CS_LOG_PREFIX_LEN], *q;
char prefix[21]; const char *p;
size_t fl = 0, ll = 0, pl = 0;
if (level > cs_log_threshold) return 0; if (level > cs_log_level && s_file_level == NULL) return 0;
if (s_filter_pattern != NULL &&
mg_match_prefix(s_filter_pattern, s_filter_pattern_len, func) == 0 && p = file + strlen(file);
mg_match_prefix(s_filter_pattern, s_filter_pattern_len, filename) == 0) {
return 0; while (p != file) {
const char c = *(p - 1);
if (c == '/' || c == '\\') break;
p--;
fl++;
}
ll = (ln < 10000 ? (ln < 1000 ? (ln < 100 ? (ln < 10 ? 1 : 2) : 3) : 4) : 5);
if (fl > (sizeof(prefix) - ll - 2)) fl = (sizeof(prefix) - ll - 2);
pl = fl + 1 + ll;
memcpy(prefix, p, fl);
q = prefix + pl;
memset(q, ' ', sizeof(prefix) - pl);
do {
*(--q) = '0' + (ln % 10);
ln /= 10;
} while (ln > 0);
*(--q) = ':';
if (s_file_level != NULL) {
enum cs_log_level pll = cs_log_level;
struct mg_str fl = mg_mk_str(s_file_level), ps = MG_MK_STR_N(prefix, pl);
struct mg_str k, v;
while ((fl = mg_next_comma_list_entry_n(fl, &k, &v)).p != NULL) {
bool yes = !(!mg_str_starts_with(ps, k) || v.len == 0);
if (!yes) continue;
pll = (enum cs_log_level)(*v.p - '0');
break;
}
if (level > pll) return 0;
} }
strncpy(prefix, func, 20);
prefix[20] = '\0';
if (cs_log_file == NULL) cs_log_file = stderr; if (cs_log_file == NULL) cs_log_file = stderr;
cs_log_cur_msg_level = level; cs_log_cur_msg_level = level;
fprintf(cs_log_file, "%-20s ", prefix); fwrite(prefix, 1, sizeof(prefix), cs_log_file);
#if CS_LOG_ENABLE_TS_DIFF #if CS_LOG_ENABLE_TS_DIFF
{ {
double now = cs_time(); double now = cs_time();
@@ -101,15 +128,15 @@ void cs_log_set_file(FILE *file) {
#else #else
void cs_log_set_filter(const char *pattern) { void cs_log_set_file_level(const char *file_level) {
(void) pattern; (void) file_level;
} }
#endif /* CS_ENABLE_STDIO */ #endif /* CS_ENABLE_STDIO */
void cs_log_set_level(enum cs_log_level level) WEAK; void cs_log_set_level(enum cs_log_level level) WEAK;
void cs_log_set_level(enum cs_log_level level) { void cs_log_set_level(enum cs_log_level level) {
cs_log_threshold = level; cs_log_level = level;
#if CS_LOG_ENABLE_TS_DIFF && CS_ENABLE_STDIO #if CS_LOG_ENABLE_TS_DIFF && CS_ENABLE_STDIO
cs_log_ts = cs_time(); cs_log_ts = cs_time();
#endif #endif
+22 -39
View File
@@ -28,6 +28,10 @@
#define CS_ENABLE_DEBUG 0 #define CS_ENABLE_DEBUG 0
#endif #endif
#ifndef CS_LOG_PREFIX_LEN
#define CS_LOG_PREFIX_LEN 24
#endif
#ifndef CS_LOG_ENABLE_TS_DIFF #ifndef CS_LOG_ENABLE_TS_DIFF
#define CS_LOG_ENABLE_TS_DIFF 0 #define CS_LOG_ENABLE_TS_DIFF 0
#endif #endif
@@ -58,51 +62,28 @@ enum cs_log_level {
void cs_log_set_level(enum cs_log_level level); void cs_log_set_level(enum cs_log_level level);
/* /*
* Set log filter. NULL (a default) logs everything. * A comma-separated set of prefix=level.
* Otherwise, function name and file name will be tested against the given * prefix is matched against the log prefix exactly as printed, including line
* pattern, and only matching messages will be printed. * number, but partial match is ok. Check stops on first matching entry.
* If nothing matches, default level is used.
* *
* For the pattern syntax, refer to `mg_match_prefix()` in `str_util.h`. * Examples:
* main.c:=4 - everything from main C at verbose debug level.
* mongoose.c=1,mjs.c=1,=4 - everything at verbose debug except mg_* and mjs_*
* *
* Example:
* ```c
* void foo(void) {
* LOG(LL_INFO, ("hello from foo"));
* }
*
* void bar(void) {
* LOG(LL_INFO, ("hello from bar"));
* }
*
* void test(void) {
* cs_log_set_filter(NULL);
* foo();
* bar();
*
* cs_log_set_filter("f*");
* foo();
* bar(); // Will NOT print anything
*
* cs_log_set_filter("bar");
* foo(); // Will NOT print anything
* bar();
* }
* ```
*/ */
void cs_log_set_filter(const char *pattern); void cs_log_set_file_level(const char *file_level);
/* /*
* Helper function which prints message prefix with the given `level`, function * Helper function which prints message prefix with the given `level`.
* name `func` and `filename`. If message should be printed (accordingly to the * If message should be printed (according to the current log level
* current log level and filter), prints the prefix and returns 1, otherwise * and filter), prints the prefix and returns 1, otherwise returns 0.
* returns 0.
* *
* Clients should typically just use `LOG()` macro. * Clients should typically just use `LOG()` macro.
*/ */
int cs_log_print_prefix(enum cs_log_level level, const char *func, int cs_log_print_prefix(enum cs_log_level level, const char *fname, int line);
const char *filename);
extern enum cs_log_level cs_log_threshold; extern enum cs_log_level cs_log_level;
#if CS_ENABLE_STDIO #if CS_ENABLE_STDIO
@@ -127,9 +108,11 @@ void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2);
* LOG(LL_DEBUG, ("my debug message: %d", 123)); * LOG(LL_DEBUG, ("my debug message: %d", 123));
* ``` * ```
*/ */
#define LOG(l, x) \ #define LOG(l, x) \
do { \ do { \
if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \ if (cs_log_print_prefix(l, __FILE__, __LINE__)) { \
cs_log_printf x; \
} \
} while (0) } while (0)
#else #else
+1
View File
@@ -69,6 +69,7 @@
#define MG_NET_IF_SIMPLELINK 2 #define MG_NET_IF_SIMPLELINK 2
#define MG_NET_IF_LWIP_LOW_LEVEL 3 #define MG_NET_IF_LWIP_LOW_LEVEL 3
#define MG_NET_IF_PIC32 4 #define MG_NET_IF_PIC32 4
#define MG_NET_IF_NULL 5
#define MG_SSL_IF_OPENSSL 1 #define MG_SSL_IF_OPENSSL 1
#define MG_SSL_IF_MBEDTLS 2 #define MG_SSL_IF_MBEDTLS 2
+17 -6
View File
@@ -27,6 +27,10 @@
#include "mgos_core_dump.h" #include "mgos_core_dump.h"
#include "mgos_hal.h" #include "mgos_hal.h"
#ifndef MGOS_ENABLE_CORE_DUMP
#define MGOS_ENABLE_CORE_DUMP 1
#endif
struct arm_exc_frame { struct arm_exc_frame {
uint32_t r0; uint32_t r0;
uint32_t r1; uint32_t r1;
@@ -53,7 +57,7 @@ struct arm_gdb_reg_file {
uint32_t fpscr; uint32_t fpscr;
} __attribute__((packed)); } __attribute__((packed));
#if ARM_HAVE_FPU #if ARM_HAVE_FPU && !defined(MGOS_BOOT_BUILD)
static void save_s16_s31(uint32_t *dst) { static void save_s16_s31(uint32_t *dst) {
__asm volatile( __asm volatile(
"\ "\
@@ -91,6 +95,7 @@ void arm_exc_handler_bottom(uint8_t isr_no, struct arm_exc_frame *ef,
struct arm_gdb_reg_file *rf) { struct arm_gdb_reg_file *rf) {
char buf[8]; char buf[8];
const char *name; const char *name;
(void) ef;
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
switch (isr_no) { switch (isr_no) {
case 0: case 0:
@@ -134,16 +139,20 @@ void arm_exc_handler_bottom(uint8_t isr_no, struct arm_exc_frame *ef,
name = "SysTick"; name = "SysTick";
break; break;
default: { default: {
#ifndef MGOS_BOOT_BUILD
sprintf(buf, "IRQ%u", isr_no - 16); sprintf(buf, "IRQ%u", isr_no - 16);
#endif
name = buf; name = buf;
} }
} }
mgos_cd_printf("\n\n--- Exception %u (%s) ---\n", isr_no, name); mgos_cd_printf("\n\n--- Exception %u (%s) ---\n", isr_no, name);
if (rf != NULL) { if (rf != NULL) {
mgos_cd_printf(" R0: 0x%08lx R1: 0x%08lx R2: 0x%08lx R3: 0x%08lx\n", mgos_cd_printf(
rf->r[0], rf->r[1], rf->r[2], rf->r[3]); " R%d: 0x%08lx R%d: 0x%08lx R%d: 0x%08lx R%d: 0x%08lx\n", 0,
mgos_cd_printf(" R4: 0x%08lx R5: 0x%08lx R6: 0x%08lx R7: 0x%08lx\n", rf->r[0], 1, rf->r[1], 2, rf->r[2], 3, rf->r[3]);
rf->r[4], rf->r[5], rf->r[6], rf->r[7]); mgos_cd_printf(
" R%d: 0x%08lx R%d: 0x%08lx R%d: 0x%08lx R%d: 0x%08lx\n", 4,
rf->r[4], 5, rf->r[5], 6, rf->r[6], 7, rf->r[7]);
mgos_cd_printf(" R8: 0x%08lx R9: 0x%08lx R10: 0x%08lx R11: 0x%08lx\n", mgos_cd_printf(" R8: 0x%08lx R9: 0x%08lx R10: 0x%08lx R11: 0x%08lx\n",
rf->r[8], rf->r[9], rf->r[10], rf->r[11]); rf->r[8], rf->r[9], rf->r[10], rf->r[11]);
mgos_cd_printf(" R12: 0x%08lx SP: 0x%08lx LR: 0x%08lx PC: 0x%08lx\n", mgos_cd_printf(" R12: 0x%08lx SP: 0x%08lx LR: 0x%08lx PC: 0x%08lx\n",
@@ -151,7 +160,7 @@ void arm_exc_handler_bottom(uint8_t isr_no, struct arm_exc_frame *ef,
mgos_cd_printf(" PSR: 0x%08lx\n", rf->cpsr); mgos_cd_printf(" PSR: 0x%08lx\n", rf->cpsr);
} }
memset(rf->d, 0, sizeof(rf->d)); memset(rf->d, 0, sizeof(rf->d));
#if ARM_HAVE_FPU #if ARM_HAVE_FPU && !defined(MGOS_BOOT_BUILD)
rf->fpscr = ef->fpscr; rf->fpscr = ef->fpscr;
memcpy((uint8_t *) rf->d, ef->s, sizeof(ef->s)); memcpy((uint8_t *) rf->d, ef->s, sizeof(ef->s));
print_fpu_regs((uint32_t *) rf->d, 0, ARRAY_SIZE(ef->s)); print_fpu_regs((uint32_t *) rf->d, 0, ARRAY_SIZE(ef->s));
@@ -164,10 +173,12 @@ void arm_exc_handler_bottom(uint8_t isr_no, struct arm_exc_frame *ef,
#else #else
rf->fpscr = 0; rf->fpscr = 0;
#endif #endif
#if MGOS_ENABLE_CORE_DUMP
mgos_cd_emit_header(); mgos_cd_emit_header();
mgos_cd_emit_section(MGOS_CORE_DUMP_SECTION_REGS, rf, sizeof(*rf)); mgos_cd_emit_section(MGOS_CORE_DUMP_SECTION_REGS, rf, sizeof(*rf));
mgos_cd_emit_section("SRAM", (void *) SRAM_BASE_ADDR, SRAM_SIZE); mgos_cd_emit_section("SRAM", (void *) SRAM_BASE_ADDR, SRAM_SIZE);
mgos_cd_emit_footer(); mgos_cd_emit_footer();
#endif
#ifdef MGOS_HALT_ON_EXCEPTION #ifdef MGOS_HALT_ON_EXCEPTION
mgos_cd_printf("Halting\n"); mgos_cd_printf("Halting\n");
while (1) { while (1) {
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2014-2019 Cesanta Software Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the ""License"");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an ""AS IS"" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.arch armv7e-m
.syntax unified
.thumb
/* These are required to satisfy TI linker. */
.eabi_attribute Tag_ABI_align_needed, 1
.eabi_attribute Tag_ABI_align_preserved, 1
.global mgos_nsleep100_impl
.global mgos_nsleep100_loop_count
#ifdef STM32
.section .RamFunc.mgos_nsleep100_impl
#else
.section .iram.mgos_nsleep100_impl
#endif
.type mgos_nsleep100_impl, %function
.align 4
mgos_nsleep100_impl:
ldr r3, =mgos_nsleep100_loop_count
ldr r3, [r3]
mul r0, r3
mov r1, #6
udiv r0, r0, r1
cbz r0, xxx
lxx:
subs r0, #1
bne lxx
xxx:
bx lr
.align 4
.size mgos_nsleep100_impl, . - mgos_nsleep100_impl
@@ -26,7 +26,11 @@
.global mgos_nsleep100_impl .global mgos_nsleep100_impl
.global mgos_nsleep100_loop_count .global mgos_nsleep100_loop_count
#ifdef STM32
.section .RamFunc.mgos_nsleep100_impl
#else
.section .iram.mgos_nsleep100_impl .section .iram.mgos_nsleep100_impl
#endif
.type mgos_nsleep100_impl, %function .type mgos_nsleep100_impl, %function
.align 4 .align 4
@@ -34,7 +38,11 @@ mgos_nsleep100_impl:
ldr r3, =mgos_nsleep100_loop_count ldr r3, =mgos_nsleep100_loop_count
ldr r3, [r3] ldr r3, [r3]
mul r0, r3 mul r0, r3
#ifdef STM32L4
mov r1, #3
#else
mov r1, #6 mov r1, #6
#endif
udiv r0, r0, r1 udiv r0, r0, r1
cbz r0, xxx cbz r0, xxx
lxx: lxx:
@@ -26,7 +26,11 @@
.global mgos_nsleep100_impl .global mgos_nsleep100_impl
.global mgos_nsleep100_loop_count .global mgos_nsleep100_loop_count
#ifdef STM32
.section .RamFunc.mgos_nsleep100_impl
#else
.section .iram.mgos_nsleep100_impl .section .iram.mgos_nsleep100_impl
#endif
.type mgos_nsleep100_impl, %function .type mgos_nsleep100_impl, %function
.align 4 .align 4
+2 -2
View File
@@ -29,11 +29,11 @@ $(SDK_OBJS): CFLAGS += -include common/platform.h
# cc flags,file # cc flags,file
define cc define cc
$(vecho) "GCC $2 -> $@" $(vecho) "GCC $2"
$(Q) $(CC_WRAPPER) $(CC) -c $1 -o $@ $2 $(Q) $(CC_WRAPPER) $(CC) -c $1 -o $@ $2
endef endef
define cxx define cxx
$(vecho) "G++ $2 -> $@" $(vecho) "G++ $2"
$(Q) $(CC_WRAPPER) $(CXX) -c $1 -o $@ $2 $(Q) $(CC_WRAPPER) $(CXX) -c $1 -o $@ $2
endef endef
+3 -3
View File
@@ -17,17 +17,17 @@ CXXFLAGS += $(TI_C_CXX_FLAGS) $(C_CXX_FLAGS)
# cc flags,file # cc flags,file
define cc define cc
$(vecho) "TICC $2 -> $@" $(vecho) "TICC $2"
$(Q) $(CC_WRAPPER) $(CC) -c --preproc_with_compile -ppd=$@.d $1 --output_file=$@ $2 $(Q) $(CC_WRAPPER) $(CC) -c --preproc_with_compile -ppd=$@.d $1 --output_file=$@ $2
endef endef
define cxx define cxx
$(vecho) "TICXX $2 -> $@" $(vecho) "TICXX $2"
$(Q) $(CC_WRAPPER) $(CC) -c --preproc_with_compile -ppd=$@.d $1 --output_file=$@ $2 $(Q) $(CC_WRAPPER) $(CC) -c --preproc_with_compile -ppd=$@.d $1 --output_file=$@ $2
endef endef
# asm flags,file # asm flags,file
define asm define asm
$(vecho) "TIASM $2 -> $@" $(vecho) "TIASM $2"
$(Q) $(CC_WRAPPER) $(CC) -c $1 --output_file=$@ $2 $(Q) $(CC_WRAPPER) $(CC) -c $1 --output_file=$@ $2
endef endef
+30 -8
View File
@@ -25,7 +25,7 @@
#if defined(ESP8266) #if defined(ESP8266)
#include "eagle_soc.h" #include "eagle_soc.h"
#include "ets_sys.h" #include "ets_sys.h"
#include "../../../miniz.c" #include "miniz.c"
#elif defined(ESP32) #elif defined(ESP32)
#include "rom/efuse.h" #include "rom/efuse.h"
#include "rom/miniz.h" #include "rom/miniz.h"
@@ -38,7 +38,7 @@
#include "uart.h" #include "uart.h"
/* Param: baud rate. */ /* Param: baud rate. */
uint32_t params[1] __attribute__((section(".params"))); uint32_t params[2] __attribute__((section(".params")));
#define FLASH_BLOCK_SIZE 65536 #define FLASH_BLOCK_SIZE 65536
#define FLASH_SECTOR_SIZE 4096 #define FLASH_SECTOR_SIZE 4096
@@ -470,6 +470,27 @@ uint8_t cmd_loop(void) {
resp = 0; resp = 0;
break; break;
} }
case CMD_READ_REG: {
len = SLIP_recv(args, sizeof(args));
if (len == 4) {
uint32_t value = READ_PERI_REG((uint32_t *) args[0]);
SLIP_send(&value, sizeof(value));
resp = 0;
} else {
resp = 0x91;
}
break;
}
case CMD_WRITE_REG: {
len = SLIP_recv(args, sizeof(args));
if (len == 8) {
WRITE_PERI_REG((uint32_t *) args[0], args[1]);
resp = 0;
} else {
resp = 0xa1;
}
break;
}
} }
SLIP_send(&resp, 1); SLIP_send(&resp, 1);
} while (cmd != CMD_BOOT_FW && cmd != CMD_REBOOT); } while (cmd != CMD_BOOT_FW && cmd != CMD_REBOOT);
@@ -477,8 +498,7 @@ uint8_t cmd_loop(void) {
} }
void stub_main1(void) { void stub_main1(void) {
uint32_t baud_rate = params[0]; uint32_t old_baud_rate = params[0], new_baud_rate = params[1];
uint32_t greeting = 0x4941484f; /* OHAI */
uint8_t last_cmd; uint8_t last_cmd;
/* This points at us right now, reset for next boot. */ /* This points at us right now, reset for next boot. */
@@ -487,6 +507,7 @@ void stub_main1(void) {
/* Selects SPI functions for flash pins. */ /* Selects SPI functions for flash pins. */
#if defined(ESP8266) #if defined(ESP8266)
SelectSpiFunction(); SelectSpiFunction();
spi_flash_attach();
SET_PERI_REG_MASK(0x3FF00014, 1); /* Switch to 160 MHz */ SET_PERI_REG_MASK(0x3FF00014, 1); /* Switch to 160 MHz */
#elif defined(ESP32) #elif defined(ESP32)
esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), 0 /* legacy */); esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), 0 /* legacy */);
@@ -496,9 +517,10 @@ void stub_main1(void) {
0 /* deviceId */, 16 * 1024 * 1024 /* chip_size */, FLASH_BLOCK_SIZE, 0 /* deviceId */, 16 * 1024 * 1024 /* chip_size */, FLASH_BLOCK_SIZE,
FLASH_SECTOR_SIZE, FLASH_PAGE_SIZE, 0xffff /* status_mask */); FLASH_SECTOR_SIZE, FLASH_PAGE_SIZE, 0xffff /* status_mask */);
if (baud_rate > 0) { uint32_t old_div = 0;
if (new_baud_rate > 0) {
ets_delay_us(10000); ets_delay_us(10000);
set_baud_rate(0, baud_rate); old_div = set_baud_rate(0, old_baud_rate, new_baud_rate);
} }
/* Give host time to get ready too. */ /* Give host time to get ready too. */
@@ -509,7 +531,7 @@ void stub_main1(void) {
WRITE_PERI_REG(UART_FIFO_REG(0), 0x55); WRITE_PERI_REG(UART_FIFO_REG(0), 0x55);
} }
#else #else
SLIP_send(&greeting, 4); SLIP_send(&old_div, 4);
#endif #endif
last_cmd = cmd_loop(); last_cmd = cmd_loop();
@@ -525,7 +547,7 @@ void stub_main1(void) {
* then jumps to 0x4000108a, then checks strapping bits again (which will * then jumps to 0x4000108a, then checks strapping bits again (which will
* not have changed), and then proceeds to 0x400010a8. * not have changed), and then proceeds to 0x400010a8.
*/ */
volatile uint32_t *sp = &baud_rate; volatile uint32_t *sp = &old_baud_rate;
while (*sp != (uint32_t) 0x40001100) sp++; while (*sp != (uint32_t) 0x40001100) sp++;
*sp = 0x400010a8; *sp = 0x400010a8;
/* /*
+18
View File
@@ -91,6 +91,24 @@ enum stub_cmd {
* Output: arguments. * Output: arguments.
*/ */
CMD_ECHO = 8, CMD_ECHO = 8,
/*
* Read register value.
*
* Args: register address.
* Input: None.
* Output: register value.
*/
CMD_READ_REG = 9,
/*
* Write register value.
*
* Args: register address, value.
* Input: None.
* Output: None.
*/
CMD_WRITE_REG = 10,
}; };
#endif /* CS_COMMON_PLATFORMS_ESP8266_STUBS_STUB_FLASHER_H_ */ #endif /* CS_COMMON_PLATFORMS_ESP8266_STUBS_STUB_FLASHER_H_ */
+5
View File
@@ -42,5 +42,10 @@ SECTIONS {
INCLUDE "components/esp32/ld/esp32.rom.ld" INCLUDE "components/esp32/ld/esp32.rom.ld"
INCLUDE "components/esp32/ld/esp32.rom.spiram_incompatible_fns.ld" INCLUDE "components/esp32/ld/esp32.rom.spiram_incompatible_fns.ld"
PROVIDE(ets_isr_mask = 0x400067fc);
PROVIDE(ets_isr_unmask = 0x40006808);
PROVIDE(MD5Init = 0x4005da7c);
PROVIDE(MD5Update = 0x4005da9c);
PROVIDE(MD5Final = 0x4005db1c);
PROVIDE(esp_rom_spiflash_attach = 0x40062a6c); PROVIDE(esp_rom_spiflash_attach = 0x40062a6c);
PROVIDE(esp_rom_spiflash_config_clk = 0x40062bc8); PROVIDE(esp_rom_spiflash_config_clk = 0x40062bc8);
+9 -5
View File
@@ -19,9 +19,13 @@
#include "rom_functions.h" #include "rom_functions.h"
void set_baud_rate(uint32_t uart_no, uint32_t baud_rate) { uint32_t set_baud_rate(uint32_t uart_no, uint32_t old_baud_rate,
uint32_t master_freq = ets_get_detected_xtal_freq() << 4; uint32_t new_baud_rate) {
master_freq += (baud_rate / 2); uint32_t uart_reg = REG_READ(UART_CLKDIV_REG(uart_no));
uint32_t div = master_freq / baud_rate; uint32_t uart_div = uart_reg & UART_CLKDIV_M;
uart_div_modify(uart_no, div); uint32_t fraction = (uart_reg >> UART_CLKDIV_FRAG_S) & UART_CLKDIV_FRAG_V;
uart_div = (uart_div << 4) + fraction;
uint32_t master_freq = uart_div * old_baud_rate;
uart_div_modify(uart_no, master_freq / new_baud_rate);
return uart_div;
} }
+2 -1
View File
@@ -20,6 +20,7 @@
#include <stdint.h> #include <stdint.h>
void set_baud_rate(uint32_t uart_no, uint32_t baud_rate); uint32_t set_baud_rate(uint32_t uart_no, uint32_t old_baud_rate,
uint32_t new_baud_rate);
#endif /* CS_COMMON_PLATFORMS_ESP32_STUBS_UART_H_ */ #endif /* CS_COMMON_PLATFORMS_ESP32_STUBS_UART_H_ */
-77
View File
@@ -44,80 +44,3 @@ void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
const size_t *msg_lens, uint8_t *digest) { const size_t *msg_lens, uint8_t *digest) {
(void) sha1_vector(num_msgs, msgs, msg_lens, digest); (void) sha1_vector(num_msgs, msgs, msg_lens, digest);
} }
#if MG_ENABLE_SSL
#include "mbedtls/aes.h"
#include "mbedtls/sha256.h"
#define AES_PRIV_NR_POS (4 * 15)
/*
* Crypto functions in ROM/SDK.
* They come from wpa_supplicant, you can find them here https://w1.fi/cgit/
*
* Note that ROM version of the key setup function is older, does not take the
* number of bits argument and only supports AES-128. This prototype doesn't
* suit it, but since the difference is in the last aegument, it doesn't matter.
*/
extern void rijndaelKeySetupDec(void *ctx, const uint8_t *key, int bits);
extern int rijndaelKeySetupEnc(void *ctx, const uint8_t *key, int bits);
void aes_encrypt(void *ctx, const uint8_t *plain, uint8_t *crypt);
void aes_decrypt(void *ctx, const uint8_t *crypt, uint8_t *plain);
/*
* AES that comes with wpa_supplicant allocates its own AES context in
* aes_{encrypt,decrypt}_init. Ideally, we'd take that pointer and store it in
* our mbedtls_aes_context, but then a lot of space would be wasted.
* We do not call _init and go directly to key setup functions and poke number
* of rounds into the right place too. This is a bit hacky, but works fine.
* There is also a difference between older function in ROM and the one coming
* with SDK which is newer: the older one actually takes two arguments, not 3.
* But it doesn't matter, extra argument doesn't hurt and this works with both.
*/
int mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits) {
if (keybits != 128) return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
((uint32_t *) ctx)[AES_PRIV_NR_POS] = 10;
rijndaelKeySetupEnc(ctx, key, 128);
return 0;
}
int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits) {
if (keybits != 128) return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
((uint32_t *) ctx)[AES_PRIV_NR_POS] = 10;
rijndaelKeySetupDec(ctx, key, 128);
return 0;
}
int mbedtls_internal_aes_encrypt(mbedtls_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16]) {
aes_encrypt(ctx, input, output);
return 0;
}
int mbedtls_internal_aes_decrypt(mbedtls_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16]) {
aes_decrypt(ctx, input, output);
return 0;
}
/* os_get_random uses hardware RNG, so it's cool. */
int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len) {
os_get_random(buf, len);
(void) ctx;
return 0;
}
/* For CryptoAuthLib host crypto. */
int atcac_sw_sha2_256(const uint8_t *data, size_t data_size,
uint8_t digest[32]) {
mbedtls_sha256(data, data_size, digest, false /* is_224 */);
return 0;
}
#endif /* MG_ENABLE_SSL */
+3 -3
View File
@@ -23,13 +23,13 @@ all: $(STUB_ELF)
$(STUB_ELF): $(STUB) $(LIBS) $(STUB_ELF): $(STUB) $(LIBS)
@echo " CC $^ -> $@" @echo " CC $^ -> $@"
@[ -d $(BUILD_DIR) ] || mkdir $(BUILD_DIR) @[ -d $(BUILD_DIR) ] || mkdir $(BUILD_DIR)
@docker run --rm -i -v $(CURDIR)/../../../..:/src $(SDK) //bin/bash -c \ docker run --rm -i -v $(CURDIR)/../../../..:/src $(SDK) //bin/bash -c \
"cd /src/common/platforms/esp8266/stubs && \ "cd /src/common/platforms/esp8266/stubs && \
$(XT_CC) -std=c99 -Wall -Werror -Os -DESP8266 \ $(XT_CC) -std=c99 -Wall -Werror -Os -DESP8266 \
-mtext-section-literals -mlongcalls -nostdlib -fno-builtin \ -mtext-section-literals -mlongcalls -nostdlib -fno-builtin \
-I. -I/src/common/platforms/esp \ -I. -I/src/common/platforms/esp -I/src/common/platforms/esp8266 \
-I/opt/Espressif/ESP8266_SDK \ -I/opt/Espressif/ESP8266_SDK \
-Wl,-static -ffunction-sections -Wl,--gc-sections \ -Wl,-static -ffunction-sections -lgcc -Wl,--gc-sections \
-Tstub.ld $(CFLAGS) -o $@ $^" -Tstub.ld $(CFLAGS) -o $@ $^"
wrap: $(STUB_JSON) wrap: $(STUB_JSON)
@@ -41,3 +41,4 @@ INCLUDE "eagle.rom.addr.v6.ld"
PROVIDE(SPIFlashModeConfig = 0x40004568); PROVIDE(SPIFlashModeConfig = 0x40004568);
PROVIDE(SPI_erase_sector = 0x400040c0); PROVIDE(SPI_erase_sector = 0x400040c0);
PROVIDE(SPI_erase_block = 0x40004120); PROVIDE(SPI_erase_block = 0x40004120);
PROVIDE(uart_div_modify = 0x400039d8);
+10 -4
View File
@@ -18,9 +18,15 @@
#include "uart.h" #include "uart.h"
#include "ets_sys.h" #include "ets_sys.h"
#define UART_CLKDIV_26MHZ(B) (52000000 + B / 2) / B #define UART_CLKDIV_M (UART_CLKDIV_CNT << UART_CLKDIV_S)
void set_baud_rate(uint32_t uart_no, uint32_t baud_rate) { void uart_div_modify(uint8_t uart_no, uint32_t div);
uint32_t div = UART_CLKDIV_26MHZ(baud_rate);
WRITE_PERI_REG(UART_CLKDIV_REG(uart_no), div & 0xfffff); uint32_t set_baud_rate(uint32_t uart_no, uint32_t old_baud_rate,
uint32_t new_baud_rate) {
uint32_t uart_reg = READ_PERI_REG(UART_CLKDIV_REG(uart_no));
uint32_t uart_div = uart_reg & UART_CLKDIV_M;
uint32_t master_freq = uart_div * old_baud_rate;
uart_div_modify(uart_no, master_freq / new_baud_rate);
return uart_div;
} }
+4 -2
View File
@@ -20,9 +20,11 @@
#include <stdint.h> #include <stdint.h>
void set_baud_rate(uint32_t uart_no, uint32_t baud_rate); #include "uart_register.h"
uint32_t set_baud_rate(uint32_t uart_no, uint32_t old_baud_rate,
uint32_t new_baud_rate);
#define REG_UART_BASE(i) (0x60000000 + (i) *0xf00)
#define UART_FIFO_REG(i) (REG_UART_BASE(i) + 0x0) #define UART_FIFO_REG(i) (REG_UART_BASE(i) + 0x0)
#define UART_CONF1_REG(i) (REG_UART_BASE(i) + 0x24) #define UART_CONF1_REG(i) (REG_UART_BASE(i) + 0x24)
#define UART_RX_TOUT_EN (BIT(31)) #define UART_RX_TOUT_EN (BIT(31))
@@ -1,23 +0,0 @@
#!/usr/bin/python
# Analyzers output of firmware compiler with -DESP_ENABLE_MALLOC_TRACES
import re
import sys
allocs = {}
for l in sys.stdin:
m = re.match(r'(ca|ma|re|fr) (\S+)\s*(\S*)\s*(\S*)', l)
if not m: continue
op = m.group(1)
if op in ('ca', 'ma'):
allocs[m.group(2)] = long(m.group(3))
else:
if m.group(2) in allocs:
del allocs[m.group(2)]
if op == 're':
allocs[m.group(3)] = long(m.group(4))
for k, v in sorted(allocs.iteritems()):
print k, v
-1
View File
@@ -66,7 +66,6 @@ typedef int sock_t;
#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL #if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
struct mg_mgr; struct mg_mgr;
struct mg_connection; struct mg_connection;
uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr);
void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle, void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle,
int interval, int count); int interval, int count);
#endif #endif
@@ -67,7 +67,6 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
break; break;
} }
case MG_SIG_CLOSE_CONN: { case MG_SIG_CLOSE_CONN: {
nc->flags |= MG_F_SEND_AND_CLOSE;
mg_close_conn(nc); mg_close_conn(nc);
break; break;
} }
@@ -167,36 +166,4 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) {
return now; return now;
} }
uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) {
struct mg_connection *nc;
double now;
double min_timer = 0;
int num_timers = 0;
mg_ev_mgr_lwip_process_signals(mgr);
for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (nc->ev_timer_time > 0) {
if (num_timers == 0 || nc->ev_timer_time < min_timer) {
min_timer = nc->ev_timer_time;
}
num_timers++;
}
/* We want and can send data, request a poll immediately. */
if (nc->sock != INVALID_SOCKET && mg_lwip_if_can_send(nc, cs)) {
return 0;
}
}
uint32_t timeout_ms = ~0;
now = mg_time();
if (num_timers > 0) {
/* If we have a timer that is past due, do a poll ASAP. */
if (min_timer < now) return 0;
double timer_timeout_ms = (min_timer - now) * 1000 + 1 /* rounding */;
if (timer_timeout_ms < timeout_ms) {
timeout_ms = timer_timeout_ms;
}
}
return timeout_ms;
}
#endif /* MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */ #endif /* MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */
+10 -1
View File
@@ -187,6 +187,7 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
} }
mg_lwip_recv_common(nc, p); mg_lwip_recv_common(nc, p);
mgos_unlock(); mgos_unlock();
(void) err;
return ERR_OK; return ERR_OK;
} }
@@ -199,6 +200,10 @@ static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb,
nc->send_mbuf.len == 0 && tpcb->unsent == NULL && tpcb->unacked == NULL) { nc->send_mbuf.len == 0 && tpcb->unsent == NULL && tpcb->unacked == NULL) {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
} }
if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
mg_lwip_mgr_schedule_poll(nc->mgr);
}
(void) num_sent;
return ERR_OK; return ERR_OK;
} }
@@ -560,6 +565,10 @@ static int mg_lwip_if_can_send(struct mg_connection *nc,
can_send = (cs->pcb.udp != NULL); can_send = (cs->pcb.udp != NULL);
} else { } else {
can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0); can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
/* See comment above. */
#if CS_PLATFORM == CS_P_ESP8266
if (cs->pcb.tcp->unacked != NULL) can_send = 0;
#endif
} }
} }
return can_send; return can_send;
@@ -572,7 +581,7 @@ struct tcp_recved_ctx {
void tcp_recved_tcpip(void *arg) { void tcp_recved_tcpip(void *arg) {
struct tcp_recved_ctx *ctx = (struct tcp_recved_ctx *) arg; struct tcp_recved_ctx *ctx = (struct tcp_recved_ctx *) arg;
tcp_recved(ctx->tpcb, ctx->len); if (ctx->tpcb != NULL) tcp_recved(ctx->tpcb, ctx->len);
} }
static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf, static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf,
+1 -1
View File
@@ -34,7 +34,7 @@
#include <stm32_sdk_hal.h> #include <stm32_sdk_hal.h>
#define to64(x) strtoll(x, NULL, 10) #define to64(x) strtoll(x, NULL, 10)
#define INT64_FMT PRId64 #define INT64_FMT "lld"
#define SIZE_T_FMT "u" #define SIZE_T_FMT "u"
typedef struct stat cs_stat_t; typedef struct stat cs_stat_t;
#define DIRSEP '/' #define DIRSEP '/'
@@ -169,7 +169,7 @@ int sl_set_ssl_opts(int sock, struct mg_connection *nc);
#endif /* SL_MAJOR_VERSION_NUM < 2 */ #endif /* SL_MAJOR_VERSION_NUM < 2 */
int slfs_open(const unsigned char *fname, uint32_t flags); int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token);
#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */
+69 -25
View File
@@ -31,14 +31,14 @@
#include "common/mg_mem.h" #include "common/mg_mem.h"
#if SL_MAJOR_VERSION_NUM < 2 #if SL_MAJOR_VERSION_NUM < 2
int slfs_open(const unsigned char *fname, uint32_t flags) { int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token) {
_i32 fh; _i32 fh;
_i32 r = sl_FsOpen(fname, flags, NULL /* token */, &fh); _i32 r = sl_FsOpen(fname, flags, (unsigned long *) token, &fh);
return (r < 0 ? r : fh); return (r < 0 ? r : fh);
} }
#else /* SL_MAJOR_VERSION_NUM >= 2 */ #else /* SL_MAJOR_VERSION_NUM >= 2 */
int slfs_open(const unsigned char *fname, uint32_t flags) { int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token) {
return sl_FsOpen(fname, flags, NULL /* token */); return sl_FsOpen(fname, flags, (unsigned long *) token);
} }
#endif #endif
@@ -54,9 +54,11 @@ const char *drop_dir(const char *fname, bool *is_slfs);
#define FS_SLFS_MAX_FILE_SIZE (64 * 1024) #define FS_SLFS_MAX_FILE_SIZE (64 * 1024)
#endif #endif
struct sl_file_size_hint { struct sl_file_open_info {
char *name; char *name;
size_t size; size_t size;
uint32_t flags;
uint32_t *token;
}; };
struct sl_fd_info { struct sl_fd_info {
@@ -66,7 +68,10 @@ struct sl_fd_info {
}; };
static struct sl_fd_info s_sl_fds[MAX_OPEN_SLFS_FILES]; static struct sl_fd_info s_sl_fds[MAX_OPEN_SLFS_FILES];
static struct sl_file_size_hint s_sl_file_size_hints[MAX_OPEN_SLFS_FILES]; static struct sl_file_open_info s_sl_file_open_infos[MAX_OPEN_SLFS_FILES];
static struct sl_file_open_info *fs_slfs_find_foi(const char *name,
bool create);
static int sl_fs_to_errno(_i32 r) { static int sl_fs_to_errno(_i32 r) {
DBG(("SL error: %d", (int) r)); DBG(("SL error: %d", (int) r));
@@ -107,7 +112,13 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) {
_u32 am = 0; _u32 am = 0;
fi->size = (size_t) -1; fi->size = (size_t) -1;
int rw = (flags & 3); int rw = (flags & 3);
size_t new_size = FS_SLFS_MAX_FILE_SIZE; size_t new_size = 0;
struct sl_file_open_info *foi =
fs_slfs_find_foi(pathname, false /* create */);
if (foi != NULL) {
LOG(LL_DEBUG, ("FOI for %s: %d 0x%x %p", pathname, (int) foi->size,
(unsigned int) foi->flags, foi->token));
}
if (rw == O_RDONLY) { if (rw == O_RDONLY) {
SlFsFileInfo_t sl_fi; SlFsFileInfo_t sl_fi;
_i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi); _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
@@ -122,24 +133,27 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) {
return set_errno(ENOTSUP); return set_errno(ENOTSUP);
} }
if (flags & O_CREAT) { if (flags & O_CREAT) {
size_t i; if (foi->size > 0) {
for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) { new_size = foi->size;
if (s_sl_file_size_hints[i].name != NULL && } else {
strcmp(s_sl_file_size_hints[i].name, pathname) == 0) { new_size = FS_SLFS_MAX_FILE_SIZE;
new_size = s_sl_file_size_hints[i].size;
MG_FREE(s_sl_file_size_hints[i].name);
s_sl_file_size_hints[i].name = NULL;
break;
}
} }
am = FS_MODE_OPEN_CREATE(new_size, 0); am = FS_MODE_OPEN_CREATE(new_size, 0);
} else { } else {
am = SL_FS_WRITE; am = SL_FS_WRITE;
} }
#if SL_MAJOR_VERSION_NUM >= 2
am |= SL_FS_OVERWRITE;
#endif
} }
fi->fh = slfs_open((_u8 *) pathname, am); uint32_t *token = NULL;
LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x) sz %u = %d", pathname, (int) am, if (foi != NULL) {
(unsigned int) new_size, (int) fi->fh)); am |= foi->flags;
token = foi->token;
}
fi->fh = slfs_open((_u8 *) pathname, am, token);
LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x, %p) sz %u = %d", pathname, (int) am,
token, (unsigned int) new_size, (int) fi->fh));
int r; int r;
if (fi->fh >= 0) { if (fi->fh >= 0) {
fi->pos = 0; fi->pos = 0;
@@ -243,16 +257,46 @@ int fs_slfs_rename(const char *from, const char *to) {
return set_errno(ENOTSUP); return set_errno(ENOTSUP);
} }
void fs_slfs_set_new_file_size(const char *name, size_t size) { static struct sl_file_open_info *fs_slfs_find_foi(const char *name,
int i; bool create) {
int i = 0;
for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) { for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
if (s_sl_file_size_hints[i].name == NULL) { if (s_sl_file_open_infos[i].name != NULL &&
DBG(("File size hint: %s %d", name, (int) size)); strcmp(drop_dir(s_sl_file_open_infos[i].name, NULL), name) == 0) {
s_sl_file_size_hints[i].name = strdup(name);
s_sl_file_size_hints[i].size = size;
break; break;
} }
} }
if (i != MAX_OPEN_SLFS_FILES) return &s_sl_file_open_infos[i];
if (!create) return NULL;
for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
if (s_sl_file_open_infos[i].name == NULL) break;
}
if (i == MAX_OPEN_SLFS_FILES) {
i = 0; /* Evict a random slot. */
}
if (s_sl_file_open_infos[i].name != NULL) {
free(s_sl_file_open_infos[i].name);
}
s_sl_file_open_infos[i].name = strdup(name);
return &s_sl_file_open_infos[i];
}
void fs_slfs_set_file_size(const char *name, size_t size) {
struct sl_file_open_info *foi = fs_slfs_find_foi(name, true /* create */);
foi->size = size;
}
void fs_slfs_set_file_flags(const char *name, uint32_t flags, uint32_t *token) {
struct sl_file_open_info *foi = fs_slfs_find_foi(name, true /* create */);
foi->flags = flags;
foi->token = token;
}
void fs_slfs_unset_file_flags(const char *name) {
struct sl_file_open_info *foi = fs_slfs_find_foi(name, false /* create */);
if (foi == NULL) return;
free(foi->name);
memset(foi, 0, sizeof(*foi));
} }
#endif /* defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS) */ #endif /* defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS) */
+3 -1
View File
@@ -39,7 +39,9 @@ off_t fs_slfs_lseek(int fd, off_t offset, int whence);
int fs_slfs_unlink(const char *filename); int fs_slfs_unlink(const char *filename);
int fs_slfs_rename(const char *from, const char *to); int fs_slfs_rename(const char *from, const char *to);
void fs_slfs_set_new_file_size(const char *name, size_t size); void fs_slfs_set_file_size(const char *name, size_t size);
void fs_slfs_set_file_flags(const char *name, uint32_t flags, uint32_t *token);
void fs_slfs_unset_file_flags(const char *name);
#endif /* defined(MG_FS_SLFS) */ #endif /* defined(MG_FS_SLFS) */
+2 -2
View File
@@ -115,9 +115,9 @@ bool pem_to_der(const char *pem_file, const char *der_file) {
pf = fopen(pem_file, "r"); pf = fopen(pem_file, "r");
if (pf == NULL) goto clean; if (pf == NULL) goto clean;
remove(der_file); remove(der_file);
fs_slfs_set_new_file_size(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN, fs_slfs_set_file_size(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN, 2048);
2048);
df = fopen(der_file, "w"); df = fopen(der_file, "w");
fs_slfs_unset_file_flags(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN);
if (df == NULL) goto clean; if (df == NULL) goto clean;
while (1) { while (1) {
char pem_buf[70]; char pem_buf[70];
+2 -2
View File
@@ -11,7 +11,7 @@ import (
"time" "time"
"unsafe" "unsafe"
"cesanta.com/mos/flash/common" "cesanta.com/common/go/fwbundle"
"github.com/cesanta/errors" "github.com/cesanta/errors"
) )
@@ -20,7 +20,7 @@ type FlashOpts struct {
Timeout time.Duration Timeout time.Duration
} }
func Flash(fw *common.FirmwareBundle, opts *FlashOpts) error { func Flash(fw *fwbundle.FirmwareBundle, opts *FlashOpts) error {
data, err := fw.GetPartData("boot") data, err := fw.GetPartData("boot")
if err != nil { if err != nil {
return errors.Annotatef(err, "invalid manifest") return errors.Annotatef(err, "invalid manifest")
+1 -1
View File
@@ -20,7 +20,7 @@
#ifndef CS_MONGOOSE_SRC_COMMON_H_ #ifndef CS_MONGOOSE_SRC_COMMON_H_
#define CS_MONGOOSE_SRC_COMMON_H_ #define CS_MONGOOSE_SRC_COMMON_H_
#define MG_VERSION "6.12" #define MG_VERSION "6.14"
/* Local tweaks, applied before any of Mongoose's own headers. */ /* Local tweaks, applied before any of Mongoose's own headers. */
#ifdef MG_LOCALS #ifdef MG_LOCALS
+98 -44
View File
@@ -140,6 +140,7 @@ struct mg_http_multipart_stream {
void *user_data; void *user_data;
enum mg_http_multipart_stream_state state; enum mg_http_multipart_stream_state state;
int processing_part; int processing_part;
int data_avail;
}; };
struct mg_reverse_proxy_data { struct mg_reverse_proxy_data {
@@ -564,6 +565,10 @@ static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data,
n *= 16; n *= 16;
n += (s[i] >= '0' && s[i] <= '9') ? s[i] - '0' : tolower(s[i]) - 'a' + 10; n += (s[i] >= '0' && s[i] <= '9') ? s[i] - '0' : tolower(s[i]) - 'a' + 10;
i++; i++;
if (i > 6) {
/* Chunk size is unreasonable. */
return 0;
}
} }
/* Skip new line */ /* Skip new line */
@@ -754,9 +759,9 @@ void mg_http_handler(struct mg_connection *nc, int ev,
if (io->len > 0 && if (io->len > 0 &&
(req_len = mg_parse_http(io->buf, io->len, hm, is_req)) > 0) { (req_len = mg_parse_http(io->buf, io->len, hm, is_req)) > 0) {
/* /*
* For HTTP messages without Content-Length, always send HTTP message * For HTTP messages without Content-Length, always send HTTP message
* before MG_EV_CLOSE message. * before MG_EV_CLOSE message.
*/ */
int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
hm->message.len = io->len; hm->message.len = io->len;
hm->body.len = io->buf + io->len - hm->body.p; hm->body.len = io->buf + io->len - hm->body.p;
@@ -764,6 +769,9 @@ void mg_http_handler(struct mg_connection *nc, int ev,
mg_http_call_endpoint_handler(nc, ev2, hm); mg_http_call_endpoint_handler(nc, ev2, hm);
} }
pd->rcvd = 0; pd->rcvd = 0;
if (pd->endpoint_handler != NULL && pd->endpoint_handler != nc->handler) {
mg_call(nc, pd->endpoint_handler, nc->user_data, ev, NULL);
}
} }
#if MG_ENABLE_FILESYSTEM #if MG_ENABLE_FILESYSTEM
@@ -774,17 +782,24 @@ void mg_http_handler(struct mg_connection *nc, int ev,
mg_call(nc, nc->handler, nc->user_data, ev, ev_data); mg_call(nc, nc->handler, nc->user_data, ev, ev_data);
#if MG_ENABLE_HTTP_STREAMING_MULTIPART
if (pd->mp_stream.boundary != NULL &&
(ev == MG_EV_RECV || ev == MG_EV_POLL)) {
if (ev == MG_EV_RECV) {
pd->rcvd += *(int *) ev_data;
mg_http_multipart_continue(nc);
} else if (pd->mp_stream.data_avail) {
/* Try re-delivering the data. */
mg_http_multipart_continue(nc);
}
return;
}
#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
if (ev == MG_EV_RECV) { if (ev == MG_EV_RECV) {
struct mg_str *s; struct mg_str *s;
pd->rcvd += *(int *) ev_data; pd->rcvd += *(int *) ev_data;
#if MG_ENABLE_HTTP_STREAMING_MULTIPART
if (pd->mp_stream.boundary != NULL) {
mg_http_multipart_continue(nc);
return;
}
#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
again: again:
req_len = mg_parse_http(io->buf, io->len, hm, is_req); req_len = mg_parse_http(io->buf, io->len, hm, is_req);
@@ -812,16 +827,23 @@ void mg_http_handler(struct mg_connection *nc, int ev,
/* Do nothing, request is not yet fully buffered */ /* Do nothing, request is not yet fully buffered */
} }
#if MG_ENABLE_HTTP_WEBSOCKET #if MG_ENABLE_HTTP_WEBSOCKET
else if (nc->listener == NULL && else if (nc->listener == NULL && (nc->flags & MG_F_IS_WEBSOCKET)) {
mg_get_http_header(hm, "Sec-WebSocket-Accept")) {
/* We're websocket client, got handshake response from server. */ /* We're websocket client, got handshake response from server. */
/* TODO(lsm): check the validity of accept Sec-WebSocket-Accept */ DBG(("%p WebSocket upgrade code %d", nc, hm->resp_code));
mbuf_remove(io, req_len); if (hm->resp_code == 101 &&
nc->proto_handler = mg_ws_handler; mg_get_http_header(hm, "Sec-WebSocket-Accept")) {
nc->flags |= MG_F_IS_WEBSOCKET; /* TODO(lsm): check the validity of accept Sec-WebSocket-Accept */
mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE, mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE,
NULL); hm);
mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data)); mbuf_remove(io, req_len);
nc->proto_handler = mg_ws_handler;
mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data));
} else {
mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE,
hm);
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
mbuf_remove(io, req_len);
}
} else if (nc->listener != NULL && } else if (nc->listener != NULL &&
(vec = mg_get_http_header(hm, "Sec-WebSocket-Key")) != NULL) { (vec = mg_get_http_header(hm, "Sec-WebSocket-Key")) != NULL) {
struct mg_http_endpoint *ep; struct mg_http_endpoint *ep;
@@ -852,7 +874,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
mg_ws_handshake(nc, vec, hm); mg_ws_handshake(nc, vec, hm);
} }
mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE, mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE,
NULL); hm);
mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data)); mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data));
} }
} }
@@ -869,6 +891,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
} }
} else { } else {
/* We did receive all HTTP body. */ /* We did receive all HTTP body. */
int request_done = 1;
int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
char addr[32]; char addr[32];
mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
@@ -880,8 +903,28 @@ void mg_http_handler(struct mg_connection *nc, int ev,
mg_http_call_endpoint_handler(nc, trigger_ev, hm); mg_http_call_endpoint_handler(nc, trigger_ev, hm);
mbuf_remove(io, hm->message.len); mbuf_remove(io, hm->message.len);
pd->rcvd -= hm->message.len; pd->rcvd -= hm->message.len;
if (io->len > 0) { #if MG_ENABLE_FILESYSTEM
goto again; /* We don't have a generic mechanism of communicating that we are done
* responding to a request (should probably add one). But if we are
* serving
* a file, we are definitely not done. */
if (pd->file.fp != NULL) request_done = 0;
#endif
#if MG_ENABLE_HTTP_CGI
/* If this is a CGI request, we are not done either. */
if (pd->cgi.cgi_nc != NULL) request_done = 0;
#endif
if (request_done) {
/* This request is done but we may receive another on this connection.
*/
mg_http_conn_destructor(pd);
nc->proto_data = NULL;
if (io->len > 0) {
/* We already have data for the next one, restart parsing. */
pd = mg_http_get_proto_data(nc);
pd->rcvd = io->len;
goto again;
}
} }
} }
} }
@@ -958,8 +1001,9 @@ exit_mp:
#define CONTENT_DISPOSITION "Content-Disposition: " #define CONTENT_DISPOSITION "Content-Disposition: "
static void mg_http_multipart_call_handler(struct mg_connection *c, int ev, static size_t mg_http_multipart_call_handler(struct mg_connection *c, int ev,
const char *data, size_t data_len) { const char *data,
size_t data_len) {
struct mg_http_multipart_part mp; struct mg_http_multipart_part mp;
struct mg_http_proto_data *pd = mg_http_get_proto_data(c); struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
memset(&mp, 0, sizeof(mp)); memset(&mp, 0, sizeof(mp));
@@ -969,8 +1013,11 @@ static void mg_http_multipart_call_handler(struct mg_connection *c, int ev,
mp.user_data = pd->mp_stream.user_data; mp.user_data = pd->mp_stream.user_data;
mp.data.p = data; mp.data.p = data;
mp.data.len = data_len; mp.data.len = data_len;
mp.num_data_consumed = data_len;
mg_call(c, pd->endpoint_handler, c->user_data, ev, &mp); mg_call(c, pd->endpoint_handler, c->user_data, ev, &mp);
pd->mp_stream.user_data = mp.user_data; pd->mp_stream.user_data = mp.user_data;
pd->mp_stream.data_avail = (mp.num_data_consumed != data_len);
return mp.num_data_consumed;
} }
static int mg_http_multipart_finalize(struct mg_connection *c) { static int mg_http_multipart_finalize(struct mg_connection *c) {
@@ -1108,19 +1155,25 @@ static int mg_http_multipart_continue_wait_for_chunk(struct mg_connection *c) {
boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len); boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
if (boundary == NULL) { if (boundary == NULL) {
int data_size = (io->len - (pd->mp_stream.boundary_len + 6)); int data_len = (io->len - (pd->mp_stream.boundary_len + 6));
if (data_size > 0) { if (data_len > 0) {
mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, size_t consumed = mg_http_multipart_call_handler(
data_size); c, MG_EV_HTTP_PART_DATA, io->buf, (size_t) data_len);
mbuf_remove(io, data_size); mbuf_remove(io, consumed);
} }
return 0; return 0;
} else if (boundary != NULL) { } else if (boundary != NULL) {
int data_size = (boundary - io->buf - 4); size_t data_len = ((size_t)(boundary - io->buf) - 4);
mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, data_size); size_t consumed = mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA,
mbuf_remove(io, (boundary - io->buf)); io->buf, data_len);
pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY; mbuf_remove(io, consumed);
return 1; if (consumed == data_len) {
mbuf_remove(io, 4);
pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
return 1;
} else {
return 0;
}
} else { } else {
return 0; return 0;
} }
@@ -1898,7 +1951,7 @@ int mg_check_digest_auth(struct mg_str method, struct mg_str uri,
struct mg_str nc, struct mg_str nonce, struct mg_str nc, struct mg_str nonce,
struct mg_str auth_domain, FILE *fp) { struct mg_str auth_domain, FILE *fp) {
char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)]; char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)];
char expected_response[33]; char exp_resp[33];
/* /*
* Read passwords file line by line. If should have htdigest format, * Read passwords file line by line. If should have htdigest format,
@@ -1912,11 +1965,10 @@ int mg_check_digest_auth(struct mg_str method, struct mg_str uri,
/* Username and domain matched, check the password */ /* Username and domain matched, check the password */
mg_mkmd5resp(method.p, method.len, uri.p, uri.len, f_ha1, strlen(f_ha1), mg_mkmd5resp(method.p, method.len, uri.p, uri.len, f_ha1, strlen(f_ha1),
nonce.p, nonce.len, nc.p, nc.len, cnonce.p, cnonce.len, nonce.p, nonce.len, nc.p, nc.len, cnonce.p, cnonce.len,
qop.p, qop.len, expected_response); qop.p, qop.len, exp_resp);
LOG(LL_DEBUG, LOG(LL_DEBUG, ("%.*s %s %.*s %s", (int) username.len, username.p,
("%.*s %s %.*s %s", (int) username.len, username.p, f_domain, f_domain, (int) response.len, response.p, exp_resp));
(int) response.len, response.p, expected_response)); return mg_ncasecmp(response.p, exp_resp, strlen(exp_resp)) == 0;
return mg_ncasecmp(response.p, expected_response, response.len) == 0;
} }
} }
@@ -2511,9 +2563,11 @@ void mg_http_send_digest_auth_request(struct mg_connection *c,
domain, (unsigned long) mg_time()); domain, (unsigned long) mg_time());
} }
static void mg_http_send_options(struct mg_connection *nc) { static void mg_http_send_options(struct mg_connection *nc,
struct mg_serve_http_opts *opts) {
mg_send_response_line(nc, 200, opts->extra_headers);
mg_printf(nc, "%s", mg_printf(nc, "%s",
"HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, OPTIONS" "Allow: GET, POST, HEAD, CONNECT, OPTIONS"
#if MG_ENABLE_HTTP_WEBDAV #if MG_ENABLE_HTTP_WEBDAV
", MKCOL, PUT, DELETE, PROPFIND, MOVE\r\nDAV: 1,2" ", MKCOL, PUT, DELETE, PROPFIND, MOVE\r\nDAV: 1,2"
#endif #endif
@@ -2620,7 +2674,7 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
#endif #endif
#endif /* MG_ENABLE_HTTP_WEBDAV */ #endif /* MG_ENABLE_HTTP_WEBDAV */
} else if (!mg_vcmp(&hm->method, "OPTIONS")) { } else if (!mg_vcmp(&hm->method, "OPTIONS")) {
mg_http_send_options(nc); mg_http_send_options(nc, opts);
} else if (is_directory && index_file == NULL) { } else if (is_directory && index_file == NULL) {
#if MG_ENABLE_DIRECTORY_LISTING #if MG_ENABLE_DIRECTORY_LISTING
if (strcmp(opts->enable_directory_listing, "yes") == 0) { if (strcmp(opts->enable_directory_listing, "yes") == 0) {
@@ -2737,7 +2791,7 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
if (lfn.p != mp->file_name) MG_FREE((char *) lfn.p); if (lfn.p != mp->file_name) MG_FREE((char *) lfn.p);
LOG(LL_DEBUG, LOG(LL_DEBUG,
("%p Receiving file %s -> %s", nc, mp->file_name, fus->lfn)); ("%p Receiving file %s -> %s", nc, mp->file_name, fus->lfn));
fus->fp = mg_fopen(fus->lfn, "w"); fus->fp = mg_fopen(fus->lfn, "wb");
if (fus->fp == NULL) { if (fus->fp == NULL) {
mg_printf(nc, mg_printf(nc,
"HTTP/1.1 500 Internal Server Error\r\n" "HTTP/1.1 500 Internal Server Error\r\n"
+12 -2
View File
@@ -80,6 +80,14 @@ struct mg_http_multipart_part {
struct mg_str data; struct mg_str data;
int status; /* <0 on error */ int status; /* <0 on error */
void *user_data; void *user_data;
/*
* User handler can indicate how much of the data was consumed
* by setting this variable. By default, it is assumed that all
* data has been consumed by the handler.
* If not all data was consumed, user's handler will be invoked again later
* with the remainder.
*/
size_t num_data_consumed;
}; };
/* SSI call context */ /* SSI call context */
@@ -98,7 +106,7 @@ struct mg_ssi_call_ctx {
#if MG_ENABLE_HTTP_WEBSOCKET #if MG_ENABLE_HTTP_WEBSOCKET
#define MG_EV_WEBSOCKET_HANDSHAKE_REQUEST 111 /* struct http_message * */ #define MG_EV_WEBSOCKET_HANDSHAKE_REQUEST 111 /* struct http_message * */
#define MG_EV_WEBSOCKET_HANDSHAKE_DONE 112 /* NULL */ #define MG_EV_WEBSOCKET_HANDSHAKE_DONE 112 /* struct http_message * */
#define MG_EV_WEBSOCKET_FRAME 113 /* struct websocket_message * */ #define MG_EV_WEBSOCKET_FRAME 113 /* struct websocket_message * */
#define MG_EV_WEBSOCKET_CONTROL_FRAME 114 /* struct websocket_message * */ #define MG_EV_WEBSOCKET_CONTROL_FRAME 114 /* struct websocket_message * */
#endif #endif
@@ -137,7 +145,9 @@ struct mg_ssi_call_ctx {
* - MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: server has received the WebSocket * - MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: server has received the WebSocket
* handshake request. `ev_data` contains parsed HTTP request. * handshake request. `ev_data` contains parsed HTTP request.
* - MG_EV_WEBSOCKET_HANDSHAKE_DONE: server has completed the WebSocket * - MG_EV_WEBSOCKET_HANDSHAKE_DONE: server has completed the WebSocket
* handshake. `ev_data` is `NULL`. * handshake. `ev_data` is a `struct http_message` containing the
* client's request (server mode) or server's response (client).
* In client mode handler can examine `resp_code`, which should be 101.
* - MG_EV_WEBSOCKET_FRAME: new WebSocket frame has arrived. `ev_data` is * - MG_EV_WEBSOCKET_FRAME: new WebSocket frame has arrived. `ev_data` is
* `struct websocket_message *` * `struct websocket_message *`
* *
+2
View File
@@ -478,6 +478,8 @@ void mg_send_websocket_handshake3v(struct mg_connection *nc,
} }
mg_printf(nc, "\r\n"); mg_printf(nc, "\r\n");
nc->flags |= MG_F_IS_WEBSOCKET;
mbuf_free(&auth); mbuf_free(&auth);
} }
+2
View File
@@ -34,7 +34,9 @@
#include "mg_http.h" #include "mg_http.h"
#include "mg_net.h" #include "mg_net.h"
#ifndef MG_CTL_MSG_MESSAGE_SIZE
#define MG_CTL_MSG_MESSAGE_SIZE 8192 #define MG_CTL_MSG_MESSAGE_SIZE 8192
#endif
/* internals that need to be accessible in unit tests */ /* internals that need to be accessible in unit tests */
MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc, MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc,
+1
View File
@@ -64,6 +64,7 @@ SOURCES = $(COMMON)/mg_mem.h \
mg_net_if_socket.h \ mg_net_if_socket.h \
mg_net_if_socks.h \ mg_net_if_socks.h \
mg_net_if.c \ mg_net_if.c \
mg_net_if_null.c \
mg_net_if_socket.c \ mg_net_if_socket.c \
mg_net_if_socks.c \ mg_net_if_socks.c \
mg_ssl_if_openssl.c \ mg_ssl_if_openssl.c \
+34 -16
View File
@@ -196,26 +196,44 @@ static void mg_mqtt_proto_data_destructor(void *proto_data) {
MG_FREE(proto_data); MG_FREE(proto_data);
} }
static struct mg_str mg_mqtt_next_topic_component(struct mg_str *topic) {
struct mg_str res = *topic;
const char *c = mg_strchr(*topic, '/');
if (c != NULL) {
res.len = (c - topic->p);
topic->len -= (res.len + 1);
topic->p += (res.len + 1);
} else {
topic->len = 0;
}
return res;
}
/* Refernce: https://mosquitto.org/man/mqtt-7.html */
int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic) { int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic) {
/* TODO(mkm): implement real matching */ struct mg_str ec, tc;
if (memchr(exp.p, '#', exp.len)) { if (exp.len == 0) return 0;
/* exp `foo/#` will become `foo/` */ while (1) {
exp.len -= 1; ec = mg_mqtt_next_topic_component(&exp);
/* tc = mg_mqtt_next_topic_component(&topic);
* topic should be longer than the expression: e.g. topic `foo/bar` does if (ec.len == 0) {
* match `foo/#`, but neither `foo` nor `foo/` do. if (tc.len != 0) return 0;
*/ if (exp.len == 0) break;
if (topic.len <= exp.len) { continue;
}
if (mg_vcmp(&ec, "+") == 0) {
if (tc.len == 0 && topic.len == 0) return 0;
continue;
}
if (mg_vcmp(&ec, "#") == 0) {
/* Must be the last component in the expression or it's invalid. */
return (exp.len == 0);
}
if (mg_strcmp(ec, tc) != 0) {
return 0; return 0;
} }
/* Truncate topic so that it'll pass the next length check */
topic.len = exp.len;
} }
if (topic.len != exp.len) { return (tc.len == 0 && topic.len == 0);
return 0;
}
return strncmp(topic.p, exp.p, exp.len) == 0;
} }
int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic) { int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic) {
+47 -27
View File
@@ -99,6 +99,7 @@ MG_INTERNAL void mg_call(struct mg_connection *nc,
(nc->flags & _MG_CALLBACK_MODIFIABLE_FLAGS_MASK); (nc->flags & _MG_CALLBACK_MODIFIABLE_FLAGS_MASK);
} }
} }
if (ev != MG_EV_POLL) nc->mgr->num_calls++;
if (ev != MG_EV_POLL) { if (ev != MG_EV_POLL) {
DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc, DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc,
ev_handler == nc->handler ? "user" : "proto", nc->flags, ev_handler == nc->handler ? "user" : "proto", nc->flags,
@@ -127,8 +128,16 @@ MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) {
static int mg_do_recv(struct mg_connection *nc); static int mg_do_recv(struct mg_connection *nc);
int mg_if_poll(struct mg_connection *nc, double now) { int mg_if_poll(struct mg_connection *nc, double now) {
if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) || if (nc->flags & MG_F_CLOSE_IMMEDIATELY) {
(nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) { mg_close_conn(nc);
return 0;
} else if (nc->flags & MG_F_SEND_AND_CLOSE) {
if (nc->send_mbuf.len == 0) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
mg_close_conn(nc);
return 0;
}
} else if (nc->flags & MG_F_RECV_AND_CLOSE) {
mg_close_conn(nc); mg_close_conn(nc);
return 0; return 0;
} }
@@ -171,6 +180,13 @@ void mg_destroy_conn(struct mg_connection *conn, int destroy_if) {
} }
void mg_close_conn(struct mg_connection *conn) { void mg_close_conn(struct mg_connection *conn) {
/* See if there's any remaining data to deliver. Skip if user completely
* throttled the connection there will be no progress anyway. */
if (conn->sock != INVALID_SOCKET && mg_do_recv(conn) == -2) {
/* Receive is throttled, wait. */
conn->flags |= MG_F_RECV_AND_CLOSE;
return;
}
#if MG_ENABLE_SSL #if MG_ENABLE_SSL
if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) { if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) {
mg_ssl_if_conn_close_notify(conn); mg_ssl_if_conn_close_notify(conn);
@@ -261,6 +277,7 @@ void mg_mgr_free(struct mg_mgr *m) {
for (conn = m->active_connections; conn != NULL; conn = tmp_conn) { for (conn = m->active_connections; conn != NULL; conn = tmp_conn) {
tmp_conn = conn->next; tmp_conn = conn->next;
conn->flags |= MG_F_CLOSE_IMMEDIATELY;
mg_close_conn(conn); mg_close_conn(conn);
} }
@@ -276,19 +293,14 @@ void mg_mgr_free(struct mg_mgr *m) {
MG_FREE((char *) m->nameserver); MG_FREE((char *) m->nameserver);
} }
time_t mg_mgr_poll(struct mg_mgr *m, int timeout_ms) { int mg_mgr_poll(struct mg_mgr *m, int timeout_ms) {
int i; int i, num_calls_before = m->num_calls;
time_t now = 0; /* oh GCC, seriously ? */
if (m->num_ifaces == 0) {
LOG(LL_ERROR, ("cannot poll: no interfaces"));
return 0;
}
for (i = 0; i < m->num_ifaces; i++) { for (i = 0; i < m->num_ifaces; i++) {
now = m->ifaces[i]->vtable->poll(m->ifaces[i], timeout_ms); m->ifaces[i]->vtable->poll(m->ifaces[i], timeout_ms);
} }
return now;
return (m->num_calls - num_calls_before);
} }
int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap) { int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap) {
@@ -492,7 +504,6 @@ MG_INTERNAL void mg_ssl_handshake(struct mg_connection *nc) {
enum mg_ssl_if_result res; enum mg_ssl_if_result res;
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return; if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return;
res = mg_ssl_if_handshake(nc); res = mg_ssl_if_handshake(nc);
LOG(LL_DEBUG, ("%p %d res %d", nc, server_side, res));
if (res == MG_SSL_OK) { if (res == MG_SSL_OK) {
nc->flags |= MG_F_SSL_HANDSHAKE_DONE; nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
@@ -570,18 +581,23 @@ static int mg_do_recv(struct mg_connection *nc) {
((nc->flags & MG_F_LISTENING) && !(nc->flags & MG_F_UDP))) { ((nc->flags & MG_F_LISTENING) && !(nc->flags & MG_F_UDP))) {
return -1; return -1;
} }
len = recv_avail_size(nc, len); do {
if (len == 0) return -2; len = recv_avail_size(nc, len);
if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) { if (len == 0) {
mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len); res = -2;
} break;
buf = nc->recv_mbuf.buf + nc->recv_mbuf.len; }
len = nc->recv_mbuf.size - nc->recv_mbuf.len; if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) {
if (nc->flags & MG_F_UDP) { mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len);
res = mg_recv_udp(nc, buf, len); }
} else { buf = nc->recv_mbuf.buf + nc->recv_mbuf.len;
res = mg_recv_tcp(nc, buf, len); len = nc->recv_mbuf.size - nc->recv_mbuf.len;
} if (nc->flags & MG_F_UDP) {
res = mg_recv_udp(nc, buf, len);
} else {
res = mg_recv_tcp(nc, buf, len);
}
} while (res > 0 && !(nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_UDP)));
return res; return res;
} }
@@ -623,10 +639,12 @@ static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) {
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV); mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
} }
#endif #endif
mbuf_trim(&nc->recv_mbuf);
mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n); mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
} else if (n < 0) { } else if (n < 0) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY; nc->flags |= MG_F_CLOSE_IMMEDIATELY;
} }
mbuf_trim(&nc->recv_mbuf);
return n; return n;
} }
@@ -696,7 +714,9 @@ static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV); mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
} }
#endif #endif
mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n); if (n != 0) {
mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
}
} }
out: out:
@@ -738,7 +758,7 @@ void mg_if_can_send_cb(struct mg_connection *nc) {
} }
} else } else
#endif #endif
{ if (len > 0) {
if (nc->flags & MG_F_UDP) { if (nc->flags & MG_F_UDP) {
n = nc->iface->vtable->udp_send(nc, buf, len); n = nc->iface->vtable->udp_send(nc, buf, len);
} else { } else {
+6 -4
View File
@@ -89,6 +89,7 @@ struct mg_mgr {
#endif #endif
void *user_data; /* User data */ void *user_data; /* User data */
int num_ifaces; int num_ifaces;
int num_calls;
struct mg_iface **ifaces; /* network interfaces */ struct mg_iface **ifaces; /* network interfaces */
const char *nameserver; /* DNS server to use */ const char *nameserver; /* DNS server to use */
}; };
@@ -139,6 +140,7 @@ struct mg_connection {
#define MG_F_WANT_READ (1 << 6) /* SSL specific */ #define MG_F_WANT_READ (1 << 6) /* SSL specific */
#define MG_F_WANT_WRITE (1 << 7) /* SSL specific */ #define MG_F_WANT_WRITE (1 << 7) /* SSL specific */
#define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */ #define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */
#define MG_F_RECV_AND_CLOSE (1 << 9) /* Drain rx and close the connection. */
/* Flags that are settable by user */ /* Flags that are settable by user */
#define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */ #define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */
@@ -201,17 +203,17 @@ void mg_mgr_init_opt(struct mg_mgr *mgr, void *user_data,
* *
* Closes and deallocates all active connections. * Closes and deallocates all active connections.
*/ */
void mg_mgr_free(struct mg_mgr *); void mg_mgr_free(struct mg_mgr *mgr);
/* /*
* This function performs the actual IO and must be called in a loop * This function performs the actual IO and must be called in a loop
* (an event loop). It returns the current timestamp. * (an event loop). It returns number of user events generated (except POLLs).
* `milli` is the maximum number of milliseconds to sleep. * `milli` is the maximum number of milliseconds to sleep.
* `mg_mgr_poll()` checks all connections for IO readiness. If at least one * `mg_mgr_poll()` checks all connections for IO readiness. If at least one
* of the connections is IO-ready, `mg_mgr_poll()` triggers the respective * of the connections is IO-ready, `mg_mgr_poll()` triggers the respective
* event handlers and returns. * event handlers and returns.
*/ */
time_t mg_mgr_poll(struct mg_mgr *, int milli); int mg_mgr_poll(struct mg_mgr *mgr, int milli);
#if MG_ENABLE_BROADCAST #if MG_ENABLE_BROADCAST
/* /*
@@ -224,7 +226,7 @@ time_t mg_mgr_poll(struct mg_mgr *, int milli);
* `func` callback function will be called by the IO thread for each * `func` callback function will be called by the IO thread for each
* connection. When called, the event will be `MG_EV_POLL`, and a message will * connection. When called, the event will be `MG_EV_POLL`, and a message will
* be passed as the `ev_data` pointer. Maximum message size is capped * be passed as the `ev_data` pointer. Maximum message size is capped
* by `MG_CTL_MSG_MESSAGE_SIZE` which is set to 8192 bytes. * by `MG_CTL_MSG_MESSAGE_SIZE` which is set to 8192 bytes by default.
*/ */
void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data, void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data,
size_t len); size_t len);
+12
View File
@@ -39,3 +39,15 @@ struct mg_iface *mg_find_iface(struct mg_mgr *mgr,
} }
return NULL; return NULL;
} }
double mg_mgr_min_timer(const struct mg_mgr *mgr) {
double min_timer = 0;
struct mg_connection *nc;
for (nc = mgr->active_connections; nc != NULL; nc = nc->next) {
if (nc->ev_timer_time <= 0) continue;
if (min_timer == 0 || nc->ev_timer_time < min_timer) {
min_timer = nc->ev_timer_time;
}
}
return min_timer;
}
+6
View File
@@ -118,6 +118,12 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
/* Deliver a POLL event to the connection. */ /* Deliver a POLL event to the connection. */
int mg_if_poll(struct mg_connection *nc, double now); int mg_if_poll(struct mg_connection *nc, double now);
/*
* Return minimal timer value amoung connections in the manager.
* Returns 0 if there aren't any timers.
*/
double mg_mgr_min_timer(const struct mg_mgr *mgr);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
+141
View File
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2018 Cesanta Software Limited
* All rights reserved
*
* This software is dual-licensed: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. For the terms of this
* license, see <http://www.gnu.org/licenses/>.
*
* You are free to use this software under the terms of the GNU General
* Public License, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* Alternatively, you can license this software under a commercial
* license, as set out in <https://www.cesanta.com/license>.
*/
static void mg_null_if_connect_tcp(struct mg_connection *c,
const union socket_address *sa) {
c->flags |= MG_F_CLOSE_IMMEDIATELY;
(void) sa;
}
static void mg_null_if_connect_udp(struct mg_connection *c) {
c->flags |= MG_F_CLOSE_IMMEDIATELY;
}
static int mg_null_if_listen_tcp(struct mg_connection *c,
union socket_address *sa) {
(void) c;
(void) sa;
return -1;
}
static int mg_null_if_listen_udp(struct mg_connection *c,
union socket_address *sa) {
(void) c;
(void) sa;
return -1;
}
static int mg_null_if_tcp_send(struct mg_connection *c, const void *buf,
size_t len) {
(void) c;
(void) buf;
(void) len;
return -1;
}
static int mg_null_if_udp_send(struct mg_connection *c, const void *buf,
size_t len) {
(void) c;
(void) buf;
(void) len;
return -1;
}
int mg_null_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
(void) c;
(void) buf;
(void) len;
return -1;
}
int mg_null_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
union socket_address *sa, size_t *sa_len) {
(void) c;
(void) buf;
(void) len;
(void) sa;
(void) sa_len;
return -1;
}
static int mg_null_if_create_conn(struct mg_connection *c) {
(void) c;
return 1;
}
static void mg_null_if_destroy_conn(struct mg_connection *c) {
(void) c;
}
static void mg_null_if_sock_set(struct mg_connection *c, sock_t sock) {
(void) c;
(void) sock;
}
static void mg_null_if_init(struct mg_iface *iface) {
(void) iface;
}
static void mg_null_if_free(struct mg_iface *iface) {
(void) iface;
}
static void mg_null_if_add_conn(struct mg_connection *c) {
c->sock = INVALID_SOCKET;
c->flags |= MG_F_CLOSE_IMMEDIATELY;
}
static void mg_null_if_remove_conn(struct mg_connection *c) {
(void) c;
}
static time_t mg_null_if_poll(struct mg_iface *iface, int timeout_ms) {
struct mg_mgr *mgr = iface->mgr;
struct mg_connection *nc, *tmp;
double now = mg_time();
/* We basically just run timers and poll. */
for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
tmp = nc->next;
mg_if_poll(nc, now);
}
(void) timeout_ms;
return (time_t) now;
}
static void mg_null_if_get_conn_addr(struct mg_connection *c, int remote,
union socket_address *sa) {
(void) c;
(void) remote;
(void) sa;
}
#define MG_NULL_IFACE_VTABLE \
{ \
mg_null_if_init, mg_null_if_free, mg_null_if_add_conn, \
mg_null_if_remove_conn, mg_null_if_poll, mg_null_if_listen_tcp, \
mg_null_if_listen_udp, mg_null_if_connect_tcp, mg_null_if_connect_udp, \
mg_null_if_tcp_send, mg_null_if_udp_send, mg_null_if_tcp_recv, \
mg_null_if_udp_recv, mg_null_if_create_conn, mg_null_if_destroy_conn, \
mg_null_if_sock_set, mg_null_if_get_conn_addr, \
}
const struct mg_iface_vtable mg_null_iface_vtable = MG_NULL_IFACE_VTABLE;
#if MG_NET_IF == MG_NET_IF_NULL
const struct mg_iface_vtable mg_default_iface_vtable = MG_NULL_IFACE_VTABLE;
#endif /* MG_NET_IF == MG_NET_IF_NULL */
+3 -1
View File
@@ -152,7 +152,9 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
void *user_data = nc->user_data; void *user_data = nc->user_data;
#endif #endif
if (ev != MG_EV_POLL) DBG(("ev=%d user_data=%p", ev, user_data)); if (ev != MG_EV_POLL) {
DBG(("ev=%d user_data=%p", ev, user_data));
}
req = (struct mg_resolve_async_request *) user_data; req = (struct mg_resolve_async_request *) user_data;
+7 -7
View File
@@ -32,6 +32,8 @@ static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line,
} }
/* mbedTLS passes strings with \n at the end, strip it. */ /* mbedTLS passes strings with \n at the end, strip it. */
LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str)); LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str));
(void) ctx;
(void) str;
(void) file; (void) file;
(void) line; (void) line;
(void) cs_level; (void) cs_level;
@@ -221,9 +223,9 @@ static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) {
if (ctx->ca_cert != NULL) { if (ctx->ca_cert != NULL) {
mbedtls_ssl_conf_ca_chain(ctx->conf, NULL, NULL); mbedtls_ssl_conf_ca_chain(ctx->conf, NULL, NULL);
#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK #ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
if (ctx->ca_cert->ca_chain_file != NULL) { if (ctx->conf->ca_chain_file != NULL) {
MG_FREE((void *) ctx->ca_cert->ca_chain_file); MG_FREE((void *) ctx->conf->ca_chain_file);
ctx->ca_cert->ca_chain_file = NULL; ctx->conf->ca_chain_file = NULL;
} }
#endif #endif
mbedtls_x509_crt_free(ctx->ca_cert); mbedtls_x509_crt_free(ctx->ca_cert);
@@ -330,15 +332,13 @@ static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
mbedtls_x509_crt_init(ctx->ca_cert); mbedtls_x509_crt_init(ctx->ca_cert);
#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK #ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
ca_cert = strdup(ca_cert); ca_cert = strdup(ca_cert);
if (mbedtls_x509_crt_set_ca_chain_file(ctx->ca_cert, ca_cert) != 0) { mbedtls_ssl_conf_ca_chain_file(ctx->conf, ca_cert, NULL);
return MG_SSL_ERROR;
}
#else #else
if (mbedtls_x509_crt_parse_file(ctx->ca_cert, ca_cert) != 0) { if (mbedtls_x509_crt_parse_file(ctx->ca_cert, ca_cert) != 0) {
return MG_SSL_ERROR; return MG_SSL_ERROR;
} }
#endif
mbedtls_ssl_conf_ca_chain(ctx->conf, ctx->ca_cert, NULL); mbedtls_ssl_conf_ca_chain(ctx->conf, ctx->ca_cert, NULL);
#endif
mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED); mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
return MG_SSL_OK; return MG_SSL_OK;
} }
+3 -3
View File
@@ -9,7 +9,9 @@ SRC_DIR = ../src
COMMON_DIR_PUB = ../src/common COMMON_DIR_PUB = ../src/common
COMMON_DIR_DEV = ../../common COMMON_DIR_DEV = ../../common
ifneq ("$(wildcard ../../fw/defs)","") # Our dev repo and public mongoose repo have different layouts, so here
# we make it work on both
ifneq ("$(wildcard ../../fw)","")
COMMON_PARENT = ../.. COMMON_PARENT = ../..
else else
COMMON_PARENT = $(SRC_DIR) COMMON_PARENT = $(SRC_DIR)
@@ -19,8 +21,6 @@ TEST_SOURCES = unit_test.c test_util.c test_main.c
AMALGAMATED_SOURCES = ../mongoose.c AMALGAMATED_SOURCES = ../mongoose.c
KRYPTON_PATH = $(REPO_ROOT)/krypton KRYPTON_PATH = $(REPO_ROOT)/krypton
# Our dev repo and public mongoose repo have different layouts, so here
# we make it work on both
VPATH = $(MONGOOSE_DIR) $(SRC_DIR) $(COMMON_DIR_PUB) $(COMMON_DIR_DEV) $(COMMON_PARENT) VPATH = $(MONGOOSE_DIR) $(SRC_DIR) $(COMMON_DIR_PUB) $(COMMON_DIR_DEV) $(COMMON_PARENT)
# or Krypton, or mbedTLS # or Krypton, or mbedTLS
+86 -44
View File
@@ -15,12 +15,12 @@
* license, as set out in <https://www.cesanta.com/license>. * license, as set out in <https://www.cesanta.com/license>.
*/ */
#include "mongoose.h"
#include "src/mg_internal.h"
#include "unit_test.h" #include "unit_test.h"
#include "common/cs_md5.h"
#include "common/test_main.h" #include "common/test_main.h"
#include "common/test_util.h" #include "common/test_util.h"
#include "common/cs_md5.h" #include "mongoose.h"
#include "src/mg_internal.h"
#if defined(__STDC_VERSION__) && __STDC_VERSION__ < 199901L && !defined(WIN32) #if defined(__STDC_VERSION__) && __STDC_VERSION__ < 199901L && !defined(WIN32)
#define __func__ "" #define __func__ ""
@@ -2011,7 +2011,8 @@ static const char *test_http(void) {
char buf[50] = "", status[100] = "", mime1[20] = "", mime2[100] = ""; char buf[50] = "", status[100] = "", mime1[20] = "", mime2[100] = "";
char opt_buf[1024] = ""; char opt_buf[1024] = "";
const char *opt_answer = const char *opt_answer =
"HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, OPTIONS, MKCOL, " "HTTP/1.1 200 OK\r\nServer: Mongoose/" MG_VERSION
"\r\nAllow: GET, POST, HEAD, CONNECT, OPTIONS, MKCOL, "
"PUT, DELETE, PROPFIND, MOVE"; "PUT, DELETE, PROPFIND, MOVE";
char url[1000]; char url[1000];
@@ -2069,7 +2070,7 @@ static const char *test_http(void) {
nc->user_data = mime2; nc->user_data = mime2;
/* Run event loop. Use more cycles to let file download complete. */ /* Run event loop. Use more cycles to let file download complete. */
poll_until(&mgr, 5, c_str_ne, status, (void *) ""); poll_until(&mgr, 15, c_str_ne, status, (void *) "");
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
/* Check that test buffer has been filled by the callback properly. */ /* Check that test buffer has been filled by the callback properly. */
@@ -2539,32 +2540,6 @@ static const char *test_http_range(void) {
return NULL; return NULL;
} }
static void cb3(struct mg_connection *nc, int ev, void *ev_data) {
struct websocket_message *wm = (struct websocket_message *) ev_data;
if (ev == MG_EV_WEBSOCKET_FRAME) {
const char *reply = wm->size == 2 && !memcmp(wm->data, "hi", 2) ? "A" : "B";
mg_printf_websocket_frame(nc, WEBSOCKET_OP_TEXT, "%s", reply);
}
}
static void cb4(struct mg_connection *nc, int ev, void *ev_data) {
struct websocket_message *wm = (struct websocket_message *) ev_data;
if (ev == MG_EV_WEBSOCKET_FRAME) {
memcpy(nc->user_data, wm->data, wm->size);
mg_send_websocket_frame(nc, WEBSOCKET_OP_CLOSE, NULL, 0);
} else if (ev == MG_EV_WEBSOCKET_HANDSHAKE_DONE) {
/* Send "hi" to server. server must reply "A". */
struct mg_str h[2];
h[0].p = "h";
h[0].len = 1;
h[1].p = "i";
h[1].len = 1;
mg_send_websocket_framev(nc, WEBSOCKET_OP_TEXT, h, 2);
}
}
static void cb_ws_server(struct mg_connection *nc, int ev, void *ev_data) { static void cb_ws_server(struct mg_connection *nc, int ev, void *ev_data) {
struct websocket_message *wm = (struct websocket_message *) ev_data; struct websocket_message *wm = (struct websocket_message *) ev_data;
@@ -2779,6 +2754,38 @@ static const char *test_websocket(void) {
return NULL; return NULL;
} }
static void cb3(struct mg_connection *nc, int ev, void *ev_data) {
struct websocket_message *wm = (struct websocket_message *) ev_data;
if (ev != MG_EV_WEBSOCKET_FRAME) return;
DBG(("server data '%.*s'", (int) wm->size, wm->data));
const char *reply = wm->size == 2 && !memcmp(wm->data, "hi", 2) ? "A" : "B";
mg_printf_websocket_frame(nc, WEBSOCKET_OP_TEXT, "%s", reply);
}
static void cb4(struct mg_connection *nc, int ev, void *ev_data) {
char *buf = (char *) nc->user_data;
if (ev == MG_EV_WEBSOCKET_FRAME) {
struct websocket_message *wm = (struct websocket_message *) ev_data;
DBG(("client data '%.*s'", (int) wm->size, wm->data));
memcpy(buf, wm->data, wm->size);
mg_send_websocket_frame(nc, WEBSOCKET_OP_CLOSE, NULL, 0);
} else if (ev == MG_EV_WEBSOCKET_HANDSHAKE_DONE) {
struct http_message *hm = (struct http_message *) ev_data;
DBG(("code %d", hm->resp_code));
if (hm->resp_code == 101) {
/* Send "hi" to server. server must reply "A". */
struct mg_str h[2];
h[0].p = "h";
h[0].len = 1;
h[1].p = "i";
h[1].len = 1;
mg_send_websocket_framev(nc, WEBSOCKET_OP_TEXT, h, 2);
} else {
snprintf(buf, 20, "code %d", hm->resp_code);
}
}
}
static void cbwep(struct mg_connection *c, int ev, void *ev_data) { static void cbwep(struct mg_connection *c, int ev, void *ev_data) {
struct websocket_message *wm = (struct websocket_message *) ev_data; struct websocket_message *wm = (struct websocket_message *) ev_data;
char *buf = (char *) c->user_data; char *buf = (char *) c->user_data;
@@ -2786,6 +2793,9 @@ static void cbwep(struct mg_connection *c, int ev, void *ev_data) {
switch (ev) { switch (ev) {
case MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: case MG_EV_WEBSOCKET_HANDSHAKE_REQUEST:
strcat(buf, "R"); strcat(buf, "R");
if (buf[0] != '0') {
mg_http_send_error(c, 403, "I don't like you");
}
break; break;
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
strcat(buf, "D"); strcat(buf, "D");
@@ -2802,7 +2812,7 @@ static const char *test_websocket_endpoint(void) {
struct mg_mgr mgr; struct mg_mgr mgr;
struct mg_connection *nc; struct mg_connection *nc;
const char *local_addr = "127.0.0.1:7798"; const char *local_addr = "127.0.0.1:7798";
char buf[20] = "", buf2[20] = ""; char buf[20] = "", buf2[20] = "0";
mg_mgr_init(&mgr, NULL); mg_mgr_init(&mgr, NULL);
/* mgr.hexdump_file = "-"; */ /* mgr.hexdump_file = "-"; */
@@ -2817,10 +2827,21 @@ static const char *test_websocket_endpoint(void) {
nc->user_data = buf; nc->user_data = buf;
mg_send_websocket_handshake(nc, "/boo", NULL); mg_send_websocket_handshake(nc, "/boo", NULL);
poll_until(&mgr, 1, c_str_ne, buf, (void *) ""); poll_until(&mgr, 1, c_str_ne, buf, (void *) "");
mg_mgr_free(&mgr);
/* Check that test buffer has been filled by the callback properly. */ /* Check that test buffer has been filled by the callback properly. */
ASSERT_STREQ(buf, "RDF|hi"); ASSERT_STREQ(buf, "0RDF|hi");
/* Test handshake failure */
ASSERT((nc = mg_connect(&mgr, local_addr, cb4)) != NULL);
mg_set_protocol_http_websocket(nc);
buf[0] = '\0';
buf2[0] = '1';
buf2[1] = '\0';
nc->user_data = buf;
mg_send_websocket_handshake(nc, "/boo", NULL);
poll_until(&mgr, 1, c_str_ne, buf, (void *) "");
ASSERT_STREQ(buf, "code 403");
mg_mgr_free(&mgr);
return NULL; return NULL;
} }
@@ -3379,15 +3400,36 @@ static const char *test_mqtt_parse_mqtt_qos1(void) {
} }
static const char *test_mqtt_match_topic_expression(void) { static const char *test_mqtt_match_topic_expression(void) {
ASSERT_EQ(mg_mqtt_vmatch_topic_expression("foo", mg_mk_str("foo")), 1); ASSERT(mg_mqtt_vmatch_topic_expression("foo", mg_mk_str("foo")));
ASSERT_EQ(mg_mqtt_vmatch_topic_expression("foo", mg_mk_str("foo/")), 0); ASSERT(mg_mqtt_vmatch_topic_expression("/foo", mg_mk_str("/foo")));
ASSERT_EQ(mg_mqtt_vmatch_topic_expression("foo", mg_mk_str("foo/bar")), 0); ASSERT(mg_mqtt_vmatch_topic_expression("+/foo", mg_mk_str("/foo")));
ASSERT(!mg_mqtt_vmatch_topic_expression("foo", mg_mk_str("foobar")));
ASSERT(mg_mqtt_vmatch_topic_expression("foo", mg_mk_str("foo/")));
ASSERT(mg_mqtt_vmatch_topic_expression("foo", mg_mk_str("foo//")));
ASSERT(!mg_mqtt_vmatch_topic_expression("foo", mg_mk_str("foo/bar")));
ASSERT(!mg_mqtt_vmatch_topic_expression("foo", mg_mk_str("foo/+")));
ASSERT(mg_mqtt_vmatch_topic_expression("foo/bar", mg_mk_str("foo/bar")));
ASSERT(mg_mqtt_vmatch_topic_expression("foo/+", mg_mk_str("foo/bar")));
ASSERT(mg_mqtt_vmatch_topic_expression("+/bar", mg_mk_str("foo/bar")));
ASSERT(mg_mqtt_vmatch_topic_expression("+/+", mg_mk_str("foo/bar")));
ASSERT(mg_mqtt_vmatch_topic_expression("foo/+/bar", mg_mk_str("foo//bar")));
ASSERT(!mg_mqtt_vmatch_topic_expression("foo/+/+", mg_mk_str("foo/bar")));
ASSERT(mg_mqtt_vmatch_topic_expression("foo/+/#", mg_mk_str("foo/bar")));
ASSERT(mg_mqtt_vmatch_topic_expression("+/foo/bar", mg_mk_str("/foo/bar")));
ASSERT_EQ(mg_mqtt_vmatch_topic_expression("foo/#", mg_mk_str("foo")), 0); ASSERT(!mg_mqtt_vmatch_topic_expression("", mg_mk_str("")));
ASSERT_EQ(mg_mqtt_vmatch_topic_expression("foo/#", mg_mk_str("foo/")), 0); ASSERT(mg_mqtt_vmatch_topic_expression("/", mg_mk_str("")));
ASSERT_EQ(mg_mqtt_vmatch_topic_expression("foo/#", mg_mk_str("foo/bar")), 1); ASSERT(mg_mqtt_vmatch_topic_expression("/", mg_mk_str("/")));
ASSERT_EQ(mg_mqtt_vmatch_topic_expression("foo/#", mg_mk_str("foo/bar/baz")),
1); ASSERT(mg_mqtt_vmatch_topic_expression("#", mg_mk_str("")));
ASSERT(mg_mqtt_vmatch_topic_expression("#", mg_mk_str("foo")));
ASSERT(mg_mqtt_vmatch_topic_expression("#", mg_mk_str("foo/bar")));
ASSERT(mg_mqtt_vmatch_topic_expression("foo/#", mg_mk_str("foo")));
ASSERT(mg_mqtt_vmatch_topic_expression("foo/#", mg_mk_str("foo/")));
ASSERT(mg_mqtt_vmatch_topic_expression("foo/#", mg_mk_str("foo/bar")));
ASSERT(mg_mqtt_vmatch_topic_expression("foo/#", mg_mk_str("foo/bar/baz")));
ASSERT(!mg_mqtt_vmatch_topic_expression("#/foo", mg_mk_str("foo")));
ASSERT(!mg_mqtt_vmatch_topic_expression("#/foo", mg_mk_str("bar/foo")));
return NULL; return NULL;
} }
@@ -5665,7 +5707,7 @@ static const char *test_socks(void) {
mbuf_resize(&c->recv_mbuf, 10000000); mbuf_resize(&c->recv_mbuf, 10000000);
/* Run event loop. Use more cycles to let file download complete. */ /* Run event loop. Use more cycles to let file download complete. */
poll_until(&mgr, 10, c_str_ne, status, (void *) ""); poll_until(&mgr, 15, c_str_ne, status, (void *) "");
ASSERT_STREQ(status, "success"); ASSERT_STREQ(status, "success");
mg_mgr_free(&mgr); mg_mgr_free(&mgr);