mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-25 12:04:47 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
777b8e94e2 | ||
|
|
6df642623a | ||
|
|
0a3e186f11 | ||
|
|
c2d83a9db0 | ||
|
|
f33d3a4e02 | ||
|
|
86b8a56b05 | ||
|
|
ac6ec15aed | ||
|
|
31632c6361 | ||
|
|
98c99279c3 | ||
|
|
cdb8d7b692 | ||
|
|
93ac3e19f0 | ||
|
|
6a51af9efe | ||
|
|
9d73b3470b | ||
|
|
1c8449cea6 | ||
|
|
3bbbd41196 | ||
|
|
339bbee0df | ||
|
|
9ba6eb716d | ||
|
|
d949c19c7e | ||
|
|
1299d6118f | ||
|
|
244ff92e78 | ||
|
|
53f34dea04 | ||
|
|
1f5c3fac31 | ||
|
|
7014258c8d | ||
|
|
1614e7ba8d | ||
|
|
43b5a4e735 | ||
|
|
43191db63e | ||
|
|
e89be2e944 | ||
|
|
c2fbff6d0e | ||
|
|
b8eca17c55 | ||
|
|
4650e491df | ||
|
|
3e33e57707 | ||
|
|
c80f4c5313 | ||
|
|
132ecbec2f | ||
|
|
0a90cab44a | ||
|
|
d16dbc197f | ||
|
|
127f27e375 | ||
|
|
6523cc4da0 | ||
|
|
2516da1c89 | ||
|
|
0ae2b82b60 | ||
|
|
dab526936f | ||
|
|
780077d118 | ||
|
|
ad8f1d88d4 | ||
|
|
a3c4a48ef7 | ||
|
|
84a11fe3b1 |
No files matched your search
@@ -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,5 +1,5 @@
|
||||
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
|
||||
|
||||
This software is dual-licensed: you can redistribute it and/or modify
|
||||
|
||||
@@ -62,7 +62,7 @@ the functionality:
|
||||
# Contributions
|
||||
|
||||
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?
|
||||
- [Download pre-compiled Mongoose web server binary.](https://www.cesanta.com/binary.html)
|
||||
@@ -6,8 +6,5 @@ signature: |
|
||||
struct mg_str mg_url_encode(const struct mg_str src);
|
||||
---
|
||||
|
||||
URL-escape the specified string.
|
||||
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.
|
||||
Same as `mg_url_encode_opt(src, "._-$,;~()/", 0)`.
|
||||
|
||||
+1267
-1180
File diff suppressed because it is too large.
Load diff
+469
-50
@@ -23,7 +23,7 @@
|
||||
#ifndef 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. */
|
||||
#ifdef MG_LOCALS
|
||||
@@ -128,8 +128,18 @@
|
||||
|
||||
/* 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(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32)
|
||||
#if (defined(__GNUC__) || defined(__clang__) || \
|
||||
defined(__TI_COMPILER_VERSION__)) && \
|
||||
!defined(_WIN32)
|
||||
#define WEAK __attribute__((weak))
|
||||
#else
|
||||
#define WEAK
|
||||
@@ -493,8 +503,20 @@ typedef struct stat cs_stat_t;
|
||||
#line 1 "common/platforms/platform_esp32.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_ESP32_H_
|
||||
@@ -538,8 +560,20 @@ typedef struct stat cs_stat_t;
|
||||
#line 1 "common/platforms/platform_esp8266.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_ESP8266_H_
|
||||
@@ -569,10 +603,6 @@ typedef struct stat cs_stat_t;
|
||||
#define __cdecl
|
||||
#define _FILE_OFFSET_BITS 32
|
||||
|
||||
#if !defined(RTOS_SDK) && !defined(__cplusplus)
|
||||
#define fileno(x) -1
|
||||
#endif
|
||||
|
||||
#define MG_LWIP 1
|
||||
|
||||
/* 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"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_CC3100_H_
|
||||
@@ -652,8 +694,20 @@ int inet_pton(int af, const char *src, void *dst);
|
||||
#line 1 "common/platforms/platform_cc3200.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_CC3200_H_
|
||||
@@ -774,11 +828,147 @@ int stat(const char *pathname, struct stat *st);
|
||||
#endif /* CS_PLATFORM == CS_P_CC3200 */
|
||||
#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */
|
||||
#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"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_MSP432_H_
|
||||
@@ -885,8 +1075,20 @@ int _stat(const char *pathname, struct stat *st);
|
||||
#line 1 "common/platforms/platform_tm4c129.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_TM4C129_H_
|
||||
@@ -945,8 +1147,20 @@ typedef struct stat cs_stat_t;
|
||||
#line 1 "common/platforms/platform_mbed.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_MBED_H_
|
||||
@@ -1029,8 +1243,20 @@ in_addr_t inet_addr(const char *cp);
|
||||
#line 1 "common/platforms/platform_nrf51.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_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"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_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"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_SIMPLELINK_CS_SIMPLELINK_H_
|
||||
@@ -1493,8 +1743,20 @@ const char *strerror();
|
||||
#line 1 "common/platforms/platform_nxp_lpc.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_NXP_LPC_H_
|
||||
@@ -1549,8 +1811,20 @@ typedef struct stat cs_stat_t;
|
||||
#line 1 "common/platforms/platform_nxp_kinetis.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_NXP_KINETIS_H_
|
||||
@@ -1583,8 +1857,20 @@ typedef struct stat cs_stat_t;
|
||||
#line 1 "common/platforms/platform_pic32.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_PIC32_H_
|
||||
@@ -1623,8 +1909,20 @@ char *inet_ntoa(struct in_addr in);
|
||||
#line 1 "common/platforms/platform_stm32.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_STM32_H_
|
||||
@@ -1665,8 +1963,20 @@ typedef struct stat cs_stat_t;
|
||||
#line 1 "common/platforms/lwip/mg_lwip.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_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"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014 Cesanta Software Limited
|
||||
* 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_MD5_H_
|
||||
@@ -1773,8 +2095,20 @@ void cs_md5_final(unsigned char *md, cs_md5_ctx *c);
|
||||
#line 1 "common/cs_sha1.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014 Cesanta Software Limited
|
||||
* 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_SHA1_H_
|
||||
@@ -1815,8 +2149,20 @@ void cs_hmac_sha1(const unsigned char *key, size_t key_len,
|
||||
#line 1 "common/cs_time.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_CS_TIME_H_
|
||||
@@ -1848,8 +2194,20 @@ double cs_timegm(const struct tm *tm);
|
||||
#line 1 "common/mg_str.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_MG_STR_H_
|
||||
@@ -1857,8 +2215,6 @@ double cs_timegm(const struct tm *tm);
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* Amalgamated: #include "common/platform.h" */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#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);
|
||||
|
||||
/* Strip whitespace at the start and the end of s */
|
||||
struct mg_str mg_strstrip(struct mg_str s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1936,8 +2295,20 @@ const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle);
|
||||
#line 1 "common/mbuf.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2015 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -1963,6 +2334,14 @@ extern "C" {
|
||||
#define MBUF_SIZE_MULTIPLIER 1.5
|
||||
#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 */
|
||||
struct mbuf {
|
||||
char *buf; /* Buffer pointer */
|
||||
@@ -2018,8 +2397,20 @@ void mbuf_trim(struct mbuf *);
|
||||
#line 1 "common/cs_base64.h"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2014 Cesanta Software Limited
|
||||
* 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_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_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);
|
||||
|
||||
#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"
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2015 Cesanta Software Limited
|
||||
* 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_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.
|
||||
* `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
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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()`.
|
||||
*/
|
||||
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()`.
|
||||
@@ -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.
|
||||
*/
|
||||
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. */
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
void (*udp_send)(struct mg_connection *nc, const void *buf, size_t len);
|
||||
int (*tcp_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. */
|
||||
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. */
|
||||
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.
|
||||
* if `own` is true, buf must be heap-allocated and ownership is transferred
|
||||
* to the core.
|
||||
* Core will acknowledge consumption by calling iface::recved.
|
||||
* Callback that tells the core that data can be received.
|
||||
* Core will use tcp/udp_recv to retrieve the data.
|
||||
*/
|
||||
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.
|
||||
* 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,
|
||||
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); */
|
||||
|
||||
/* Deliver a POLL event to the connection. */
|
||||
void mg_if_poll(struct mg_connection *nc, time_t now);
|
||||
|
||||
/* Deliver a TIMER event to the connection. */
|
||||
void mg_if_timer(struct mg_connection *c, double now);
|
||||
int mg_if_poll(struct mg_connection *nc, double now);
|
||||
|
||||
#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.
|
||||
* 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.
|
||||
* 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);
|
||||
|
||||
#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,
|
||||
size_t buf_size)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((deprecated));
|
||||
__attribute__((deprecated))
|
||||
#endif
|
||||
;
|
||||
;
|
||||
|
||||
/*
|
||||
* Gets and parses the Authorization: Basic header
|
||||
|
||||
+14
-3
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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"
|
||||
@@ -19,13 +31,12 @@ enum cs_log_level cs_log_threshold WEAK =
|
||||
LL_ERROR;
|
||||
#endif
|
||||
|
||||
#if CS_ENABLE_STDIO
|
||||
static char *s_filter_pattern = NULL;
|
||||
static size_t s_filter_pattern_len;
|
||||
|
||||
void cs_log_set_filter(const char *pattern) WEAK;
|
||||
|
||||
#if CS_ENABLE_STDIO
|
||||
|
||||
FILE *cs_log_file WEAK = NULL;
|
||||
|
||||
#if CS_LOG_ENABLE_TS_DIFF
|
||||
|
||||
+22
-6
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_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
|
||||
* stream.
|
||||
*/
|
||||
void cs_log_printf(const char *fmt, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
#endif
|
||||
;
|
||||
void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2);
|
||||
|
||||
#if CS_ENABLE_STDIO
|
||||
|
||||
/*
|
||||
* 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; \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define LOG(l, x) ((void) l)
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef CS_NDEBUG
|
||||
|
||||
/*
|
||||
|
||||
+13
-1
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Cesanta Software Limited
|
||||
* 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_MD5_H_
|
||||
|
||||
+13
-1
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_time.h"
|
||||
|
||||
+13
-1
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_CS_TIME_H_
|
||||
|
||||
+13
-1
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_MG_MEM_H_
|
||||
|
||||
+11
-1
@@ -92,8 +92,18 @@
|
||||
|
||||
/* 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(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32)
|
||||
#if (defined(__GNUC__) || defined(__clang__) || \
|
||||
defined(__TI_COMPILER_VERSION__)) && \
|
||||
!defined(_WIN32)
|
||||
#define WEAK __attribute__((weak))
|
||||
#else
|
||||
#define WEAK
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2017 Cesanta Software Limited
|
||||
* 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 <stdint.h>
|
||||
|
||||
@@ -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
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if CS_PLATFORM == CS_P_CC3200
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* Copyright (c) 2014-2018 Cesanta Software Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* Spiffy flasher. Implements strong checksums (MD5) and can use higher
|
||||
* baud rates. Actual max baud rate will differe from device to device,
|
||||
* but 921K seems to be common.
|
||||
* 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
|
||||
*
|
||||
* SLIP protocol is used for communication.
|
||||
* First packet is a single byte - command number.
|
||||
* After that, a packet with a variable number of 32-bit (LE) arguments,
|
||||
* depending on command.
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Then command produces variable number of packets of output, but first
|
||||
* packet of length 1 is the response code: 0 for success, non-zero - error.
|
||||
*
|
||||
* See individual command description below.
|
||||
* 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 "stub_flasher.h"
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2017 Cesanta Software Limited
|
||||
* 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 "soc/gpio_reg.h"
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2017 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Cesanta Software Limited
|
||||
* 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
|
||||
*
|
||||
* 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>
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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 "uart.h"
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_ESP32_STUBS_UART_H_
|
||||
|
||||
@@ -25,7 +25,7 @@ $(Q) $(CC_WRAPPER) $(LD) $(LIBDIRS) -T$(LD_SCRIPT) $(LDFLAGS) -o $@ \
|
||||
endef
|
||||
|
||||
define compile_params
|
||||
$(vecho) "$5 $1 -> $2"
|
||||
$(vecho) "$5 $1"
|
||||
$(Q) $(CC_WRAPPER) $3 -MD -MP $(INCDIRS) $4 -c $1 -o $2
|
||||
endef
|
||||
|
||||
@@ -57,7 +57,8 @@ NO_Os_FLAGS= -fno-expensive-optimizations -fno-thread-jumps \
|
||||
-fno-tree-pre -fno-tree-vrp
|
||||
|
||||
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 \
|
||||
-D_XOPEN_SOURCE=500 \
|
||||
-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 \
|
||||
-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)
|
||||
|
||||
# linker flags used to generate the main object file
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mongoose/mongoose.h"
|
||||
#include "mongoose.h"
|
||||
|
||||
#ifdef RTOS_SDK
|
||||
#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
|
||||
*
|
||||
* 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_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_ESP8266_ESP_MISSING_INCLUDES_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_ESP8266_ESP_SSL_KRYPTON_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Cesanta Software Limited
|
||||
* 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 <string.h>
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if ESP_UMM_ENABLE
|
||||
|
||||
@@ -160,7 +160,8 @@ static uint8 calc_chksum(uint8 *start, uint8 *end) {
|
||||
}
|
||||
#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
|
||||
// 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)
|
||||
//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_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
|
||||
SPIRead(0, header, sizeof(rom_header));
|
||||
|
||||
@@ -23,7 +23,7 @@ LD := $(addprefix $(XTENSA_BINDIR)/,xtensa-lx106-elf-gcc)
|
||||
endif
|
||||
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 \
|
||||
-D__ets__ -DIRAM='__attribute__((section(".fast.text")))' \
|
||||
-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
|
||||
*
|
||||
* 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>
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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 "uart.h"
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_ESP8266_STUBS_UART_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_LWIP_MG_LWIP_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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;
|
||||
while (md->sig_queue_len > 0) {
|
||||
mgos_lock();
|
||||
int sig = md->sig_queue[md->start_index].sig;
|
||||
struct mg_connection *nc = md->sig_queue[md->start_index].nc;
|
||||
int i = md->start_index;
|
||||
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;
|
||||
md->start_index = (md->start_index + 1) % MG_SIG_QUEUE_LEN;
|
||||
md->start_index = (i + 1) % MG_SIG_QUEUE_LEN;
|
||||
md->sig_queue_len--;
|
||||
mgos_unlock();
|
||||
if (nc->iface == NULL || nc->mgr == NULL) continue;
|
||||
switch (sig) {
|
||||
case MG_SIG_CONNECT_RESULT: {
|
||||
#if MG_ENABLE_SSL
|
||||
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);
|
||||
}
|
||||
mg_if_connect_cb(nc, cs->err);
|
||||
break;
|
||||
}
|
||||
case MG_SIG_CLOSE_CONN: {
|
||||
@@ -68,11 +73,8 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
|
||||
}
|
||||
case MG_SIG_RECV: {
|
||||
cs->recv_pending = 0;
|
||||
if (nc->flags & MG_F_UDP) {
|
||||
mg_lwip_handle_recv_udp(nc);
|
||||
} else {
|
||||
mg_lwip_handle_recv_tcp(nc);
|
||||
}
|
||||
mg_if_can_recv_cb(nc);
|
||||
mbuf_trim(&nc->recv_mbuf);
|
||||
break;
|
||||
}
|
||||
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) {
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
tmp = nc->next;
|
||||
n++;
|
||||
if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
|
||||
((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 (!mg_if_poll(nc, now)) continue;
|
||||
if (nc->sock != INVALID_SOCKET &&
|
||||
!(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != 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) {
|
||||
/* Try to consume data from cs->rx_chain */
|
||||
mg_lwip_consume_rx_chain_tcp(nc);
|
||||
|
||||
/*
|
||||
* If the connection is about to close, and rx_chain is finally empty,
|
||||
* send the MG_SIG_CLOSE_CONN signal
|
||||
*/
|
||||
if (cs->draining_rx_chain && cs->rx_chain == NULL) {
|
||||
if (mg_lwip_if_can_send(nc, cs)) {
|
||||
mg_if_can_send_cb(nc);
|
||||
mbuf_trim(&nc->send_mbuf);
|
||||
}
|
||||
if (cs->rx_chain != NULL) {
|
||||
mg_if_can_recv_cb(nc);
|
||||
} else if (cs->draining_rx_chain) {
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -210,21 +181,9 @@ uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) {
|
||||
}
|
||||
num_timers++;
|
||||
}
|
||||
if (nc->send_mbuf.len > 0
|
||||
#if MG_ENABLE_SSL
|
||||
|| (nc->flags & MG_F_WANT_WRITE)
|
||||
#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;
|
||||
/* We want and can send data, request a poll immediately. */
|
||||
if (nc->sock != INVALID_SOCKET && mg_lwip_if_can_send(nc, cs)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
uint32_t timeout_ms = ~0;
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
|
||||
@@ -57,10 +69,6 @@
|
||||
typedef void (*tcpip_callback_fn)(void *arg);
|
||||
#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_free(struct mg_iface *iface);
|
||||
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) {
|
||||
struct mg_connection *nc = (struct mg_connection *) arg;
|
||||
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;
|
||||
cs->pcb.tcp = NULL; /* Has already been deallocated */
|
||||
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,
|
||||
struct pbuf *p, err_t err) {
|
||||
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 (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) {
|
||||
/*
|
||||
* 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);
|
||||
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
|
||||
* 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) {
|
||||
/* 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,
|
||||
* 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);
|
||||
if (np != NULL) {
|
||||
pbuf_copy(np, p);
|
||||
@@ -176,58 +185,9 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
|
||||
p = np;
|
||||
}
|
||||
}
|
||||
mgos_unlock();
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
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. */
|
||||
p = pbuf_coalesce(p, PBUF_RAW);
|
||||
pbuf_chain(sap, p);
|
||||
mgos_lock();
|
||||
mg_lwip_recv_common(nc, sap);
|
||||
mgos_unlock();
|
||||
(void) pcb;
|
||||
}
|
||||
|
||||
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;
|
||||
mgos_lock();
|
||||
if (cs->rx_chain == NULL) {
|
||||
cs->rx_chain = p;
|
||||
} else {
|
||||
@@ -329,32 +290,30 @@ static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) {
|
||||
cs->recv_pending = 1;
|
||||
mg_lwip_post_signal(MG_SIG_RECV, nc);
|
||||
}
|
||||
mgos_unlock();
|
||||
}
|
||||
|
||||
static void mg_lwip_handle_recv_udp(struct mg_connection *nc) {
|
||||
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
|
||||
static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
|
||||
union socket_address *sa, size_t *sa_len) {
|
||||
/*
|
||||
* 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).
|
||||
*/
|
||||
while (cs->rx_chain != NULL) {
|
||||
struct pbuf *sap = cs->rx_chain;
|
||||
struct pbuf *p = sap->next;
|
||||
cs->rx_chain = pbuf_dechain(p);
|
||||
size_t data_len = p->len;
|
||||
char *data = (char *) MG_MALLOC(data_len);
|
||||
if (data != NULL) {
|
||||
pbuf_copy_partial(p, data, data_len, 0);
|
||||
pbuf_free(p);
|
||||
mg_if_recv_udp_cb(nc, data, data_len,
|
||||
(union socket_address *) sap->payload, sap->len);
|
||||
pbuf_free(sap);
|
||||
} else {
|
||||
pbuf_free(p);
|
||||
pbuf_free(sap);
|
||||
}
|
||||
int res = 0;
|
||||
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
|
||||
if (nc->sock == INVALID_SOCKET) return -1;
|
||||
mgos_lock();
|
||||
if (cs->rx_chain != NULL) {
|
||||
struct pbuf *ap = cs->rx_chain;
|
||||
struct pbuf *dp = ap->next;
|
||||
cs->rx_chain = pbuf_dechain(dp);
|
||||
res = MIN(dp->len, len);
|
||||
pbuf_copy_partial(dp, buf, res, 0);
|
||||
pbuf_free(dp);
|
||||
pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0);
|
||||
pbuf_free(ap);
|
||||
}
|
||||
mgos_unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
|
||||
if (cs->pcb.tcp == NULL) return;
|
||||
#if MG_ENABLE_SSL
|
||||
if (cs->lc->flags & MG_F_SSL) {
|
||||
if (mg_ssl_if_conn_accept(nc, cs->lc) != MG_SSL_OK) {
|
||||
LOG(LL_ERROR, ("SSL error"));
|
||||
tcpip_callback(tcp_close_tcpip, cs->pcb.tcp);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
mg_lwip_accept_conn(nc, cs->pcb.tcp);
|
||||
}
|
||||
union socket_address sa;
|
||||
struct tcp_pcb *tpcb = cs->pcb.tcp;
|
||||
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 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;
|
||||
}
|
||||
ctx->ret = len;
|
||||
(void) unsent;
|
||||
(void) unacked;
|
||||
}
|
||||
|
||||
static int mg_lwip_tcp_write(struct mg_connection *nc, const void *data,
|
||||
uint16_t len) {
|
||||
struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = data, .len = len};
|
||||
int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) {
|
||||
struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = buf, .len = len};
|
||||
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;
|
||||
if (tpcb == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (tpcb == NULL) return -1;
|
||||
if (tpcb->snd_buf <= 0) return 0;
|
||||
tcpip_callback(mg_lwip_tcp_write_tcpip, &ctx);
|
||||
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);
|
||||
}
|
||||
|
||||
static int mg_lwip_udp_send(struct mg_connection *nc, const void *data,
|
||||
uint16_t len) {
|
||||
static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data,
|
||||
size_t len) {
|
||||
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
|
||||
if (cs->pcb.udp == NULL) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
if (nc->sock == INVALID_SOCKET || cs->pcb.udp == NULL) return -1;
|
||||
struct udp_pcb *upcb = cs->pcb.udp;
|
||||
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
|
||||
#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};
|
||||
#endif
|
||||
u16_t port = ntohs(nc->sa.sin.sin_port);
|
||||
if (p == NULL) {
|
||||
DBG(("OOM"));
|
||||
return 0;
|
||||
}
|
||||
if (p == NULL) return 0;
|
||||
memcpy(p->payload, data, len);
|
||||
struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port};
|
||||
tcpip_callback(udp_sendto_tcpip, &ctx);
|
||||
cs->err = ctx.ret;
|
||||
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) {
|
||||
int num_sent = 0;
|
||||
if (nc->sock == INVALID_SOCKET) return;
|
||||
if (nc->flags & MG_F_UDP) {
|
||||
num_sent = mg_lwip_udp_send(nc, nc->send_mbuf.buf, nc->send_mbuf.len);
|
||||
DBG(("%p mg_lwip_udp_send %u = %d", nc, nc->send_mbuf.len, num_sent));
|
||||
} else {
|
||||
num_sent = mg_lwip_tcp_write(nc, nc->send_mbuf.buf, nc->send_mbuf.len);
|
||||
DBG(("%p mg_lwip_tcp_write %u = %d", nc, nc->send_mbuf.len, num_sent));
|
||||
static int mg_lwip_if_can_send(struct mg_connection *nc,
|
||||
struct mg_lwip_conn_state *cs) {
|
||||
int can_send = 0;
|
||||
if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
if (num_sent == 0) return;
|
||||
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);
|
||||
return can_send;
|
||||
}
|
||||
|
||||
struct tcp_recved_ctx {
|
||||
@@ -654,27 +575,35 @@ void tcp_recved_tcpip(void *arg) {
|
||||
tcp_recved(ctx->tpcb, ctx->len);
|
||||
}
|
||||
|
||||
void mg_lwip_if_recved(struct mg_connection *nc, size_t len) {
|
||||
if (nc->flags & MG_F_UDP) return;
|
||||
static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf,
|
||||
size_t len) {
|
||||
int res = 0;
|
||||
char *bufp = buf;
|
||||
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
|
||||
if (nc->sock == INVALID_SOCKET || cs->pcb.tcp == NULL) {
|
||||
DBG(("%p invalid socket", nc));
|
||||
return;
|
||||
if (nc->sock == INVALID_SOCKET) return -1;
|
||||
mgos_lock();
|
||||
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,
|
||||
(cs->rx_chain ? cs->rx_chain->tot_len : 0)));
|
||||
struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = len};
|
||||
#if MG_ENABLE_SSL
|
||||
if (!(nc->flags & MG_F_SSL)) {
|
||||
mgos_unlock();
|
||||
if (res > 0) {
|
||||
struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = res};
|
||||
tcpip_callback(tcp_recved_tcpip, &ctx);
|
||||
} else {
|
||||
/* Currently SSL acknowledges data immediately.
|
||||
* TODO(rojer): Find a way to propagate mg_lwip_if_recved. */
|
||||
}
|
||||
#else
|
||||
tcpip_callback(tcp_recved_tcpip, &ctx);
|
||||
#endif
|
||||
mbuf_trim(&nc->recv_mbuf);
|
||||
return res;
|
||||
}
|
||||
|
||||
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_tcp_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_destroy_conn, \
|
||||
mg_lwip_if_sock_set, \
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_LWIP_MG_NET_IF_LWIP_H_
|
||||
@@ -30,9 +42,9 @@ struct mg_lwip_conn_state {
|
||||
/* Last SSL write size, for retries. */
|
||||
int last_ssl_write_size;
|
||||
/* 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 */
|
||||
int draining_rx_chain : 1;
|
||||
int draining_rx_chain;
|
||||
};
|
||||
|
||||
enum mg_sig_type {
|
||||
|
||||
@@ -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 */
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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/platform.h"
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if CS_PLATFORM == CS_P_MSP432
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if (CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52) && \
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if MG_ENABLE_NET_IF_PIC32
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_PIC32_NET_IF_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_CC3100_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_CC3200_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_
|
||||
@@ -22,7 +34,9 @@
|
||||
#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)
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_ESP32_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_ESP8266_H_
|
||||
@@ -30,10 +42,6 @@ typedef struct stat cs_stat_t;
|
||||
#define __cdecl
|
||||
#define _FILE_OFFSET_BITS 32
|
||||
|
||||
#if !defined(RTOS_SDK) && !defined(__cplusplus)
|
||||
#define fileno(x) -1
|
||||
#endif
|
||||
|
||||
#define MG_LWIP 1
|
||||
|
||||
/* struct timeval is defined in sys/time.h. */
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_MBED_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_MSP432_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_NRF51_H_
|
||||
#define CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_NRF52_H_
|
||||
#define CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_NXP_KINETIS_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_NXP_LPC_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_PIC32_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_STM32_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_TM4C129_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_SIMPLELINK_CS_SIMPLELINK_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if MG_NET_IF == MG_NET_IF_SIMPLELINK && \
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Standard libc interface to TI SimpleLink FS. */
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_SIMPLELINK_SL_FS_SLFS_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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/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,
|
||||
int proto);
|
||||
|
||||
void mg_set_non_blocking_mode(sock_t sock) {
|
||||
static void mg_set_non_blocking_mode(sock_t sock) {
|
||||
SlSockNonblocking_t opt;
|
||||
#if SL_MAJOR_VERSION_NUM < 2
|
||||
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);
|
||||
}
|
||||
|
||||
void mg_sl_if_connect_tcp(struct mg_connection *nc,
|
||||
const union socket_address *sa) {
|
||||
static void mg_sl_if_connect_tcp(struct mg_connection *nc,
|
||||
const union socket_address *sa) {
|
||||
int proto = 0;
|
||||
#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
|
||||
if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
|
||||
#endif
|
||||
sock_t sock = sl_Socket(AF_INET, SOCK_STREAM, proto);
|
||||
if (sock < 0) {
|
||||
nc->err = sock;
|
||||
goto out;
|
||||
}
|
||||
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);
|
||||
if (nc->err != 0) goto out;
|
||||
#endif
|
||||
@@ -51,7 +65,7 @@ out:
|
||||
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);
|
||||
if (sock < 0) {
|
||||
nc->err = sock;
|
||||
@@ -61,7 +75,8 @@ void mg_sl_if_connect_udp(struct mg_connection *nc) {
|
||||
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;
|
||||
if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
if (sock == INVALID_SOCKET) return (errno ? errno : 1);
|
||||
mg_sock_set(nc, sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) {
|
||||
mbuf_append(&nc->send_mbuf, buf, len);
|
||||
static int mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf,
|
||||
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) {
|
||||
mbuf_append(&nc->send_mbuf, buf, len);
|
||||
static int mg_sl_if_udp_send(struct mg_connection *nc, const void *buf,
|
||||
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) {
|
||||
(void) nc;
|
||||
(void) len;
|
||||
static int mg_sl_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len) {
|
||||
int n = sl_Recv(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)) {
|
||||
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;
|
||||
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),
|
||||
ntohs(sa.sin.sin_port)));
|
||||
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);
|
||||
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);
|
||||
sock_t sock = sl_Socket(sa->sa.sa_family, type, proto);
|
||||
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 (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;
|
||||
}
|
||||
mg_set_non_blocking_mode(sock);
|
||||
@@ -151,86 +188,18 @@ clean:
|
||||
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_WRITE 1 << 1
|
||||
#define _MG_F_FD_ERROR 1 << 2
|
||||
|
||||
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));
|
||||
|
||||
if (!mg_if_poll(nc, now)) return;
|
||||
|
||||
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);
|
||||
} else {
|
||||
/* 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;
|
||||
}
|
||||
if (nc->flags & MG_F_SSL && nc->err == 0) {
|
||||
nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
|
||||
}
|
||||
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 (nc->flags & MG_F_UDP) {
|
||||
mg_handle_udp_read(nc);
|
||||
mg_if_can_recv_cb(nc);
|
||||
} else {
|
||||
if (nc->flags & MG_F_LISTENING) {
|
||||
mg_accept_conn(nc);
|
||||
} 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) && nc->send_mbuf.len > 0) {
|
||||
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);
|
||||
if (fd_flags & _MG_F_FD_CAN_WRITE) {
|
||||
mg_if_can_send_cb(nc);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -464,7 +415,8 @@ void sl_restart_cb(struct mg_mgr *mgr) {
|
||||
mg_sl_if_connect_udp, \
|
||||
mg_sl_if_tcp_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_destroy_conn, \
|
||||
mg_sl_if_sock_set, \
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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_SIMPLELINK_SL_NET_IF_H_
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if MG_NET_IF == MG_NET_IF_SIMPLELINK
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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) {
|
||||
/* Nothing to do */
|
||||
(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;
|
||||
DBG(("%p ssl ctx: %p", nc, ctx));
|
||||
|
||||
if (ctx != NULL) {
|
||||
DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"),
|
||||
(ctx->ssl_key ? ctx->ssl_cert : "-"),
|
||||
(ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"),
|
||||
(ctx->ssl_server_name ? ctx->ssl_server_name : "-")));
|
||||
if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) {
|
||||
char *ssl_cert = sl_pem2der(ctx->ssl_cert);
|
||||
char *ssl_key = sl_pem2der(ctx->ssl_key);
|
||||
if (ssl_cert != NULL && ssl_key != NULL) {
|
||||
err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
|
||||
SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert,
|
||||
strlen(ssl_cert));
|
||||
LOG(LL_INFO, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err));
|
||||
if (ctx == NULL) return 0;
|
||||
DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"),
|
||||
(ctx->ssl_key ? ctx->ssl_cert : "-"),
|
||||
(ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"),
|
||||
(ctx->ssl_server_name ? ctx->ssl_server_name : "-")));
|
||||
if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) {
|
||||
char *ssl_cert = sl_pem2der(ctx->ssl_cert), *ssl_key = NULL;
|
||||
if (ssl_cert != NULL) {
|
||||
err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
|
||||
SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert,
|
||||
strlen(ssl_cert));
|
||||
MG_FREE(ssl_cert);
|
||||
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,
|
||||
SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, 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 {
|
||||
err = -1;
|
||||
}
|
||||
MG_FREE(ssl_cert);
|
||||
MG_FREE(ssl_key);
|
||||
} else {
|
||||
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 (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_INFO, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err));
|
||||
} else {
|
||||
err = -1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef WINCE
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Cesanta Software Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* 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/test_util.h"
|
||||
|
||||
+110
-52
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Cesanta Software Limited
|
||||
* Copyright (c) 2014-2018 Cesanta Software Limited
|
||||
* All rights reserved
|
||||
* This software is dual-licensed: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. For the terms of this
|
||||
* license, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
* 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
|
||||
*
|
||||
* Alternatively, you can license this software under a commercial
|
||||
* license, as set out in <https://www.cesanta.com/license>.
|
||||
* 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_UTIL_H_
|
||||
@@ -28,6 +28,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
extern int g_num_tests;
|
||||
extern int g_num_checks;
|
||||
|
||||
#ifdef MG_TEST_ABORT_ON_FAIL
|
||||
#define MG_TEST_ABORT abort()
|
||||
@@ -48,7 +49,7 @@ void _strfail(const char *a, const char *e, int len);
|
||||
|
||||
#define ASSERT(expr) \
|
||||
do { \
|
||||
g_num_tests++; \
|
||||
g_num_checks++; \
|
||||
if (!(expr)) FAIL(#expr, __LINE__); \
|
||||
} while (0)
|
||||
#define ASSERT_TRUE(expr) ASSERT(expr)
|
||||
@@ -71,55 +72,108 @@ void _strfail(const char *a, const char *e, int len);
|
||||
elapsed = cs_time() - elapsed; \
|
||||
printf(" [%.3f] %s\n", elapsed, test_name); \
|
||||
fflush(stdout); \
|
||||
g_num_tests++; \
|
||||
} \
|
||||
if (msg) return msg; \
|
||||
} 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)
|
||||
#define AS_DOUBLE(d) (double)(int64_t)(d)
|
||||
#define LONG_TYPE int64_t
|
||||
#else
|
||||
#define AS_DOUBLE(d) (double)(d)
|
||||
#define LONG_TYPE long long
|
||||
#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
|
||||
* printing both are convetrted to double.
|
||||
* Numeric equality assertion.
|
||||
* 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) \
|
||||
do { \
|
||||
g_num_tests++; \
|
||||
if (!((actual) == (expected))) { \
|
||||
printf("%f != %f\n", AS_DOUBLE(actual), AS_DOUBLE(expected)); \
|
||||
FAIL(#actual " == " #expected, __LINE__); \
|
||||
} \
|
||||
#define ASSERT_EQ(actual, expected) \
|
||||
do { \
|
||||
const double ad = AS_DOUBLE(actual); \
|
||||
const double ed = AS_DOUBLE(expected); \
|
||||
if (RANGE_CHECK(ad) || RANGE_CHECK(ed)) { \
|
||||
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)
|
||||
|
||||
/* "Less than" assertion. */
|
||||
#define ASSERT_LT(a, b) \
|
||||
do { \
|
||||
g_num_tests++; \
|
||||
if (!((a) < (b))) { \
|
||||
printf("%f >= %f\n", AS_DOUBLE(a), AS_DOUBLE(b)); \
|
||||
FAIL(#a " < " #b, __LINE__); \
|
||||
} \
|
||||
#define ASSERT_LT(a, b) \
|
||||
do { \
|
||||
const double ad = AS_DOUBLE(a); \
|
||||
const double bd = AS_DOUBLE(b); \
|
||||
g_num_checks++; \
|
||||
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)
|
||||
|
||||
/* "Greater than" assertion. */
|
||||
#define ASSERT_GT(a, b) \
|
||||
do { \
|
||||
g_num_tests++; \
|
||||
if (!((a) > (b))) { \
|
||||
printf("%f <= %f\n", AS_DOUBLE(a), AS_DOUBLE(b)); \
|
||||
FAIL(#a " > " #b, __LINE__); \
|
||||
} \
|
||||
#define ASSERT_GT(a, b) \
|
||||
do { \
|
||||
const double ad = AS_DOUBLE(a); \
|
||||
const double bd = AS_DOUBLE(b); \
|
||||
g_num_checks++; \
|
||||
if (!(ad > bd)) { \
|
||||
printf("%lf <= %lf\n", ad, bd); \
|
||||
FAIL(#a " > " #b, __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Assert that actual == expected, where both are NUL-terminated. */
|
||||
#define ASSERT_STREQ(actual, expected) \
|
||||
do { \
|
||||
g_num_tests++; \
|
||||
if (!_assert_streq(actual, expected)) { \
|
||||
g_num_checks++; \
|
||||
if (!_assert_streq((actual), (expected))) { \
|
||||
FAIL("ASSERT_STREQ(" #actual ", " #expected ")", __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
@@ -127,27 +181,31 @@ void _strfail(const char *a, const char *e, int len);
|
||||
/* Assert that actual == expected, where both are pointers */
|
||||
#define ASSERT_PTREQ(actual, expected) \
|
||||
do { \
|
||||
g_num_tests++; \
|
||||
if (actual != expected) { \
|
||||
printf("%p != %p\n", actual, expected); \
|
||||
const void *ap = (const void *) (actual); \
|
||||
const void *ep = (const void *) (expected); \
|
||||
g_num_checks++; \
|
||||
if (!(ap == ep)) { \
|
||||
printf("%p != %p\n", ap, ep); \
|
||||
FAIL("ASSERT_PTREQ(" #actual ", " #expected ")", __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Assert that actual != expected, where both are pointers */
|
||||
#define ASSERT_PTRNEQ(actual, expected) \
|
||||
do { \
|
||||
g_num_tests++; \
|
||||
if (actual == expected) { \
|
||||
printf("%p == %p\n", actual, expected); \
|
||||
FAIL("ASSERT_PTRNEQ(" #actual ", " #expected ")", __LINE__); \
|
||||
} \
|
||||
#define ASSERT_PTRNE(actual, expected) \
|
||||
do { \
|
||||
const void *ap = (const void *) (actual); \
|
||||
const void *ep = (const void *) (expected); \
|
||||
g_num_checks++; \
|
||||
if (!(ap != ep)) { \
|
||||
printf("%p == %p\n", ap, ep); \
|
||||
FAIL("ASSERT_PTRNE(" #actual ", " #expected ")", __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Same as STREQ, but only expected is NUL-terminated. */
|
||||
#define ASSERT_STREQ_NZ(actual, expected) \
|
||||
do { \
|
||||
g_num_tests++; \
|
||||
g_num_checks++; \
|
||||
if (!_assert_streq_nz(actual, expected)) { \
|
||||
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) \
|
||||
do { \
|
||||
g_num_tests++; \
|
||||
g_num_checks++; \
|
||||
if ((actual).len != strlen(expected) || \
|
||||
memcmp((actual).p, expected, (actual).len) != 0) { \
|
||||
printf("'%.*s' (%d) != '%s'\n", (int)(actual).len, (actual).p, \
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
#ifndef 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. */
|
||||
#ifdef MG_LOCALS
|
||||
|
||||
+36
-45
@@ -127,7 +127,6 @@ enum mg_http_multipart_stream_state {
|
||||
MPS_BEGIN,
|
||||
MPS_WAITING_FOR_BOUNDARY,
|
||||
MPS_WAITING_FOR_CHUNK,
|
||||
MPS_GOT_CHUNK,
|
||||
MPS_GOT_BOUNDARY,
|
||||
MPS_FINALIZE,
|
||||
MPS_FINISHED
|
||||
@@ -139,7 +138,6 @@ struct mg_http_multipart_stream {
|
||||
const char *var_name;
|
||||
const char *file_name;
|
||||
void *user_data;
|
||||
int prev_io_len;
|
||||
enum mg_http_multipart_stream_state state;
|
||||
int processing_part;
|
||||
};
|
||||
@@ -787,6 +785,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
|
||||
}
|
||||
#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
|
||||
|
||||
again:
|
||||
req_len = mg_parse_http(io->buf, io->len, hm, is_req);
|
||||
|
||||
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 */
|
||||
mg_http_call_endpoint_handler(nc, trigger_ev, hm);
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
if (boundary == NULL && pd->mp_stream.prev_io_len == 0) {
|
||||
pd->mp_stream.prev_io_len = io->len;
|
||||
if (boundary == NULL) {
|
||||
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;
|
||||
} 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) {
|
||||
int data_size = (boundary - io->buf - 4);
|
||||
mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, data_size);
|
||||
mbuf_remove(io, (boundary - io->buf));
|
||||
pd->mp_stream.prev_io_len = 0;
|
||||
pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
|
||||
return 1;
|
||||
} else {
|
||||
@@ -1164,12 +1152,6 @@ static void mg_http_multipart_continue(struct mg_connection *c) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MPS_GOT_CHUNK: {
|
||||
if (mg_http_multipart_got_chunk(c) == 0) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MPS_FINALIZE: {
|
||||
if (mg_http_multipart_finalize(c) == 0) {
|
||||
return;
|
||||
@@ -1177,7 +1159,6 @@ static void mg_http_multipart_continue(struct mg_connection *c) {
|
||||
break;
|
||||
}
|
||||
case MPS_FINISHED: {
|
||||
mbuf_remove(&c->recv_mbuf, c->recv_mbuf.len);
|
||||
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,
|
||||
const struct mg_str extra_headers) {
|
||||
mg_printf(nc, "HTTP/1.1 %d %s\r\nServer: %s\r\n", status_code,
|
||||
mg_status_message(status_code), mg_version_header);
|
||||
mg_printf(nc, "HTTP/1.1 %d %s\r\n", status_code,
|
||||
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) {
|
||||
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,
|
||||
const char *var_name,
|
||||
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;
|
||||
|
||||
/* 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) {
|
||||
s += n + 1;
|
||||
if (*s == '"' || *s == '\'') {
|
||||
ch = ch1 = *s++;
|
||||
ch = ch1 = ch2 = *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++;
|
||||
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,
|
||||
void (*func)(struct mg_connection *, const char *,
|
||||
cs_stat_t *)) {
|
||||
char path[MG_MAX_PATH];
|
||||
char path[MG_MAX_PATH + 1];
|
||||
cs_stat_t st;
|
||||
struct dirent *dp;
|
||||
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: {
|
||||
struct mg_http_multipart_part *mp =
|
||||
(struct mg_http_multipart_part *) ev_data;
|
||||
struct file_upload_state *fus =
|
||||
(struct file_upload_state *) MG_CALLOC(1, sizeof(*fus));
|
||||
struct file_upload_state *fus;
|
||||
struct mg_str lfn = local_name_fn(nc, mg_mk_str(mp->file_name));
|
||||
mp->user_data = NULL;
|
||||
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;
|
||||
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);
|
||||
memcpy(fus->lfn, lfn.p, lfn.len);
|
||||
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) {
|
||||
LOG(LL_DEBUG, ("%p Uploaded %s (%s), %d bytes", nc, mp->file_name,
|
||||
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 {
|
||||
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);
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
+2
-3
@@ -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,
|
||||
fds[1]) != 0) {
|
||||
size_t n = nc->recv_mbuf.len - (hm->message.len - hm->body.len);
|
||||
struct mg_connection *cgi_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);
|
||||
@@ -488,8 +487,8 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
|
||||
#endif
|
||||
nc->flags |= MG_F_HTTP_CGI_PARSE_HEADERS;
|
||||
/* Push POST data to the CGI */
|
||||
if (n > 0 && n < nc->recv_mbuf.len) {
|
||||
mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, n);
|
||||
if (hm->body.len > 0) {
|
||||
mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, hm->body.len);
|
||||
}
|
||||
mbuf_remove(&nc->recv_mbuf, nc->recv_mbuf.len);
|
||||
} else {
|
||||
|
||||
@@ -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,
|
||||
size_t buf_size)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((deprecated));
|
||||
__attribute__((deprecated))
|
||||
#endif
|
||||
;
|
||||
;
|
||||
|
||||
/*
|
||||
* Gets and parses the Authorization: Basic header
|
||||
|
||||
+1
-1
@@ -8,6 +8,7 @@ HEADERS = mg_common.h \
|
||||
$(COMMON)/platforms/platform_esp8266.h \
|
||||
$(COMMON)/platforms/platform_cc3100.h \
|
||||
$(COMMON)/platforms/platform_cc3200.h \
|
||||
$(COMMON)/platforms/platform_cc3220.h \
|
||||
$(COMMON)/platforms/platform_msp432.h \
|
||||
$(COMMON)/platforms/platform_tm4c129.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.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/pic32/pic32_net_if.h \
|
||||
$(COMMON)/platforms/pic32/pic32_net_if.c \
|
||||
|
||||
+109
-82
@@ -228,18 +228,13 @@ void mg_set_protocol_mqtt(struct mg_connection *nc) {
|
||||
nc->proto_data_destructor = mg_mqtt_proto_data_destructor;
|
||||
}
|
||||
|
||||
static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd,
|
||||
uint8_t flags, size_t len) {
|
||||
static void mg_send_mqtt_header(struct mg_connection *nc, uint8_t cmd,
|
||||
uint8_t flags, size_t len) {
|
||||
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 *vlen = &buf[1];
|
||||
|
||||
assert(nc->send_mbuf.len >= len);
|
||||
|
||||
buf[0] = header;
|
||||
buf[0] = (cmd << 4) | flags;
|
||||
|
||||
/* mqtt variable length encoding */
|
||||
do {
|
||||
@@ -249,7 +244,7 @@ static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd,
|
||||
vlen++;
|
||||
} while (len > 0);
|
||||
|
||||
mbuf_insert(&nc->send_mbuf, off, buf, vlen - buf);
|
||||
mg_send(nc, buf, vlen - buf);
|
||||
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,
|
||||
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;
|
||||
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);
|
||||
rem_len += 7;
|
||||
if (client_id != NULL) {
|
||||
id_len = strlen(client_id);
|
||||
}
|
||||
|
||||
total_len = 7 + 1 + 2 + 2 + id_len;
|
||||
|
||||
if (opts.user_name != NULL) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (opts.keep_alive == 0) {
|
||||
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);
|
||||
rem_len += 1;
|
||||
|
||||
nlen = htons(opts.keep_alive);
|
||||
mg_send(nc, &nlen, 2);
|
||||
rem_len += 2;
|
||||
netbytes = htons(opts.keep_alive);
|
||||
mg_send(nc, &netbytes, 2);
|
||||
|
||||
hlen = strlen(client_id);
|
||||
nlen = htons((uint16_t) hlen);
|
||||
mg_send(nc, &nlen, 2);
|
||||
mg_send(nc, client_id, hlen);
|
||||
rem_len += 2 + hlen;
|
||||
netbytes = htons(id_len);
|
||||
mg_send(nc, &netbytes, 2);
|
||||
mg_send(nc, client_id, id_len);
|
||||
|
||||
if (opts.flags & MG_MQTT_HAS_WILL) {
|
||||
hlen = strlen(opts.will_topic);
|
||||
nlen = htons((uint16_t) hlen);
|
||||
mg_send(nc, &nlen, 2);
|
||||
mg_send(nc, opts.will_topic, hlen);
|
||||
rem_len += 2 + hlen;
|
||||
netbytes = htons(wt_len);
|
||||
mg_send(nc, &netbytes, 2);
|
||||
mg_send(nc, opts.will_topic, wt_len);
|
||||
|
||||
hlen = strlen(opts.will_message);
|
||||
nlen = htons((uint16_t) hlen);
|
||||
mg_send(nc, &nlen, 2);
|
||||
mg_send(nc, opts.will_message, hlen);
|
||||
rem_len += 2 + hlen;
|
||||
netbytes = htons(wm_len);
|
||||
mg_send(nc, &netbytes, 2);
|
||||
mg_send(nc, opts.will_message, wm_len);
|
||||
}
|
||||
|
||||
if (opts.flags & MG_MQTT_HAS_USER_NAME) {
|
||||
hlen = strlen(opts.user_name);
|
||||
nlen = htons((uint16_t) hlen);
|
||||
mg_send(nc, &nlen, 2);
|
||||
mg_send(nc, opts.user_name, hlen);
|
||||
rem_len += 2 + hlen;
|
||||
netbytes = htons(user_len);
|
||||
mg_send(nc, &netbytes, 2);
|
||||
mg_send(nc, opts.user_name, user_len);
|
||||
}
|
||||
if (opts.flags & MG_MQTT_HAS_PASSWORD) {
|
||||
hlen = strlen(opts.password);
|
||||
nlen = htons((uint16_t) hlen);
|
||||
mg_send(nc, &nlen, 2);
|
||||
mg_send(nc, opts.password, hlen);
|
||||
rem_len += 2 + hlen;
|
||||
netbytes = htons(pw_len);
|
||||
mg_send(nc, &netbytes, 2);
|
||||
mg_send(nc, opts.password, pw_len);
|
||||
}
|
||||
|
||||
mg_mqtt_prepend_header(nc, MG_MQTT_CMD_CONNECT, 0, rem_len);
|
||||
|
||||
if (pd != NULL) {
|
||||
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,
|
||||
uint16_t message_id, int flags, const void *data,
|
||||
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));
|
||||
uint16_t message_id_net = htons(message_id);
|
||||
|
||||
mg_send(nc, &topic_len, 2);
|
||||
mg_send(nc, topic, strlen(topic));
|
||||
size_t total_len = 2 + topic_len + len;
|
||||
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,
|
||||
nc->send_mbuf.len - old_len);
|
||||
mg_send_mqtt_header(nc, MG_MQTT_CMD_PUBLISH, flags, total_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,
|
||||
const struct mg_mqtt_topic_expression *topics,
|
||||
size_t topics_len, uint16_t message_id) {
|
||||
size_t old_len = nc->send_mbuf.len;
|
||||
|
||||
uint16_t message_id_n = htons(message_id);
|
||||
uint16_t netbytes;
|
||||
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++) {
|
||||
uint16_t topic_len_n = htons((uint16_t) strlen(topics[i].topic));
|
||||
mg_send(nc, &topic_len_n, 2);
|
||||
mg_send(nc, topics[i].topic, strlen(topics[i].topic));
|
||||
mg_send(nc, &topics[i].qos, 1);
|
||||
total_len += 2 + strlen(topics[i].topic) + 1;
|
||||
}
|
||||
|
||||
mg_mqtt_prepend_header(nc, MG_MQTT_CMD_SUBSCRIBE, MG_MQTT_QOS(1),
|
||||
nc->send_mbuf.len - old_len);
|
||||
mg_send_mqtt_header(nc, MG_MQTT_CMD_SUBSCRIBE, MG_MQTT_QOS(1), total_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,
|
||||
@@ -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,
|
||||
size_t topics_len, uint16_t message_id) {
|
||||
size_t old_len = nc->send_mbuf.len;
|
||||
|
||||
uint16_t message_id_n = htons(message_id);
|
||||
uint16_t netbytes;
|
||||
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++) {
|
||||
uint16_t topic_len_n = htons((uint16_t) strlen(topics[i]));
|
||||
mg_send(nc, &topic_len_n, 2);
|
||||
mg_send(nc, topics[i], strlen(topics[i]));
|
||||
total_len += 2 + strlen(topics[i]);
|
||||
}
|
||||
|
||||
mg_mqtt_prepend_header(nc, MG_MQTT_CMD_UNSUBSCRIBE, MG_MQTT_QOS(1),
|
||||
nc->send_mbuf.len - old_len);
|
||||
mg_send_mqtt_header(nc, MG_MQTT_CMD_UNSUBSCRIBE, MG_MQTT_QOS(1), total_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) {
|
||||
uint8_t unused = 0;
|
||||
mg_send_mqtt_header(nc, MG_MQTT_CMD_CONNACK, 0, 2);
|
||||
mg_send(nc, &unused, 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,
|
||||
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);
|
||||
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) {
|
||||
@@ -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,
|
||||
uint16_t message_id) {
|
||||
size_t i;
|
||||
uint16_t message_id_net = htons(message_id);
|
||||
mg_send(nc, &message_id_net, 2);
|
||||
uint16_t netbytes;
|
||||
|
||||
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++) {
|
||||
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) {
|
||||
@@ -452,15 +479,15 @@ void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) {
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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 */
|
||||
+276
-103
@@ -24,6 +24,13 @@
|
||||
|
||||
#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) \
|
||||
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_event_handler_t ev_handler, void *user_data, int ev,
|
||||
void *ev_data) {
|
||||
static int nesting_level = 0;
|
||||
nesting_level++;
|
||||
if (ev_handler == NULL) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
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,
|
||||
(int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
|
||||
}
|
||||
@@ -87,33 +92,24 @@ MG_INTERNAL void mg_call(struct mg_connection *nc,
|
||||
#endif
|
||||
if (ev_handler != NULL) {
|
||||
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));
|
||||
recved = (recv_mbuf_before - nc->recv_mbuf.len);
|
||||
/* Prevent user handler from fiddling with system flags. */
|
||||
if (ev_handler == nc->handler && nc->flags != flags_before) {
|
||||
nc->flags = (flags_before & ~_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) {
|
||||
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,
|
||||
(int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
|
||||
}
|
||||
nesting_level--;
|
||||
#if !MG_ENABLE_CALLBACK_USERDATA
|
||||
(void) user_data;
|
||||
#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) {
|
||||
double old_value = c->ev_timer_time;
|
||||
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) {
|
||||
if (!(nc->flags & MG_F_SSL) || (nc->flags & MG_F_SSL_HANDSHAKE_DONE)) {
|
||||
mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now);
|
||||
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 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) {
|
||||
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 (conn->proto_data != NULL && conn->proto_data_destructor != NULL) {
|
||||
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) {
|
||||
DBG(("%p %lu %d", conn, conn->flags, conn->sock));
|
||||
#if MG_ENABLE_SSL
|
||||
if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) {
|
||||
mg_ssl_if_conn_close_notify(conn);
|
||||
}
|
||||
#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);
|
||||
conn->iface->vtable->destroy_conn(conn);
|
||||
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);
|
||||
#endif
|
||||
|
||||
#if MG_ENABLE_SSL
|
||||
{
|
||||
static int init_done;
|
||||
if (!init_done) {
|
||||
mg_ssl_if_init();
|
||||
init_done++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
{
|
||||
int i;
|
||||
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->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]->vtable->init(m->ifaces[i]);
|
||||
}
|
||||
@@ -211,6 +234,15 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data,
|
||||
}
|
||||
DBG(("=================================="));
|
||||
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) {
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
#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_add_sock_opts opts;
|
||||
struct mg_connection *nc;
|
||||
@@ -466,95 +529,125 @@ struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) {
|
||||
nc->iface = lc->iface;
|
||||
if (lc->flags & MG_F_SSL) nc->flags |= MG_F_SSL;
|
||||
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;
|
||||
}
|
||||
|
||||
void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa,
|
||||
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;
|
||||
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) {
|
||||
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) {
|
||||
nc->iface->vtable->udp_send(nc, buf, len);
|
||||
res = mg_recv_udp(nc, buf, len);
|
||||
} 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) {
|
||||
DBG(("%p %d", nc, num_sent));
|
||||
#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);
|
||||
void mg_if_can_recv_cb(struct mg_connection *nc) {
|
||||
mg_do_recv(nc);
|
||||
}
|
||||
|
||||
MG_INTERNAL void mg_recv_common(struct mg_connection *nc, void *buf, int len,
|
||||
int own) {
|
||||
DBG(("%p %d %u", nc, len, (unsigned int) nc->recv_mbuf.len));
|
||||
|
||||
#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
|
||||
if (nc->mgr && nc->mgr->hexdump_file != NULL) {
|
||||
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, len, MG_EV_RECV);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nc->flags & MG_F_CLOSE_IMMEDIATELY) {
|
||||
DBG(("%p discarded %d bytes", nc, len));
|
||||
/*
|
||||
* This connection will not survive next poll. Do not deliver events,
|
||||
* send data to /dev/null without acking.
|
||||
*/
|
||||
if (own) {
|
||||
MG_FREE(buf);
|
||||
static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) {
|
||||
int n = 0;
|
||||
#if MG_ENABLE_SSL
|
||||
if (nc->flags & MG_F_SSL) {
|
||||
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
|
||||
n = mg_ssl_if_read(nc, buf, len);
|
||||
DBG(("%p <- %d bytes (SSL)", nc, n));
|
||||
if (n < 0) {
|
||||
if (n == MG_SSL_WANT_READ) {
|
||||
nc->flags |= MG_F_WANT_READ;
|
||||
n = 0;
|
||||
} else {
|
||||
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
}
|
||||
} else if (n > 0) {
|
||||
nc->flags &= ~MG_F_WANT_READ;
|
||||
}
|
||||
} 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 (!own) {
|
||||
mbuf_append(&nc->recv_mbuf, buf, len);
|
||||
} else if (nc->recv_mbuf.len == 0) {
|
||||
/* Adopt buf as recv_mbuf's backing store. */
|
||||
mbuf_free(&nc->recv_mbuf);
|
||||
nc->recv_mbuf.buf = (char *) buf;
|
||||
nc->recv_mbuf.size = nc->recv_mbuf.len = len;
|
||||
} else {
|
||||
mbuf_append(&nc->recv_mbuf, buf, len);
|
||||
MG_FREE(buf);
|
||||
if (n > 0) {
|
||||
nc->recv_mbuf.len += n;
|
||||
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);
|
||||
} else if (n < 0) {
|
||||
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) {
|
||||
mg_recv_common(nc, buf, len, own);
|
||||
}
|
||||
|
||||
void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
|
||||
union socket_address *sa, size_t sa_len) {
|
||||
assert(nc->flags & MG_F_UDP);
|
||||
DBG(("%p %u", nc, (unsigned int) len));
|
||||
static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
|
||||
int n = 0;
|
||||
struct mg_connection *lc = nc;
|
||||
union socket_address sa;
|
||||
size_t sa_len = sizeof(sa);
|
||||
n = nc->iface->vtable->udp_recv(lc, buf, len, &sa, &sa_len);
|
||||
if (n < 0) {
|
||||
lc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
goto out;
|
||||
}
|
||||
if (nc->flags & MG_F_LISTENING) {
|
||||
struct mg_connection *lc = nc;
|
||||
/*
|
||||
* Do we have an existing connection for this source?
|
||||
* 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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -566,7 +659,7 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
|
||||
if (nc != NULL) {
|
||||
nc->sock = lc->sock;
|
||||
nc->listener = lc;
|
||||
nc->sa = *sa;
|
||||
nc->sa = sa;
|
||||
nc->proto_handler = lc->proto_handler;
|
||||
nc->user_data = lc->user_data;
|
||||
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;
|
||||
mg_add_conn(lc->mgr, nc);
|
||||
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) {
|
||||
mg_recv_common(nc, buf, len, 1);
|
||||
} else {
|
||||
/* Drop on the floor. */
|
||||
MG_FREE(buf);
|
||||
DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
|
||||
ntohs(nc->sa.sin.sin_port)));
|
||||
if (nc == lc) {
|
||||
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,
|
||||
int proto,
|
||||
union socket_address *sa) {
|
||||
DBG(("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp",
|
||||
inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
|
||||
LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp",
|
||||
inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
|
||||
|
||||
nc->flags |= MG_F_CONNECTING;
|
||||
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) {
|
||||
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;
|
||||
if (err != 0) {
|
||||
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
|
||||
@@ -717,7 +889,8 @@ struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address,
|
||||
#endif
|
||||
|
||||
#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_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),
|
||||
(unsigned long) timestamp));
|
||||
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;
|
||||
}
|
||||
|
||||
+10
-15
@@ -54,10 +54,12 @@ struct mg_iface_vtable {
|
||||
void (*connect_udp)(struct mg_connection *nc);
|
||||
|
||||
/* 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);
|
||||
void (*udp_send)(struct mg_connection *nc, const void *buf, size_t len);
|
||||
int (*tcp_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. */
|
||||
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. */
|
||||
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.
|
||||
* if `own` is true, buf must be heap-allocated and ownership is transferred
|
||||
* to the core.
|
||||
* Core will acknowledge consumption by calling iface::recved.
|
||||
* Callback that tells the core that data can be received.
|
||||
* Core will use tcp/udp_recv to retrieve the data.
|
||||
*/
|
||||
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.
|
||||
* 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,
|
||||
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); */
|
||||
|
||||
/* Deliver a POLL event to the connection. */
|
||||
void mg_if_poll(struct mg_connection *nc, time_t now);
|
||||
|
||||
/* Deliver a TIMER event to the connection. */
|
||||
void mg_if_timer(struct mg_connection *c, double now);
|
||||
int mg_if_poll(struct mg_connection *nc, double now);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+54
-221
@@ -9,14 +9,8 @@
|
||||
#include "mg_internal.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,
|
||||
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) {
|
||||
#ifdef _WIN32
|
||||
@@ -85,27 +79,48 @@ int mg_socket_if_listen_tcp(struct mg_connection *nc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mg_socket_if_listen_udp(struct mg_connection *nc,
|
||||
union socket_address *sa) {
|
||||
static int mg_socket_if_listen_udp(struct mg_connection *nc,
|
||||
union socket_address *sa) {
|
||||
sock_t sock = mg_open_listening_socket(sa, SOCK_DGRAM, 0);
|
||||
if (sock == INVALID_SOCKET) return (mg_get_errno() ? mg_get_errno() : 1);
|
||||
mg_sock_set(nc, sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf,
|
||||
size_t len) {
|
||||
mbuf_append(&nc->send_mbuf, buf, len);
|
||||
static int mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf,
|
||||
size_t 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,
|
||||
size_t len) {
|
||||
mbuf_append(&nc->send_mbuf, buf, len);
|
||||
static int mg_socket_if_udp_send(struct mg_connection *nc, const void *buf,
|
||||
size_t 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) {
|
||||
(void) nc;
|
||||
(void) len;
|
||||
static int mg_socket_if_tcp_recv(struct mg_connection *nc, void *buf,
|
||||
size_t 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) {
|
||||
@@ -131,7 +146,9 @@ static int mg_accept_conn(struct mg_connection *lc) {
|
||||
/* NOTE(lsm): on Windows, sock is always > FD_SETSIZE */
|
||||
sock_t sock = accept(lc->sock, &sa.sa, &sa_len);
|
||||
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;
|
||||
}
|
||||
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),
|
||||
ntohs(sa.sin.sin_port)));
|
||||
mg_sock_set(nc, sock);
|
||||
#if MG_ENABLE_SSL
|
||||
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);
|
||||
}
|
||||
mg_if_accept_tcp_cb(nc, &sa, sa_len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -200,165 +210,6 @@ static sock_t mg_open_listening_socket(union socket_address *sa, int type,
|
||||
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_WRITE 1 << 1
|
||||
#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 =
|
||||
fd_flags != 0 || (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE));
|
||||
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,
|
||||
(int) nc->send_mbuf.len));
|
||||
}
|
||||
|
||||
if (!mg_if_poll(nc, now)) return;
|
||||
|
||||
if (nc->flags & MG_F_CONNECTING) {
|
||||
if (fd_flags != 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;
|
||||
#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);
|
||||
#endif
|
||||
} else if (nc->err != 0) {
|
||||
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 (nc->flags & MG_F_UDP) {
|
||||
mg_handle_udp_read(nc);
|
||||
mg_if_can_recv_cb(nc);
|
||||
} else {
|
||||
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);
|
||||
} 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) && nc->send_mbuf.len > 0) {
|
||||
mg_write_to_socket(nc);
|
||||
}
|
||||
mg_if_poll(nc, (time_t) now);
|
||||
mg_if_timer(nc, now);
|
||||
}
|
||||
if (fd_flags & _MG_F_FD_CAN_WRITE) mg_if_can_send_cb(nc);
|
||||
|
||||
if (worth_logging) {
|
||||
DBG(("%p after fd=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, nc->flags,
|
||||
(int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,8 +386,7 @@ time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(nc->flags & MG_F_WANT_WRITE) &&
|
||||
nc->recv_mbuf.len < nc->recv_mbuf_limit &&
|
||||
if (nc->recv_mbuf.len < nc->recv_mbuf_limit &&
|
||||
(!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
union socket_address sa;
|
||||
union socket_address sa, sa2;
|
||||
sock_t sock;
|
||||
socklen_t len = sizeof(sa.sin);
|
||||
int ret = 0;
|
||||
@@ -661,18 +491,20 @@ int mg_socketpair(sock_t sp[2], int sock_type) {
|
||||
|
||||
(void) memset(&sa, 0, sizeof(sa));
|
||||
sa.sin.sin_family = AF_INET;
|
||||
sa.sin.sin_port = htons(0);
|
||||
sa.sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
|
||||
sa2 = sa;
|
||||
|
||||
if ((sock = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
|
||||
} else if (bind(sock, &sa.sa, len) != 0) {
|
||||
} else if (sock_type == SOCK_STREAM && listen(sock, 1) != 0) {
|
||||
} else if (getsockname(sock, &sa.sa, &len) != 0) {
|
||||
} 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 &&
|
||||
(getsockname(sp[0], &sa.sa, &len) != 0 ||
|
||||
connect(sock, &sa.sa, len) != 0)) {
|
||||
(bind(sp[0], &sa2.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(
|
||||
sock, &sa, len))) ==
|
||||
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_tcp_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_destroy_conn, \
|
||||
mg_socket_if_sock_set, \
|
||||
|
||||
+65
-37
@@ -9,18 +9,35 @@ struct socksdata {
|
||||
char *proxy_addr; /* HOST:PORT of the socks5 proxy server */
|
||||
struct mg_connection *s; /* Respective connection to the server */
|
||||
struct mg_connection *c; /* Connection to the client */
|
||||
struct mbuf tmp; /* Temporary buffer for sent data */
|
||||
};
|
||||
|
||||
static void socks_if_disband(struct socksdata *d) {
|
||||
LOG(LL_DEBUG, ("disbanding proxy %p %p", d->c, d->s));
|
||||
if (d->c) d->c->flags |= MG_F_SEND_AND_CLOSE;
|
||||
if (d->s) d->s->flags |= MG_F_SEND_AND_CLOSE;
|
||||
d->c = d->s = NULL;
|
||||
if (d->c) {
|
||||
d->c->flags |= MG_F_SEND_AND_CLOSE;
|
||||
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) {
|
||||
struct socksdata *d = (struct socksdata *) c->user_data;
|
||||
if (d == NULL) return;
|
||||
if (ev == MG_EV_CONNECT) {
|
||||
int res = *(int *) ev_data;
|
||||
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 + 8, &d->c->sa.sin.sin_port, 2);
|
||||
mg_send(c, buf, sizeof(buf));
|
||||
LOG(LL_DEBUG, ("%p Sent connect request", c));
|
||||
}
|
||||
/* Process connect request */
|
||||
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);
|
||||
c->flags |= MG_SOCKS_CONNECT_DONE;
|
||||
/* Connected. Move sent data from client, if any, to server */
|
||||
if (d->s && d->c) {
|
||||
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);
|
||||
LOG(LL_DEBUG, ("%p Connect done %p", c, d->c));
|
||||
mg_if_connect_cb(d->c, 0);
|
||||
}
|
||||
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->s = mg_connect(c->mgr, d->proxy_addr, socks_if_handler);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -107,29 +120,44 @@ static int mg_socks_if_listen_udp(struct mg_connection *c,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void mg_socks_if_tcp_send(struct mg_connection *c, const void *buf,
|
||||
size_t len) {
|
||||
static int mg_socks_if_tcp_send(struct mg_connection *c, const void *buf,
|
||||
size_t len) {
|
||||
int res;
|
||||
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 && d->s && d->s->flags & MG_SOCKS_CONNECT_DONE) {
|
||||
mbuf_append(&d->s->send_mbuf, d->tmp.buf, d->tmp.len);
|
||||
mbuf_append(&d->s->send_mbuf, buf, len);
|
||||
mbuf_free(&d->tmp);
|
||||
} else {
|
||||
mbuf_append(&d->tmp, buf, len);
|
||||
}
|
||||
if (d->s == NULL) return -1;
|
||||
res = (int) mbuf_append(&d->s->send_mbuf, buf, len);
|
||||
DBG(("%p -> %d -> %p", c, res, d->s));
|
||||
return res;
|
||||
}
|
||||
|
||||
static void mg_socks_if_udp_send(struct mg_connection *c, const void *buf,
|
||||
size_t len) {
|
||||
static int mg_socks_if_udp_send(struct mg_connection *c, const void *buf,
|
||||
size_t len) {
|
||||
(void) c;
|
||||
(void) buf;
|
||||
(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) buf;
|
||||
(void) len;
|
||||
(void) sa;
|
||||
(void) sa_len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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));
|
||||
if (d != NULL) {
|
||||
socks_if_disband(d);
|
||||
mbuf_free(&d->tmp);
|
||||
MG_FREE(d->proxy_addr);
|
||||
MG_FREE(d);
|
||||
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 = {
|
||||
mg_socks_if_init, mg_socks_if_free,
|
||||
mg_socks_if_add_conn, mg_socks_if_remove_conn,
|
||||
mg_socks_if_poll, mg_socks_if_listen_tcp,
|
||||
mg_socks_if_listen_udp, mg_socks_if_connect_tcp,
|
||||
mg_socks_if_connect_udp, mg_socks_if_tcp_send,
|
||||
mg_socks_if_udp_send, mg_socks_if_recved,
|
||||
mg_socks_if_create_conn, mg_socks_if_destroy_conn,
|
||||
mg_socks_if_sock_set, mg_socks_if_get_conn_addr,
|
||||
mg_socks_if_init, mg_socks_if_free,
|
||||
mg_socks_if_add_conn, mg_socks_if_remove_conn,
|
||||
mg_socks_if_poll, mg_socks_if_listen_tcp,
|
||||
mg_socks_if_listen_udp, mg_socks_if_connect_tcp,
|
||||
mg_socks_if_connect_udp, mg_socks_if_tcp_send,
|
||||
mg_socks_if_udp_send, mg_socks_if_tcp_recv,
|
||||
mg_socks_if_udp_recv, mg_socks_if_create_conn,
|
||||
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) {
|
||||
|
||||
+4
-6
@@ -148,7 +148,6 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
|
||||
time_t now = (time_t) mg_time();
|
||||
struct mg_resolve_async_request *req;
|
||||
struct mg_dns_message *msg;
|
||||
int first = 0;
|
||||
#if !MG_ENABLE_CALLBACK_USERDATA
|
||||
void *user_data = nc->user_data;
|
||||
#endif
|
||||
@@ -162,17 +161,16 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int 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:
|
||||
if (req->retries > req->max_retries) {
|
||||
req->err = MG_RESOLVE_EXCEEDED_RETRY_COUNT;
|
||||
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
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);
|
||||
req->last_time = now;
|
||||
req->retries++;
|
||||
|
||||
+63
-32
@@ -7,9 +7,12 @@
|
||||
|
||||
#include <mbedtls/debug.h>
|
||||
#include <mbedtls/ecp.h>
|
||||
#include <mbedtls/net.h>
|
||||
#include <mbedtls/platform.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
#include <mbedtls/ssl_internal.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,
|
||||
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;
|
||||
break;
|
||||
case 2:
|
||||
cs_level = LL_INFO;
|
||||
break;
|
||||
case 3:
|
||||
cs_level = LL_DEBUG;
|
||||
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));
|
||||
(void) file;
|
||||
(void) line;
|
||||
(void) cs_level;
|
||||
}
|
||||
|
||||
struct mg_ssl_if_ctx {
|
||||
@@ -38,12 +44,14 @@ struct mg_ssl_if_ctx {
|
||||
mbedtls_pk_context *key;
|
||||
mbedtls_x509_crt *ca_cert;
|
||||
struct mbuf cipher_suites;
|
||||
size_t saved_len;
|
||||
};
|
||||
|
||||
/* 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);
|
||||
|
||||
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,
|
||||
@@ -67,9 +75,11 @@ static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
|
||||
const char *cert);
|
||||
static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx,
|
||||
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,
|
||||
const char *identity,
|
||||
const char *key);
|
||||
#endif
|
||||
|
||||
enum mg_ssl_if_result mg_ssl_if_conn_init(
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
|
||||
if (mg_ssl_if_mbed_set_psk(ctx, params->psk_identity, params->psk_key) !=
|
||||
MG_SSL_OK) {
|
||||
MG_SET_PTRPTR(err_msg, "Invalid PSK settings");
|
||||
return MG_SSL_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(nc->flags & MG_F_LISTENING)) {
|
||||
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;
|
||||
}
|
||||
|
||||
#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
|
||||
int ssl_socket_send(void *ctx, const unsigned char *buf, 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) {
|
||||
static int mg_ssl_if_mbed_send(void *ctx, const unsigned char *buf,
|
||||
size_t len) {
|
||||
struct mg_connection *nc = (struct mg_connection *) ctx;
|
||||
int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0);
|
||||
LOG(LL_DEBUG, ("%p %d -> %d", nc, (int) len, n));
|
||||
if (n >= 0) return n;
|
||||
n = mg_get_errno();
|
||||
return ((n == EAGAIN || n == EINPROGRESS) ? MBEDTLS_ERR_SSL_WANT_WRITE : -1);
|
||||
int n = nc->iface->vtable->tcp_send(nc, buf, len);
|
||||
if (n > 0) return n;
|
||||
if (n == 0) return MBEDTLS_ERR_SSL_WANT_WRITE;
|
||||
return MBEDTLS_ERR_NET_SEND_FAILED;
|
||||
}
|
||||
|
||||
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;
|
||||
int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0);
|
||||
LOG(LL_DEBUG, ("%p %d <- %d", nc, (int) len, n));
|
||||
if (n >= 0) return n;
|
||||
n = mg_get_errno();
|
||||
return ((n == EAGAIN || n == EINPROGRESS) ? MBEDTLS_ERR_SSL_WANT_READ : -1);
|
||||
int n = nc->iface->vtable->tcp_recv(nc, buf, len);
|
||||
if (n > 0) return n;
|
||||
if (n == 0) return MBEDTLS_ERR_SSL_WANT_READ;
|
||||
return MBEDTLS_ERR_NET_RECV_FAILED;
|
||||
}
|
||||
#endif
|
||||
|
||||
static enum mg_ssl_if_result mg_ssl_if_mbed_err(struct mg_connection *nc,
|
||||
int ret) {
|
||||
if (ret == MBEDTLS_ERR_SSL_WANT_READ) return MG_SSL_WANT_READ;
|
||||
if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) return MG_SSL_WANT_WRITE;
|
||||
if (ret !=
|
||||
MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { /* CLOSE_NOTIFY = Normal shutdown */
|
||||
LOG(LL_ERROR, ("%p SSL error: %d", nc, ret));
|
||||
enum mg_ssl_if_result res = MG_SSL_OK;
|
||||
if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
|
||||
res = MG_SSL_WANT_READ;
|
||||
} else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
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->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
return MG_SSL_ERROR;
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
/* If bio is not yet set, do it now. */
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, buf_size);
|
||||
DBG(("%p %d -> %d", nc, (int) buf_size, n));
|
||||
int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, len);
|
||||
DBG(("%p %d -> %d", nc, (int) len, n));
|
||||
if (n < 0) return mg_ssl_if_mbed_err(nc, n);
|
||||
if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
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;
|
||||
int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) data, len);
|
||||
DBG(("%p %d -> %d", nc, (int) len, n));
|
||||
if (n < 0) return mg_ssl_if_mbed_err(nc, n);
|
||||
/* Per mbedTLS docs, if write returns WANT_READ or WANT_WRITE, the operation
|
||||
* should be retried with the same data and length.
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -416,6 +445,7 @@ static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx,
|
||||
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,
|
||||
const char *identity,
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
|
||||
const char *ca_cert) {
|
||||
|
||||
+11
-8
@@ -10,6 +10,9 @@
|
||||
#endif
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#ifndef KR_VERSION
|
||||
#include <openssl/tls1.h>
|
||||
#endif
|
||||
|
||||
struct mg_ssl_if_ctx {
|
||||
SSL *ssl;
|
||||
@@ -94,14 +97,6 @@ enum mg_ssl_if_result mg_ssl_if_conn_init(
|
||||
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) {
|
||||
MG_SET_PTRPTR(err_msg, "Invalid cipher suite list");
|
||||
return MG_SSL_ERROR;
|
||||
@@ -120,6 +115,14 @@ enum mg_ssl_if_result mg_ssl_if_conn_init(
|
||||
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;
|
||||
|
||||
return MG_SSL_OK;
|
||||
|
||||
+13
-5
@@ -144,7 +144,7 @@ int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len,
|
||||
goto cleanup;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
#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));
|
||||
}
|
||||
|
||||
struct mg_str mg_url_encode(const struct mg_str src) {
|
||||
static const char *dont_escape = "._-$,;~()/";
|
||||
static const char *hex = "0123456789abcdef";
|
||||
struct mg_str mg_url_encode_opt(const struct mg_str src,
|
||||
const struct mg_str safe, unsigned int flags) {
|
||||
const char *hex =
|
||||
(flags & MG_URL_ENCODE_F_UPPERCASE_HEX ? "0123456789ABCDEF"
|
||||
: "0123456789abcdef");
|
||||
size_t i = 0;
|
||||
struct mbuf mb;
|
||||
mbuf_init(&mb, src.len);
|
||||
|
||||
for (i = 0; i < src.len; 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);
|
||||
} else if (c == ' ' && (flags & MG_URL_ENCODE_F_SPACE_AS_PLUS)) {
|
||||
mbuf_append(&mb, "+", 1);
|
||||
} else {
|
||||
mbuf_append(&mb, "%", 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);
|
||||
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
@@ -196,10 +196,17 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@
|
||||
# OSX clang doesn't build ASAN. Use brew:
|
||||
# $ brew tap homebrew/versions
|
||||
# $ 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)
|
||||
|
||||
|
||||
+261
-14
@@ -928,10 +928,38 @@ static const char *test_mg_uri_to_local_path(void) {
|
||||
static const char *test_mg_url_encode(void) {
|
||||
const struct mg_str encode_me =
|
||||
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(
|
||||
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(encode_me);
|
||||
ASSERT_MG_STREQ(
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1145,7 +1173,7 @@ static const char *test_timer(void) {
|
||||
ASSERT((c = mg_connect(&m, "awful.sad:1234", ev_timer_handler)) != NULL);
|
||||
c->user_data = &n;
|
||||
mg_set_timer(c, 1);
|
||||
mg_mgr_poll(&m, 1);
|
||||
poll_until(&m, 1, c_int_eq, &n, (void *) 101);
|
||||
ASSERT_EQ(n, 101);
|
||||
|
||||
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_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(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(req.resp_code, 200);
|
||||
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);
|
||||
|
||||
@@ -2019,6 +2047,7 @@ static const char *test_http(void) {
|
||||
ASSERT((nc = mg_connect(&mgr, local_addr, cb7)) != NULL);
|
||||
mg_set_protocol_http_websocket(nc);
|
||||
nc->user_data = status;
|
||||
mbuf_resize(&nc->recv_mbuf, 10000000);
|
||||
|
||||
/* Wine and GDB set argv0 to full path: strip the dir component */
|
||||
if ((this_binary = strrchr(g_argv_0, '\\')) != NULL) {
|
||||
@@ -2051,6 +2080,40 @@ static const char *test_http(void) {
|
||||
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) {
|
||||
struct mg_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");
|
||||
ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13);
|
||||
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");
|
||||
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 int i;
|
||||
static int i = -1;
|
||||
(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++];
|
||||
int l = strlen((char *) nc->user_data);
|
||||
if (ch != '\0') {
|
||||
mg_send(nc, &ch, 1);
|
||||
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;
|
||||
|
||||
c->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
mbuf_free(&mpd.res);
|
||||
memset(&mpd, 0, sizeof(mpd));
|
||||
mbuf_init(&mpd.res, 0);
|
||||
@@ -4253,6 +4320,178 @@ static const char *test_http_multipart2(void) {
|
||||
|
||||
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 */
|
||||
|
||||
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 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");
|
||||
char buf[20];
|
||||
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_STREQ(buf, "2");
|
||||
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;
|
||||
}
|
||||
@@ -5420,12 +5662,14 @@ static const char *test_socks(void) {
|
||||
this_binary = g_argv_0;
|
||||
}
|
||||
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. */
|
||||
poll_until(&mgr, 5, c_str_ne, status, (void *) "");
|
||||
mg_mgr_free(&mgr);
|
||||
poll_until(&mgr, 10, c_str_ne, status, (void *) "");
|
||||
ASSERT_STREQ(status, "success");
|
||||
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
@@ -5461,6 +5705,7 @@ const char *tests_run(const char *filter) {
|
||||
RUN_TEST(test_http_serve_file);
|
||||
RUN_TEST(test_http_serve_file_streaming);
|
||||
RUN_TEST(test_http);
|
||||
RUN_TEST(test_http_pipeline);
|
||||
RUN_TEST(test_http_send_redirect);
|
||||
RUN_TEST(test_http_digest_auth);
|
||||
RUN_TEST(test_http_errors);
|
||||
@@ -5476,6 +5721,8 @@ const char *tests_run(const char *filter) {
|
||||
RUN_TEST(test_http_multipart);
|
||||
#if MG_ENABLE_HTTP_STREAMING_MULTIPART
|
||||
RUN_TEST(test_http_multipart2);
|
||||
RUN_TEST(test_http_multipart_pipeline);
|
||||
RUN_TEST(test_http_multipart_upload);
|
||||
#endif
|
||||
RUN_TEST(test_parse_date_string);
|
||||
RUN_TEST(test_websocket);
|
||||
|
||||
+6
-3
@@ -57,7 +57,7 @@ parser.add_argument('--norel', action='store_true',
|
||||
help="do not try to compute a friendly relative path")
|
||||
parser.add_argument('--exportable-headers', dest="export", action='store_true',
|
||||
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')
|
||||
|
||||
class File(object):
|
||||
@@ -97,10 +97,13 @@ def resolve(path, parent_name):
|
||||
elif path_from_parent != None and os.path.exists(path_from_parent):
|
||||
p = path_from_parent
|
||||
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:
|
||||
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, '/')
|
||||
|
||||
def emit_line_directive(out, name, parent_name):
|
||||
|
||||
Reference in new issue
Block a user