Compare commits

...
44 Commits
Author SHA1 Message Date
Deomid Ryabkov 777b8e94e2 Merge branch 'dev' (Mongoose 6.12) 2018-08-13 19:30:06 +03:00
Sergey Lyubka 6df642623a Delete CONTRIBUTING.md 2018-08-13 19:28:18 +03:00
Deomid Ryabkov 0a3e186f11 Mongoose 6.12
CL: Mongoose 6.12

PUBLISHED_FROM=8008e4db2f6d94d972fb6e1077525e262c8744aa
2018-08-13 14:41:42 +00:00
Deomid Ryabkov c2d83a9db0 Don't touch send_mbuf when sending MQTT messages
h/t @M4GNV5

Fixes https://github.com/cesanta/mongoose/issues/943
Closes https://github.com/cesanta/mongoose/issues/944

CL: mg: Don't touch send_mbuf when sending MQTT messages

PUBLISHED_FROM=da7b4f8acec2e403caa4addd5739d036a6a74c76
2018-08-13 14:04:49 +00:00
Deomid Ryabkov f33d3a4e02 Fix body length calculation in mg_handle_cgi
Fixes https://nvd.nist.gov/vuln/detail/CVE-2018-10945

CL: mg: Fix body length calculation in mg_handle_cgi

PUBLISHED_FROM=0c30cf36fdb67c75f6148468701e23d6ee72d953
2018-08-13 13:05:22 +00:00
Deomid Ryabkov 86b8a56b05 Add host name verification for OpenSSL
Closes https://github.com/cesanta/mongoose/pull/955

CL: mg: Add host name verification for OpenSSL

PUBLISHED_FROM=e35dd636ba7ce63116f0a38031074d22f6cd5dac
2018-08-13 13:05:21 +00:00
Бобби ac6ec15aed Make esp8266 compilation a little less verbose
CL: Make esp8266 compilation a little less verbose

PUBLISHED_FROM=0ec1412ea32243f263d52fbe0877ecca1efc5aef
2018-07-23 15:26:47 +00:00
Deomid Ryabkov 31632c6361 Fix build with CS_ENABLE_STDIO=0
Closes https://github.com/cesanta/mongoose/pull/945

CL: Fix build with CS_ENABLE_STDIO=0

PUBLISHED_FROM=7d15f17fc42241facdba5b1004b5b7f3dda599dc
2018-07-12 20:42:45 +00:00
Deomid Ryabkov 98c99279c3 Fix warnings on newer versions of GCC
PUBLISHED_FROM=f1d25145446057fed9e8d634ca637364ca43a5e8
2018-07-09 08:34:29 +00:00
Deomid Ryabkov cdb8d7b692 Add mg_strstrip: trims whitespace at the ends of s
CL: Add mg_strstrip: trims whitespace at the ends of s

PUBLISHED_FROM=a7e10054ac25fa2b3a878876da93a6b30d9507b3
2018-07-07 14:04:42 +00:00
Deomid Ryabkov 93ac3e19f0 Stringify multi-word macros correctly
Use vararg macros for this.

PUBLISHED_FROM=735c40b79dedef17a1fdbb5b846e984df0ae7018
2018-07-03 15:05:23 +00:00
Deomid Ryabkov 6a51af9efe Fix a bug in mg_mgr_init_opt with opts.num_ifaces
h/t @YankunLi

Closes https://github.com/cesanta/mongoose/pull/939

CL: mg: Fix a bug in mg_mgr_init_opt with opts.num_ifaces

PUBLISHED_FROM=a87518b3505429a3cf9cd6d84b3b781e7dbdcfd5
2018-06-27 08:50:07 +00:00
Deomid Ryabkov 9d73b3470b Add LFS (littleFS) library
CL: mos support for LFS (littlefs) https://github.com/ARMmbed/littlefs

PUBLISHED_FROM=e72957b4fb2c78949af4cf6d5bfef135ddba9fd9
2018-06-26 16:49:42 +00:00
Deomid Ryabkov 1c8449cea6 Fix pipelining issue with multipart upload
Do not clear buffer at the end of multipart request to allow following request to proceed.

Closes https://github.com/cesanta/mongoose/pull/940

CL: mg: Fix pipelining issue with multipart upload

PUBLISHED_FROM=cc7d38b126eaa863553ee4e124cfafcd72030fcf
2018-06-26 12:05:04 +00:00
Deomid Ryabkov 3bbbd41196 Add missing CC3220 sub-header to mongoose.h
CL: Add missing CC3220 sub-header to mongoose.h

PUBLISHED_FROM=a143485b629109c6e16c66b035f02f7552f76129
2018-06-21 16:34:56 +00:00
Deomid Ryabkov 339bbee0df mg_file_upload_handler: Support multiple files
curl -F file1 -F file2 ...

Add a unit test and fix a minor memory leak when returning an error.

CL: mg_file_upload_handler: Support multiple files

PUBLISHED_FROM=5c4bf2be676346fb782e80f50f79df6a6721ac88
2018-06-20 13:35:31 +00:00
Deomid Ryabkov 9ba6eb716d mg_lwip: Fix race during clean conenction teardown
Set CLOSE_IMMEDIATELY flag when destroying conn.
This avoid some races in LWIP adapter.

CL: mg_lwip: Fix race during clean conenction teardown

PUBLISHED_FROM=5c67982390dfaf83527e85d1291f64c6050aa932
2018-06-18 16:35:04 +00:00
Deomid Ryabkov d949c19c7e mgos_nsleep100 impl for ARM-based platforms
startup cleanup on CC3220

CL: none

PUBLISHED_FROM=0998fad82fbcdbde30dca42833f2e48d148592bf
2018-06-06 08:04:33 +00:00
Deomid Ryabkov 1299d6118f Add MG_HIDE_SERVER_INFO
Closes https://github.com/cesanta/mos-libs/pull/2

CL: Add MG_HIDE_SERVER_INFO

PUBLISHED_FROM=ed8a5b65f1c8238df414cd1c1f8bb1f579082f55
2018-05-17 16:20:44 +00:00
Deomid Ryabkov 244ff92e78 Minor build optimization
PUBLISHED_FROM=9997c64ed0c713b5b8b29df7a49b532e880eac53
2018-05-10 19:05:40 +00:00
Deomid Ryabkov 53f34dea04 Fix TZ on ESP8266
CL: Fix TZ on ESP8266

PUBLISHED_FROM=435a501a8b52524bccb67bb5a8ae7e09dfb4d44a
2018-04-26 15:26:39 +00:00
Sergey Lyubka 1f5c3fac31 Delete CONTRIBUTING.md 2018-04-17 15:08:35 +01:00
Sergey Lyubka 7014258c8d Remove copyright notices - that explained in the CLA.
CL: none

PUBLISHED_FROM=9cb4b915906d471ef5de4e0825567d0b942d3f7b
2018-04-17 11:45:31 +00:00
Deomid Ryabkov 1614e7ba8d Restore FFI-ability of struct mg_str
mgos_dlsym needs to include mg_str for ffi_exports to be able to use it

PUBLISHED_FROM=a2dd167c8e8f9e9b7316a856f19a4603080c3632
2018-04-13 17:12:07 +00:00
Deomid Ryabkov 43b5a4e735 Add a special attribute to printf-like funcs
Enables extra compile-time checks

CL: none

PUBLISHED_FROM=9f7d658fbda5c721cf40293bf29967bb056d0437
2018-04-13 17:12:06 +00:00
Deomid Ryabkov 43191db63e Fix boot loader UART baud rate on soft reboot
Also remove `-O3` optimization flasg, it negates `-Os`. Saves ~400 bytes.

CL: none

PUBLISHED_FROM=f40f42e4f54a8e0e003ab65ec8f5838c2d932876
2018-04-11 18:35:15 +00:00
Deomid Ryabkov e89be2e944 Add mg_url_encode_opt()
CL: Add `mg_url_encode_opt()` - a parametrized version of `mg_url_encode()`

PUBLISHED_FROM=17fa57a7a5325b51b6e3aef3855eac4e82c35782
2018-04-10 11:04:31 +00:00
Deomid Ryabkov c2fbff6d0e Fix mg_http_parse_header
Per standard, cookies are delimited by `; `.

CL: Fix mg_http_parse_header: treat ";" as a delimiter.

PUBLISHED_FROM=039243c30f5fabf4a4700a43506f841b3268306a
2018-04-10 10:19:36 +00:00
Deomid Ryabkov b8eca17c55 Reamalgam mongoose.{c,h}
PUBLISHED_FROM=8828792097bd19774472b8a2e61420565684d174
2018-04-03 16:08:21 +00:00
Sergey Lyubka 4650e491df Apache license to common/
CL: Apache license to common/

PUBLISHED_FROM=901e9e4b12a31289b3515d1f86dd56a7f0f35c5e
2018-04-03 11:49:59 +00:00
Deomid Ryabkov 3e33e57707 Mongoose net_if and ssl_if refactoring
A major cleanup, disentangling net_if and ssl_if.
Pulled a lot of common logic into the core and reduced size of net_if implementations.

CL: Mongoose net_if and ssl_if refactoring

PUBLISHED_FROM=29bd4dcb264a1fd96b3dd164e2d880e1c2c0921e
2018-03-30 23:19:49 +00:00
Deomid Ryabkov c80f4c5313 Fix an edge case in multipart HTTP upload parsing
Consume buffer as soon as we know there is no boundary there, no need to delay until next chunk arrives.
This prevents stall where buffer fills up in one go and next chunk never arrives.

CL: Fix an edge case in multipart HTTP upload parsing

PUBLISHED_FROM=025f9001d272df2a75ece22b199b1944d5db9840
2018-03-30 19:35:20 +00:00
Deomid Ryabkov 132ecbec2f Fix Mongoose and Frozen include paths
In preparation for making moving to lib.
Reduce amount of makefile copypasta a bit.

CL: none

PUBLISHED_FROM=70a016491f9605e37708385bdd698f48a8d64119
2018-03-28 14:12:23 +00:00
Deomid Ryabkov 0a90cab44a Improve mbuf allocation behavior
* Limit total amount of headroom, in absolute terms (`MBUF_SIZE_MAX_HEADROOM`).
 * If unable to allocate with headroom, fall back to allocating the required minimum.
 * For mOS, set default `MBUF_SIZE_MULTIPLIER` to 2 to avoid floating point operations.
   Since max headroom size is now capped to 128 bytes, this will not result in much of a bloat.

PUBLISHED_FROM=11d4fc65a46a805bb7c8960f89a3d0b753c58bb8
2018-03-22 07:49:57 +00:00
Serge A. Zaitsev d16dbc197f mongoose: fix http pipeline
mongoose: fix formatting

mongoose: fix formatting

mongoose: remove debugging messages

PUBLISHED_FROM=1194e018001cc5f2b598096593d7aac4ec8dc04d
2018-03-20 16:41:56 +00:00
Serge A. Zaitsev 127f27e375 mongoose: unit test for http get pipeline
PUBLISHED_FROM=00e8634913232eb2e50a0d739f85e81706dbc400
2018-03-17 16:35:04 +00:00
novlean 6523cc4da0 2018
PUBLISHED_FROM=63ce52177f5f13cb76f0fcb4689efb65a04318a2
2018-03-12 21:20:20 +00:00
novlean 2516da1c89 updated to 2018 2018-03-12 16:49:45 +00:00
Serge A. Zaitsev 0ae2b82b60 freshen: early attempts to make ota and config work
freshen: implement ota rollback

freshen: api for rpc

freshen: implement rpc api (without transport)

PUBLISHED_FROM=9f935f676161c81464a0dc53d5d8d085b2437ffb
2018-02-27 14:19:33 +00:00
Sergey Lyubka dab526936f Add missing test files to mongoose repo
PUBLISHED_FROM=9a81cc34aa0039a75c851bc3685055f46936252e
2018-02-23 11:19:42 +00:00
Бобби 780077d118 Fix mg_socketpair for lwip + UDP
CL: Fix mg_socketpair for lwip + UDP

PUBLISHED_FROM=6dd09136b3837016026523fb34acb5cc893cadbe
2018-02-18 16:49:38 +00:00
Deomid Ryabkov ad8f1d88d4 Fix buffer size passed to inet_ntop()
Fixes https://github.com/cesanta/mongoose-os/issues/394

CL: Fix buffer size passed to inet_ntop()

PUBLISHED_FROM=4a6702527627ccbb780f45200274b09a28be69ee
2018-02-13 12:49:53 +00:00
Deomid Ryabkov a3c4a48ef7 Make sure test assertions are evaluated once
E.g. if `ASSERT_EQ(myfunc(), 123)` fails, `myfunc()` would be invoked again to print the actual value.
This can cause confusion sometimes.
To avoid this, we cast arguments to double, which is wide enough for most cases and we provide a variant for 64 bit value types for when it's not.
We also perform a check and fail if argument to the check results in loss of precision.

CL: none

PUBLISHED_FROM=a14551289d92e8a5dead21d16471ebddebe938a8
2018-02-10 12:19:40 +00:00
Deomid Ryabkov 84a11fe3b1 Count both tests and individual checks
CL: none

PUBLISHED_FROM=ab7f50e1c68154832e862ebfb4a02d385ef7c6be
2018-02-08 19:20:00 +00:00
92 changed files with 4027 additions and 2563 deletions

No files matched your search

-8
View File
@@ -1,8 +0,0 @@
People who have agreed to the
[Cesanta CLA](https://docs.cesanta.com/contributors_la.shtml)
can make contributions. Note that the CLA isn't a copyright
_assigment_ but rather a copyright _license_.
You retain the copyright on your contributions.
We follow the Google C/C++ style guide: https://google.github.io/styleguide/cppguide.html
We'd appreciate if your contribution follows the same style guide.
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com> Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
Copyright (c) 2013-2016 Cesanta Software Limited Copyright (c) 2013-2018 Cesanta Software Limited
All rights reserved All rights reserved
This software is dual-licensed: you can redistribute it and/or modify This software is dual-licensed: you can redistribute it and/or modify
+1 -1
View File
@@ -62,7 +62,7 @@ the functionality:
# Contributions # Contributions
To submit contributions, sign [Cesanta CLA](https://cesanta.com/cla.html) To submit contributions, sign [Cesanta CLA](https://cesanta.com/cla.html)
and send GitHub pull request. You retain the copyright on your contributions. and send GitHub pull request.
# Looking for a pre-compiled Mongoose web server Windows or Mac binary? # Looking for a pre-compiled Mongoose web server Windows or Mac binary?
- [Download pre-compiled Mongoose web server binary.](https://www.cesanta.com/binary.html) - [Download pre-compiled Mongoose web server binary.](https://www.cesanta.com/binary.html)
+1 -4
View File
@@ -6,8 +6,5 @@ signature: |
struct mg_str mg_url_encode(const struct mg_str src); struct mg_str mg_url_encode(const struct mg_str src);
--- ---
URL-escape the specified string. Same as `mg_url_encode_opt(src, "._-$,;~()/", 0)`.
All non-printable characters are escaped, plus `._-$,;~()/`.
Input need not be NUL-terminated, but the returned string is.
Returned string is heap-allocated and must be free()'d.
+1267 -1180
View File
File diff suppressed because it is too large. Load diff
+469 -50
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.11" #define MG_VERSION "6.12"
/* 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
@@ -128,8 +128,18 @@
/* Common stuff */ /* Common stuff */
#if !defined(PRINTF_LIKE)
#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__)
#define PRINTF_LIKE(f, a) __attribute__((format(printf, f, a)))
#else
#define PRINTF_LIKE(f, a)
#endif
#endif
#if !defined(WEAK) #if !defined(WEAK)
#if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32) #if (defined(__GNUC__) || defined(__clang__) || \
defined(__TI_COMPILER_VERSION__)) && \
!defined(_WIN32)
#define WEAK __attribute__((weak)) #define WEAK __attribute__((weak))
#else #else
#define WEAK #define WEAK
@@ -493,8 +503,20 @@ typedef struct stat cs_stat_t;
#line 1 "common/platforms/platform_esp32.h" #line 1 "common/platforms/platform_esp32.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_ESP32_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_
@@ -538,8 +560,20 @@ typedef struct stat cs_stat_t;
#line 1 "common/platforms/platform_esp8266.h" #line 1 "common/platforms/platform_esp8266.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_ESP8266_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_
@@ -569,10 +603,6 @@ typedef struct stat cs_stat_t;
#define __cdecl #define __cdecl
#define _FILE_OFFSET_BITS 32 #define _FILE_OFFSET_BITS 32
#if !defined(RTOS_SDK) && !defined(__cplusplus)
#define fileno(x) -1
#endif
#define MG_LWIP 1 #define MG_LWIP 1
/* struct timeval is defined in sys/time.h. */ /* struct timeval is defined in sys/time.h. */
@@ -603,8 +633,20 @@ typedef struct stat cs_stat_t;
#line 1 "common/platforms/platform_cc3100.h" #line 1 "common/platforms/platform_cc3100.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_CC3100_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_
@@ -652,8 +694,20 @@ int inet_pton(int af, const char *src, void *dst);
#line 1 "common/platforms/platform_cc3200.h" #line 1 "common/platforms/platform_cc3200.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_CC3200_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_
@@ -774,11 +828,147 @@ int stat(const char *pathname, struct stat *st);
#endif /* CS_PLATFORM == CS_P_CC3200 */ #endif /* CS_PLATFORM == CS_P_CC3200 */
#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */ #endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */
#ifdef MG_MODULE_LINES #ifdef MG_MODULE_LINES
#line 1 "common/platforms/platform_cc3220.h"
#endif
/*
* Copyright (c) 2014-2018 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.
*/
#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_
#define CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_
#if CS_PLATFORM == CS_P_CC3220
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#ifndef __TI_COMPILER_VERSION__
#include <fcntl.h>
#include <sys/time.h>
#endif
#define MG_NET_IF MG_NET_IF_SIMPLELINK
#ifndef MG_SSL_IF
#define MG_SSL_IF MG_SSL_IF_SIMPLELINK
#endif
/* Only SPIFFS supports directories, SLFS does not. */
#if defined(CC3220_FS_SPIFFS) && !defined(MG_ENABLE_DIRECTORY_LISTING)
#define MG_ENABLE_DIRECTORY_LISTING 1
#endif
/* Amalgamated: #include "common/platforms/simplelink/cs_simplelink.h" */
typedef int sock_t;
#define INVALID_SOCKET (-1)
#define SIZE_T_FMT "u"
typedef struct stat cs_stat_t;
#define DIRSEP '/'
#define to64(x) strtoll(x, NULL, 10)
#define INT64_FMT PRId64
#define INT64_X_FMT PRIx64
#define __cdecl
#define fileno(x) -1
/* Some functions we implement for Mongoose. */
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __TI_COMPILER_VERSION__
struct SlTimeval_t;
#define timeval SlTimeval_t
int gettimeofday(struct timeval *t, void *tz);
int settimeofday(const struct timeval *tv, const void *tz);
int asprintf(char **strp, const char *fmt, ...);
#endif
/* TI's libc does not have stat & friends, add them. */
#ifdef __TI_COMPILER_VERSION__
#include <file.h>
typedef unsigned int mode_t;
typedef size_t _off_t;
typedef long ssize_t;
struct stat {
int st_ino;
mode_t st_mode;
int st_nlink;
time_t st_mtime;
off_t st_size;
};
int _stat(const char *pathname, struct stat *st);
int stat(const char *pathname, struct stat *st);
#define __S_IFMT 0170000
#define __S_IFDIR 0040000
#define __S_IFCHR 0020000
#define __S_IFREG 0100000
#define __S_ISTYPE(mode, mask) (((mode) &__S_IFMT) == (mask))
#define S_IFDIR __S_IFDIR
#define S_IFCHR __S_IFCHR
#define S_IFREG __S_IFREG
#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)
#endif /* __TI_COMPILER_VERSION__ */
#ifndef CS_ENABLE_STDIO
#define CS_ENABLE_STDIO 1
#endif
#ifdef __cplusplus
}
#endif
#endif /* CS_PLATFORM == CS_P_CC3220 */
#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */
#ifdef MG_MODULE_LINES
#line 1 "common/platforms/platform_msp432.h" #line 1 "common/platforms/platform_msp432.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_MSP432_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_MSP432_H_
@@ -885,8 +1075,20 @@ int _stat(const char *pathname, struct stat *st);
#line 1 "common/platforms/platform_tm4c129.h" #line 1 "common/platforms/platform_tm4c129.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_TM4C129_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_TM4C129_H_
@@ -945,8 +1147,20 @@ typedef struct stat cs_stat_t;
#line 1 "common/platforms/platform_mbed.h" #line 1 "common/platforms/platform_mbed.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_MBED_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_MBED_H_
@@ -1029,8 +1243,20 @@ in_addr_t inet_addr(const char *cp);
#line 1 "common/platforms/platform_nrf51.h" #line 1 "common/platforms/platform_nrf51.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_NRF51_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_
#define CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ #define CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_
@@ -1074,8 +1300,20 @@ int gettimeofday(struct timeval *tp, void *tzp);
#line 1 "common/platforms/platform_nrf52.h" #line 1 "common/platforms/platform_nrf52.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_NRF52_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_
#define CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ #define CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_
@@ -1122,8 +1360,20 @@ int gettimeofday(struct timeval *tp, void *tzp);
#line 1 "common/platforms/simplelink/cs_simplelink.h" #line 1 "common/platforms/simplelink/cs_simplelink.h"
#endif #endif
/* /*
* 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_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_
@@ -1493,8 +1743,20 @@ const char *strerror();
#line 1 "common/platforms/platform_nxp_lpc.h" #line 1 "common/platforms/platform_nxp_lpc.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_NXP_LPC_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_
@@ -1549,8 +1811,20 @@ typedef struct stat cs_stat_t;
#line 1 "common/platforms/platform_nxp_kinetis.h" #line 1 "common/platforms/platform_nxp_kinetis.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_NXP_KINETIS_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_
@@ -1583,8 +1857,20 @@ typedef struct stat cs_stat_t;
#line 1 "common/platforms/platform_pic32.h" #line 1 "common/platforms/platform_pic32.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_PIC32_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_
@@ -1623,8 +1909,20 @@ char *inet_ntoa(struct in_addr in);
#line 1 "common/platforms/platform_stm32.h" #line 1 "common/platforms/platform_stm32.h"
#endif #endif
/* /*
* 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_PLATFORMS_PLATFORM_STM32_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_STM32_H_
@@ -1665,8 +1963,20 @@ typedef struct stat cs_stat_t;
#line 1 "common/platforms/lwip/mg_lwip.h" #line 1 "common/platforms/lwip/mg_lwip.h"
#endif #endif
/* /*
* 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_PLATFORMS_LWIP_MG_LWIP_H_ #ifndef CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_
@@ -1737,8 +2047,20 @@ void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle,
#line 1 "common/cs_md5.h" #line 1 "common/cs_md5.h"
#endif #endif
/* /*
* Copyright (c) 2014 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_MD5_H_ #ifndef CS_COMMON_MD5_H_
@@ -1773,8 +2095,20 @@ void cs_md5_final(unsigned char *md, cs_md5_ctx *c);
#line 1 "common/cs_sha1.h" #line 1 "common/cs_sha1.h"
#endif #endif
/* /*
* Copyright (c) 2014 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_SHA1_H_ #ifndef CS_COMMON_SHA1_H_
@@ -1815,8 +2149,20 @@ void cs_hmac_sha1(const unsigned char *key, size_t key_len,
#line 1 "common/cs_time.h" #line 1 "common/cs_time.h"
#endif #endif
/* /*
* 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_TIME_H_ #ifndef CS_COMMON_CS_TIME_H_
@@ -1848,8 +2194,20 @@ double cs_timegm(const struct tm *tm);
#line 1 "common/mg_str.h" #line 1 "common/mg_str.h"
#endif #endif
/* /*
* 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_MG_STR_H_ #ifndef CS_COMMON_MG_STR_H_
@@ -1857,8 +2215,6 @@ double cs_timegm(const struct tm *tm);
#include <stddef.h> #include <stddef.h>
/* Amalgamated: #include "common/platform.h" */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -1927,6 +2283,9 @@ int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n);
*/ */
const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle);
/* Strip whitespace at the start and the end of s */
struct mg_str mg_strstrip(struct mg_str s);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@@ -1936,8 +2295,20 @@ const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle);
#line 1 "common/mbuf.h" #line 1 "common/mbuf.h"
#endif #endif
/* /*
* Copyright (c) 2015 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.
*/ */
/* /*
@@ -1963,6 +2334,14 @@ extern "C" {
#define MBUF_SIZE_MULTIPLIER 1.5 #define MBUF_SIZE_MULTIPLIER 1.5
#endif #endif
#ifndef MBUF_SIZE_MAX_HEADROOM
#ifdef BUFSIZ
#define MBUF_SIZE_MAX_HEADROOM BUFSIZ
#else
#define MBUF_SIZE_MAX_HEADROOM 1024
#endif
#endif
/* Memory buffer descriptor */ /* Memory buffer descriptor */
struct mbuf { struct mbuf {
char *buf; /* Buffer pointer */ char *buf; /* Buffer pointer */
@@ -2018,8 +2397,20 @@ void mbuf_trim(struct mbuf *);
#line 1 "common/cs_base64.h" #line 1 "common/cs_base64.h"
#endif #endif
/* /*
* Copyright (c) 2014 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_BASE64_H_ #ifndef CS_COMMON_CS_BASE64_H_
@@ -2054,6 +2445,14 @@ void cs_base64_finish(struct cs_base64_ctx *ctx);
void cs_base64_encode(const unsigned char *src, int src_len, char *dst); void cs_base64_encode(const unsigned char *src, int src_len, char *dst);
void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len); void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len);
/*
* Decodes a base64 string `s` length `len` into `dst`.
* `dst` must have enough space to hold the result.
* `*dec_len` will contain the resulting length of the string in `dst`
* while return value will return number of processed bytes in `src`.
* Return value == len indicates successful processing of all the data.
*/
int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len); int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len);
#ifdef __cplusplus #ifdef __cplusplus
@@ -2067,8 +2466,20 @@ int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len);
#line 1 "common/str_util.h" #line 1 "common/str_util.h"
#endif #endif
/* /*
* Copyright (c) 2015 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_STR_UTIL_H_ #ifndef CS_COMMON_STR_UTIL_H_
@@ -2092,7 +2503,11 @@ int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len);
* Expands to a string representation of its argument: e.g. * Expands to a string representation of its argument: e.g.
* `CS_STRINGIFY_LIT(5) expands to "5"` * `CS_STRINGIFY_LIT(5) expands to "5"`
*/ */
#if !defined(_MSC_VER) || _MSC_VER >= 1900
#define CS_STRINGIFY_LIT(...) #__VA_ARGS__
#else
#define CS_STRINGIFY_LIT(x) #x #define CS_STRINGIFY_LIT(x) #x
#endif
/* /*
* Expands to a string representation of its argument, which is allowed * Expands to a string representation of its argument, which is allowed
@@ -2117,7 +2532,8 @@ size_t c_strnlen(const char *s, size_t maxlen);
/* /*
* Equivalent of standard `snprintf()`. * Equivalent of standard `snprintf()`.
*/ */
int c_snprintf(char *buf, size_t buf_size, const char *format, ...); int c_snprintf(char *buf, size_t buf_size, const char *format, ...)
PRINTF_LIKE(3, 4);
/* /*
* Equivalent of standard `vsnprintf()`. * Equivalent of standard `vsnprintf()`.
@@ -2185,7 +2601,8 @@ int mg_casecmp(const char *s1, const char *s2);
* *
* The purpose of this is to avoid malloc-ing if generated strings are small. * The purpose of this is to avoid malloc-ing if generated strings are small.
*/ */
int mg_asprintf(char **buf, size_t size, const char *fmt, ...); int mg_asprintf(char **buf, size_t size, const char *fmt, ...)
PRINTF_LIKE(3, 4);
/* Same as mg_asprintf, but takes varargs list. */ /* Same as mg_asprintf, but takes varargs list. */
int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap);
@@ -3237,10 +3654,12 @@ struct mg_iface_vtable {
void (*connect_udp)(struct mg_connection *nc); void (*connect_udp)(struct mg_connection *nc);
/* Send functions for TCP and UDP. Sent data is copied before return. */ /* Send functions for TCP and UDP. Sent data is copied before return. */
void (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len); int (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len);
void (*udp_send)(struct mg_connection *nc, const void *buf, size_t len); int (*udp_send)(struct mg_connection *nc, const void *buf, size_t len);
void (*recved)(struct mg_connection *nc, size_t len); int (*tcp_recv)(struct mg_connection *nc, void *buf, size_t len);
int (*udp_recv)(struct mg_connection *nc, void *buf, size_t len,
union socket_address *sa, size_t *sa_len);
/* Perform interface-related connection initialization. Return 1 on ok. */ /* Perform interface-related connection initialization. Return 1 on ok. */
int (*create_conn)(struct mg_connection *nc); int (*create_conn)(struct mg_connection *nc);
@@ -3281,19 +3700,15 @@ void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa,
/* Callback invoked by connect methods. err = 0 -> ok, != 0 -> error. */ /* Callback invoked by connect methods. err = 0 -> ok, != 0 -> error. */
void mg_if_connect_cb(struct mg_connection *nc, int err); void mg_if_connect_cb(struct mg_connection *nc, int err);
/* Callback that reports that data has been put on the wire. */
void mg_if_sent_cb(struct mg_connection *nc, int num_sent);
/* /*
* Receive callback. * Callback that tells the core that data can be received.
* if `own` is true, buf must be heap-allocated and ownership is transferred * Core will use tcp/udp_recv to retrieve the data.
* to the core.
* Core will acknowledge consumption by calling iface::recved.
*/ */
void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own); void mg_if_can_recv_cb(struct mg_connection *nc);
void mg_if_can_send_cb(struct mg_connection *nc);
/* /*
* Receive callback. * Receive callback.
* buf must be heap-allocated and ownership is transferred to the core. * buf must be heap-allocated and ownership is transferred to the core.
* Core will acknowledge consumption by calling iface::recved.
*/ */
void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
union socket_address *sa, size_t sa_len); union socket_address *sa, size_t sa_len);
@@ -3301,10 +3716,7 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
/* void mg_if_close_conn(struct mg_connection *nc); */ /* void mg_if_close_conn(struct mg_connection *nc); */
/* Deliver a POLL event to the connection. */ /* Deliver a POLL event to the connection. */
void mg_if_poll(struct mg_connection *nc, time_t now); int mg_if_poll(struct mg_connection *nc, double now);
/* Deliver a TIMER event to the connection. */
void mg_if_timer(struct mg_connection *c, double now);
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -4234,10 +4646,17 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
/* /*
* URL-escape the specified string. * URL-escape the specified string.
* All non-printable characters are escaped, plus `._-$,;~()/`. * All characters acept letters, numbers and characters listed in
* `safe` are escaped. If `hex_upper`is true, `A-F` are used for hex digits.
* Input need not be NUL-terminated, but the returned string is. * Input need not be NUL-terminated, but the returned string is.
* Returned string is heap-allocated and must be free()'d. * Returned string is heap-allocated and must be free()'d.
*/ */
#define MG_URL_ENCODE_F_SPACE_AS_PLUS (1 << 0)
#define MG_URL_ENCODE_F_UPPERCASE_HEX (1 << 1)
struct mg_str mg_url_encode_opt(const struct mg_str src,
const struct mg_str safe, unsigned int flags);
/* Same as `mg_url_encode_opt(src, "._-$,;~()/", 0)`. */
struct mg_str mg_url_encode(const struct mg_str src); struct mg_str mg_url_encode(const struct mg_str src);
#ifdef __cplusplus #ifdef __cplusplus
@@ -4680,9 +5099,9 @@ int mg_http_parse_header2(struct mg_str *hdr, const char *var_name, char **buf,
int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf, int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
size_t buf_size) size_t buf_size)
#ifdef __GNUC__ #ifdef __GNUC__
__attribute__((deprecated)); __attribute__((deprecated))
#endif #endif
; ;
/* /*
* Gets and parses the Authorization: Basic header * Gets and parses the Authorization: Basic header
+14 -3
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#include "common/cs_dbg.h" #include "common/cs_dbg.h"
@@ -19,13 +31,12 @@ enum cs_log_level cs_log_threshold WEAK =
LL_ERROR; LL_ERROR;
#endif #endif
#if CS_ENABLE_STDIO
static char *s_filter_pattern = NULL; static char *s_filter_pattern = NULL;
static size_t s_filter_pattern_len; static size_t s_filter_pattern_len;
void cs_log_set_filter(const char *pattern) WEAK; void cs_log_set_filter(const char *pattern) WEAK;
#if CS_ENABLE_STDIO
FILE *cs_log_file WEAK = NULL; FILE *cs_log_file WEAK = NULL;
#if CS_LOG_ENABLE_TS_DIFF #if CS_LOG_ENABLE_TS_DIFF
+22 -6
View File
@@ -1,6 +1,18 @@
/* /*
* 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_
@@ -103,11 +115,9 @@ void cs_log_set_file(FILE *file);
* Prints log to the current log file, appends "\n" in the end and flushes the * Prints log to the current log file, appends "\n" in the end and flushes the
* stream. * stream.
*/ */
void cs_log_printf(const char *fmt, ...) void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2);
#ifdef __GNUC__
__attribute__((format(printf, 1, 2))) #if CS_ENABLE_STDIO
#endif
;
/* /*
* Format and print message `x` with the given level `l`. Example: * Format and print message `x` with the given level `l`. Example:
@@ -122,6 +132,12 @@ void cs_log_printf(const char *fmt, ...)
if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \ if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \
} while (0) } while (0)
#else
#define LOG(l, x) ((void) l)
#endif
#ifndef CS_NDEBUG #ifndef CS_NDEBUG
/* /*
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* Copyright (c) 2014 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_MD5_H_ #ifndef CS_COMMON_MD5_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#include "common/cs_time.h" #include "common/cs_time.h"
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_TIME_H_ #ifndef CS_COMMON_CS_TIME_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_MG_MEM_H_ #ifndef CS_COMMON_MG_MEM_H_
+11 -1
View File
@@ -92,8 +92,18 @@
/* Common stuff */ /* Common stuff */
#if !defined(PRINTF_LIKE)
#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__)
#define PRINTF_LIKE(f, a) __attribute__((format(printf, f, a)))
#else
#define PRINTF_LIKE(f, a)
#endif
#endif
#if !defined(WEAK) #if !defined(WEAK)
#if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32) #if (defined(__GNUC__) || defined(__clang__) || \
defined(__TI_COMPILER_VERSION__)) && \
!defined(_WIN32)
#define WEAK __attribute__((weak)) #define WEAK __attribute__((weak))
#else #else
#define WEAK #define WEAK
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* Copyright (c) 2014-2017 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.
*/ */
#include <stdint.h> #include <stdint.h>
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2014-2018 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.
*/
#include <math.h>
#include "mgos.h"
#include "mgos_system.h"
void (*mgos_nsleep100)(uint32_t n);
uint32_t mgos_nsleep100_loop_count = 0;
/* Provided by arm_nsleep100_{m4,m7}.S for M4 and M7 respectively. */
extern void mgos_nsleep100_impl(uint32_t n);
void mgos_nsleep100_cal(void) {
uint32_t cpu_freq = mgos_get_cpu_freq();
/* # of instruction cycles per 100 ns */
mgos_nsleep100_loop_count =
roundf((100.0f / 1000000000.0f) / (1.0f / cpu_freq));
mgos_nsleep100 = mgos_nsleep100_impl;
}
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2014-2018 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
.section .iram.mgos_nsleep100_impl
.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
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2014-2018 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
.section .iram.mgos_nsleep100_impl
.type mgos_nsleep100_impl, %function
.align 4
mgos_nsleep100_impl:
ldr r3, =mgos_nsleep100_loop_count
ldr r3, [r3]
/* Because of speculative fetch, the core loop only takes 1 cycle. */
muls r0, r3
cbz r0, xxx
lxx:
subs r0, #1
bne lxx
xxx:
bx lr
.align 4
.size mgos_nsleep100_impl, . - mgos_nsleep100_impl
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#if CS_PLATFORM == CS_P_CC3200 #if CS_PLATFORM == CS_P_CC3200
+10 -12
View File
@@ -1,20 +1,18 @@
/* /*
* Copyright (c) 2014-2016 Cesanta Software Limited * Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved * All rights reserved
* *
* Spiffy flasher. Implements strong checksums (MD5) and can use higher * Licensed under the Apache License, Version 2.0 (the ""License"");
* baud rates. Actual max baud rate will differe from device to device, * you may not use this file except in compliance with the License.
* but 921K seems to be common. * You may obtain a copy of the License at
* *
* SLIP protocol is used for communication. * http://www.apache.org/licenses/LICENSE-2.0
* First packet is a single byte - command number.
* After that, a packet with a variable number of 32-bit (LE) arguments,
* depending on command.
* *
* Then command produces variable number of packets of output, but first * Unless required by applicable law or agreed to in writing, software
* packet of length 1 is the response code: 0 for success, non-zero - error. * distributed under the License is distributed on an ""AS IS"" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See individual command description below. * See the License for the specific language governing permissions and
* limitations under the License.
*/ */
#include "stub_flasher.h" #include "stub_flasher.h"
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* Copyright (c) 2014-2017 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.
*/ */
#include "soc/gpio_reg.h" #include "soc/gpio_reg.h"
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* Copyright (c) 2014-2017 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.
*/ */
#pragma once #pragma once
+11 -2
View File
@@ -1,9 +1,18 @@
/* /*
* Copyright (c) 2015 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
* *
* Stub template. * 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.
*/ */
#include <inttypes.h> #include <inttypes.h>
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#include "uart.h" #include "uart.h"
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_ESP32_STUBS_UART_H_ #ifndef CS_COMMON_PLATFORMS_ESP32_STUBS_UART_H_
+4 -3
View File
@@ -25,7 +25,7 @@ $(Q) $(CC_WRAPPER) $(LD) $(LIBDIRS) -T$(LD_SCRIPT) $(LDFLAGS) -o $@ \
endef endef
define compile_params define compile_params
$(vecho) "$5 $1 -> $2" $(vecho) "$5 $1"
$(Q) $(CC_WRAPPER) $3 -MD -MP $(INCDIRS) $4 -c $1 -o $2 $(Q) $(CC_WRAPPER) $3 -MD -MP $(INCDIRS) $4 -c $1 -o $2
endef endef
@@ -57,7 +57,8 @@ NO_Os_FLAGS= -fno-expensive-optimizations -fno-thread-jumps \
-fno-tree-pre -fno-tree-vrp -fno-tree-pre -fno-tree-vrp
C_CXX_FLAGS = -W -Wall -Werror -Wundef -Wno-comment -Wno-variadic-macros -Wpointer-arith \ C_CXX_FLAGS = -W -Wall -Werror -Wundef -Wno-comment -Wno-variadic-macros -Wpointer-arith \
-Os $(NO_Os_FLAGS) -g3 \ -Wno-missing-field-initializers \
-pipe -Os $(NO_Os_FLAGS) -g3 \
-Wl,-EL -fno-inline-functions \ -Wl,-EL -fno-inline-functions \
-D_XOPEN_SOURCE=500 \ -D_XOPEN_SOURCE=500 \
-nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DSTATIC=static \ -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DSTATIC=static \
@@ -68,7 +69,7 @@ C_CXX_FLAGS = -W -Wall -Werror -Wundef -Wno-comment -Wno-variadic-macros -Wpoin
-DCS_PLATFORM=3 \ -DCS_PLATFORM=3 \
-ffunction-sections -fdata-sections -ffunction-sections -fdata-sections
CFLAGS = -std=c99 $(C_CXX_FLAGS) CFLAGS = -std=gnu99 $(C_CXX_FLAGS)
CXXFLAGS = -std=gnu++11 -fno-exceptions $(C_CXX_FLAGS) CXXFLAGS = -std=gnu++11 -fno-exceptions $(C_CXX_FLAGS)
# linker flags used to generate the main object file # linker flags used to generate the main object file
+14 -2
View File
@@ -1,13 +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.
*/ */
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include "mongoose/mongoose.h" #include "mongoose.h"
#ifdef RTOS_SDK #ifdef RTOS_SDK
#include "esp_libc.h" #include "esp_libc.h"
@@ -1,6 +1,18 @@
/* /*
* Copyright (c) 2014-2017 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_PLATFORMS_ESP8266_ESP_HW_WDT_REGISTER_H_ #ifndef CS_COMMON_PLATFORMS_ESP8266_ESP_HW_WDT_REGISTER_H_
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_ESP8266_ESP_MISSING_INCLUDES_H_ #ifndef CS_COMMON_PLATFORMS_ESP8266_ESP_MISSING_INCLUDES_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_ESP8266_ESP_SSL_KRYPTON_H_ #ifndef CS_COMMON_PLATFORMS_ESP8266_ESP_SSL_KRYPTON_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* Copyright (c) 2014 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.
*/ */
#include <string.h> #include <string.h>
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* Copyright (c) 2014 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.
*/ */
#if ESP_UMM_ENABLE #if ESP_UMM_ENABLE
@@ -160,7 +160,8 @@ static uint8 calc_chksum(uint8 *start, uint8 *end) {
} }
#endif #endif
#define UART_CLKDIV_26MHZ(B) (52000000 + B / 2) / B #define UART_CLKDIV_80MHZ(B) (80000000 + B / 2) / B
#define UART_CLKDIV_52MHZ(B) (52000000 + B / 2) / B
// prevent this function being placed inline with main // prevent this function being placed inline with main
// to keep main's stack size as small as possible // to keep main's stack size as small as possible
@@ -182,10 +183,23 @@ uint32 NOINLINE find_image(void) {
// delay to slow boot (help see messages when debugging) // delay to slow boot (help see messages when debugging)
//ets_delay_us(2000000); //ets_delay_us(2000000);
uart_div_modify(0, UART_CLKDIV_26MHZ(115200)); /*
* UART divider depends on the APB frequency. Cold boot starts with 52MHz APB,
* SDK configures PLL, sets it to 80 and it persists across soft reset
* so on soft reset a different divider should be used. What we really want to
* know is if the PLL is running but since that is completely undocumented
* we use CPU frequency bit as a workaround: mos sets CPU to 160 MHz on startup
* so we assume that if frequency is preserved, then it's soft reset, PLL is
* running and APB is at 80 MHz.
*/
if (READ_PERI_REG(0x3ff00014) & 1) {
uart_div_modify(0, UART_CLKDIV_80MHZ(115200));
} else {
uart_div_modify(0, UART_CLKDIV_52MHZ(115200));
}
ets_delay_us(1000); ets_delay_us(1000);
ets_printf("\r\nrBoot v1.2.1 - richardaburton@gmail.com\r\n"); ets_printf("\r\nrBoot v1.2.1-cesanta1 - richardaburton@gmail.com\r\n");
// read rom header // read rom header
SPIRead(0, header, sizeof(rom_header)); SPIRead(0, header, sizeof(rom_header));
@@ -23,7 +23,7 @@ LD := $(addprefix $(XTENSA_BINDIR)/,xtensa-lx106-elf-gcc)
endif endif
CC_WRAPPER ?= CC_WRAPPER ?=
CFLAGS = -Os -O3 -Wpointer-arith -Wundef -Werror -Wl,-EL \ CFLAGS = -Os -Wpointer-arith -Wundef -Werror -Wl,-EL \
-fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals \ -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals \
-D__ets__ -DIRAM='__attribute__((section(".fast.text")))' \ -D__ets__ -DIRAM='__attribute__((section(".fast.text")))' \
-DNOINSTR='__attribute__((no_instrument_function))' \ -DNOINSTR='__attribute__((no_instrument_function))' \
@@ -1,9 +1,18 @@
/* /*
* Copyright (c) 2015 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
* *
* Stub template. * 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.
*/ */
#include <inttypes.h> #include <inttypes.h>
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#include "uart.h" #include "uart.h"
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_ESP8266_STUBS_UART_H_ #ifndef CS_COMMON_PLATFORMS_ESP8266_STUBS_UART_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_LWIP_MG_LWIP_H_ #ifndef CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_
+37 -78
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL #if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
@@ -41,24 +53,17 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
(struct mg_ev_mgr_lwip_data *) mgr->ifaces[MG_MAIN_IFACE]->data; (struct mg_ev_mgr_lwip_data *) mgr->ifaces[MG_MAIN_IFACE]->data;
while (md->sig_queue_len > 0) { while (md->sig_queue_len > 0) {
mgos_lock(); mgos_lock();
int sig = md->sig_queue[md->start_index].sig; int i = md->start_index;
struct mg_connection *nc = md->sig_queue[md->start_index].nc; int sig = md->sig_queue[i].sig;
struct mg_connection *nc = md->sig_queue[i].nc;
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
md->start_index = (md->start_index + 1) % MG_SIG_QUEUE_LEN; md->start_index = (i + 1) % MG_SIG_QUEUE_LEN;
md->sig_queue_len--; md->sig_queue_len--;
mgos_unlock(); mgos_unlock();
if (nc->iface == NULL || nc->mgr == NULL) continue; if (nc->iface == NULL || nc->mgr == NULL) continue;
switch (sig) { switch (sig) {
case MG_SIG_CONNECT_RESULT: { case MG_SIG_CONNECT_RESULT: {
#if MG_ENABLE_SSL mg_if_connect_cb(nc, cs->err);
if (cs->err == 0 && (nc->flags & MG_F_SSL) &&
!(nc->flags & MG_F_SSL_HANDSHAKE_DONE)) {
mg_lwip_ssl_do_hs(nc);
} else
#endif
{
mg_if_connect_cb(nc, cs->err);
}
break; break;
} }
case MG_SIG_CLOSE_CONN: { case MG_SIG_CLOSE_CONN: {
@@ -68,11 +73,8 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
} }
case MG_SIG_RECV: { case MG_SIG_RECV: {
cs->recv_pending = 0; cs->recv_pending = 0;
if (nc->flags & MG_F_UDP) { mg_if_can_recv_cb(nc);
mg_lwip_handle_recv_udp(nc); mbuf_trim(&nc->recv_mbuf);
} else {
mg_lwip_handle_recv_tcp(nc);
}
break; break;
} }
case MG_SIG_TOMBSTONE: { case MG_SIG_TOMBSTONE: {
@@ -87,7 +89,8 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
} }
void mg_lwip_if_init(struct mg_iface *iface) { void mg_lwip_if_init(struct mg_iface *iface) {
LOG(LL_INFO, ("%p Mongoose init", iface)); LOG(LL_INFO, ("Mongoose %s, LwIP %u.%u.%u", MG_VERSION, LWIP_VERSION_MAJOR,
LWIP_VERSION_MINOR, LWIP_VERSION_REVISION));
iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data)); iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data));
} }
@@ -126,42 +129,7 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
tmp = nc->next; tmp = nc->next;
n++; n++;
if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) || if (!mg_if_poll(nc, now)) continue;
((nc->flags & MG_F_SEND_AND_CLOSE) && (nc->flags & MG_F_UDP) &&
(nc->send_mbuf.len == 0))) {
mg_close_conn(nc);
continue;
}
mg_if_poll(nc, now);
mg_if_timer(nc, now);
#if MG_ENABLE_SSL
if ((nc->flags & MG_F_SSL) && cs != NULL && cs->pcb.tcp != NULL &&
cs->pcb.tcp->state == ESTABLISHED) {
if (((nc->flags & MG_F_WANT_WRITE) ||
((nc->send_mbuf.len > 0) &&
(nc->flags & MG_F_SSL_HANDSHAKE_DONE))) &&
cs->pcb.tcp->snd_buf > 0) {
/* Can write more. */
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_send(nc);
} else {
mg_lwip_ssl_do_hs(nc);
}
}
if (cs->rx_chain != NULL || (nc->flags & MG_F_WANT_READ)) {
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_recv(nc);
} else {
mg_lwip_ssl_do_hs(nc);
}
}
} else
#endif /* MG_ENABLE_SSL */
{
if (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING)) {
mg_lwip_send_more(nc);
}
}
if (nc->sock != INVALID_SOCKET && if (nc->sock != INVALID_SOCKET &&
!(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL && !(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL &&
cs->pcb.tcp->unsent != NULL) { cs->pcb.tcp->unsent != NULL) {
@@ -175,14 +143,17 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) {
} }
if (nc->sock != INVALID_SOCKET) { if (nc->sock != INVALID_SOCKET) {
/* Try to consume data from cs->rx_chain */ if (mg_lwip_if_can_send(nc, cs)) {
mg_lwip_consume_rx_chain_tcp(nc); mg_if_can_send_cb(nc);
mbuf_trim(&nc->send_mbuf);
/* }
* If the connection is about to close, and rx_chain is finally empty, if (cs->rx_chain != NULL) {
* send the MG_SIG_CLOSE_CONN signal mg_if_can_recv_cb(nc);
*/ } else if (cs->draining_rx_chain) {
if (cs->draining_rx_chain && cs->rx_chain == NULL) { /*
* If the connection is about to close, and rx_chain is finally empty,
* send the MG_SIG_CLOSE_CONN signal
*/
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
} }
} }
@@ -210,21 +181,9 @@ uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) {
} }
num_timers++; num_timers++;
} }
if (nc->send_mbuf.len > 0 /* We want and can send data, request a poll immediately. */
#if MG_ENABLE_SSL if (nc->sock != INVALID_SOCKET && mg_lwip_if_can_send(nc, cs)) {
|| (nc->flags & MG_F_WANT_WRITE) return 0;
#endif
) {
int can_send = 0;
/* We have stuff to send, but can we? */
if (nc->flags & MG_F_UDP) {
/* UDP is always ready for sending. */
can_send = (cs->pcb.udp != NULL);
} else {
can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
}
/* We want and can send, request a poll immediately. */
if (can_send) return 0;
} }
} }
uint32_t timeout_ms = ~0; uint32_t timeout_ms = ~0;
+95 -165
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL #if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
@@ -57,10 +69,6 @@
typedef void (*tcpip_callback_fn)(void *arg); typedef void (*tcpip_callback_fn)(void *arg);
#endif #endif
void mg_lwip_ssl_do_hs(struct mg_connection *nc);
void mg_lwip_ssl_send(struct mg_connection *nc);
void mg_lwip_ssl_recv(struct mg_connection *nc);
void mg_lwip_if_init(struct mg_iface *iface); void mg_lwip_if_init(struct mg_iface *iface);
void mg_lwip_if_free(struct mg_iface *iface); void mg_lwip_if_free(struct mg_iface *iface);
void mg_lwip_if_add_conn(struct mg_connection *nc); void mg_lwip_if_add_conn(struct mg_connection *nc);
@@ -118,7 +126,7 @@ static err_t mg_lwip_tcp_conn_cb(void *arg, struct tcp_pcb *tpcb, err_t err) {
static void mg_lwip_tcp_error_cb(void *arg, err_t err) { static void mg_lwip_tcp_error_cb(void *arg, err_t err) {
struct mg_connection *nc = (struct mg_connection *) arg; struct mg_connection *nc = (struct mg_connection *) arg;
DBG(("%p conn error %d", nc, err)); DBG(("%p conn error %d", nc, err));
if (nc == NULL) return; if (nc == NULL || (nc->flags & MG_F_CLOSE_IMMEDIATELY)) return;
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
cs->pcb.tcp = NULL; /* Has already been deallocated */ cs->pcb.tcp = NULL; /* Has already been deallocated */
if (nc->flags & MG_F_CONNECTING) { if (nc->flags & MG_F_CONNECTING) {
@@ -132,10 +140,12 @@ static void mg_lwip_tcp_error_cb(void *arg, err_t err) {
static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
struct pbuf *p, err_t err) { struct pbuf *p, err_t err) {
struct mg_connection *nc = (struct mg_connection *) arg; struct mg_connection *nc = (struct mg_connection *) arg;
DBG(("%p %p %u %d", nc, tpcb, (p != NULL ? p->tot_len : 0), err)); struct mg_lwip_conn_state *cs =
(nc ? (struct mg_lwip_conn_state *) nc->sock : NULL);
DBG(("%p %p %p %p %u %d", nc, cs, tpcb, p, (p != NULL ? p->tot_len : 0),
err));
if (p == NULL) { if (p == NULL) {
if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (cs->rx_chain != NULL) { if (cs->rx_chain != NULL) {
/* /*
* rx_chain still contains non-consumed data, don't close the * rx_chain still contains non-consumed data, don't close the
@@ -153,7 +163,6 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
tcp_abort(tpcb); tcp_abort(tpcb);
return ERR_ARG; return ERR_ARG;
} }
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
/* /*
* If we get a chain of more than one segment at once, we need to bump * If we get a chain of more than one segment at once, we need to bump
* refcount on the subsequent bufs to make them independent. * refcount on the subsequent bufs to make them independent.
@@ -168,7 +177,7 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
} else if (pbuf_clen(cs->rx_chain) >= 4) { } else if (pbuf_clen(cs->rx_chain) >= 4) {
/* ESP SDK has a limited pool of 5 pbufs. We must not hog them all or RX /* ESP SDK has a limited pool of 5 pbufs. We must not hog them all or RX
* will be completely blocked. We already have at least 4 in the chain, * will be completely blocked. We already have at least 4 in the chain,
* this one is, so we have to make a copy and release this one. */ * this one is the last, so we have to make a copy and release this one. */
struct pbuf *np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); struct pbuf *np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
if (np != NULL) { if (np != NULL) {
pbuf_copy(np, p); pbuf_copy(np, p);
@@ -176,58 +185,9 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
p = np; p = np;
} }
} }
mgos_unlock();
mg_lwip_recv_common(nc, p); mg_lwip_recv_common(nc, p);
return ERR_OK;
}
static void mg_lwip_consume_rx_chain_tcp(struct mg_connection *nc) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (cs->rx_chain == NULL) return;
#if MG_ENABLE_SSL
if (nc->flags & MG_F_SSL) {
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
mg_lwip_ssl_recv(nc);
} else {
mg_lwip_ssl_do_hs(nc);
}
return;
}
#endif
mgos_lock();
while (cs->rx_chain != NULL && nc->recv_mbuf.len < nc->recv_mbuf_limit) {
struct pbuf *seg = cs->rx_chain;
size_t seg_len = (seg->len - cs->rx_offset);
size_t buf_avail = (nc->recv_mbuf_limit - nc->recv_mbuf.len);
size_t len = MIN(seg_len, buf_avail);
char *data = (char *) MG_MALLOC(len);
if (data == NULL) {
mgos_unlock();
DBG(("OOM"));
return;
}
pbuf_copy_partial(seg, data, len, cs->rx_offset);
cs->rx_offset += len;
if (cs->rx_offset == cs->rx_chain->len) {
cs->rx_chain = pbuf_dechain(cs->rx_chain);
pbuf_free(seg);
cs->rx_offset = 0;
}
mgos_unlock();
mg_if_recv_tcp_cb(nc, data, len, 1 /* own */);
mgos_lock();
}
mgos_unlock(); mgos_unlock();
} return ERR_OK;
static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) {
mg_lwip_consume_rx_chain_tcp(nc);
if (nc->send_mbuf.len > 0) {
mg_lwip_mgr_schedule_poll(nc->mgr);
}
} }
static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb,
@@ -313,13 +273,14 @@ static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
/* Logic in the recv handler requires that there be exactly one data pbuf. */ /* Logic in the recv handler requires that there be exactly one data pbuf. */
p = pbuf_coalesce(p, PBUF_RAW); p = pbuf_coalesce(p, PBUF_RAW);
pbuf_chain(sap, p); pbuf_chain(sap, p);
mgos_lock();
mg_lwip_recv_common(nc, sap); mg_lwip_recv_common(nc, sap);
mgos_unlock();
(void) pcb; (void) pcb;
} }
static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) { static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
mgos_lock();
if (cs->rx_chain == NULL) { if (cs->rx_chain == NULL) {
cs->rx_chain = p; cs->rx_chain = p;
} else { } else {
@@ -329,32 +290,30 @@ static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) {
cs->recv_pending = 1; cs->recv_pending = 1;
mg_lwip_post_signal(MG_SIG_RECV, nc); mg_lwip_post_signal(MG_SIG_RECV, nc);
} }
mgos_unlock();
} }
static void mg_lwip_handle_recv_udp(struct mg_connection *nc) { static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; union socket_address *sa, size_t *sa_len) {
/* /*
* For UDP, RX chain consists of interleaved address and packet bufs: * For UDP, RX chain consists of interleaved address and packet bufs:
* Address pbuf followed by exactly one data pbuf (recv_cb took care of that). * Address pbuf followed by exactly one data pbuf (recv_cb took care of that).
*/ */
while (cs->rx_chain != NULL) { int res = 0;
struct pbuf *sap = cs->rx_chain; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
struct pbuf *p = sap->next; if (nc->sock == INVALID_SOCKET) return -1;
cs->rx_chain = pbuf_dechain(p); mgos_lock();
size_t data_len = p->len; if (cs->rx_chain != NULL) {
char *data = (char *) MG_MALLOC(data_len); struct pbuf *ap = cs->rx_chain;
if (data != NULL) { struct pbuf *dp = ap->next;
pbuf_copy_partial(p, data, data_len, 0); cs->rx_chain = pbuf_dechain(dp);
pbuf_free(p); res = MIN(dp->len, len);
mg_if_recv_udp_cb(nc, data, data_len, pbuf_copy_partial(dp, buf, res, 0);
(union socket_address *) sap->payload, sap->len); pbuf_free(dp);
pbuf_free(sap); pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0);
} else { pbuf_free(ap);
pbuf_free(p);
pbuf_free(sap);
}
} }
mgos_unlock();
return res;
} }
static void mg_lwip_if_connect_udp_tcpip(void *arg) { static void mg_lwip_if_connect_udp_tcpip(void *arg) {
@@ -376,13 +335,6 @@ void mg_lwip_if_connect_udp(struct mg_connection *nc) {
tcpip_callback(mg_lwip_if_connect_udp_tcpip, nc); tcpip_callback(mg_lwip_if_connect_udp_tcpip, nc);
} }
void mg_lwip_accept_conn(struct mg_connection *nc, struct tcp_pcb *tpcb) {
union socket_address sa;
SET_ADDR(&sa, &tpcb->remote_ip);
sa.sin.sin_port = htons(tpcb->remote_port);
mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin));
}
static void tcp_close_tcpip(void *arg) { static void tcp_close_tcpip(void *arg) {
tcp_close((struct tcp_pcb *) arg); tcp_close((struct tcp_pcb *) arg);
} }
@@ -390,17 +342,11 @@ static void tcp_close_tcpip(void *arg) {
void mg_lwip_handle_accept(struct mg_connection *nc) { void mg_lwip_handle_accept(struct mg_connection *nc) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (cs->pcb.tcp == NULL) return; if (cs->pcb.tcp == NULL) return;
#if MG_ENABLE_SSL union socket_address sa;
if (cs->lc->flags & MG_F_SSL) { struct tcp_pcb *tpcb = cs->pcb.tcp;
if (mg_ssl_if_conn_accept(nc, cs->lc) != MG_SSL_OK) { SET_ADDR(&sa, &tpcb->remote_ip);
LOG(LL_ERROR, ("SSL error")); sa.sin.sin_port = htons(tpcb->remote_port);
tcpip_callback(tcp_close_tcpip, cs->pcb.tcp); mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin));
}
} else
#endif
{
mg_lwip_accept_conn(nc, cs->pcb.tcp);
}
} }
static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) { static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) {
@@ -555,16 +501,17 @@ static void mg_lwip_tcp_write_tcpip(void *arg) {
return; return;
} }
ctx->ret = len; ctx->ret = len;
(void) unsent;
(void) unacked;
} }
static int mg_lwip_tcp_write(struct mg_connection *nc, const void *data, int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) {
uint16_t len) { struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = buf, .len = len};
struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = data, .len = len};
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (nc->sock == INVALID_SOCKET) return -1;
struct tcp_pcb *tpcb = cs->pcb.tcp; struct tcp_pcb *tpcb = cs->pcb.tcp;
if (tpcb == NULL) { if (tpcb == NULL) return -1;
return -1; if (tpcb->snd_buf <= 0) return 0;
}
tcpip_callback(mg_lwip_tcp_write_tcpip, &ctx); tcpip_callback(mg_lwip_tcp_write_tcpip, &ctx);
return ctx.ret; return ctx.ret;
} }
@@ -582,18 +529,10 @@ static void udp_sendto_tcpip(void *arg) {
ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port); ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port);
} }
static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data,
uint16_t len) { size_t len) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (cs->pcb.udp == NULL) { if (nc->sock == INVALID_SOCKET || cs->pcb.udp == NULL) return -1;
/*
* In case of UDP, this usually means, what
* async DNS resolve is still in progress and connection
* is not ready yet
*/
DBG(("%p socket is not connected", nc));
return -1;
}
struct udp_pcb *upcb = cs->pcb.udp; struct udp_pcb *upcb = cs->pcb.udp;
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
#if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6 #if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6
@@ -602,46 +541,28 @@ static int mg_lwip_udp_send(struct mg_connection *nc, const void *data,
ip_addr_t ip = {.addr = nc->sa.sin.sin_addr.s_addr}; ip_addr_t ip = {.addr = nc->sa.sin.sin_addr.s_addr};
#endif #endif
u16_t port = ntohs(nc->sa.sin.sin_port); u16_t port = ntohs(nc->sa.sin.sin_port);
if (p == NULL) { if (p == NULL) return 0;
DBG(("OOM"));
return 0;
}
memcpy(p->payload, data, len); memcpy(p->payload, data, len);
struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port}; struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port};
tcpip_callback(udp_sendto_tcpip, &ctx); tcpip_callback(udp_sendto_tcpip, &ctx);
cs->err = ctx.ret; cs->err = ctx.ret;
pbuf_free(p); pbuf_free(p);
return (cs->err == ERR_OK ? len : -1); return (cs->err == ERR_OK ? (int) len : -2);
} }
static void mg_lwip_send_more(struct mg_connection *nc) { static int mg_lwip_if_can_send(struct mg_connection *nc,
int num_sent = 0; struct mg_lwip_conn_state *cs) {
if (nc->sock == INVALID_SOCKET) return; int can_send = 0;
if (nc->flags & MG_F_UDP) { if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
num_sent = mg_lwip_udp_send(nc, nc->send_mbuf.buf, nc->send_mbuf.len); /* We have stuff to send, but can we? */
DBG(("%p mg_lwip_udp_send %u = %d", nc, nc->send_mbuf.len, num_sent)); if (nc->flags & MG_F_UDP) {
} else { /* UDP is always ready for sending. */
num_sent = mg_lwip_tcp_write(nc, nc->send_mbuf.buf, nc->send_mbuf.len); can_send = (cs->pcb.udp != NULL);
DBG(("%p mg_lwip_tcp_write %u = %d", nc, nc->send_mbuf.len, num_sent)); } else {
can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
}
} }
if (num_sent == 0) return; return can_send;
if (num_sent > 0) {
mg_if_sent_cb(nc, num_sent);
} else {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
}
}
void mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf,
size_t len) {
mbuf_append(&nc->send_mbuf, buf, len);
mg_lwip_mgr_schedule_poll(nc->mgr);
}
void mg_lwip_if_udp_send(struct mg_connection *nc, const void *buf,
size_t len) {
mbuf_append(&nc->send_mbuf, buf, len);
mg_lwip_mgr_schedule_poll(nc->mgr);
} }
struct tcp_recved_ctx { struct tcp_recved_ctx {
@@ -654,27 +575,35 @@ void tcp_recved_tcpip(void *arg) {
tcp_recved(ctx->tpcb, ctx->len); tcp_recved(ctx->tpcb, ctx->len);
} }
void mg_lwip_if_recved(struct mg_connection *nc, size_t len) { static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf,
if (nc->flags & MG_F_UDP) return; size_t len) {
int res = 0;
char *bufp = buf;
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (nc->sock == INVALID_SOCKET || cs->pcb.tcp == NULL) { if (nc->sock == INVALID_SOCKET) return -1;
DBG(("%p invalid socket", nc)); mgos_lock();
return; while (cs->rx_chain != NULL && len > 0) {
struct pbuf *seg = cs->rx_chain;
size_t seg_len = (seg->len - cs->rx_offset);
size_t copy_len = MIN(len, seg_len);
pbuf_copy_partial(seg, bufp, copy_len, cs->rx_offset);
len -= copy_len;
res += copy_len;
bufp += copy_len;
cs->rx_offset += copy_len;
if (cs->rx_offset == cs->rx_chain->len) {
cs->rx_chain = pbuf_dechain(cs->rx_chain);
pbuf_free(seg);
cs->rx_offset = 0;
}
} }
DBG(("%p %p %u %u", nc, cs->pcb.tcp, len, mgos_unlock();
(cs->rx_chain ? cs->rx_chain->tot_len : 0))); if (res > 0) {
struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = len}; struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = res};
#if MG_ENABLE_SSL
if (!(nc->flags & MG_F_SSL)) {
tcpip_callback(tcp_recved_tcpip, &ctx); tcpip_callback(tcp_recved_tcpip, &ctx);
} else {
/* Currently SSL acknowledges data immediately.
* TODO(rojer): Find a way to propagate mg_lwip_if_recved. */
} }
#else return res;
tcpip_callback(tcp_recved_tcpip, &ctx);
#endif
mbuf_trim(&nc->recv_mbuf);
} }
int mg_lwip_if_create_conn(struct mg_connection *nc) { int mg_lwip_if_create_conn(struct mg_connection *nc) {
@@ -763,7 +692,8 @@ void mg_lwip_if_sock_set(struct mg_connection *nc, sock_t sock) {
mg_lwip_if_connect_udp, \ mg_lwip_if_connect_udp, \
mg_lwip_if_tcp_send, \ mg_lwip_if_tcp_send, \
mg_lwip_if_udp_send, \ mg_lwip_if_udp_send, \
mg_lwip_if_recved, \ mg_lwip_if_tcp_recv, \
mg_lwip_if_udp_recv, \
mg_lwip_if_create_conn, \ mg_lwip_if_create_conn, \
mg_lwip_if_destroy_conn, \ mg_lwip_if_destroy_conn, \
mg_lwip_if_sock_set, \ mg_lwip_if_sock_set, \
+15 -3
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_ #ifndef CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_
@@ -30,9 +42,9 @@ struct mg_lwip_conn_state {
/* Last SSL write size, for retries. */ /* Last SSL write size, for retries. */
int last_ssl_write_size; int last_ssl_write_size;
/* Whether MG_SIG_RECV is already pending for this connection */ /* Whether MG_SIG_RECV is already pending for this connection */
int recv_pending : 1; int recv_pending;
/* Whether the connection is about to close, just `rx_chain` needs to drain */ /* Whether the connection is about to close, just `rx_chain` needs to drain */
int draining_rx_chain : 1; int draining_rx_chain;
}; };
enum mg_sig_type { enum mg_sig_type {
-197
View File
@@ -1,197 +0,0 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#if MG_ENABLE_SSL && MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
#include "common/mg_mem.h"
#include "common/cs_dbg.h"
#include <lwip/pbuf.h>
#include <lwip/tcp.h>
#ifndef MG_LWIP_SSL_IO_SIZE
#define MG_LWIP_SSL_IO_SIZE 1024
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
void mg_lwip_ssl_do_hs(struct mg_connection *nc) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
int server_side = (nc->listener != NULL);
enum mg_ssl_if_result res;
if (nc->flags & MG_F_CLOSE_IMMEDIATELY) return;
res = mg_ssl_if_handshake(nc);
DBG(("%p %lu %d %d", nc, nc->flags, server_side, res));
if (res != MG_SSL_OK) {
if (res == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
cs->err = 0;
} else if (res == MG_SSL_WANT_READ) {
/*
* Nothing to do in particular, we are callback-driven.
* What we definitely do not need anymore is SSL reading (nothing left).
*/
nc->flags &= ~MG_F_WANT_READ;
cs->err = 0;
} else {
cs->err = res;
if (server_side) {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
} else {
mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
}
}
} else {
cs->err = 0;
nc->flags &= ~MG_F_WANT_WRITE;
/*
* Handshake is done. Schedule a read immediately to consume app data
* which may already be waiting.
*/
nc->flags |= (MG_F_SSL_HANDSHAKE_DONE | MG_F_WANT_READ);
if (server_side) {
mg_lwip_accept_conn(nc, cs->pcb.tcp);
} else {
mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
}
}
}
void mg_lwip_ssl_send(struct mg_connection *nc) {
if (nc->sock == INVALID_SOCKET) {
DBG(("%p invalid socket", nc));
return;
}
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
/* It's ok if the buffer is empty. Return value of 0 may also be valid. */
int len = cs->last_ssl_write_size;
if (len == 0) {
len = MIN(MG_LWIP_SSL_IO_SIZE, nc->send_mbuf.len);
}
int ret = mg_ssl_if_write(nc, nc->send_mbuf.buf, len);
DBG(("%p SSL_write %u = %d", nc, len, ret));
if (ret > 0) {
mg_if_sent_cb(nc, ret);
cs->last_ssl_write_size = 0;
} else if (ret < 0) {
/* This is tricky. We must remember the exact data we were sending to retry
* exactly the same send next time. */
cs->last_ssl_write_size = len;
}
if (ret == len) {
nc->flags &= ~MG_F_WANT_WRITE;
} else if (ret == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
} else {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
}
}
void mg_lwip_ssl_recv(struct mg_connection *nc) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
/* Don't deliver data before connect callback */
if (nc->flags & MG_F_CONNECTING) return;
while (nc->recv_mbuf.len < nc->recv_mbuf_limit) {
char *buf = (char *) MG_MALLOC(MG_LWIP_SSL_IO_SIZE);
if (buf == NULL) return;
int ret = mg_ssl_if_read(nc, buf, MG_LWIP_SSL_IO_SIZE);
DBG(("%p %p SSL_read %u = %d", nc, cs->rx_chain, MG_LWIP_SSL_IO_SIZE, ret));
if (ret <= 0) {
MG_FREE(buf);
if (ret == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
return;
} else if (ret == MG_SSL_WANT_READ) {
/*
* Nothing to do in particular, we are callback-driven.
* What we definitely do not need anymore is SSL reading (nothing left).
*/
nc->flags &= ~MG_F_WANT_READ;
cs->err = 0;
return;
} else {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
return;
}
} else {
mg_if_recv_tcp_cb(nc, buf, ret, 1 /* own */);
}
}
}
#ifdef KR_VERSION
ssize_t kr_send(int fd, const void *buf, size_t len) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) fd;
int ret = mg_lwip_tcp_write(cs->nc, buf, len);
DBG(("%p mg_lwip_tcp_write %u = %d", cs->nc, len, ret));
if (ret == 0) ret = KR_IO_WOULDBLOCK;
return ret;
}
ssize_t kr_recv(int fd, void *buf, size_t len) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) fd;
struct pbuf *seg = cs->rx_chain;
if (seg == NULL) {
DBG(("%u - nothing to read", len));
return KR_IO_WOULDBLOCK;
}
size_t seg_len = (seg->len - cs->rx_offset);
DBG(("%u %u %u %u", len, cs->rx_chain->len, seg_len, cs->rx_chain->tot_len));
len = MIN(len, seg_len);
pbuf_copy_partial(seg, buf, len, cs->rx_offset);
cs->rx_offset += len;
tcp_recved(cs->pcb.tcp, len);
if (cs->rx_offset == cs->rx_chain->len) {
cs->rx_chain = pbuf_dechain(cs->rx_chain);
pbuf_free(seg);
cs->rx_offset = 0;
}
return len;
}
#elif MG_SSL_IF == MG_SSL_IF_MBEDTLS
int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len) {
struct mg_connection *nc = (struct mg_connection *) ctx;
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
int ret = mg_lwip_tcp_write(cs->nc, buf, len);
if (ret == 0) ret = MBEDTLS_ERR_SSL_WANT_WRITE;
LOG(LL_DEBUG, ("%p %d -> %d", nc, len, ret));
return ret;
}
int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len) {
struct mg_connection *nc = (struct mg_connection *) ctx;
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
struct pbuf *seg = cs->rx_chain;
if (seg == NULL) {
DBG(("%u - nothing to read", len));
return MBEDTLS_ERR_SSL_WANT_READ;
}
size_t seg_len = (seg->len - cs->rx_offset);
DBG(("%u %u %u %u", len, cs->rx_chain->len, seg_len, cs->rx_chain->tot_len));
mgos_lock();
len = MIN(len, seg_len);
pbuf_copy_partial(seg, buf, len, cs->rx_offset);
cs->rx_offset += len;
/* TCP PCB may be NULL if connection has already been closed
* but we still have data to deliver to SSL. */
if (cs->pcb.tcp != NULL) tcp_recved(cs->pcb.tcp, len);
if (cs->rx_offset == cs->rx_chain->len) {
cs->rx_chain = pbuf_dechain(cs->rx_chain);
pbuf_free(seg);
cs->rx_offset = 0;
}
mgos_unlock();
LOG(LL_DEBUG, ("%p <- %d", nc, (int) len));
return len;
}
#endif
#endif /* MG_ENABLE_SSL && MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#include "common/platform.h" #include "common/platform.h"
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#if CS_PLATFORM == CS_P_MSP432 #if CS_PLATFORM == CS_P_MSP432
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#if (CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52) && \ #if (CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52) && \
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#if MG_ENABLE_NET_IF_PIC32 #if MG_ENABLE_NET_IF_PIC32
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PIC32_NET_IF_H_ #ifndef CS_COMMON_PLATFORMS_PIC32_NET_IF_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_CC3100_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_CC3200_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_
+15 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_CC3220_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_
@@ -22,7 +34,9 @@
#endif #endif
#define MG_NET_IF MG_NET_IF_SIMPLELINK #define MG_NET_IF MG_NET_IF_SIMPLELINK
#ifndef MG_SSL_IF
#define MG_SSL_IF MG_SSL_IF_SIMPLELINK #define MG_SSL_IF MG_SSL_IF_SIMPLELINK
#endif
/* Only SPIFFS supports directories, SLFS does not. */ /* Only SPIFFS supports directories, SLFS does not. */
#if defined(CC3220_FS_SPIFFS) && !defined(MG_ENABLE_DIRECTORY_LISTING) #if defined(CC3220_FS_SPIFFS) && !defined(MG_ENABLE_DIRECTORY_LISTING)
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_ESP32_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_
+13 -5
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_ESP8266_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_
@@ -30,10 +42,6 @@ typedef struct stat cs_stat_t;
#define __cdecl #define __cdecl
#define _FILE_OFFSET_BITS 32 #define _FILE_OFFSET_BITS 32
#if !defined(RTOS_SDK) && !defined(__cplusplus)
#define fileno(x) -1
#endif
#define MG_LWIP 1 #define MG_LWIP 1
/* struct timeval is defined in sys/time.h. */ /* struct timeval is defined in sys/time.h. */
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_MBED_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_MBED_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_MSP432_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_MSP432_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_NRF51_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_
#define CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ #define CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_NRF52_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_
#define CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ #define CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_NXP_KINETIS_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_NXP_LPC_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_PIC32_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_STM32_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_STM32_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_PLATFORM_TM4C129_H_ #ifndef CS_COMMON_PLATFORMS_PLATFORM_TM4C129_H_
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#if MG_NET_IF == MG_NET_IF_SIMPLELINK && \ #if MG_NET_IF == MG_NET_IF_SIMPLELINK && \
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
/* Standard libc interface to TI SimpleLink FS. */ /* Standard libc interface to TI SimpleLink FS. */
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_ #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
+68 -116
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#include "common/platforms/simplelink/sl_net_if.h" #include "common/platforms/simplelink/sl_net_if.h"
@@ -17,7 +29,7 @@ static sock_t mg_open_listening_socket(struct mg_connection *nc,
union socket_address *sa, int type, union socket_address *sa, int type,
int proto); int proto);
void mg_set_non_blocking_mode(sock_t sock) { static void mg_set_non_blocking_mode(sock_t sock) {
SlSockNonblocking_t opt; SlSockNonblocking_t opt;
#if SL_MAJOR_VERSION_NUM < 2 #if SL_MAJOR_VERSION_NUM < 2
opt.NonblockingEnabled = 1; opt.NonblockingEnabled = 1;
@@ -31,17 +43,19 @@ static int mg_is_error(int n) {
return (n < 0 && n != SL_ERROR_BSD_EALREADY && n != SL_ERROR_BSD_EAGAIN); return (n < 0 && n != SL_ERROR_BSD_EALREADY && n != SL_ERROR_BSD_EAGAIN);
} }
void mg_sl_if_connect_tcp(struct mg_connection *nc, static void mg_sl_if_connect_tcp(struct mg_connection *nc,
const union socket_address *sa) { const union socket_address *sa) {
int proto = 0; int proto = 0;
#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET; if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
#endif
sock_t sock = sl_Socket(AF_INET, SOCK_STREAM, proto); sock_t sock = sl_Socket(AF_INET, SOCK_STREAM, proto);
if (sock < 0) { if (sock < 0) {
nc->err = sock; nc->err = sock;
goto out; goto out;
} }
mg_sock_set(nc, sock); mg_sock_set(nc, sock);
#if MG_ENABLE_SSL #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
nc->err = sl_set_ssl_opts(sock, nc); nc->err = sl_set_ssl_opts(sock, nc);
if (nc->err != 0) goto out; if (nc->err != 0) goto out;
#endif #endif
@@ -51,7 +65,7 @@ out:
ntohs(sa->sin.sin_port), nc->sock, proto, nc->err)); ntohs(sa->sin.sin_port), nc->sock, proto, nc->err));
} }
void mg_sl_if_connect_udp(struct mg_connection *nc) { static void mg_sl_if_connect_udp(struct mg_connection *nc) {
sock_t sock = sl_Socket(AF_INET, SOCK_DGRAM, 0); sock_t sock = sl_Socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) { if (sock < 0) {
nc->err = sock; nc->err = sock;
@@ -61,7 +75,8 @@ void mg_sl_if_connect_udp(struct mg_connection *nc) {
nc->err = 0; nc->err = 0;
} }
int mg_sl_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) { static int mg_sl_if_listen_tcp(struct mg_connection *nc,
union socket_address *sa) {
int proto = 0; int proto = 0;
if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET; if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
sock_t sock = mg_open_listening_socket(nc, sa, SOCK_STREAM, proto); sock_t sock = mg_open_listening_socket(nc, sa, SOCK_STREAM, proto);
@@ -70,27 +85,50 @@ int mg_sl_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) {
return 0; return 0;
} }
int mg_sl_if_listen_udp(struct mg_connection *nc, union socket_address *sa) { static int mg_sl_if_listen_udp(struct mg_connection *nc,
union socket_address *sa) {
sock_t sock = mg_open_listening_socket(nc, sa, SOCK_DGRAM, 0); sock_t sock = mg_open_listening_socket(nc, sa, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET) return (errno ? errno : 1); if (sock == INVALID_SOCKET) return (errno ? errno : 1);
mg_sock_set(nc, sock); mg_sock_set(nc, sock);
return 0; return 0;
} }
void mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) { static int mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf,
mbuf_append(&nc->send_mbuf, buf, len); size_t len) {
int n = (int) sl_Send(nc->sock, buf, len, 0);
if (n < 0 && !mg_is_error(n)) n = 0;
return n;
} }
void mg_sl_if_udp_send(struct mg_connection *nc, const void *buf, size_t len) { static int mg_sl_if_udp_send(struct mg_connection *nc, const void *buf,
mbuf_append(&nc->send_mbuf, buf, len); size_t len) {
int n = sl_SendTo(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
if (n < 0 && !mg_is_error(n)) n = 0;
return n;
} }
void mg_sl_if_recved(struct mg_connection *nc, size_t len) { static int mg_sl_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len) {
(void) nc; int n = sl_Recv(nc->sock, buf, len, 0);
(void) len; if (n == 0) {
/* Orderly shutdown of the socket, try flushing output. */
nc->flags |= MG_F_SEND_AND_CLOSE;
} else if (n < 0 && !mg_is_error(n)) {
n = 0;
}
return n;
} }
int mg_sl_if_create_conn(struct mg_connection *nc) { static int mg_sl_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
union socket_address *sa, size_t *sa_len) {
SlSocklen_t sa_len_t = *sa_len;
int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0,
(SlSockAddr_t *) sa, &sa_len_t);
*sa_len = sa_len_t;
if (n < 0 && !mg_is_error(n)) n = 0;
return n;
}
static int mg_sl_if_create_conn(struct mg_connection *nc) {
(void) nc; (void) nc;
return 1; return 1;
} }
@@ -121,7 +159,6 @@ static int mg_accept_conn(struct mg_connection *lc) {
DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr), DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
ntohs(sa.sin.sin_port))); ntohs(sa.sin.sin_port)));
mg_sock_set(nc, sock); mg_sock_set(nc, sock);
if (nc->flags & MG_F_SSL) nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
mg_if_accept_tcp_cb(nc, &sa, sa_len); mg_if_accept_tcp_cb(nc, &sa, sa_len);
return 1; return 1;
} }
@@ -135,11 +172,11 @@ static sock_t mg_open_listening_socket(struct mg_connection *nc,
(sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6); (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
sock_t sock = sl_Socket(sa->sa.sa_family, type, proto); sock_t sock = sl_Socket(sa->sa.sa_family, type, proto);
if (sock < 0) return sock; if (sock < 0) return sock;
#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean;
#endif
if ((r = sl_Bind(sock, &sa->sa, sa_len)) < 0) goto clean; if ((r = sl_Bind(sock, &sa->sa, sa_len)) < 0) goto clean;
if (type != SOCK_DGRAM) { if (type != SOCK_DGRAM) {
#if MG_ENABLE_SSL
if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean;
#endif
if ((r = sl_Listen(sock, SOMAXCONN)) < 0) goto clean; if ((r = sl_Listen(sock, SOMAXCONN)) < 0) goto clean;
} }
mg_set_non_blocking_mode(sock); mg_set_non_blocking_mode(sock);
@@ -151,86 +188,18 @@ clean:
return sock; return sock;
} }
static void mg_write_to_socket(struct mg_connection *nc) {
struct mbuf *io = &nc->send_mbuf;
int n = 0;
if (nc->flags & MG_F_UDP) {
n = sl_SendTo(nc->sock, io->buf, io->len, 0, &nc->sa.sa,
sizeof(nc->sa.sin));
DBG(("%p %d %d %d %s:%hu", nc, nc->sock, n, errno,
inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port)));
} else {
n = (int) sl_Send(nc->sock, io->buf, io->len, 0);
DBG(("%p %d bytes -> %d", nc, n, nc->sock));
}
if (n > 0) {
mg_if_sent_cb(nc, n);
} else if (n < 0 && mg_is_error(n)) {
/* Something went wrong, drop the connection. */
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
}
MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) {
size_t avail;
if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0;
avail = conn->recv_mbuf_limit - conn->recv_mbuf.len;
return avail > max ? max : avail;
}
static void mg_handle_tcp_read(struct mg_connection *conn) {
int n = 0;
char *buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE);
if (buf == NULL) {
DBG(("OOM"));
return;
}
n = (int) sl_Recv(conn->sock, buf,
recv_avail_size(conn, MG_TCP_RECV_BUFFER_SIZE), 0);
DBG(("%p %d bytes <- %d", conn, n, conn->sock));
if (n > 0) {
mg_if_recv_tcp_cb(conn, buf, n, 1 /* own */);
} else {
MG_FREE(buf);
}
if (n == 0) {
/* Orderly shutdown of the socket, try flushing output. */
conn->flags |= MG_F_SEND_AND_CLOSE;
} else if (mg_is_error(n)) {
conn->flags |= MG_F_CLOSE_IMMEDIATELY;
}
}
static void mg_handle_udp_read(struct mg_connection *nc) {
char *buf = (char *) MG_MALLOC(MG_UDP_RECV_BUFFER_SIZE);
if (buf == NULL) return;
union socket_address sa;
socklen_t sa_len = sizeof(sa);
int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0,
(SlSockAddr_t *) &sa, &sa_len);
DBG(("%p %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
ntohs(nc->sa.sin.sin_port)));
if (n > 0) {
mg_if_recv_udp_cb(nc, buf, n, &sa, sa_len);
} else {
MG_FREE(buf);
}
}
#define _MG_F_FD_CAN_READ 1 #define _MG_F_FD_CAN_READ 1
#define _MG_F_FD_CAN_WRITE 1 << 1 #define _MG_F_FD_CAN_WRITE 1 << 1
#define _MG_F_FD_ERROR 1 << 2 #define _MG_F_FD_ERROR 1 << 2
void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
DBG(("%p fd=%d fd_flags=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
if (!mg_if_poll(nc, now)) return;
if (nc->flags & MG_F_CONNECTING) { if (nc->flags & MG_F_CONNECTING) {
if (nc->flags & MG_F_UDP || nc->err != SL_ERROR_BSD_EALREADY) { if ((nc->flags & MG_F_UDP) || nc->err != SL_ERROR_BSD_EALREADY) {
mg_if_connect_cb(nc, nc->err); mg_if_connect_cb(nc, nc->err);
} else { } else {
/* In SimpleLink, to get status of non-blocking connect() we need to wait /* In SimpleLink, to get status of non-blocking connect() we need to wait
@@ -252,9 +221,6 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
) { ) {
nc->err = 0; nc->err = 0;
} }
if (nc->flags & MG_F_SSL && nc->err == 0) {
nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
}
mg_if_connect_cb(nc, nc->err); mg_if_connect_cb(nc, nc->err);
} }
} }
@@ -264,28 +230,21 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
if (fd_flags & _MG_F_FD_CAN_READ) { if (fd_flags & _MG_F_FD_CAN_READ) {
if (nc->flags & MG_F_UDP) { if (nc->flags & MG_F_UDP) {
mg_handle_udp_read(nc); mg_if_can_recv_cb(nc);
} else { } else {
if (nc->flags & MG_F_LISTENING) { if (nc->flags & MG_F_LISTENING) {
mg_accept_conn(nc); mg_accept_conn(nc);
} else { } else {
mg_handle_tcp_read(nc); mg_if_can_recv_cb(nc);
} }
} }
} }
if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { if (fd_flags & _MG_F_FD_CAN_WRITE) {
if ((fd_flags & _MG_F_FD_CAN_WRITE) && nc->send_mbuf.len > 0) { mg_if_can_send_cb(nc);
mg_write_to_socket(nc);
}
if (!(fd_flags & (_MG_F_FD_CAN_READ | _MG_F_FD_CAN_WRITE))) {
mg_if_poll(nc, now);
}
mg_if_timer(nc, now);
} }
DBG(("%p after fd=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, nc->flags, DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, nc->flags,
(int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
} }
@@ -406,14 +365,6 @@ time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) {
mg_mgr_handle_conn(nc, fd_flags, now); mg_mgr_handle_conn(nc, fd_flags, now);
} }
for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
tmp = nc->next;
if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
(nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) {
mg_close_conn(nc);
}
}
return now; return now;
} }
@@ -464,7 +415,8 @@ void sl_restart_cb(struct mg_mgr *mgr) {
mg_sl_if_connect_udp, \ mg_sl_if_connect_udp, \
mg_sl_if_tcp_send, \ mg_sl_if_tcp_send, \
mg_sl_if_udp_send, \ mg_sl_if_udp_send, \
mg_sl_if_recved, \ mg_sl_if_tcp_recv, \
mg_sl_if_udp_recv, \
mg_sl_if_create_conn, \ mg_sl_if_create_conn, \
mg_sl_if_destroy_conn, \ mg_sl_if_destroy_conn, \
mg_sl_if_sock_set, \ mg_sl_if_sock_set, \
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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_PLATFORMS_SIMPLELINK_SL_NET_IF_H_ #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#if MG_NET_IF == MG_NET_IF_SIMPLELINK #if MG_NET_IF == MG_NET_IF_SIMPLELINK
+83 -43
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
@@ -54,6 +66,31 @@ enum mg_ssl_if_result mg_ssl_if_conn_init(
return MG_SSL_OK; return MG_SSL_OK;
} }
enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc,
struct mg_connection *lc) {
/* SimpleLink does everything for us, nothing for us to do. */
(void) nc;
(void) lc;
return MG_SSL_OK;
}
enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
/* SimpleLink has already performed the handshake, nothing to do. */
return MG_SSL_OK;
}
int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
/* SimpelLink handles TLS, so this is just a pass-through. */
int n = nc->iface->vtable->tcp_recv(nc, buf, len);
if (n == 0) nc->flags |= MG_F_WANT_READ;
return n;
}
int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
/* SimpelLink handles TLS, so this is just a pass-through. */
return nc->iface->vtable->tcp_send(nc, buf, len);
}
void mg_ssl_if_conn_close_notify(struct mg_connection *nc) { void mg_ssl_if_conn_close_notify(struct mg_connection *nc) {
/* Nothing to do */ /* Nothing to do */
(void) nc; (void) nc;
@@ -154,56 +191,59 @@ int sl_set_ssl_opts(int sock, struct mg_connection *nc) {
const struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; const struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
DBG(("%p ssl ctx: %p", nc, ctx)); DBG(("%p ssl ctx: %p", nc, ctx));
if (ctx != NULL) { if (ctx == NULL) return 0;
DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"), DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"),
(ctx->ssl_key ? ctx->ssl_cert : "-"), (ctx->ssl_key ? ctx->ssl_cert : "-"),
(ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"), (ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"),
(ctx->ssl_server_name ? ctx->ssl_server_name : "-"))); (ctx->ssl_server_name ? ctx->ssl_server_name : "-")));
if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) { if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) {
char *ssl_cert = sl_pem2der(ctx->ssl_cert); char *ssl_cert = sl_pem2der(ctx->ssl_cert), *ssl_key = NULL;
char *ssl_key = sl_pem2der(ctx->ssl_key); if (ssl_cert != NULL) {
if (ssl_cert != NULL && ssl_key != NULL) { err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
err = sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert,
SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert, strlen(ssl_cert));
strlen(ssl_cert)); MG_FREE(ssl_cert);
LOG(LL_INFO, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err)); LOG(LL_DEBUG, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err));
ssl_key = sl_pem2der(ctx->ssl_key);
if (ssl_key != NULL) {
err = sl_SetSockOpt(sock, SL_SOL_SOCKET, err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, ssl_key, SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, ssl_key,
strlen(ssl_key)); strlen(ssl_key));
LOG(LL_INFO, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err)); MG_FREE(ssl_key);
LOG(LL_DEBUG, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err));
} else { } else {
err = -1; err = -1;
} }
MG_FREE(ssl_cert); } else {
MG_FREE(ssl_key); err = -1;
}
if (err != 0) return err;
}
if (ctx->ssl_ca_cert != NULL) {
if (ctx->ssl_ca_cert[0] != '\0') {
char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert);
if (ssl_ca_cert != NULL) {
err =
sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME,
ssl_ca_cert, strlen(ssl_ca_cert));
LOG(LL_DEBUG, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err));
} else {
err = -1;
}
MG_FREE(ssl_ca_cert);
if (err != 0) return err; if (err != 0) return err;
} }
if (ctx->ssl_ca_cert != NULL) { }
if (ctx->ssl_ca_cert[0] != '\0') { if (ctx->ssl_server_name != NULL) {
char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert); err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
if (ssl_ca_cert != NULL) { SL_SO_SECURE_DOMAIN_NAME_VERIFICATION,
err = sl_SetSockOpt(sock, SL_SOL_SOCKET, ctx->ssl_server_name, strlen(ctx->ssl_server_name));
SL_SO_SECURE_FILES_CA_FILE_NAME, ssl_ca_cert, DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err));
strlen(ssl_ca_cert)); /* Domain name verificationw as added in a NWP service pack, older
LOG(LL_INFO, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err)); * versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do
} else { * about it,
err = -1; * so we ignore the error. */
} if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err;
MG_FREE(ssl_ca_cert);
if (err != 0) return err;
}
}
if (ctx->ssl_server_name != NULL) {
err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
SL_SO_SECURE_DOMAIN_NAME_VERIFICATION,
ctx->ssl_server_name, strlen(ctx->ssl_server_name));
DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err));
/* Domain name verificationw as added in a NWP service pack, older
* versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do
* about it,
* so we ignore the error. */
if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err;
}
} }
return 0; return 0;
} }
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* Copyright (c) 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.
*/ */
#ifdef WINCE #ifdef WINCE
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* Copyright (c) 2017 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.
*/ */
#ifdef _WIN32 #ifdef _WIN32
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2014-2018 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.
*/
#include "common/cs_dbg.h"
#include "common/test_main.h"
#include "common/test_util.h"
#if defined(_MSC_VER) && _MSC_VER >= 1900
#include <crtdbg.h>
int __cdecl CrtDbgHook(int nReportType, char *szMsg, int *pnRet) {
(void) nReportType;
(void) szMsg;
(void) pnRet;
fprintf(stderr, "CRT debug hook: type: %d, msg: %s\n", nReportType, szMsg);
/* Return true - Abort,Retry,Ignore dialog will *not* be displayed */
return 1;
}
#endif
#ifndef __cdecl
#define __cdecl
#endif
int g_num_tests = 0;
int g_num_checks = 0;
const char *g_argv_0 = NULL;
int __cdecl main(int argc, char *argv[]) {
const char *fail_msg;
const char *filter = argc > 1 ? argv[1] : "";
char *seed_str = getenv("TEST_SEED");
double started;
int seed = 0;
if (seed_str != NULL) {
seed = atoi(seed_str);
} else {
seed = (int) time(NULL);
}
printf("seed: %d\n", seed);
srand(seed);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
#if defined(_MSC_VER) && _MSC_VER >= 1900
/* NOTE: not available on wine/vc6 */
_CrtSetReportHook2(_CRT_RPTHOOK_INSTALL, CrtDbgHook);
#endif
g_argv_0 = argv[0];
tests_setup();
started = cs_time();
fail_msg = tests_run(filter);
printf("%s, ran %d tests (%d checks) in %.3lfs\n", fail_msg ? "FAIL" : "PASS",
g_num_tests, g_num_checks, cs_time() - started);
tests_teardown();
if (fail_msg != NULL) {
/* Prevent leak analyzer from running: there will be "leaks" because of
* premature return from the test, and in this case we don't care. */
_exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2014-2018 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.
*/
#ifndef CS_COMMON_TEST_MAIN_H_
#define CS_COMMON_TEST_MAIN_H_
#ifdef __cplusplus
extern "C" {
#endif
void tests_setup(void);
const char *tests_run(const char *filter);
void tests_teardown(void);
extern const char *g_argv_0;
#ifdef __cplusplus
}
#endif
#endif /* CS_COMMON_TEST_MAIN_H_ */
+13 -1
View File
@@ -1,6 +1,18 @@
/* /*
* 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.
*/ */
#include "common/test_util.h" #include "common/test_util.h"
+110 -52
View File
@@ -1,18 +1,18 @@
/* /*
* Copyright (c) 2015 Cesanta Software Limited * Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved * 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 * Licensed under the Apache License, Version 2.0 (the ""License"");
* Public License, but WITHOUT ANY WARRANTY; without even the implied * you may not use this file except in compliance with the License.
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * You may obtain a copy of the License at
* See the GNU General Public License for more details.
* *
* Alternatively, you can license this software under a commercial * http://www.apache.org/licenses/LICENSE-2.0
* license, as set out in <https://www.cesanta.com/license>. *
* 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_TEST_UTIL_H_ #ifndef CS_COMMON_TEST_UTIL_H_
@@ -28,6 +28,7 @@ extern "C" {
#endif #endif
extern int g_num_tests; extern int g_num_tests;
extern int g_num_checks;
#ifdef MG_TEST_ABORT_ON_FAIL #ifdef MG_TEST_ABORT_ON_FAIL
#define MG_TEST_ABORT abort() #define MG_TEST_ABORT abort()
@@ -48,7 +49,7 @@ void _strfail(const char *a, const char *e, int len);
#define ASSERT(expr) \ #define ASSERT(expr) \
do { \ do { \
g_num_tests++; \ g_num_checks++; \
if (!(expr)) FAIL(#expr, __LINE__); \ if (!(expr)) FAIL(#expr, __LINE__); \
} while (0) } while (0)
#define ASSERT_TRUE(expr) ASSERT(expr) #define ASSERT_TRUE(expr) ASSERT(expr)
@@ -71,55 +72,108 @@ void _strfail(const char *a, const char *e, int len);
elapsed = cs_time() - elapsed; \ elapsed = cs_time() - elapsed; \
printf(" [%.3f] %s\n", elapsed, test_name); \ printf(" [%.3f] %s\n", elapsed, test_name); \
fflush(stdout); \ fflush(stdout); \
g_num_tests++; \
} \ } \
if (msg) return msg; \ if (msg) return msg; \
} while (0) } while (0)
/* VC6 doesn't know how to cast an unsigned 64-bit int to double */ /* VC6 doesn't have long long. */
#if (defined(_MSC_VER) && _MSC_VER <= 1200) #if (defined(_MSC_VER) && _MSC_VER <= 1200)
#define AS_DOUBLE(d) (double)(int64_t)(d) #define LONG_TYPE int64_t
#else #else
#define AS_DOUBLE(d) (double)(d) #define LONG_TYPE long long
#endif #endif
#define AS_DOUBLE(d) (double)(d)
#define RANGE_CHECK(x) (fabs(x) > 4503599627370496.0 /* 2 << 51 */)
/* /*
* Numeric equality assertion. Comparison is made in native types but for * Numeric equality assertion.
* printing both are convetrted to double. * Args are cast to double to ensure aruemnts are only evaluated once.
* This will work fine for all integer types except large 64-bit values.
*/ */
#define ASSERT_EQ(actual, expected) \ #define ASSERT_EQ(actual, expected) \
do { \ do { \
g_num_tests++; \ const double ad = AS_DOUBLE(actual); \
if (!((actual) == (expected))) { \ const double ed = AS_DOUBLE(expected); \
printf("%f != %f\n", AS_DOUBLE(actual), AS_DOUBLE(expected)); \ if (RANGE_CHECK(ad) || RANGE_CHECK(ed)) { \
FAIL(#actual " == " #expected, __LINE__); \ FAIL("loss of precision, use ASSERT_EQ64", __LINE__); \
} \ } \
g_num_checks++; \
if (!(ad == ed)) { \
printf("%lf != %lf\n", ad, ed); \
FAIL(#actual " != " #expected, __LINE__); \
} \
} while (0)
#define ASSERT_EQ64(actual, expected) \
do { \
const LONG_TYPE a64 = (LONG_TYPE)(actual); \
const LONG_TYPE e64 = (LONG_TYPE)(expected); \
g_num_checks++; \
if (!(a64 == e64)) { \
printf("%lld != %lld\n", a64, e64); \
FAIL(#actual " != " #expected, __LINE__); \
} \
} while (0)
#define ASSERT_NE(actual, expected) \
do { \
const double ad = AS_DOUBLE(actual); \
const double ed = AS_DOUBLE(expected); \
g_num_checks++; \
if (RANGE_CHECK(ad) || RANGE_CHECK(ed)) { \
FAIL("loss of precision, use ASSERT_NE64", __LINE__); \
} \
if (!(ad != ed)) { \
printf("%lf == %lf\n", ad, ed); \
FAIL(#actual " == " #expected, __LINE__); \
} \
} while (0)
#define ASSERT_NE64(actual, expected) \
do { \
const LONG_TYPE a64 = (LONG_TYPE)(actual); \
const LONG_TYPE e64 = (LONG_TYPE)(expected); \
g_num_checks++; \
if (!(a64 != e64)) { \
printf("%lld == %lld\n", a64, e64); \
FAIL(#actual " == " #expected, __LINE__); \
} \
} while (0) } while (0)
/* "Less than" assertion. */ /* "Less than" assertion. */
#define ASSERT_LT(a, b) \ #define ASSERT_LT(a, b) \
do { \ do { \
g_num_tests++; \ const double ad = AS_DOUBLE(a); \
if (!((a) < (b))) { \ const double bd = AS_DOUBLE(b); \
printf("%f >= %f\n", AS_DOUBLE(a), AS_DOUBLE(b)); \ g_num_checks++; \
FAIL(#a " < " #b, __LINE__); \ if (RANGE_CHECK(ad) || RANGE_CHECK(bd)) { \
} \ FAIL("loss of precision in comparison", __LINE__); \
} \
if (!(ad < bd)) { \
printf("%lf >= %lf\n", ad, bd); \
FAIL(#a " < " #b, __LINE__); \
} \
} while (0) } while (0)
/* "Greater than" assertion. */ /* "Greater than" assertion. */
#define ASSERT_GT(a, b) \ #define ASSERT_GT(a, b) \
do { \ do { \
g_num_tests++; \ const double ad = AS_DOUBLE(a); \
if (!((a) > (b))) { \ const double bd = AS_DOUBLE(b); \
printf("%f <= %f\n", AS_DOUBLE(a), AS_DOUBLE(b)); \ g_num_checks++; \
FAIL(#a " > " #b, __LINE__); \ if (!(ad > bd)) { \
} \ printf("%lf <= %lf\n", ad, bd); \
FAIL(#a " > " #b, __LINE__); \
} \
} while (0) } while (0)
/* Assert that actual == expected, where both are NUL-terminated. */ /* Assert that actual == expected, where both are NUL-terminated. */
#define ASSERT_STREQ(actual, expected) \ #define ASSERT_STREQ(actual, expected) \
do { \ do { \
g_num_tests++; \ g_num_checks++; \
if (!_assert_streq(actual, expected)) { \ if (!_assert_streq((actual), (expected))) { \
FAIL("ASSERT_STREQ(" #actual ", " #expected ")", __LINE__); \ FAIL("ASSERT_STREQ(" #actual ", " #expected ")", __LINE__); \
} \ } \
} while (0) } while (0)
@@ -127,27 +181,31 @@ void _strfail(const char *a, const char *e, int len);
/* Assert that actual == expected, where both are pointers */ /* Assert that actual == expected, where both are pointers */
#define ASSERT_PTREQ(actual, expected) \ #define ASSERT_PTREQ(actual, expected) \
do { \ do { \
g_num_tests++; \ const void *ap = (const void *) (actual); \
if (actual != expected) { \ const void *ep = (const void *) (expected); \
printf("%p != %p\n", actual, expected); \ g_num_checks++; \
if (!(ap == ep)) { \
printf("%p != %p\n", ap, ep); \
FAIL("ASSERT_PTREQ(" #actual ", " #expected ")", __LINE__); \ FAIL("ASSERT_PTREQ(" #actual ", " #expected ")", __LINE__); \
} \ } \
} while (0) } while (0)
/* Assert that actual != expected, where both are pointers */ /* Assert that actual != expected, where both are pointers */
#define ASSERT_PTRNEQ(actual, expected) \ #define ASSERT_PTRNE(actual, expected) \
do { \ do { \
g_num_tests++; \ const void *ap = (const void *) (actual); \
if (actual == expected) { \ const void *ep = (const void *) (expected); \
printf("%p == %p\n", actual, expected); \ g_num_checks++; \
FAIL("ASSERT_PTRNEQ(" #actual ", " #expected ")", __LINE__); \ if (!(ap != ep)) { \
} \ printf("%p == %p\n", ap, ep); \
FAIL("ASSERT_PTRNE(" #actual ", " #expected ")", __LINE__); \
} \
} while (0) } while (0)
/* Same as STREQ, but only expected is NUL-terminated. */ /* Same as STREQ, but only expected is NUL-terminated. */
#define ASSERT_STREQ_NZ(actual, expected) \ #define ASSERT_STREQ_NZ(actual, expected) \
do { \ do { \
g_num_tests++; \ g_num_checks++; \
if (!_assert_streq_nz(actual, expected)) { \ if (!_assert_streq_nz(actual, expected)) { \
FAIL("ASSERT_STREQ_NZ(" #actual ", " #expected ")", __LINE__); \ FAIL("ASSERT_STREQ_NZ(" #actual ", " #expected ")", __LINE__); \
} \ } \
@@ -155,7 +213,7 @@ void _strfail(const char *a, const char *e, int len);
#define ASSERT_MG_STREQ(actual, expected) \ #define ASSERT_MG_STREQ(actual, expected) \
do { \ do { \
g_num_tests++; \ g_num_checks++; \
if ((actual).len != strlen(expected) || \ if ((actual).len != strlen(expected) || \
memcmp((actual).p, expected, (actual).len) != 0) { \ memcmp((actual).p, expected, (actual).len) != 0) { \
printf("'%.*s' (%d) != '%s'\n", (int)(actual).len, (actual).p, \ printf("'%.*s' (%d) != '%s'\n", (int)(actual).len, (actual).p, \
+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.11" #define MG_VERSION "6.12"
/* 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
+36 -45
View File
@@ -127,7 +127,6 @@ enum mg_http_multipart_stream_state {
MPS_BEGIN, MPS_BEGIN,
MPS_WAITING_FOR_BOUNDARY, MPS_WAITING_FOR_BOUNDARY,
MPS_WAITING_FOR_CHUNK, MPS_WAITING_FOR_CHUNK,
MPS_GOT_CHUNK,
MPS_GOT_BOUNDARY, MPS_GOT_BOUNDARY,
MPS_FINALIZE, MPS_FINALIZE,
MPS_FINISHED MPS_FINISHED
@@ -139,7 +138,6 @@ struct mg_http_multipart_stream {
const char *var_name; const char *var_name;
const char *file_name; const char *file_name;
void *user_data; void *user_data;
int prev_io_len;
enum mg_http_multipart_stream_state state; enum mg_http_multipart_stream_state state;
int processing_part; int processing_part;
}; };
@@ -787,6 +785,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
} }
#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
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);
if (req_len > 0 && if (req_len > 0 &&
@@ -880,7 +879,10 @@ void mg_http_handler(struct mg_connection *nc, int ev,
/* Whole HTTP message is fully buffered, call event handler */ /* Whole HTTP message is fully buffered, call event handler */
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 = 0; pd->rcvd -= hm->message.len;
if (io->len > 0) {
goto again;
}
} }
} }
} }
@@ -971,19 +973,6 @@ static void mg_http_multipart_call_handler(struct mg_connection *c, int ev,
pd->mp_stream.user_data = mp.user_data; pd->mp_stream.user_data = mp.user_data;
} }
static int mg_http_multipart_got_chunk(struct mg_connection *c) {
struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
struct mbuf *io = &c->recv_mbuf;
mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf,
pd->mp_stream.prev_io_len);
mbuf_remove(io, pd->mp_stream.prev_io_len);
pd->mp_stream.prev_io_len = 0;
pd->mp_stream.state = MPS_WAITING_FOR_CHUNK;
return 0;
}
static int mg_http_multipart_finalize(struct mg_connection *c) { static int mg_http_multipart_finalize(struct mg_connection *c) {
struct mg_http_proto_data *pd = mg_http_get_proto_data(c); struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
@@ -1118,19 +1107,18 @@ 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 && pd->mp_stream.prev_io_len == 0) { if (boundary == NULL) {
pd->mp_stream.prev_io_len = io->len; int data_size = (io->len - (pd->mp_stream.boundary_len + 6));
if (data_size > 0) {
mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf,
data_size);
mbuf_remove(io, data_size);
}
return 0; return 0;
} else if (boundary == NULL &&
(int) io->len >
pd->mp_stream.prev_io_len + pd->mp_stream.boundary_len + 4) {
pd->mp_stream.state = MPS_GOT_CHUNK;
return 1;
} else if (boundary != NULL) { } else if (boundary != NULL) {
int data_size = (boundary - io->buf - 4); int data_size = (boundary - io->buf - 4);
mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, data_size); mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, data_size);
mbuf_remove(io, (boundary - io->buf)); mbuf_remove(io, (boundary - io->buf));
pd->mp_stream.prev_io_len = 0;
pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY; pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
return 1; return 1;
} else { } else {
@@ -1164,12 +1152,6 @@ static void mg_http_multipart_continue(struct mg_connection *c) {
} }
break; break;
} }
case MPS_GOT_CHUNK: {
if (mg_http_multipart_got_chunk(c) == 0) {
return;
}
break;
}
case MPS_FINALIZE: { case MPS_FINALIZE: {
if (mg_http_multipart_finalize(c) == 0) { if (mg_http_multipart_finalize(c) == 0) {
return; return;
@@ -1177,7 +1159,6 @@ static void mg_http_multipart_continue(struct mg_connection *c) {
break; break;
} }
case MPS_FINISHED: { case MPS_FINISHED: {
mbuf_remove(&c->recv_mbuf, c->recv_mbuf.len);
return; return;
} }
} }
@@ -1329,8 +1310,11 @@ const char *mg_status_message(int status_code) {
void mg_send_response_line_s(struct mg_connection *nc, int status_code, void mg_send_response_line_s(struct mg_connection *nc, int status_code,
const struct mg_str extra_headers) { const struct mg_str extra_headers) {
mg_printf(nc, "HTTP/1.1 %d %s\r\nServer: %s\r\n", status_code, mg_printf(nc, "HTTP/1.1 %d %s\r\n", status_code,
mg_status_message(status_code), mg_version_header); mg_status_message(status_code));
#ifndef MG_HIDE_SERVER_INFO
mg_printf(nc, "Server: %s\r\n", mg_version_header);
#endif
if (extra_headers.len > 0) { if (extra_headers.len > 0) {
mg_printf(nc, "%.*s\r\n", (int) extra_headers.len, extra_headers.p); mg_printf(nc, "%.*s\r\n", (int) extra_headers.len, extra_headers.p);
} }
@@ -1662,7 +1646,7 @@ void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...) {
static void mg_http_parse_header_internal(struct mg_str *hdr, static void mg_http_parse_header_internal(struct mg_str *hdr,
const char *var_name, const char *var_name,
struct altbuf *ab) { struct altbuf *ab) {
int ch = ' ', ch1 = ',', n = strlen(var_name); int ch = ' ', ch1 = ',', ch2 = ';', n = strlen(var_name);
const char *p, *end = hdr ? hdr->p + hdr->len : NULL, *s = NULL; const char *p, *end = hdr ? hdr->p + hdr->len : NULL, *s = NULL;
/* Find where variable starts */ /* Find where variable starts */
@@ -1675,10 +1659,10 @@ static void mg_http_parse_header_internal(struct mg_str *hdr,
if (s != NULL && &s[n + 1] < end) { if (s != NULL && &s[n + 1] < end) {
s += n + 1; s += n + 1;
if (*s == '"' || *s == '\'') { if (*s == '"' || *s == '\'') {
ch = ch1 = *s++; ch = ch1 = ch2 = *s++;
} }
p = s; p = s;
while (p < end && p[0] != ch && p[0] != ch1) { while (p < end && p[0] != ch && p[0] != ch1 && p[0] != ch2) {
if (ch != ' ' && p[0] == '\\' && p[1] == ch) p++; if (ch != ' ' && p[0] == '\\' && p[1] == ch) p++;
altbuf_append(ab, *p++); altbuf_append(ab, *p++);
} }
@@ -2042,7 +2026,7 @@ static void mg_scan_directory(struct mg_connection *nc, const char *dir,
const struct mg_serve_http_opts *opts, const struct mg_serve_http_opts *opts,
void (*func)(struct mg_connection *, const char *, void (*func)(struct mg_connection *, const char *,
cs_stat_t *)) { cs_stat_t *)) {
char path[MG_MAX_PATH]; char path[MG_MAX_PATH + 1];
cs_stat_t st; cs_stat_t st;
struct dirent *dp; struct dirent *dp;
DIR *dirp; DIR *dirp;
@@ -2728,8 +2712,7 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
case MG_EV_HTTP_PART_BEGIN: { case MG_EV_HTTP_PART_BEGIN: {
struct mg_http_multipart_part *mp = struct mg_http_multipart_part *mp =
(struct mg_http_multipart_part *) ev_data; (struct mg_http_multipart_part *) ev_data;
struct file_upload_state *fus = struct file_upload_state *fus;
(struct file_upload_state *) MG_CALLOC(1, sizeof(*fus));
struct mg_str lfn = local_name_fn(nc, mg_mk_str(mp->file_name)); struct mg_str lfn = local_name_fn(nc, mg_mk_str(mp->file_name));
mp->user_data = NULL; mp->user_data = NULL;
if (lfn.p == NULL || lfn.len == 0) { if (lfn.p == NULL || lfn.len == 0) {
@@ -2743,6 +2726,11 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
nc->flags |= MG_F_SEND_AND_CLOSE; nc->flags |= MG_F_SEND_AND_CLOSE;
return; return;
} }
fus = (struct file_upload_state *) MG_CALLOC(1, sizeof(*fus));
if (fus == NULL) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
return;
}
fus->lfn = (char *) MG_MALLOC(lfn.len + 1); fus->lfn = (char *) MG_MALLOC(lfn.len + 1);
memcpy(fus->lfn, lfn.p, lfn.len); memcpy(fus->lfn, lfn.p, lfn.len);
fus->lfn[lfn.len] = '\0'; fus->lfn[lfn.len] = '\0';
@@ -2814,12 +2802,6 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
if (mp->status >= 0 && fus->fp != NULL) { if (mp->status >= 0 && fus->fp != NULL) {
LOG(LL_DEBUG, ("%p Uploaded %s (%s), %d bytes", nc, mp->file_name, LOG(LL_DEBUG, ("%p Uploaded %s (%s), %d bytes", nc, mp->file_name,
fus->lfn, (int) fus->num_recd)); fus->lfn, (int) fus->num_recd));
mg_printf(nc,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n"
"Ok, %s - %d bytes.\r\n",
mp->file_name, (int) fus->num_recd);
} else { } else {
LOG(LL_ERROR, ("Failed to store %s (%s)", mp->file_name, fus->lfn)); LOG(LL_ERROR, ("Failed to store %s (%s)", mp->file_name, fus->lfn));
/* /*
@@ -2831,6 +2813,15 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
MG_FREE(fus->lfn); MG_FREE(fus->lfn);
MG_FREE(fus); MG_FREE(fus);
mp->user_data = NULL; mp->user_data = NULL;
/* Don't close the connection yet, there may be more files to come. */
break;
}
case MG_EV_HTTP_MULTIPART_REQUEST_END: {
mg_printf(nc,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n"
"Ok.\r\n");
nc->flags |= MG_F_SEND_AND_CLOSE; nc->flags |= MG_F_SEND_AND_CLOSE;
break; break;
} }
+2 -3
View File
@@ -478,7 +478,6 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir, if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir,
fds[1]) != 0) { fds[1]) != 0) {
size_t n = nc->recv_mbuf.len - (hm->message.len - hm->body.len);
struct mg_connection *cgi_nc = struct mg_connection *cgi_nc =
mg_add_sock(nc->mgr, fds[0], mg_cgi_ev_handler MG_UD_ARG(nc)); mg_add_sock(nc->mgr, fds[0], mg_cgi_ev_handler MG_UD_ARG(nc));
struct mg_http_proto_data *cgi_pd = mg_http_get_proto_data(nc); struct mg_http_proto_data *cgi_pd = mg_http_get_proto_data(nc);
@@ -488,8 +487,8 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
#endif #endif
nc->flags |= MG_F_HTTP_CGI_PARSE_HEADERS; nc->flags |= MG_F_HTTP_CGI_PARSE_HEADERS;
/* Push POST data to the CGI */ /* Push POST data to the CGI */
if (n > 0 && n < nc->recv_mbuf.len) { if (hm->body.len > 0) {
mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, n); mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, hm->body.len);
} }
mbuf_remove(&nc->recv_mbuf, nc->recv_mbuf.len); mbuf_remove(&nc->recv_mbuf, nc->recv_mbuf.len);
} else { } else {
+2 -2
View File
@@ -64,9 +64,9 @@ int mg_http_parse_header2(struct mg_str *hdr, const char *var_name, char **buf,
int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf, int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
size_t buf_size) size_t buf_size)
#ifdef __GNUC__ #ifdef __GNUC__
__attribute__((deprecated)); __attribute__((deprecated))
#endif #endif
; ;
/* /*
* Gets and parses the Authorization: Basic header * Gets and parses the Authorization: Basic header
+1 -1
View File
@@ -8,6 +8,7 @@ HEADERS = mg_common.h \
$(COMMON)/platforms/platform_esp8266.h \ $(COMMON)/platforms/platform_esp8266.h \
$(COMMON)/platforms/platform_cc3100.h \ $(COMMON)/platforms/platform_cc3100.h \
$(COMMON)/platforms/platform_cc3200.h \ $(COMMON)/platforms/platform_cc3200.h \
$(COMMON)/platforms/platform_cc3220.h \
$(COMMON)/platforms/platform_msp432.h \ $(COMMON)/platforms/platform_msp432.h \
$(COMMON)/platforms/platform_tm4c129.h \ $(COMMON)/platforms/platform_tm4c129.h \
$(COMMON)/platforms/platform_mbed.h \ $(COMMON)/platforms/platform_mbed.h \
@@ -96,7 +97,6 @@ SOURCES = $(COMMON)/mg_mem.h \
$(COMMON)/platforms/lwip/mg_lwip_net_if.h \ $(COMMON)/platforms/lwip/mg_lwip_net_if.h \
$(COMMON)/platforms/lwip/mg_lwip_net_if.c \ $(COMMON)/platforms/lwip/mg_lwip_net_if.c \
$(COMMON)/platforms/lwip/mg_lwip_ev_mgr.c \ $(COMMON)/platforms/lwip/mg_lwip_ev_mgr.c \
$(COMMON)/platforms/lwip/mg_lwip_ssl_if.c \
$(COMMON)/platforms/wince/wince_libc.c \ $(COMMON)/platforms/wince/wince_libc.c \
$(COMMON)/platforms/pic32/pic32_net_if.h \ $(COMMON)/platforms/pic32/pic32_net_if.h \
$(COMMON)/platforms/pic32/pic32_net_if.c \ $(COMMON)/platforms/pic32/pic32_net_if.c \
+109 -82
View File
@@ -228,18 +228,13 @@ void mg_set_protocol_mqtt(struct mg_connection *nc) {
nc->proto_data_destructor = mg_mqtt_proto_data_destructor; nc->proto_data_destructor = mg_mqtt_proto_data_destructor;
} }
static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd, static void mg_send_mqtt_header(struct mg_connection *nc, uint8_t cmd,
uint8_t flags, size_t len) { uint8_t flags, size_t len) {
struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data; struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data;
size_t off = nc->send_mbuf.len - len;
uint8_t header = cmd << 4 | (uint8_t) flags;
uint8_t buf[1 + sizeof(size_t)]; uint8_t buf[1 + sizeof(size_t)];
uint8_t *vlen = &buf[1]; uint8_t *vlen = &buf[1];
assert(nc->send_mbuf.len >= len); buf[0] = (cmd << 4) | flags;
buf[0] = header;
/* mqtt variable length encoding */ /* mqtt variable length encoding */
do { do {
@@ -249,7 +244,7 @@ static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd,
vlen++; vlen++;
} while (len > 0); } while (len > 0);
mbuf_insert(&nc->send_mbuf, off, buf, vlen - buf); mg_send(nc, buf, vlen - buf);
pd->last_control_time = mg_time(); pd->last_control_time = mg_time();
} }
@@ -260,11 +255,16 @@ void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id) {
void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id,
struct mg_send_mqtt_handshake_opts opts) { struct mg_send_mqtt_handshake_opts opts) {
uint16_t hlen, nlen, rem_len = 0;
struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data; struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data;
uint16_t id_len = 0, wt_len = 0, wm_len = 0, user_len = 0, pw_len = 0;
uint16_t netbytes;
size_t total_len;
mg_send(nc, "\00\04MQTT\04", 7); if (client_id != NULL) {
rem_len += 7; id_len = strlen(client_id);
}
total_len = 7 + 1 + 2 + 2 + id_len;
if (opts.user_name != NULL) { if (opts.user_name != NULL) {
opts.flags |= MG_MQTT_HAS_USER_NAME; opts.flags |= MG_MQTT_HAS_USER_NAME;
@@ -273,56 +273,58 @@ void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id,
opts.flags |= MG_MQTT_HAS_PASSWORD; opts.flags |= MG_MQTT_HAS_PASSWORD;
} }
if (opts.will_topic != NULL && opts.will_message != NULL) { if (opts.will_topic != NULL && opts.will_message != NULL) {
wt_len = strlen(opts.will_topic);
wm_len = strlen(opts.will_message);
opts.flags |= MG_MQTT_HAS_WILL; opts.flags |= MG_MQTT_HAS_WILL;
} }
if (opts.keep_alive == 0) { if (opts.keep_alive == 0) {
opts.keep_alive = 60; opts.keep_alive = 60;
} }
if (opts.flags & MG_MQTT_HAS_WILL) {
total_len += 2 + wt_len + 2 + wm_len;
}
if (opts.flags & MG_MQTT_HAS_USER_NAME) {
user_len = strlen(opts.user_name);
total_len += 2 + user_len;
}
if (opts.flags & MG_MQTT_HAS_PASSWORD) {
pw_len = strlen(opts.password);
total_len += 2 + pw_len;
}
mg_send_mqtt_header(nc, MG_MQTT_CMD_CONNECT, 0, total_len);
mg_send(nc, "\00\04MQTT\04", 7);
mg_send(nc, &opts.flags, 1); mg_send(nc, &opts.flags, 1);
rem_len += 1;
nlen = htons(opts.keep_alive); netbytes = htons(opts.keep_alive);
mg_send(nc, &nlen, 2); mg_send(nc, &netbytes, 2);
rem_len += 2;
hlen = strlen(client_id); netbytes = htons(id_len);
nlen = htons((uint16_t) hlen); mg_send(nc, &netbytes, 2);
mg_send(nc, &nlen, 2); mg_send(nc, client_id, id_len);
mg_send(nc, client_id, hlen);
rem_len += 2 + hlen;
if (opts.flags & MG_MQTT_HAS_WILL) { if (opts.flags & MG_MQTT_HAS_WILL) {
hlen = strlen(opts.will_topic); netbytes = htons(wt_len);
nlen = htons((uint16_t) hlen); mg_send(nc, &netbytes, 2);
mg_send(nc, &nlen, 2); mg_send(nc, opts.will_topic, wt_len);
mg_send(nc, opts.will_topic, hlen);
rem_len += 2 + hlen;
hlen = strlen(opts.will_message); netbytes = htons(wm_len);
nlen = htons((uint16_t) hlen); mg_send(nc, &netbytes, 2);
mg_send(nc, &nlen, 2); mg_send(nc, opts.will_message, wm_len);
mg_send(nc, opts.will_message, hlen);
rem_len += 2 + hlen;
} }
if (opts.flags & MG_MQTT_HAS_USER_NAME) { if (opts.flags & MG_MQTT_HAS_USER_NAME) {
hlen = strlen(opts.user_name); netbytes = htons(user_len);
nlen = htons((uint16_t) hlen); mg_send(nc, &netbytes, 2);
mg_send(nc, &nlen, 2); mg_send(nc, opts.user_name, user_len);
mg_send(nc, opts.user_name, hlen);
rem_len += 2 + hlen;
} }
if (opts.flags & MG_MQTT_HAS_PASSWORD) { if (opts.flags & MG_MQTT_HAS_PASSWORD) {
hlen = strlen(opts.password); netbytes = htons(pw_len);
nlen = htons((uint16_t) hlen); mg_send(nc, &netbytes, 2);
mg_send(nc, &nlen, 2); mg_send(nc, opts.password, pw_len);
mg_send(nc, opts.password, hlen);
rem_len += 2 + hlen;
} }
mg_mqtt_prepend_header(nc, MG_MQTT_CMD_CONNECT, 0, rem_len);
if (pd != NULL) { if (pd != NULL) {
pd->keep_alive = opts.keep_alive; pd->keep_alive = opts.keep_alive;
} }
@@ -331,40 +333,52 @@ void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id,
void mg_mqtt_publish(struct mg_connection *nc, const char *topic, void mg_mqtt_publish(struct mg_connection *nc, const char *topic,
uint16_t message_id, int flags, const void *data, uint16_t message_id, int flags, const void *data,
size_t len) { size_t len) {
size_t old_len = nc->send_mbuf.len; uint16_t netbytes;
uint16_t topic_len = strlen(topic);
uint16_t topic_len = htons((uint16_t) strlen(topic)); size_t total_len = 2 + topic_len + len;
uint16_t message_id_net = htons(message_id);
mg_send(nc, &topic_len, 2);
mg_send(nc, topic, strlen(topic));
if (MG_MQTT_GET_QOS(flags) > 0) { if (MG_MQTT_GET_QOS(flags) > 0) {
mg_send(nc, &message_id_net, 2); total_len += 2;
} }
mg_send(nc, data, len);
mg_mqtt_prepend_header(nc, MG_MQTT_CMD_PUBLISH, flags, mg_send_mqtt_header(nc, MG_MQTT_CMD_PUBLISH, flags, total_len);
nc->send_mbuf.len - old_len);
netbytes = htons(topic_len);
mg_send(nc, &netbytes, 2);
mg_send(nc, topic, topic_len);
if (MG_MQTT_GET_QOS(flags) > 0) {
netbytes = htons(message_id);
mg_send(nc, &netbytes, 2);
}
mg_send(nc, data, len);
} }
void mg_mqtt_subscribe(struct mg_connection *nc, void mg_mqtt_subscribe(struct mg_connection *nc,
const struct mg_mqtt_topic_expression *topics, const struct mg_mqtt_topic_expression *topics,
size_t topics_len, uint16_t message_id) { size_t topics_len, uint16_t message_id) {
size_t old_len = nc->send_mbuf.len; uint16_t netbytes;
uint16_t message_id_n = htons(message_id);
size_t i; size_t i;
uint16_t topic_len;
size_t total_len = 2;
mg_send(nc, (char *) &message_id_n, 2);
for (i = 0; i < topics_len; i++) { for (i = 0; i < topics_len; i++) {
uint16_t topic_len_n = htons((uint16_t) strlen(topics[i].topic)); total_len += 2 + strlen(topics[i].topic) + 1;
mg_send(nc, &topic_len_n, 2);
mg_send(nc, topics[i].topic, strlen(topics[i].topic));
mg_send(nc, &topics[i].qos, 1);
} }
mg_mqtt_prepend_header(nc, MG_MQTT_CMD_SUBSCRIBE, MG_MQTT_QOS(1), mg_send_mqtt_header(nc, MG_MQTT_CMD_SUBSCRIBE, MG_MQTT_QOS(1), total_len);
nc->send_mbuf.len - old_len);
netbytes = htons(message_id);
mg_send(nc, (char *) &netbytes, 2);
for (i = 0; i < topics_len; i++) {
topic_len = strlen(topics[i].topic);
netbytes = htons(topic_len);
mg_send(nc, &netbytes, 2);
mg_send(nc, topics[i].topic, topic_len);
mg_send(nc, &topics[i].qos, 1);
}
} }
int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg,
@@ -384,27 +398,33 @@ int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg,
void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics, void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics,
size_t topics_len, uint16_t message_id) { size_t topics_len, uint16_t message_id) {
size_t old_len = nc->send_mbuf.len; uint16_t netbytes;
uint16_t message_id_n = htons(message_id);
size_t i; size_t i;
uint16_t topic_len;
size_t total_len = 2;
mg_send(nc, (char *) &message_id_n, 2);
for (i = 0; i < topics_len; i++) { for (i = 0; i < topics_len; i++) {
uint16_t topic_len_n = htons((uint16_t) strlen(topics[i])); total_len += 2 + strlen(topics[i]);
mg_send(nc, &topic_len_n, 2);
mg_send(nc, topics[i], strlen(topics[i]));
} }
mg_mqtt_prepend_header(nc, MG_MQTT_CMD_UNSUBSCRIBE, MG_MQTT_QOS(1), mg_send_mqtt_header(nc, MG_MQTT_CMD_UNSUBSCRIBE, MG_MQTT_QOS(1), total_len);
nc->send_mbuf.len - old_len);
netbytes = htons(message_id);
mg_send(nc, (char *) &netbytes, 2);
for (i = 0; i < topics_len; i++) {
topic_len = strlen(topics[i]);
netbytes = htons(topic_len);
mg_send(nc, &netbytes, 2);
mg_send(nc, topics[i], topic_len);
}
} }
void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code) { void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code) {
uint8_t unused = 0; uint8_t unused = 0;
mg_send_mqtt_header(nc, MG_MQTT_CMD_CONNACK, 0, 2);
mg_send(nc, &unused, 1); mg_send(nc, &unused, 1);
mg_send(nc, &return_code, 1); mg_send(nc, &return_code, 1);
mg_mqtt_prepend_header(nc, MG_MQTT_CMD_CONNACK, 0, 2);
} }
/* /*
@@ -414,10 +434,13 @@ void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code) {
*/ */
static void mg_send_mqtt_short_command(struct mg_connection *nc, uint8_t cmd, static void mg_send_mqtt_short_command(struct mg_connection *nc, uint8_t cmd,
uint16_t message_id) { uint16_t message_id) {
uint16_t message_id_net = htons(message_id); uint16_t netbytes;
uint8_t flags = (cmd == MG_MQTT_CMD_PUBREL ? 2 : 0); uint8_t flags = (cmd == MG_MQTT_CMD_PUBREL ? 2 : 0);
mg_send(nc, &message_id_net, 2);
mg_mqtt_prepend_header(nc, cmd, flags, 2 /* len */); mg_send_mqtt_header(nc, cmd, flags, 2 /* len */);
netbytes = htons(message_id);
mg_send(nc, &netbytes, 2);
} }
void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id) { void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id) {
@@ -439,12 +462,16 @@ void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id) {
void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len, void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len,
uint16_t message_id) { uint16_t message_id) {
size_t i; size_t i;
uint16_t message_id_net = htons(message_id); uint16_t netbytes;
mg_send(nc, &message_id_net, 2);
mg_send_mqtt_header(nc, MG_MQTT_CMD_SUBACK, MG_MQTT_QOS(1), 2 + qoss_len);
netbytes = htons(message_id);
mg_send(nc, &netbytes, 2);
for (i = 0; i < qoss_len; i++) { for (i = 0; i < qoss_len; i++) {
mg_send(nc, &qoss[i], 1); mg_send(nc, &qoss[i], 1);
} }
mg_mqtt_prepend_header(nc, MG_MQTT_CMD_SUBACK, MG_MQTT_QOS(1), 2 + qoss_len);
} }
void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) { void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) {
@@ -452,15 +479,15 @@ void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) {
} }
void mg_mqtt_ping(struct mg_connection *nc) { void mg_mqtt_ping(struct mg_connection *nc) {
mg_mqtt_prepend_header(nc, MG_MQTT_CMD_PINGREQ, 0, 0); mg_send_mqtt_header(nc, MG_MQTT_CMD_PINGREQ, 0, 0);
} }
void mg_mqtt_pong(struct mg_connection *nc) { void mg_mqtt_pong(struct mg_connection *nc) {
mg_mqtt_prepend_header(nc, MG_MQTT_CMD_PINGRESP, 0, 0); mg_send_mqtt_header(nc, MG_MQTT_CMD_PINGRESP, 0, 0);
} }
void mg_mqtt_disconnect(struct mg_connection *nc) { void mg_mqtt_disconnect(struct mg_connection *nc) {
mg_mqtt_prepend_header(nc, MG_MQTT_CMD_DISCONNECT, 0, 0); mg_send_mqtt_header(nc, MG_MQTT_CMD_DISCONNECT, 0, 0);
} }
#endif /* MG_ENABLE_MQTT */ #endif /* MG_ENABLE_MQTT */
+276 -103
View File
@@ -24,6 +24,13 @@
#define MG_MAX_HOST_LEN 200 #define MG_MAX_HOST_LEN 200
#ifndef MG_TCP_IO_SIZE
#define MG_TCP_IO_SIZE 1460
#endif
#ifndef MG_UDP_IO_SIZE
#define MG_UDP_IO_SIZE 1460
#endif
#define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src) \ #define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src) \
memcpy(dst, src, sizeof(*dst)); memcpy(dst, src, sizeof(*dst));
@@ -64,8 +71,6 @@ MG_INTERNAL void mg_remove_conn(struct mg_connection *conn) {
MG_INTERNAL void mg_call(struct mg_connection *nc, MG_INTERNAL void mg_call(struct mg_connection *nc,
mg_event_handler_t ev_handler, void *user_data, int ev, mg_event_handler_t ev_handler, void *user_data, int ev,
void *ev_data) { void *ev_data) {
static int nesting_level = 0;
nesting_level++;
if (ev_handler == NULL) { if (ev_handler == NULL) {
/* /*
* If protocol handler is specified, call it. Otherwise, call user-specified * If protocol handler is specified, call it. Otherwise, call user-specified
@@ -74,7 +79,7 @@ MG_INTERNAL void mg_call(struct mg_connection *nc,
ev_handler = nc->proto_handler ? nc->proto_handler : nc->handler; ev_handler = nc->proto_handler ? nc->proto_handler : nc->handler;
} }
if (ev != MG_EV_POLL) { if (ev != MG_EV_POLL) {
DBG(("%p %s ev=%d ev_data=%p flags=%lu rmbl=%d smbl=%d", nc, DBG(("%p %s ev=%d ev_data=%p flags=0x%lx rmbl=%d smbl=%d", nc,
ev_handler == nc->handler ? "user" : "proto", ev, ev_data, nc->flags, ev_handler == nc->handler ? "user" : "proto", ev, ev_data, nc->flags,
(int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
} }
@@ -87,33 +92,24 @@ MG_INTERNAL void mg_call(struct mg_connection *nc,
#endif #endif
if (ev_handler != NULL) { if (ev_handler != NULL) {
unsigned long flags_before = nc->flags; unsigned long flags_before = nc->flags;
size_t recv_mbuf_before = nc->recv_mbuf.len, recved;
ev_handler(nc, ev, ev_data MG_UD_ARG(user_data)); ev_handler(nc, ev, ev_data MG_UD_ARG(user_data));
recved = (recv_mbuf_before - nc->recv_mbuf.len);
/* Prevent user handler from fiddling with system flags. */ /* Prevent user handler from fiddling with system flags. */
if (ev_handler == nc->handler && nc->flags != flags_before) { if (ev_handler == nc->handler && nc->flags != flags_before) {
nc->flags = (flags_before & ~_MG_CALLBACK_MODIFIABLE_FLAGS_MASK) | nc->flags = (flags_before & ~_MG_CALLBACK_MODIFIABLE_FLAGS_MASK) |
(nc->flags & _MG_CALLBACK_MODIFIABLE_FLAGS_MASK); (nc->flags & _MG_CALLBACK_MODIFIABLE_FLAGS_MASK);
} }
/* It's important to not double-count recved bytes, and since mg_call can be
* called recursively (e.g. proto_handler invokes user handler), we keep
* track of recursion and only report received bytes at the top level. */
if (nesting_level == 1 && recved > 0 && !(nc->flags & MG_F_UDP)) {
nc->iface->vtable->recved(nc, recved);
}
} }
if (ev != MG_EV_POLL) { if (ev != MG_EV_POLL) {
DBG(("%p after %s flags=%lu 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,
(int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
} }
nesting_level--;
#if !MG_ENABLE_CALLBACK_USERDATA #if !MG_ENABLE_CALLBACK_USERDATA
(void) user_data; (void) user_data;
#endif #endif
} }
void mg_if_timer(struct mg_connection *c, double now) { MG_INTERNAL void mg_timer(struct mg_connection *c, double now) {
if (c->ev_timer_time > 0 && now >= c->ev_timer_time) { if (c->ev_timer_time > 0 && now >= c->ev_timer_time) {
double old_value = c->ev_timer_time; double old_value = c->ev_timer_time;
c->ev_timer_time = 0; c->ev_timer_time = 0;
@@ -121,13 +117,45 @@ void mg_if_timer(struct mg_connection *c, double now) {
} }
} }
void mg_if_poll(struct mg_connection *nc, time_t now) { MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) {
if (!(nc->flags & MG_F_SSL) || (nc->flags & MG_F_SSL_HANDSHAKE_DONE)) { size_t avail;
mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now); if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0;
avail = conn->recv_mbuf_limit - conn->recv_mbuf.len;
return avail > max ? max : avail;
}
static int mg_do_recv(struct mg_connection *nc);
int mg_if_poll(struct mg_connection *nc, double now) {
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;
} }
#if MG_ENABLE_SSL
if ((nc->flags & (MG_F_SSL | MG_F_LISTENING | MG_F_CONNECTING)) == MG_F_SSL) {
/* SSL library may have data to be delivered to the app in its buffers,
* drain them. */
int recved = 0;
do {
if (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE)) break;
if (recv_avail_size(nc, MG_TCP_IO_SIZE) <= 0) break;
recved = mg_do_recv(nc);
} while (recved > 0);
}
#endif /* MG_ENABLE_SSL */
mg_timer(nc, now);
{
time_t now_t = (time_t) now;
mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now_t);
}
return 1;
} }
void mg_destroy_conn(struct mg_connection *conn, int destroy_if) { void mg_destroy_conn(struct mg_connection *conn, int destroy_if) {
if (conn->sock != INVALID_SOCKET) { /* Don't print timer-only conns */
LOG(LL_DEBUG, ("%p 0x%lx %d", conn, conn->flags, destroy_if));
}
if (destroy_if) conn->iface->vtable->destroy_conn(conn); if (destroy_if) conn->iface->vtable->destroy_conn(conn);
if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) { if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) {
conn->proto_data_destructor(conn->proto_data); conn->proto_data_destructor(conn->proto_data);
@@ -143,12 +171,16 @@ 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) {
DBG(("%p %lu %d", conn, conn->flags, conn->sock));
#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);
} }
#endif #endif
/*
* Clearly mark the connection as going away (if not already).
* Some net_if impls (LwIP) need this for cleanly handling half-dead conns.
*/
conn->flags |= MG_F_CLOSE_IMMEDIATELY;
mg_remove_conn(conn); mg_remove_conn(conn);
conn->iface->vtable->destroy_conn(conn); conn->iface->vtable->destroy_conn(conn);
mg_call(conn, NULL, conn->user_data, MG_EV_CLOSE, NULL); mg_call(conn, NULL, conn->user_data, MG_EV_CLOSE, NULL);
@@ -180,15 +212,6 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data,
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
#endif #endif
#if MG_ENABLE_SSL
{
static int init_done;
if (!init_done) {
mg_ssl_if_init();
init_done++;
}
}
#endif
{ {
int i; int i;
if (opts.num_ifaces == 0) { if (opts.num_ifaces == 0) {
@@ -201,7 +224,7 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data,
m->num_ifaces = opts.num_ifaces; m->num_ifaces = opts.num_ifaces;
m->ifaces = m->ifaces =
(struct mg_iface **) MG_MALLOC(sizeof(*m->ifaces) * opts.num_ifaces); (struct mg_iface **) MG_MALLOC(sizeof(*m->ifaces) * opts.num_ifaces);
for (i = 0; i < mg_num_ifaces; i++) { for (i = 0; i < opts.num_ifaces; i++) {
m->ifaces[i] = mg_if_create_iface(opts.ifaces[i], m); m->ifaces[i] = mg_if_create_iface(opts.ifaces[i], m);
m->ifaces[i]->vtable->init(m->ifaces[i]); m->ifaces[i]->vtable->init(m->ifaces[i]);
} }
@@ -211,6 +234,15 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data,
} }
DBG(("==================================")); DBG(("=================================="));
DBG(("init mgr=%p", m)); DBG(("init mgr=%p", m));
#if MG_ENABLE_SSL
{
static int init_done;
if (!init_done) {
mg_ssl_if_init();
init_done++;
}
}
#endif
} }
void mg_mgr_free(struct mg_mgr *m) { void mg_mgr_free(struct mg_mgr *m) {
@@ -453,6 +485,37 @@ MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa,
return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1; return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1;
} }
#if MG_ENABLE_SSL
MG_INTERNAL void mg_ssl_handshake(struct mg_connection *nc) {
int err = 0;
int server_side = (nc->listener != NULL);
enum mg_ssl_if_result res;
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return;
res = mg_ssl_if_handshake(nc);
LOG(LL_DEBUG, ("%p %d res %d", nc, server_side, res));
if (res == MG_SSL_OK) {
nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE);
if (server_side) {
mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
} else {
mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
}
} else if (res == MG_SSL_WANT_READ) {
nc->flags |= MG_F_WANT_READ;
} else if (res == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
} else {
if (!server_side) {
err = res;
mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
}
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
}
#endif /* MG_ENABLE_SSL */
struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) { struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) {
struct mg_add_sock_opts opts; struct mg_add_sock_opts opts;
struct mg_connection *nc; struct mg_connection *nc;
@@ -466,95 +529,125 @@ struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) {
nc->iface = lc->iface; nc->iface = lc->iface;
if (lc->flags & MG_F_SSL) nc->flags |= MG_F_SSL; if (lc->flags & MG_F_SSL) nc->flags |= MG_F_SSL;
mg_add_conn(nc->mgr, nc); mg_add_conn(nc->mgr, nc);
DBG(("%p %p %d %d", lc, nc, nc->sock, (int) nc->flags)); LOG(LL_DEBUG, ("%p %p %d %d", lc, nc, nc->sock, (int) nc->flags));
return nc; return nc;
} }
void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa, void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa,
size_t sa_len) { size_t sa_len) {
(void) sa_len; LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"),
inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
nc->sa = *sa; nc->sa = *sa;
mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa); #if MG_ENABLE_SSL
if (nc->listener->flags & MG_F_SSL) {
nc->flags |= MG_F_SSL;
if (mg_ssl_if_conn_accept(nc, nc->listener) == MG_SSL_OK) {
mg_ssl_handshake(nc);
} else {
mg_close_conn(nc);
}
} else
#endif
{
mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
}
(void) sa_len;
} }
void mg_send(struct mg_connection *nc, const void *buf, int len) { void mg_send(struct mg_connection *nc, const void *buf, int len) {
nc->last_io_time = (time_t) mg_time(); nc->last_io_time = (time_t) mg_time();
mbuf_append(&nc->send_mbuf, buf, len);
}
static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len);
static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len);
static int mg_do_recv(struct mg_connection *nc) {
int res = 0;
char *buf = NULL;
size_t len = (nc->flags & MG_F_UDP ? MG_UDP_IO_SIZE : MG_TCP_IO_SIZE);
if ((nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_CONNECTING)) ||
((nc->flags & MG_F_LISTENING) && !(nc->flags & MG_F_UDP))) {
return -1;
}
len = recv_avail_size(nc, len);
if (len == 0) return -2;
if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) {
mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len);
}
buf = nc->recv_mbuf.buf + nc->recv_mbuf.len;
len = nc->recv_mbuf.size - nc->recv_mbuf.len;
if (nc->flags & MG_F_UDP) { if (nc->flags & MG_F_UDP) {
nc->iface->vtable->udp_send(nc, buf, len); res = mg_recv_udp(nc, buf, len);
} else { } else {
nc->iface->vtable->tcp_send(nc, buf, len); res = mg_recv_tcp(nc, buf, len);
} }
return res;
} }
void mg_if_sent_cb(struct mg_connection *nc, int num_sent) { void mg_if_can_recv_cb(struct mg_connection *nc) {
DBG(("%p %d", nc, num_sent)); mg_do_recv(nc);
#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
if (nc->mgr && nc->mgr->hexdump_file != NULL) {
char *buf = nc->send_mbuf.buf;
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, num_sent, MG_EV_SEND);
}
#endif
if (num_sent < 0) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
} else {
mbuf_remove(&nc->send_mbuf, num_sent);
mbuf_trim(&nc->send_mbuf);
}
mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &num_sent);
} }
MG_INTERNAL void mg_recv_common(struct mg_connection *nc, void *buf, int len, static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) {
int own) { int n = 0;
DBG(("%p %d %u", nc, len, (unsigned int) nc->recv_mbuf.len)); #if MG_ENABLE_SSL
if (nc->flags & MG_F_SSL) {
#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
if (nc->mgr && nc->mgr->hexdump_file != NULL) { n = mg_ssl_if_read(nc, buf, len);
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, len, MG_EV_RECV); DBG(("%p <- %d bytes (SSL)", nc, n));
} if (n < 0) {
#endif if (n == MG_SSL_WANT_READ) {
nc->flags |= MG_F_WANT_READ;
if (nc->flags & MG_F_CLOSE_IMMEDIATELY) { n = 0;
DBG(("%p discarded %d bytes", nc, len)); } else {
/* nc->flags |= MG_F_CLOSE_IMMEDIATELY;
* This connection will not survive next poll. Do not deliver events, }
* send data to /dev/null without acking. } else if (n > 0) {
*/ nc->flags &= ~MG_F_WANT_READ;
if (own) { }
MG_FREE(buf); } else {
mg_ssl_handshake(nc);
} }
return; } else
#endif
{
n = nc->iface->vtable->tcp_recv(nc, buf, len);
DBG(("%p <- %d bytes", nc, n));
} }
nc->last_io_time = (time_t) mg_time(); if (n > 0) {
if (!own) { nc->recv_mbuf.len += n;
mbuf_append(&nc->recv_mbuf, buf, len); nc->last_io_time = (time_t) mg_time();
} else if (nc->recv_mbuf.len == 0) { #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
/* Adopt buf as recv_mbuf's backing store. */ if (nc->mgr && nc->mgr->hexdump_file != NULL) {
mbuf_free(&nc->recv_mbuf); mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
nc->recv_mbuf.buf = (char *) buf; }
nc->recv_mbuf.size = nc->recv_mbuf.len = len; #endif
} else { mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
mbuf_append(&nc->recv_mbuf, buf, len); } else if (n < 0) {
MG_FREE(buf); nc->flags |= MG_F_CLOSE_IMMEDIATELY;
} }
mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &len); return n;
} }
void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own) { static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
mg_recv_common(nc, buf, len, own); int n = 0;
} struct mg_connection *lc = nc;
union socket_address sa;
void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, size_t sa_len = sizeof(sa);
union socket_address *sa, size_t sa_len) { n = nc->iface->vtable->udp_recv(lc, buf, len, &sa, &sa_len);
assert(nc->flags & MG_F_UDP); if (n < 0) {
DBG(("%p %u", nc, (unsigned int) len)); lc->flags |= MG_F_CLOSE_IMMEDIATELY;
goto out;
}
if (nc->flags & MG_F_LISTENING) { if (nc->flags & MG_F_LISTENING) {
struct mg_connection *lc = nc;
/* /*
* Do we have an existing connection for this source? * Do we have an existing connection for this source?
* This is very inefficient for long connection lists. * This is very inefficient for long connection lists.
*/ */
lc = nc;
for (nc = mg_next(lc->mgr, NULL); nc != NULL; nc = mg_next(lc->mgr, nc)) { for (nc = mg_next(lc->mgr, NULL); nc != NULL; nc = mg_next(lc->mgr, nc)) {
if (memcmp(&nc->sa.sa, &sa->sa, sa_len) == 0 && nc->listener == lc) { if (memcmp(&nc->sa.sa, &sa.sa, sa_len) == 0 && nc->listener == lc) {
break; break;
} }
} }
@@ -566,7 +659,7 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
if (nc != NULL) { if (nc != NULL) {
nc->sock = lc->sock; nc->sock = lc->sock;
nc->listener = lc; nc->listener = lc;
nc->sa = *sa; nc->sa = sa;
nc->proto_handler = lc->proto_handler; nc->proto_handler = lc->proto_handler;
nc->user_data = lc->user_data; nc->user_data = lc->user_data;
nc->recv_mbuf_limit = lc->recv_mbuf_limit; nc->recv_mbuf_limit = lc->recv_mbuf_limit;
@@ -585,18 +678,88 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
nc->flags |= MG_F_SEND_AND_CLOSE; nc->flags |= MG_F_SEND_AND_CLOSE;
mg_add_conn(lc->mgr, nc); mg_add_conn(lc->mgr, nc);
mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa); mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
} else {
DBG(("OOM"));
/* No return here, we still need to drop on the floor */
} }
} }
} }
if (nc != NULL) { if (nc != NULL) {
mg_recv_common(nc, buf, len, 1); DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
} else { ntohs(nc->sa.sin.sin_port)));
/* Drop on the floor. */ if (nc == lc) {
MG_FREE(buf); nc->recv_mbuf.len += n;
} else {
mbuf_append(&nc->recv_mbuf, buf, n);
}
mbuf_trim(&lc->recv_mbuf);
lc->last_io_time = nc->last_io_time = (time_t) mg_time();
#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
if (nc->mgr && nc->mgr->hexdump_file != NULL) {
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
}
#endif
mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
} }
out:
mbuf_free(&lc->recv_mbuf);
return n;
}
void mg_if_can_send_cb(struct mg_connection *nc) {
int n = 0;
const char *buf = nc->send_mbuf.buf;
size_t len = nc->send_mbuf.len;
if (nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_CONNECTING)) {
return;
}
if (!(nc->flags & MG_F_UDP)) {
if (nc->flags & MG_F_LISTENING) return;
if (len > MG_TCP_IO_SIZE) len = MG_TCP_IO_SIZE;
}
#if MG_ENABLE_SSL
if (nc->flags & MG_F_SSL) {
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
if (len > 0) {
n = mg_ssl_if_write(nc, buf, len);
DBG(("%p -> %d bytes (SSL)", nc, n));
}
if (n < 0) {
if (n == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
n = 0;
} else {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
} else {
nc->flags &= ~MG_F_WANT_WRITE;
}
} else {
mg_ssl_handshake(nc);
}
} else
#endif
{
if (nc->flags & MG_F_UDP) {
n = nc->iface->vtable->udp_send(nc, buf, len);
} else {
n = nc->iface->vtable->tcp_send(nc, buf, len);
}
DBG(("%p -> %d bytes", nc, n));
}
#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
if (n > 0 && nc->mgr && nc->mgr->hexdump_file != NULL) {
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_SEND);
}
#endif
if (n < 0) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
} else if (n > 0) {
nc->last_io_time = (time_t) mg_time();
mbuf_remove(&nc->send_mbuf, n);
mbuf_trim(&nc->send_mbuf);
}
if (n != 0) mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &n);
} }
/* /*
@@ -608,8 +771,8 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc, MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc,
int proto, int proto,
union socket_address *sa) { union socket_address *sa) {
DBG(("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp", LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp",
inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port))); inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
nc->flags |= MG_F_CONNECTING; nc->flags |= MG_F_CONNECTING;
if (proto == SOCK_DGRAM) { if (proto == SOCK_DGRAM) {
@@ -622,12 +785,21 @@ MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc,
} }
void mg_if_connect_cb(struct mg_connection *nc, int err) { void mg_if_connect_cb(struct mg_connection *nc, int err) {
DBG(("%p connect, err=%d", nc, err)); LOG(LL_DEBUG,
("%p %s://%s:%hu -> %d", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"),
inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port), err));
nc->flags &= ~MG_F_CONNECTING; nc->flags &= ~MG_F_CONNECTING;
if (err != 0) { if (err != 0) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY; nc->flags |= MG_F_CLOSE_IMMEDIATELY;
} }
mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err); #if MG_ENABLE_SSL
if (err == 0 && (nc->flags & MG_F_SSL)) {
mg_ssl_handshake(nc);
} else
#endif
{
mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
}
} }
#if MG_ENABLE_ASYNC_RESOLVER #if MG_ENABLE_ASYNC_RESOLVER
@@ -717,7 +889,8 @@ struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address,
#endif #endif
#if MG_ENABLE_SSL #if MG_ENABLE_SSL
DBG(("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"), LOG(LL_DEBUG,
("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
(opts.ssl_key ? opts.ssl_key : "-"), (opts.ssl_key ? opts.ssl_key : "-"),
(opts.ssl_ca_cert ? opts.ssl_ca_cert : "-"))); (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-")));
@@ -963,7 +1136,7 @@ double mg_set_timer(struct mg_connection *c, double timestamp) {
DBG(("%p %p %d -> %lu", c, c->priv_2, (c->flags & MG_F_RESOLVING ? 1 : 0), DBG(("%p %p %d -> %lu", c, c->priv_2, (c->flags & MG_F_RESOLVING ? 1 : 0),
(unsigned long) timestamp)); (unsigned long) timestamp));
if ((c->flags & MG_F_RESOLVING) && c->priv_2 != NULL) { if ((c->flags & MG_F_RESOLVING) && c->priv_2 != NULL) {
((struct mg_connection *) c->priv_2)->ev_timer_time = timestamp; mg_set_timer((struct mg_connection *) c->priv_2, timestamp);
} }
return result; return result;
} }
+10 -15
View File
@@ -54,10 +54,12 @@ struct mg_iface_vtable {
void (*connect_udp)(struct mg_connection *nc); void (*connect_udp)(struct mg_connection *nc);
/* Send functions for TCP and UDP. Sent data is copied before return. */ /* Send functions for TCP and UDP. Sent data is copied before return. */
void (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len); int (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len);
void (*udp_send)(struct mg_connection *nc, const void *buf, size_t len); int (*udp_send)(struct mg_connection *nc, const void *buf, size_t len);
void (*recved)(struct mg_connection *nc, size_t len); int (*tcp_recv)(struct mg_connection *nc, void *buf, size_t len);
int (*udp_recv)(struct mg_connection *nc, void *buf, size_t len,
union socket_address *sa, size_t *sa_len);
/* Perform interface-related connection initialization. Return 1 on ok. */ /* Perform interface-related connection initialization. Return 1 on ok. */
int (*create_conn)(struct mg_connection *nc); int (*create_conn)(struct mg_connection *nc);
@@ -98,19 +100,15 @@ void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa,
/* Callback invoked by connect methods. err = 0 -> ok, != 0 -> error. */ /* Callback invoked by connect methods. err = 0 -> ok, != 0 -> error. */
void mg_if_connect_cb(struct mg_connection *nc, int err); void mg_if_connect_cb(struct mg_connection *nc, int err);
/* Callback that reports that data has been put on the wire. */
void mg_if_sent_cb(struct mg_connection *nc, int num_sent);
/* /*
* Receive callback. * Callback that tells the core that data can be received.
* if `own` is true, buf must be heap-allocated and ownership is transferred * Core will use tcp/udp_recv to retrieve the data.
* to the core.
* Core will acknowledge consumption by calling iface::recved.
*/ */
void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own); void mg_if_can_recv_cb(struct mg_connection *nc);
void mg_if_can_send_cb(struct mg_connection *nc);
/* /*
* Receive callback. * Receive callback.
* buf must be heap-allocated and ownership is transferred to the core. * buf must be heap-allocated and ownership is transferred to the core.
* Core will acknowledge consumption by calling iface::recved.
*/ */
void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
union socket_address *sa, size_t sa_len); union socket_address *sa, size_t sa_len);
@@ -118,10 +116,7 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
/* void mg_if_close_conn(struct mg_connection *nc); */ /* void mg_if_close_conn(struct mg_connection *nc); */
/* Deliver a POLL event to the connection. */ /* Deliver a POLL event to the connection. */
void mg_if_poll(struct mg_connection *nc, time_t now); int mg_if_poll(struct mg_connection *nc, double now);
/* Deliver a TIMER event to the connection. */
void mg_if_timer(struct mg_connection *c, double now);
#ifdef __cplusplus #ifdef __cplusplus
} }
+54 -221
View File
@@ -9,14 +9,8 @@
#include "mg_internal.h" #include "mg_internal.h"
#include "mg_util.h" #include "mg_util.h"
#define MG_TCP_RECV_BUFFER_SIZE 1024
#define MG_UDP_RECV_BUFFER_SIZE 1500
static sock_t mg_open_listening_socket(union socket_address *sa, int type, static sock_t mg_open_listening_socket(union socket_address *sa, int type,
int proto); int proto);
#if MG_ENABLE_SSL
static void mg_ssl_begin(struct mg_connection *nc);
#endif
void mg_set_non_blocking_mode(sock_t sock) { void mg_set_non_blocking_mode(sock_t sock) {
#ifdef _WIN32 #ifdef _WIN32
@@ -85,27 +79,48 @@ int mg_socket_if_listen_tcp(struct mg_connection *nc,
return 0; return 0;
} }
int mg_socket_if_listen_udp(struct mg_connection *nc, static int mg_socket_if_listen_udp(struct mg_connection *nc,
union socket_address *sa) { union socket_address *sa) {
sock_t sock = mg_open_listening_socket(sa, SOCK_DGRAM, 0); sock_t sock = mg_open_listening_socket(sa, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET) return (mg_get_errno() ? mg_get_errno() : 1); if (sock == INVALID_SOCKET) return (mg_get_errno() ? mg_get_errno() : 1);
mg_sock_set(nc, sock); mg_sock_set(nc, sock);
return 0; return 0;
} }
void mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf, static int mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf,
size_t len) { size_t len) {
mbuf_append(&nc->send_mbuf, buf, len); int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0);
if (n < 0 && !mg_is_error()) n = 0;
return n;
} }
void mg_socket_if_udp_send(struct mg_connection *nc, const void *buf, static int mg_socket_if_udp_send(struct mg_connection *nc, const void *buf,
size_t len) { size_t len) {
mbuf_append(&nc->send_mbuf, buf, len); int n = sendto(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
if (n < 0 && !mg_is_error()) n = 0;
return n;
} }
void mg_socket_if_recved(struct mg_connection *nc, size_t len) { static int mg_socket_if_tcp_recv(struct mg_connection *nc, void *buf,
(void) nc; size_t len) {
(void) len; int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0);
if (n == 0) {
/* Orderly shutdown of the socket, try flushing output. */
nc->flags |= MG_F_SEND_AND_CLOSE;
} else if (n < 0 && !mg_is_error()) {
n = 0;
}
return n;
}
static int mg_socket_if_udp_recv(struct mg_connection *nc, void *buf,
size_t len, union socket_address *sa,
size_t *sa_len) {
socklen_t sa_len_st = *sa_len;
int n = recvfrom(nc->sock, buf, len, 0, &sa->sa, &sa_len_st);
*sa_len = sa_len_st;
if (n < 0 && !mg_is_error()) n = 0;
return n;
} }
int mg_socket_if_create_conn(struct mg_connection *nc) { int mg_socket_if_create_conn(struct mg_connection *nc) {
@@ -131,7 +146,9 @@ static int mg_accept_conn(struct mg_connection *lc) {
/* NOTE(lsm): on Windows, sock is always > FD_SETSIZE */ /* NOTE(lsm): on Windows, sock is always > FD_SETSIZE */
sock_t sock = accept(lc->sock, &sa.sa, &sa_len); sock_t sock = accept(lc->sock, &sa.sa, &sa_len);
if (sock == INVALID_SOCKET) { if (sock == INVALID_SOCKET) {
if (mg_is_error()) DBG(("%p: failed to accept: %d", lc, mg_get_errno())); if (mg_is_error()) {
DBG(("%p: failed to accept: %d", lc, mg_get_errno()));
}
return 0; return 0;
} }
nc = mg_if_accept_new_conn(lc); nc = mg_if_accept_new_conn(lc);
@@ -142,14 +159,7 @@ static int mg_accept_conn(struct mg_connection *lc) {
DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr), DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
ntohs(sa.sin.sin_port))); ntohs(sa.sin.sin_port)));
mg_sock_set(nc, sock); mg_sock_set(nc, sock);
#if MG_ENABLE_SSL mg_if_accept_tcp_cb(nc, &sa, sa_len);
if (lc->flags & MG_F_SSL) {
if (mg_ssl_if_conn_accept(nc, lc) != MG_SSL_OK) mg_close_conn(nc);
} else
#endif
{
mg_if_accept_tcp_cb(nc, &sa, sa_len);
}
return 1; return 1;
} }
@@ -200,165 +210,6 @@ static sock_t mg_open_listening_socket(union socket_address *sa, int type,
return sock; return sock;
} }
static void mg_write_to_socket(struct mg_connection *nc) {
struct mbuf *io = &nc->send_mbuf;
int n = 0;
#if MG_LWIP
/* With LWIP we don't know if the socket is ready */
if (io->len == 0) return;
#endif
assert(io->len > 0);
if (nc->flags & MG_F_UDP) {
int n =
sendto(nc->sock, io->buf, io->len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
DBG(("%p %d %d %d %s:%hu", nc, nc->sock, n, mg_get_errno(),
inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port)));
mg_if_sent_cb(nc, n);
return;
}
#if MG_ENABLE_SSL
if (nc->flags & MG_F_SSL) {
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
n = mg_ssl_if_write(nc, io->buf, io->len);
DBG(("%p %d bytes -> %d (SSL)", nc, n, nc->sock));
if (n < 0) {
if (n != MG_SSL_WANT_READ && n != MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
return;
} else {
/* Successful SSL operation, clear off SSL wait flags */
nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE);
}
} else {
mg_ssl_begin(nc);
return;
}
} else
#endif
{
n = (int) MG_SEND_FUNC(nc->sock, io->buf, io->len, 0);
DBG(("%p %d bytes -> %d", nc, n, nc->sock));
}
mg_if_sent_cb(nc, n);
}
MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) {
size_t avail;
if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0;
avail = conn->recv_mbuf_limit - conn->recv_mbuf.len;
return avail > max ? max : avail;
}
static void mg_handle_tcp_read(struct mg_connection *conn) {
int n = 0;
char *buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE);
if (buf == NULL) {
DBG(("OOM"));
return;
}
#if MG_ENABLE_SSL
if (conn->flags & MG_F_SSL) {
if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) {
/* SSL library may have more bytes ready to read than we ask to read.
* Therefore, read in a loop until we read everything. Without the loop,
* we skip to the next select() cycle which can just timeout. */
while ((n = mg_ssl_if_read(conn, buf, MG_TCP_RECV_BUFFER_SIZE)) > 0) {
DBG(("%p %d bytes <- %d (SSL)", conn, n, conn->sock));
mg_if_recv_tcp_cb(conn, buf, n, 1 /* own */);
buf = NULL;
if (conn->flags & MG_F_CLOSE_IMMEDIATELY) break;
/* buf has been freed, we need a new one. */
buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE);
if (buf == NULL) break;
}
MG_FREE(buf);
if (n < 0 && n != MG_SSL_WANT_READ) conn->flags |= MG_F_CLOSE_IMMEDIATELY;
} else {
MG_FREE(buf);
mg_ssl_begin(conn);
return;
}
} else
#endif
{
n = (int) MG_RECV_FUNC(conn->sock, buf,
recv_avail_size(conn, MG_TCP_RECV_BUFFER_SIZE), 0);
DBG(("%p %d bytes (PLAIN) <- %d", conn, n, conn->sock));
if (n > 0) {
mg_if_recv_tcp_cb(conn, buf, n, 1 /* own */);
} else {
MG_FREE(buf);
}
if (n == 0) {
/* Orderly shutdown of the socket, try flushing output. */
conn->flags |= MG_F_SEND_AND_CLOSE;
} else if (n < 0 && mg_is_error()) {
conn->flags |= MG_F_CLOSE_IMMEDIATELY;
}
}
}
static int mg_recvfrom(struct mg_connection *nc, union socket_address *sa,
socklen_t *sa_len, char **buf) {
int n;
*buf = (char *) MG_MALLOC(MG_UDP_RECV_BUFFER_SIZE);
if (*buf == NULL) {
DBG(("Out of memory"));
return -ENOMEM;
}
n = recvfrom(nc->sock, *buf, MG_UDP_RECV_BUFFER_SIZE, 0, &sa->sa, sa_len);
if (n <= 0) {
DBG(("%p recvfrom: %s", nc, strerror(mg_get_errno())));
MG_FREE(*buf);
}
return n;
}
static void mg_handle_udp_read(struct mg_connection *nc) {
char *buf = NULL;
union socket_address sa;
socklen_t sa_len = sizeof(sa);
int n = mg_recvfrom(nc, &sa, &sa_len, &buf);
DBG(("%p %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
ntohs(nc->sa.sin.sin_port)));
mg_if_recv_udp_cb(nc, buf, n, &sa, sa_len);
}
#if MG_ENABLE_SSL
static void mg_ssl_begin(struct mg_connection *nc) {
int server_side = (nc->listener != NULL);
enum mg_ssl_if_result res = mg_ssl_if_handshake(nc);
DBG(("%p %d res %d", nc, server_side, res));
if (res == MG_SSL_OK) {
nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE);
if (server_side) {
union socket_address sa;
socklen_t sa_len = sizeof(sa);
(void) getpeername(nc->sock, &sa.sa, &sa_len);
mg_if_accept_tcp_cb(nc, &sa, sa_len);
} else {
mg_if_connect_cb(nc, 0);
}
} else if (res != MG_SSL_WANT_READ && res != MG_SSL_WANT_WRITE) {
if (!server_side) {
mg_if_connect_cb(nc, res);
}
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
}
#endif /* MG_ENABLE_SSL */
#define _MG_F_FD_CAN_READ 1 #define _MG_F_FD_CAN_READ 1
#define _MG_F_FD_CAN_WRITE 1 << 1 #define _MG_F_FD_CAN_WRITE 1 << 1
#define _MG_F_FD_ERROR 1 << 2 #define _MG_F_FD_ERROR 1 << 2
@@ -367,11 +218,13 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
int worth_logging = int worth_logging =
fd_flags != 0 || (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE)); fd_flags != 0 || (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE));
if (worth_logging) { if (worth_logging) {
DBG(("%p fd=%d fd_flags=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
fd_flags, nc->flags, (int) nc->recv_mbuf.len, fd_flags, nc->flags, (int) nc->recv_mbuf.len,
(int) nc->send_mbuf.len)); (int) nc->send_mbuf.len));
} }
if (!mg_if_poll(nc, now)) return;
if (nc->flags & MG_F_CONNECTING) { if (nc->flags & MG_F_CONNECTING) {
if (fd_flags != 0) { if (fd_flags != 0) {
int err = 0; int err = 0;
@@ -392,15 +245,7 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
*/ */
err = nc->err; err = nc->err;
#endif #endif
#if MG_ENABLE_SSL
if ((nc->flags & MG_F_SSL) && err == 0) {
mg_ssl_begin(nc);
} else {
mg_if_connect_cb(nc, err);
}
#else
mg_if_connect_cb(nc, err); mg_if_connect_cb(nc, err);
#endif
} else if (nc->err != 0) { } else if (nc->err != 0) {
mg_if_connect_cb(nc, nc->err); mg_if_connect_cb(nc, nc->err);
} }
@@ -408,7 +253,7 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
if (fd_flags & _MG_F_FD_CAN_READ) { if (fd_flags & _MG_F_FD_CAN_READ) {
if (nc->flags & MG_F_UDP) { if (nc->flags & MG_F_UDP) {
mg_handle_udp_read(nc); mg_if_can_recv_cb(nc);
} else { } else {
if (nc->flags & MG_F_LISTENING) { if (nc->flags & MG_F_LISTENING) {
/* /*
@@ -418,22 +263,16 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
*/ */
mg_accept_conn(nc); mg_accept_conn(nc);
} else { } else {
mg_handle_tcp_read(nc); mg_if_can_recv_cb(nc);
} }
} }
} }
if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { if (fd_flags & _MG_F_FD_CAN_WRITE) mg_if_can_send_cb(nc);
if ((fd_flags & _MG_F_FD_CAN_WRITE) && nc->send_mbuf.len > 0) {
mg_write_to_socket(nc);
}
mg_if_poll(nc, (time_t) now);
mg_if_timer(nc, now);
}
if (worth_logging) { if (worth_logging) {
DBG(("%p after fd=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, nc->flags, DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
(int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
} }
} }
@@ -547,8 +386,7 @@ time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) {
} }
#endif #endif
if (!(nc->flags & MG_F_WANT_WRITE) && if (nc->recv_mbuf.len < nc->recv_mbuf_limit &&
nc->recv_mbuf.len < nc->recv_mbuf_limit &&
(!(nc->flags & MG_F_UDP) || nc->listener == NULL)) { (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
mg_add_to_set(nc->sock, &read_set, &max_fd); mg_add_to_set(nc->sock, &read_set, &max_fd);
} }
@@ -619,14 +457,6 @@ time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) {
mg_mgr_handle_conn(nc, fd_flags, now); mg_mgr_handle_conn(nc, fd_flags, now);
} }
for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
tmp = nc->next;
if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
(nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) {
mg_close_conn(nc);
}
}
return (time_t) now; return (time_t) now;
} }
@@ -652,7 +482,7 @@ mg_socketpair_accept(sock_t sock, union socket_address *sa, socklen_t sa_len) {
} }
int mg_socketpair(sock_t sp[2], int sock_type) { int mg_socketpair(sock_t sp[2], int sock_type) {
union socket_address sa; union socket_address sa, sa2;
sock_t sock; sock_t sock;
socklen_t len = sizeof(sa.sin); socklen_t len = sizeof(sa.sin);
int ret = 0; int ret = 0;
@@ -661,18 +491,20 @@ int mg_socketpair(sock_t sp[2], int sock_type) {
(void) memset(&sa, 0, sizeof(sa)); (void) memset(&sa, 0, sizeof(sa));
sa.sin.sin_family = AF_INET; sa.sin.sin_family = AF_INET;
sa.sin.sin_port = htons(0);
sa.sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ sa.sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
sa2 = sa;
if ((sock = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) { if ((sock = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
} else if (bind(sock, &sa.sa, len) != 0) { } else if (bind(sock, &sa.sa, len) != 0) {
} else if (sock_type == SOCK_STREAM && listen(sock, 1) != 0) { } else if (sock_type == SOCK_STREAM && listen(sock, 1) != 0) {
} else if (getsockname(sock, &sa.sa, &len) != 0) { } else if (getsockname(sock, &sa.sa, &len) != 0) {
} else if ((sp[0] = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) { } else if ((sp[0] = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
} else if (connect(sp[0], &sa.sa, len) != 0) { } else if (sock_type == SOCK_STREAM && connect(sp[0], &sa.sa, len) != 0) {
} else if (sock_type == SOCK_DGRAM && } else if (sock_type == SOCK_DGRAM &&
(getsockname(sp[0], &sa.sa, &len) != 0 || (bind(sp[0], &sa2.sa, len) != 0 ||
connect(sock, &sa.sa, len) != 0)) { getsockname(sp[0], &sa2.sa, &len) != 0 ||
connect(sp[0], &sa.sa, len) != 0 ||
connect(sock, &sa2.sa, len) != 0)) {
} else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock : mg_socketpair_accept( } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock : mg_socketpair_accept(
sock, &sa, len))) == sock, &sa, len))) ==
INVALID_SOCKET) { INVALID_SOCKET) {
@@ -733,7 +565,8 @@ void mg_socket_if_get_conn_addr(struct mg_connection *nc, int remote,
mg_socket_if_connect_udp, \ mg_socket_if_connect_udp, \
mg_socket_if_tcp_send, \ mg_socket_if_tcp_send, \
mg_socket_if_udp_send, \ mg_socket_if_udp_send, \
mg_socket_if_recved, \ mg_socket_if_tcp_recv, \
mg_socket_if_udp_recv, \
mg_socket_if_create_conn, \ mg_socket_if_create_conn, \
mg_socket_if_destroy_conn, \ mg_socket_if_destroy_conn, \
mg_socket_if_sock_set, \ mg_socket_if_sock_set, \
+65 -37
View File
@@ -9,18 +9,35 @@ struct socksdata {
char *proxy_addr; /* HOST:PORT of the socks5 proxy server */ char *proxy_addr; /* HOST:PORT of the socks5 proxy server */
struct mg_connection *s; /* Respective connection to the server */ struct mg_connection *s; /* Respective connection to the server */
struct mg_connection *c; /* Connection to the client */ struct mg_connection *c; /* Connection to the client */
struct mbuf tmp; /* Temporary buffer for sent data */
}; };
static void socks_if_disband(struct socksdata *d) { static void socks_if_disband(struct socksdata *d) {
LOG(LL_DEBUG, ("disbanding proxy %p %p", d->c, d->s)); LOG(LL_DEBUG, ("disbanding proxy %p %p", d->c, d->s));
if (d->c) d->c->flags |= MG_F_SEND_AND_CLOSE; if (d->c) {
if (d->s) d->s->flags |= MG_F_SEND_AND_CLOSE; d->c->flags |= MG_F_SEND_AND_CLOSE;
d->c = d->s = NULL; d->c->user_data = NULL;
d->c = NULL;
}
if (d->s) {
d->s->flags |= MG_F_SEND_AND_CLOSE;
d->s->user_data = NULL;
d->s = NULL;
}
}
static void socks_if_relay(struct mg_connection *s) {
struct socksdata *d = (struct socksdata *) s->user_data;
if (d == NULL || d->c == NULL || !(s->flags & MG_SOCKS_CONNECT_DONE) ||
d->s == NULL) {
return;
}
if (s->recv_mbuf.len > 0) mg_if_can_recv_cb(d->c);
if (d->c->send_mbuf.len > 0 && s->send_mbuf.len == 0) mg_if_can_send_cb(d->c);
} }
static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) { static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) {
struct socksdata *d = (struct socksdata *) c->user_data; struct socksdata *d = (struct socksdata *) c->user_data;
if (d == NULL) return;
if (ev == MG_EV_CONNECT) { if (ev == MG_EV_CONNECT) {
int res = *(int *) ev_data; int res = *(int *) ev_data;
if (res == 0) { if (res == 0) {
@@ -53,6 +70,7 @@ static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) {
memcpy(buf + 4, &d->c->sa.sin.sin_addr, 4); memcpy(buf + 4, &d->c->sa.sin.sin_addr, 4);
memcpy(buf + 8, &d->c->sa.sin.sin_port, 2); memcpy(buf + 8, &d->c->sa.sin.sin_port, 2);
mg_send(c, buf, sizeof(buf)); mg_send(c, buf, sizeof(buf));
LOG(LL_DEBUG, ("%p Sent connect request", c));
} }
/* Process connect request */ /* Process connect request */
if ((c->flags & MG_SOCKS_HANDSHAKE_DONE) && if ((c->flags & MG_SOCKS_HANDSHAKE_DONE) &&
@@ -65,17 +83,12 @@ static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) {
} }
mbuf_remove(&c->recv_mbuf, 10); mbuf_remove(&c->recv_mbuf, 10);
c->flags |= MG_SOCKS_CONNECT_DONE; c->flags |= MG_SOCKS_CONNECT_DONE;
/* Connected. Move sent data from client, if any, to server */ LOG(LL_DEBUG, ("%p Connect done %p", c, d->c));
if (d->s && d->c) { mg_if_connect_cb(d->c, 0);
mbuf_append(&d->s->send_mbuf, d->tmp.buf, d->tmp.len);
mbuf_free(&d->tmp);
}
}
/* All flags are set, we're in relay mode */
if ((c->flags & MG_SOCKS_CONNECT_DONE) && d->c && d->s) {
mbuf_append(&d->c->recv_mbuf, d->s->recv_mbuf.buf, d->s->recv_mbuf.len);
mbuf_remove(&d->s->recv_mbuf, d->s->recv_mbuf.len);
} }
socks_if_relay(c);
} else if (ev == MG_EV_SEND || ev == MG_EV_POLL) {
socks_if_relay(c);
} }
} }
@@ -85,7 +98,7 @@ static void mg_socks_if_connect_tcp(struct mg_connection *c,
d->c = c; d->c = c;
d->s = mg_connect(c->mgr, d->proxy_addr, socks_if_handler); d->s = mg_connect(c->mgr, d->proxy_addr, socks_if_handler);
d->s->user_data = d; d->s->user_data = d;
LOG(LL_DEBUG, ("%p %s", c, d->proxy_addr)); LOG(LL_DEBUG, ("%p %s %p %p", c, d->proxy_addr, d, d->s));
(void) sa; (void) sa;
} }
@@ -107,29 +120,44 @@ static int mg_socks_if_listen_udp(struct mg_connection *c,
return -1; return -1;
} }
static void mg_socks_if_tcp_send(struct mg_connection *c, const void *buf, static int mg_socks_if_tcp_send(struct mg_connection *c, const void *buf,
size_t len) { size_t len) {
int res;
struct socksdata *d = (struct socksdata *) c->iface->data; struct socksdata *d = (struct socksdata *) c->iface->data;
LOG(LL_DEBUG, ("%p -> %p %d %d", c, buf, (int) len, (int) c->send_mbuf.len)); if (d->s == NULL) return -1;
if (d && d->s && d->s->flags & MG_SOCKS_CONNECT_DONE) { res = (int) mbuf_append(&d->s->send_mbuf, buf, len);
mbuf_append(&d->s->send_mbuf, d->tmp.buf, d->tmp.len); DBG(("%p -> %d -> %p", c, res, d->s));
mbuf_append(&d->s->send_mbuf, buf, len); return res;
mbuf_free(&d->tmp);
} else {
mbuf_append(&d->tmp, buf, len);
}
} }
static void mg_socks_if_udp_send(struct mg_connection *c, const void *buf, static int mg_socks_if_udp_send(struct mg_connection *c, const void *buf,
size_t len) { size_t len) {
(void) c; (void) c;
(void) buf; (void) buf;
(void) len; (void) len;
return -1;
} }
static void mg_socks_if_recved(struct mg_connection *c, size_t len) { int mg_socks_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
struct socksdata *d = (struct socksdata *) c->iface->data;
if (d->s == NULL) return -1;
if (len > d->s->recv_mbuf.len) len = d->s->recv_mbuf.len;
if (len > 0) {
memcpy(buf, d->s->recv_mbuf.buf, len);
mbuf_remove(&d->s->recv_mbuf, len);
}
DBG(("%p <- %d <- %p", c, (int) len, d->s));
return len;
}
int mg_socks_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
union socket_address *sa, size_t *sa_len) {
(void) c; (void) c;
(void) buf;
(void) len; (void) len;
(void) sa;
(void) sa_len;
return -1;
} }
static int mg_socks_if_create_conn(struct mg_connection *c) { static int mg_socks_if_create_conn(struct mg_connection *c) {
@@ -158,7 +186,6 @@ static void mg_socks_if_free(struct mg_iface *iface) {
LOG(LL_DEBUG, ("%p", iface)); LOG(LL_DEBUG, ("%p", iface));
if (d != NULL) { if (d != NULL) {
socks_if_disband(d); socks_if_disband(d);
mbuf_free(&d->tmp);
MG_FREE(d->proxy_addr); MG_FREE(d->proxy_addr);
MG_FREE(d); MG_FREE(d);
iface->data = NULL; iface->data = NULL;
@@ -189,14 +216,15 @@ static void mg_socks_if_get_conn_addr(struct mg_connection *c, int remote,
} }
const struct mg_iface_vtable mg_socks_iface_vtable = { const struct mg_iface_vtable mg_socks_iface_vtable = {
mg_socks_if_init, mg_socks_if_free, mg_socks_if_init, mg_socks_if_free,
mg_socks_if_add_conn, mg_socks_if_remove_conn, mg_socks_if_add_conn, mg_socks_if_remove_conn,
mg_socks_if_poll, mg_socks_if_listen_tcp, mg_socks_if_poll, mg_socks_if_listen_tcp,
mg_socks_if_listen_udp, mg_socks_if_connect_tcp, mg_socks_if_listen_udp, mg_socks_if_connect_tcp,
mg_socks_if_connect_udp, mg_socks_if_tcp_send, mg_socks_if_connect_udp, mg_socks_if_tcp_send,
mg_socks_if_udp_send, mg_socks_if_recved, mg_socks_if_udp_send, mg_socks_if_tcp_recv,
mg_socks_if_create_conn, mg_socks_if_destroy_conn, mg_socks_if_udp_recv, mg_socks_if_create_conn,
mg_socks_if_sock_set, mg_socks_if_get_conn_addr, mg_socks_if_destroy_conn, mg_socks_if_sock_set,
mg_socks_if_get_conn_addr,
}; };
struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) { struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) {
+4 -6
View File
@@ -148,7 +148,6 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
time_t now = (time_t) mg_time(); time_t now = (time_t) mg_time();
struct mg_resolve_async_request *req; struct mg_resolve_async_request *req;
struct mg_dns_message *msg; struct mg_dns_message *msg;
int first = 0;
#if !MG_ENABLE_CALLBACK_USERDATA #if !MG_ENABLE_CALLBACK_USERDATA
void *user_data = nc->user_data; void *user_data = nc->user_data;
#endif #endif
@@ -162,17 +161,16 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
} }
switch (ev) { switch (ev) {
case MG_EV_CONNECT:
/* don't depend on timer not being at epoch for sending out first req */
first = 1;
/* fallthrough */
case MG_EV_POLL: case MG_EV_POLL:
if (req->retries > req->max_retries) { if (req->retries > req->max_retries) {
req->err = MG_RESOLVE_EXCEEDED_RETRY_COUNT; req->err = MG_RESOLVE_EXCEEDED_RETRY_COUNT;
nc->flags |= MG_F_CLOSE_IMMEDIATELY; nc->flags |= MG_F_CLOSE_IMMEDIATELY;
break; break;
} }
if (first || now - req->last_time >= req->timeout) { if (nc->flags & MG_F_CONNECTING) break;
/* fallthrough */
case MG_EV_CONNECT:
if (req->retries == 0 || now - req->last_time >= req->timeout) {
mg_send_dns_query(nc, req->name, req->query); mg_send_dns_query(nc, req->name, req->query);
req->last_time = now; req->last_time = now;
req->retries++; req->retries++;
+63 -32
View File
@@ -7,9 +7,12 @@
#include <mbedtls/debug.h> #include <mbedtls/debug.h>
#include <mbedtls/ecp.h> #include <mbedtls/ecp.h>
#include <mbedtls/net.h>
#include <mbedtls/platform.h> #include <mbedtls/platform.h>
#include <mbedtls/ssl.h> #include <mbedtls/ssl.h>
#include <mbedtls/ssl_internal.h>
#include <mbedtls/x509_crt.h> #include <mbedtls/x509_crt.h>
#include <mbedtls/version.h>
static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line, static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line,
const char *str) { const char *str) {
@@ -19,6 +22,8 @@ static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line,
cs_level = LL_ERROR; cs_level = LL_ERROR;
break; break;
case 2: case 2:
cs_level = LL_INFO;
break;
case 3: case 3:
cs_level = LL_DEBUG; cs_level = LL_DEBUG;
break; break;
@@ -29,6 +34,7 @@ static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line,
LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str)); LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str));
(void) file; (void) file;
(void) line; (void) line;
(void) cs_level;
} }
struct mg_ssl_if_ctx { struct mg_ssl_if_ctx {
@@ -38,12 +44,14 @@ struct mg_ssl_if_ctx {
mbedtls_pk_context *key; mbedtls_pk_context *key;
mbedtls_x509_crt *ca_cert; mbedtls_x509_crt *ca_cert;
struct mbuf cipher_suites; struct mbuf cipher_suites;
size_t saved_len;
}; };
/* Must be provided by the platform. ctx is struct mg_connection. */ /* Must be provided by the platform. ctx is struct mg_connection. */
extern int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len); extern int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len);
void mg_ssl_if_init() { void mg_ssl_if_init() {
LOG(LL_INFO, ("%s", MBEDTLS_VERSION_STRING_FULL));
} }
enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc, enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc,
@@ -67,9 +75,11 @@ static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
const char *cert); const char *cert);
static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx, static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx,
const char *ciphers); const char *ciphers);
#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx, static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx,
const char *identity, const char *identity,
const char *key); const char *key);
#endif
enum mg_ssl_if_result mg_ssl_if_conn_init( enum mg_ssl_if_result mg_ssl_if_conn_init(
struct mg_connection *nc, const struct mg_ssl_if_conn_params *params, struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
@@ -118,11 +128,13 @@ enum mg_ssl_if_result mg_ssl_if_conn_init(
return MG_SSL_ERROR; return MG_SSL_ERROR;
} }
#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
if (mg_ssl_if_mbed_set_psk(ctx, params->psk_identity, params->psk_key) != if (mg_ssl_if_mbed_set_psk(ctx, params->psk_identity, params->psk_key) !=
MG_SSL_OK) { MG_SSL_OK) {
MG_SET_PTRPTR(err_msg, "Invalid PSK settings"); MG_SET_PTRPTR(err_msg, "Invalid PSK settings");
return MG_SSL_ERROR; return MG_SSL_ERROR;
} }
#endif
if (!(nc->flags & MG_F_LISTENING)) { if (!(nc->flags & MG_F_LISTENING)) {
ctx->ssl = (mbedtls_ssl_context *) MG_CALLOC(1, sizeof(*ctx->ssl)); ctx->ssl = (mbedtls_ssl_context *) MG_CALLOC(1, sizeof(*ctx->ssl));
@@ -160,40 +172,41 @@ enum mg_ssl_if_result mg_ssl_if_conn_init(
return MG_SSL_OK; return MG_SSL_OK;
} }
#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL static int mg_ssl_if_mbed_send(void *ctx, const unsigned char *buf,
int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len); size_t len) {
int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len);
#else
static int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len) {
struct mg_connection *nc = (struct mg_connection *) ctx; struct mg_connection *nc = (struct mg_connection *) ctx;
int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0); int n = nc->iface->vtable->tcp_send(nc, buf, len);
LOG(LL_DEBUG, ("%p %d -> %d", nc, (int) len, n)); if (n > 0) return n;
if (n >= 0) return n; if (n == 0) return MBEDTLS_ERR_SSL_WANT_WRITE;
n = mg_get_errno(); return MBEDTLS_ERR_NET_SEND_FAILED;
return ((n == EAGAIN || n == EINPROGRESS) ? MBEDTLS_ERR_SSL_WANT_WRITE : -1);
} }
static int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len) { static int mg_ssl_if_mbed_recv(void *ctx, unsigned char *buf, size_t len) {
struct mg_connection *nc = (struct mg_connection *) ctx; struct mg_connection *nc = (struct mg_connection *) ctx;
int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0); int n = nc->iface->vtable->tcp_recv(nc, buf, len);
LOG(LL_DEBUG, ("%p %d <- %d", nc, (int) len, n)); if (n > 0) return n;
if (n >= 0) return n; if (n == 0) return MBEDTLS_ERR_SSL_WANT_READ;
n = mg_get_errno(); return MBEDTLS_ERR_NET_RECV_FAILED;
return ((n == EAGAIN || n == EINPROGRESS) ? MBEDTLS_ERR_SSL_WANT_READ : -1);
} }
#endif
static enum mg_ssl_if_result mg_ssl_if_mbed_err(struct mg_connection *nc, static enum mg_ssl_if_result mg_ssl_if_mbed_err(struct mg_connection *nc,
int ret) { int ret) {
if (ret == MBEDTLS_ERR_SSL_WANT_READ) return MG_SSL_WANT_READ; enum mg_ssl_if_result res = MG_SSL_OK;
if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) return MG_SSL_WANT_WRITE; if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
if (ret != res = MG_SSL_WANT_READ;
MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { /* CLOSE_NOTIFY = Normal shutdown */ } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
LOG(LL_ERROR, ("%p SSL error: %d", nc, ret)); res = MG_SSL_WANT_WRITE;
} else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
LOG(LL_DEBUG, ("%p TLS connection closed by peer", nc));
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
res = MG_SSL_OK;
} else {
LOG(LL_ERROR, ("%p mbedTLS error: -0x%04x", nc, -ret));
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
res = MG_SSL_ERROR;
} }
nc->err = ret; nc->err = ret;
nc->flags |= MG_F_CLOSE_IMMEDIATELY; return res;
return MG_SSL_ERROR;
} }
static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) { static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) {
@@ -224,7 +237,8 @@ enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
int err; int err;
/* If bio is not yet set, do it now. */ /* If bio is not yet set, do it now. */
if (ctx->ssl->p_bio == NULL) { if (ctx->ssl->p_bio == NULL) {
mbedtls_ssl_set_bio(ctx->ssl, nc, ssl_socket_send, ssl_socket_recv, NULL); mbedtls_ssl_set_bio(ctx->ssl, nc, mg_ssl_if_mbed_send, mg_ssl_if_mbed_recv,
NULL);
} }
err = mbedtls_ssl_handshake(ctx->ssl); err = mbedtls_ssl_handshake(ctx->ssl);
if (err != 0) return mg_ssl_if_mbed_err(nc, err); if (err != 0) return mg_ssl_if_mbed_err(nc, err);
@@ -250,20 +264,35 @@ enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
return MG_SSL_OK; return MG_SSL_OK;
} }
int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t buf_size) { int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, buf_size); int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, len);
DBG(("%p %d -> %d", nc, (int) buf_size, n)); DBG(("%p %d -> %d", nc, (int) len, n));
if (n < 0) return mg_ssl_if_mbed_err(nc, n); if (n < 0) return mg_ssl_if_mbed_err(nc, n);
if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY; if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY;
return n; return n;
} }
int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len) { int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) data, len); /* Per mbedTLS docs, if write returns WANT_READ or WANT_WRITE, the operation
DBG(("%p %d -> %d", nc, (int) len, n)); * should be retried with the same data and length.
if (n < 0) return mg_ssl_if_mbed_err(nc, n); * Here we assume that the data being pushed will remain the same but the
* amount may grow between calls so we save the length that was used and
* retry. The assumption being that the data itself won't change and won't
* be removed. */
size_t l = len;
if (ctx->saved_len > 0 && ctx->saved_len < l) l = ctx->saved_len;
int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) buf, l);
DBG(("%p %d,%d,%d -> %d", nc, (int) len, (int) ctx->saved_len, (int) l, n));
if (n < 0) {
if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) {
ctx->saved_len = len;
}
return mg_ssl_if_mbed_err(nc, n);
} else if (n > 0) {
ctx->saved_len = 0;
}
return n; return n;
} }
@@ -416,6 +445,7 @@ static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx,
return MG_SSL_OK; return MG_SSL_OK;
} }
#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx, static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx,
const char *identity, const char *identity,
const char *key_str) { const char *key_str) {
@@ -452,6 +482,7 @@ static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx,
} }
return MG_SSL_OK; return MG_SSL_OK;
} }
#endif
const char *mg_set_ssl(struct mg_connection *nc, const char *cert, const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
const char *ca_cert) { const char *ca_cert) {
+11 -8
View File
@@ -10,6 +10,9 @@
#endif #endif
#include <openssl/ssl.h> #include <openssl/ssl.h>
#ifndef KR_VERSION
#include <openssl/tls1.h>
#endif
struct mg_ssl_if_ctx { struct mg_ssl_if_ctx {
SSL *ssl; SSL *ssl;
@@ -94,14 +97,6 @@ enum mg_ssl_if_result mg_ssl_if_conn_init(
return MG_SSL_ERROR; return MG_SSL_ERROR;
} }
if (params->server_name != NULL) {
#ifdef KR_VERSION
SSL_CTX_kr_set_verify_name(ctx->ssl_ctx, params->server_name);
#else
/* TODO(rojer): Implement server name verification on OpenSSL. */
#endif
}
if (mg_set_cipher_list(ctx->ssl_ctx, params->cipher_suites) != MG_SSL_OK) { if (mg_set_cipher_list(ctx->ssl_ctx, params->cipher_suites) != MG_SSL_OK) {
MG_SET_PTRPTR(err_msg, "Invalid cipher suite list"); MG_SET_PTRPTR(err_msg, "Invalid cipher suite list");
return MG_SSL_ERROR; return MG_SSL_ERROR;
@@ -120,6 +115,14 @@ enum mg_ssl_if_result mg_ssl_if_conn_init(
return MG_SSL_ERROR; return MG_SSL_ERROR;
} }
if (params->server_name != NULL) {
#ifdef KR_VERSION
SSL_CTX_kr_set_verify_name(ctx->ssl_ctx, params->server_name);
#else
SSL_set_tlsext_host_name(ctx->ssl, params->server_name);
#endif
}
nc->flags |= MG_F_SSL; nc->flags |= MG_F_SSL;
return MG_SSL_OK; return MG_SSL_OK;
+13 -5
View File
@@ -144,7 +144,7 @@ int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len,
goto cleanup; goto cleanup;
} }
#else #else
if (inet_ntop(AF_INET, (void *) &sa->sin.sin_addr, buf, len - 1) == NULL) { if (inet_ntop(AF_INET, (void *) &sa->sin.sin_addr, buf, len) == NULL) {
goto cleanup; goto cleanup;
} }
#endif #endif
@@ -313,17 +313,21 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
mbuf_append(buf, header_suffix, strlen(header_suffix)); mbuf_append(buf, header_suffix, strlen(header_suffix));
} }
struct mg_str mg_url_encode(const struct mg_str src) { struct mg_str mg_url_encode_opt(const struct mg_str src,
static const char *dont_escape = "._-$,;~()/"; const struct mg_str safe, unsigned int flags) {
static const char *hex = "0123456789abcdef"; const char *hex =
(flags & MG_URL_ENCODE_F_UPPERCASE_HEX ? "0123456789ABCDEF"
: "0123456789abcdef");
size_t i = 0; size_t i = 0;
struct mbuf mb; struct mbuf mb;
mbuf_init(&mb, src.len); mbuf_init(&mb, src.len);
for (i = 0; i < src.len; i++) { for (i = 0; i < src.len; i++) {
const unsigned char c = *((const unsigned char *) src.p + i); const unsigned char c = *((const unsigned char *) src.p + i);
if (isalnum(c) || strchr(dont_escape, c) != NULL) { if (isalnum(c) || mg_strchr(safe, c) != NULL) {
mbuf_append(&mb, &c, 1); mbuf_append(&mb, &c, 1);
} else if (c == ' ' && (flags & MG_URL_ENCODE_F_SPACE_AS_PLUS)) {
mbuf_append(&mb, "+", 1);
} else { } else {
mbuf_append(&mb, "%", 1); mbuf_append(&mb, "%", 1);
mbuf_append(&mb, &hex[c >> 4], 1); mbuf_append(&mb, &hex[c >> 4], 1);
@@ -334,3 +338,7 @@ struct mg_str mg_url_encode(const struct mg_str src) {
mbuf_trim(&mb); mbuf_trim(&mb);
return mg_mk_str_n(mb.buf, mb.len - 1); return mg_mk_str_n(mb.buf, mb.len - 1);
} }
struct mg_str mg_url_encode(const struct mg_str src) {
return mg_url_encode_opt(src, mg_mk_str("._-$,;~()/"), 0);
}
+8 -1
View File
@@ -196,10 +196,17 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
/* /*
* URL-escape the specified string. * URL-escape the specified string.
* All non-printable characters are escaped, plus `._-$,;~()/`. * All characters acept letters, numbers and characters listed in
* `safe` are escaped. If `hex_upper`is true, `A-F` are used for hex digits.
* Input need not be NUL-terminated, but the returned string is. * Input need not be NUL-terminated, but the returned string is.
* Returned string is heap-allocated and must be free()'d. * Returned string is heap-allocated and must be free()'d.
*/ */
#define MG_URL_ENCODE_F_SPACE_AS_PLUS (1 << 0)
#define MG_URL_ENCODE_F_UPPERCASE_HEX (1 << 1)
struct mg_str mg_url_encode_opt(const struct mg_str src,
const struct mg_str safe, unsigned int flags);
/* Same as `mg_url_encode_opt(src, "._-$,;~()/", 0)`. */
struct mg_str mg_url_encode(const struct mg_str src); struct mg_str mg_url_encode(const struct mg_str src);
#ifdef __cplusplus #ifdef __cplusplus
+1 -1
View File
@@ -28,7 +28,7 @@
# OSX clang doesn't build ASAN. Use brew: # OSX clang doesn't build ASAN. Use brew:
# $ brew tap homebrew/versions # $ brew tap homebrew/versions
# $ brew install llvm36 --with-clang --with-asan # $ brew install llvm36 --with-clang --with-asan
CLANG:=clang-3.6 CLANG:=clang
PEDANTIC=$(shell gcc --version 2>/dev/null | grep -q clang && echo -pedantic) PEDANTIC=$(shell gcc --version 2>/dev/null | grep -q clang && echo -pedantic)
+261 -14
View File
@@ -928,10 +928,38 @@ static const char *test_mg_uri_to_local_path(void) {
static const char *test_mg_url_encode(void) { static const char *test_mg_url_encode(void) {
const struct mg_str encode_me = const struct mg_str encode_me =
MG_MK_STR("I'm a.little_tea-pot,here's$my;spout~oink(oink)oink/!"); MG_MK_STR("I'm a.little_tea-pot,here's$my;spout~oink(oink)oink/!");
struct mg_str encoded = mg_url_encode(encode_me); {
ASSERT_MG_STREQ( struct mg_str encoded = mg_url_encode(encode_me);
encoded, "I%27m%20a.little_tea-pot,here%27s$my;spout~oink(oink)oink/%21"); ASSERT_MG_STREQ(
free((void *) encoded.p); encoded,
"I%27m%20a.little_tea-pot,here%27s$my;spout~oink(oink)oink/%21");
free((void *) encoded.p);
}
{
struct mg_str encoded = mg_url_encode_opt(encode_me, mg_mk_str(NULL), 0);
ASSERT_MG_STREQ(encoded,
"I%27m%20a%2elittle%5ftea%2dpot%2chere%27s%24my%3bspout%"
"7eoink%28oink%29oink%2f%21");
free((void *) encoded.p);
}
{
struct mg_str encoded = mg_url_encode_opt(encode_me, mg_mk_str(" /!"),
MG_URL_ENCODE_F_UPPERCASE_HEX);
ASSERT_MG_STREQ(encoded,
"I%27m "
"a%2Elittle%5Ftea%2Dpot%2Chere%27s%24my%3Bspout%7Eoink%"
"28oink%29oink/!");
free((void *) encoded.p);
}
{
struct mg_str encoded = mg_url_encode_opt(
encode_me, mg_mk_str("/!"),
MG_URL_ENCODE_F_SPACE_AS_PLUS | MG_URL_ENCODE_F_UPPERCASE_HEX);
ASSERT_MG_STREQ(encoded,
"I%27m+a%2Elittle%5Ftea%2Dpot%2Chere%27s%24my%3Bspout%"
"7Eoink%28oink%29oink/!");
free((void *) encoded.p);
}
return NULL; return NULL;
} }
@@ -1145,7 +1173,7 @@ static const char *test_timer(void) {
ASSERT((c = mg_connect(&m, "awful.sad:1234", ev_timer_handler)) != NULL); ASSERT((c = mg_connect(&m, "awful.sad:1234", ev_timer_handler)) != NULL);
c->user_data = &n; c->user_data = &n;
mg_set_timer(c, 1); mg_set_timer(c, 1);
mg_mgr_poll(&m, 1); poll_until(&m, 1, c_int_eq, &n, (void *) 101);
ASSERT_EQ(n, 101); ASSERT_EQ(n, 101);
mg_mgr_free(&m); mg_mgr_free(&m);
@@ -1533,7 +1561,7 @@ static const char *test_parse_http_message(void) {
ASSERT_EQ(mg_vcmp(&req.query_string, "a=b&c=d"), 0); ASSERT_EQ(mg_vcmp(&req.query_string, "a=b&c=d"), 0);
ASSERT_EQ(mg_parse_http(f, strlen(f), &req, 1), (int) strlen(f)); ASSERT_EQ(mg_parse_http(f, strlen(f), &req, 1), (int) strlen(f));
ASSERT_EQ(req.body.len, (size_t) ~0); ASSERT_EQ64(req.body.len, (size_t) ~0);
ASSERT_EQ(mg_parse_http(g, strlen(g), &req, 1), (int) strlen(g)); ASSERT_EQ(mg_parse_http(g, strlen(g), &req, 1), (int) strlen(g));
ASSERT_EQ(req.body.len, 0); ASSERT_EQ(req.body.len, 0);
@@ -1542,7 +1570,7 @@ static const char *test_parse_http_message(void) {
ASSERT_EQ(mg_vcmp(&req.proto, "HTTP/1.0"), 0); ASSERT_EQ(mg_vcmp(&req.proto, "HTTP/1.0"), 0);
ASSERT_EQ(req.resp_code, 200); ASSERT_EQ(req.resp_code, 200);
ASSERT_EQ(mg_vcmp(&req.resp_status_msg, "OK"), 0); ASSERT_EQ(mg_vcmp(&req.resp_status_msg, "OK"), 0);
ASSERT_EQ(req.body.len, (size_t) ~0); ASSERT_EQ64(req.body.len, (size_t) ~0);
ASSERT_EQ(mg_parse_http(i, strlen(i), &req, 0), -1); ASSERT_EQ(mg_parse_http(i, strlen(i), &req, 0), -1);
@@ -2019,6 +2047,7 @@ static const char *test_http(void) {
ASSERT((nc = mg_connect(&mgr, local_addr, cb7)) != NULL); ASSERT((nc = mg_connect(&mgr, local_addr, cb7)) != NULL);
mg_set_protocol_http_websocket(nc); mg_set_protocol_http_websocket(nc);
nc->user_data = status; nc->user_data = status;
mbuf_resize(&nc->recv_mbuf, 10000000);
/* Wine and GDB set argv0 to full path: strip the dir component */ /* Wine and GDB set argv0 to full path: strip the dir component */
if ((this_binary = strrchr(g_argv_0, '\\')) != NULL) { if ((this_binary = strrchr(g_argv_0, '\\')) != NULL) {
@@ -2051,6 +2080,40 @@ static const char *test_http(void) {
return NULL; return NULL;
} }
static void http_pipeline_handler(struct mg_connection *c, int ev,
void *ev_data) {
(void) ev_data;
int *status = (int *) c->mgr->user_data;
if (ev == MG_EV_HTTP_REQUEST) {
/* Server request handler */
mg_send_response_line(c, 200,
"Content-Type: text/plain\r\nContent-Length: 5\r\n");
mg_printf(c, "Hello");
*status = *status + 1;
} else if (ev == MG_EV_HTTP_REPLY) {
/* Client reply handler */
*status = *status + 10;
}
}
static const char *test_http_pipeline(void) {
struct mg_mgr mgr;
struct mg_connection *lc, *nc1;
const char *local_addr = "127.0.0.1:7777";
int status = 0;
mg_mgr_init(&mgr, (void *) &status);
ASSERT(lc = mg_bind(&mgr, local_addr, http_pipeline_handler));
mg_set_protocol_http_websocket(lc);
ASSERT(nc1 = mg_connect(&mgr, local_addr, http_pipeline_handler));
mg_set_protocol_http_websocket(nc1);
mg_printf(nc1, "GET / HTTP/1.1\r\n\r\nGET / HTTP/1.1\r\n\r\n");
poll_until(&mgr, 1, c_int_eq, &status, (void *) 22);
ASSERT_EQ(status, 22);
mg_mgr_free(&mgr);
return NULL;
}
static const char *test_http_send_redirect(void) { static const char *test_http_send_redirect(void) {
struct mg_connection nc; struct mg_connection nc;
init_test_connection(&nc); init_test_connection(&nc);
@@ -3921,7 +3984,7 @@ static const char *test_http_chunk2(void) {
strcat(buf, "3\r\n...\r\na\r\n0123456789\r\n0\r"); strcat(buf, "3\r\n...\r\na\r\n0123456789\r\n0\r");
ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13); ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13);
ASSERT_STREQ(buf, "...01234567890\r"); ASSERT_STREQ(buf, "...01234567890\r");
ASSERT_EQ(hm.message.len, (size_t) ~0); ASSERT_EQ64(hm.message.len, (size_t) ~0);
strcat(buf, "\n\r\n"); strcat(buf, "\n\r\n");
ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13); ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13);
@@ -4013,14 +4076,19 @@ static void cb_mp_srv(struct mg_connection *nc, int ev, void *p) {
} }
static void cb_mp_send_one_byte(struct mg_connection *nc, int ev, void *p) { static void cb_mp_send_one_byte(struct mg_connection *nc, int ev, void *p) {
static int i; static int i = -1;
(void) p; (void) p;
if (ev == MG_EV_POLL) { if (ev == MG_EV_CONNECT) {
i = 0;
} else if (i >= 0 && ev == MG_EV_POLL) {
char ch = ((char *) nc->user_data)[i++]; char ch = ((char *) nc->user_data)[i++];
int l = strlen((char *) nc->user_data); int l = strlen((char *) nc->user_data);
if (ch != '\0') { if (ch != '\0') {
mg_send(nc, &ch, 1); mg_send(nc, &ch, 1);
DBG(("%p sent %d of %d", (void *) nc, i, l)); DBG(("%p sent %d of %d", (void *) nc, i, l));
} else {
nc->flags |= MG_F_SEND_AND_CLOSE;
i = -1;
} }
} }
} }
@@ -4146,7 +4214,6 @@ static const char *test_http_multipart2(void) {
if ((r = test_http_multipart_check_res(&mpd.res)) != NULL) return r; if ((r = test_http_multipart_check_res(&mpd.res)) != NULL) return r;
c->flags |= MG_F_CLOSE_IMMEDIATELY;
mbuf_free(&mpd.res); mbuf_free(&mpd.res);
memset(&mpd, 0, sizeof(mpd)); memset(&mpd, 0, sizeof(mpd));
mbuf_init(&mpd.res, 0); mbuf_init(&mpd.res, 0);
@@ -4253,6 +4320,178 @@ static const char *test_http_multipart2(void) {
return NULL; return NULL;
} }
static const char *test_http_multipart_pipeline(void) {
struct mg_mgr mgr;
struct mg_connection *nc_listen;
const char multi_part_req_fmt[] =
"%s"
"Content-Disposition: form-data; name=\"a\"; filename=\"foo\"\r\n"
"\r\n"
"%s"
"\r\n--Asrf456BGe4h\r\n"
"Content-Disposition: form-data; name=\"b\"\r\n"
"\r\n"
"%s"
"\r\n--Asrf456BGe4h\r\n"
"Content-Disposition: form-data; name=\"c\"; filename=\"bar\"\r\n"
"\r\n"
"%s"
"\r\n--Asrf456BGe4h--\r\n"
"\r\n";
char multi_part_req[1024 * 5];
struct mg_connection *c;
const char *ptr;
int i;
struct cb_mp_srv_data mpd;
memset(&mpd, 0, sizeof(mpd));
mbuf_init(&mpd.res, 0);
mg_mgr_init(&mgr, NULL);
nc_listen = mg_bind(&mgr, "8765", cb_mp_srv);
nc_listen->user_data = &mpd;
mg_set_protocol_http_websocket(nc_listen);
snprintf(multi_part_req, sizeof(multi_part_req), multi_part_req_fmt,
"\r\n--Asrf456BGe4h\r\n", b1, b2, b4);
ASSERT((c = mg_connect_http(&mgr, cb_mp_empty, "http://127.0.0.1:8765/test",
"Content-Type: "
"multipart/form-data;boundary=Asrf456BGe4h\r\n"
"Connection: keep-alive",
multi_part_req)) != NULL);
c->user_data = multi_part_req;
mg_printf(c,
"POST /test HTTP/1.1\r\n"
"Connection: keep-alive\r\n"
"Content-Type: multipart/form-data;boundary=Asrf456BGe4h\r\n"
"Content-Length: %d\r\n%s",
(int) strlen(multi_part_req), multi_part_req);
poll_until(&mgr, 10, c_int_eq, &mpd.request_end, (void *) 1);
ptr = mpd.res.buf;
for (i = 0; i < 2; i++) {
ASSERT_STREQ_NZ(ptr, "<MPRQ/test");
ptr += 10;
ASSERT_STREQ_NZ(ptr, "afoo");
ptr += 4;
ASSERT_STREQ_NZ(ptr, b1);
ptr += sizeof(b1) - 1;
ASSERT_STREQ_NZ(ptr, "afooFIN");
ptr += 7;
/* No file_name for second part */
ASSERT_STREQ_NZ(ptr, "b");
ptr++;
ASSERT_STREQ_NZ(ptr, b2);
ptr += sizeof(b2) - 1;
ASSERT_STREQ_NZ(ptr, "bFIN");
ptr += 4;
ASSERT_STREQ_NZ(ptr, "cbar");
ptr += 4;
ASSERT_STREQ_NZ(ptr, b4);
ptr += sizeof(b4) - 1;
ASSERT_STREQ_NZ(ptr, "cbarFIN");
ptr += 7;
ASSERT_STREQ_NZ(ptr, "+11MPRQ>");
ptr += 8;
}
ASSERT_EQ((size_t)(ptr - mpd.res.buf), mpd.res.len);
mbuf_free(&mpd.res);
mg_mgr_free(&mgr);
return NULL;
}
static struct mg_str upload_lfn_same(struct mg_connection *nc,
struct mg_str fn) {
if (fn.len == 0) {
fn = mg_strdup(mg_mk_str("bar"));
}
(void) nc;
return fn;
}
static void cb_mp_srv_upload(struct mg_connection *nc, int ev, void *p) {
mg_file_upload_handler(nc, ev, p, upload_lfn_same);
if (ev == MG_EV_CLOSE && nc->listener != NULL) {
*((int *) nc->listener->user_data) = 1;
}
(void) p;
}
static const char *test_http_multipart_upload(void) {
struct mg_mgr mgr;
const char req_fmt[] =
"%s"
"Content-Disposition: form-data; name=\"a\"; filename=\"foo\"\r\n"
"\r\n"
"%s"
"\r\n--Asrf456BGe4h\r\n"
"Content-Disposition: form-data; name=\"b\"\r\n"
"\r\n"
"%s"
"\r\n--Asrf456BGe4h\r\n"
"Content-Disposition: form-data; name=\"c\"; filename=\"baz\"\r\n"
"\r\n"
"%s"
"\r\n--Asrf456BGe4h--\r\n"
"\r\n";
char req[1024 * 5], *data;
struct mg_connection *c, *lc;
size_t size;
int done = 0;
mg_mgr_init(&mgr, NULL);
lc = mg_bind(&mgr, "8766", cb_mp_srv_upload);
mg_set_protocol_http_websocket(lc);
lc->user_data = &done;
(void) remove("foo");
(void) remove("bar");
(void) remove("baz");
snprintf(req, sizeof(req), req_fmt, "", b1, b2, b4);
ASSERT((c = mg_connect_http(&mgr, cb_mp_send_one_byte,
"http://127.0.0.1:8766/test",
"Content-Type: "
"multipart/form-data;boundary=Asrf456BGe4h",
"\r\n--Asrf456BGe4h\r\n")) != NULL);
c->user_data = req;
poll_until(&mgr, 5, c_int_eq, &done, (void *) 1);
data = read_file("foo", &size);
ASSERT_PTRNE(data, NULL);
ASSERT_STREQ_NZ(data, b1);
(void) remove("foo");
free(data);
data = read_file("bar", &size);
ASSERT_PTRNE(data, NULL);
ASSERT_STREQ_NZ(data, b2);
(void) remove("bar");
free(data);
data = read_file("baz", &size);
ASSERT_PTRNE(data, NULL);
ASSERT_STREQ_NZ(data, b4);
(void) remove("baz");
free(data);
mg_mgr_free(&mgr);
return NULL;
}
#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
static const char *test_http_multipart(void) { static const char *test_http_multipart(void) {
@@ -4938,7 +5177,7 @@ static const char *test_buffer_limit(void) {
static const char *test_http_parse_header(void) { static const char *test_http_parse_header(void) {
static struct mg_str h = MG_MK_STR( static struct mg_str h = MG_MK_STR(
"xx=1 kl yy, ert=234 kl=123, " "xx=1 kl yy, ert=234 kl=123, qq=ww;"
"uri=\"/?naii=x,y\";ii=\"12\\\"34\" zz='aa bb',tt=2,gf=\"xx d=1234"); "uri=\"/?naii=x,y\";ii=\"12\\\"34\" zz='aa bb',tt=2,gf=\"xx d=1234");
char buf[20]; char buf[20];
char *buf2; char *buf2;
@@ -4986,6 +5225,9 @@ static const char *test_http_parse_header(void) {
ASSERT_EQ(mg_http_parse_header(&h, "tt", buf, sizeof(buf)), 1); ASSERT_EQ(mg_http_parse_header(&h, "tt", buf, sizeof(buf)), 1);
ASSERT_STREQ(buf, "2"); ASSERT_STREQ(buf, "2");
ASSERT(mg_http_parse_header(&h, "uri", buf, sizeof(buf)) > 0); ASSERT(mg_http_parse_header(&h, "uri", buf, sizeof(buf)) > 0);
ASSERT_STREQ(buf, "/?naii=x,y");
ASSERT(mg_http_parse_header(&h, "qq", buf, sizeof(buf)) > 0);
ASSERT_STREQ(buf, "ww");
return NULL; return NULL;
} }
@@ -5420,12 +5662,14 @@ static const char *test_socks(void) {
this_binary = g_argv_0; this_binary = g_argv_0;
} }
mg_printf(c, "GET /%s HTTP/1.0\n\n", this_binary); mg_printf(c, "GET /%s HTTP/1.0\n\n", this_binary);
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, 5, c_str_ne, status, (void *) ""); poll_until(&mgr, 10, c_str_ne, status, (void *) "");
mg_mgr_free(&mgr);
ASSERT_STREQ(status, "success"); ASSERT_STREQ(status, "success");
mg_mgr_free(&mgr);
return NULL; return NULL;
} }
#endif #endif
@@ -5461,6 +5705,7 @@ const char *tests_run(const char *filter) {
RUN_TEST(test_http_serve_file); RUN_TEST(test_http_serve_file);
RUN_TEST(test_http_serve_file_streaming); RUN_TEST(test_http_serve_file_streaming);
RUN_TEST(test_http); RUN_TEST(test_http);
RUN_TEST(test_http_pipeline);
RUN_TEST(test_http_send_redirect); RUN_TEST(test_http_send_redirect);
RUN_TEST(test_http_digest_auth); RUN_TEST(test_http_digest_auth);
RUN_TEST(test_http_errors); RUN_TEST(test_http_errors);
@@ -5476,6 +5721,8 @@ const char *tests_run(const char *filter) {
RUN_TEST(test_http_multipart); RUN_TEST(test_http_multipart);
#if MG_ENABLE_HTTP_STREAMING_MULTIPART #if MG_ENABLE_HTTP_STREAMING_MULTIPART
RUN_TEST(test_http_multipart2); RUN_TEST(test_http_multipart2);
RUN_TEST(test_http_multipart_pipeline);
RUN_TEST(test_http_multipart_upload);
#endif #endif
RUN_TEST(test_parse_date_string); RUN_TEST(test_parse_date_string);
RUN_TEST(test_websocket); RUN_TEST(test_websocket);
+6 -3
View File
@@ -57,7 +57,7 @@ parser.add_argument('--norel', action='store_true',
help="do not try to compute a friendly relative path") help="do not try to compute a friendly relative path")
parser.add_argument('--exportable-headers', dest="export", action='store_true', parser.add_argument('--exportable-headers', dest="export", action='store_true',
help='allow exporting internal headers') help='allow exporting internal headers')
parser.add_argument('-I', default=".", dest='include_path', help='include path') parser.add_argument('-I', default=['.'], dest='include_path', help='include path', action='append')
parser.add_argument('sources', nargs='*', help='sources') parser.add_argument('sources', nargs='*', help='sources')
class File(object): class File(object):
@@ -97,10 +97,13 @@ def resolve(path, parent_name):
elif path_from_parent != None and os.path.exists(path_from_parent): elif path_from_parent != None and os.path.exists(path_from_parent):
p = path_from_parent p = path_from_parent
else: else:
p = os.path.join(args.include_path, path) for ip in args.include_path:
p = os.path.join(ip, path)
if os.path.exists(p):
break
if os.path.exists(p) and not args.norel: if os.path.exists(p) and not args.norel:
p = os.path.realpath(p).replace('%s%s' % (os.getcwd(), os.sep), '') p = os.path.realpath(p).replace('%s%s' % (os.getcwd(), os.sep), '')
# print >>sys.stderr, '%s -> %s (cwd %s)' % (path, p, os.getcwd()) # print >>sys.stderr, '%s %s -> %s (cwd %s)' % (path, parent_name, p, os.getcwd())
return p.replace(os.sep, '/') return p.replace(os.sep, '/')
def emit_line_directive(out, name, parent_name): def emit_line_directive(out, name, parent_name):