Merge branch 'dev' (Mongoose 6.12)

This commit is contained in:
Deomid Ryabkov committed 2018-08-13 19:30:06 +03:00
commit 777b8e94e2
90 files changed
+4026 -2554

No files matched your search

+1 -1
View File
@@ -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)
+1 -4
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+469 -50
View File
@@ -23,7 +23,7 @@
#ifndef CS_MONGOOSE_SRC_COMMON_H_
#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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2017 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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>
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the ""License"");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an ""AS IS"" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <math.h>
#include "mgos.h"
#include "mgos_system.h"
void (*mgos_nsleep100)(uint32_t n);
uint32_t mgos_nsleep100_loop_count = 0;
/* Provided by arm_nsleep100_{m4,m7}.S for M4 and M7 respectively. */
extern void mgos_nsleep100_impl(uint32_t n);
void mgos_nsleep100_cal(void) {
uint32_t cpu_freq = mgos_get_cpu_freq();
/* # of instruction cycles per 100 ns */
mgos_nsleep100_loop_count =
roundf((100.0f / 1000000000.0f) / (1.0f / cpu_freq));
mgos_nsleep100 = mgos_nsleep100_impl;
}
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the ""License"");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an ""AS IS"" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.arch armv7e-m
.syntax unified
.thumb
/* These are required to satisfy TI linker. */
.eabi_attribute Tag_ABI_align_needed, 1
.eabi_attribute Tag_ABI_align_preserved, 1
.global mgos_nsleep100_impl
.global mgos_nsleep100_loop_count
.section .iram.mgos_nsleep100_impl
.type mgos_nsleep100_impl, %function
.align 4
mgos_nsleep100_impl:
ldr r3, =mgos_nsleep100_loop_count
ldr r3, [r3]
mul r0, r3
mov r1, #6
udiv r0, r0, r1
cbz r0, xxx
lxx:
subs r0, #1
bne lxx
xxx:
bx lr
.align 4
.size mgos_nsleep100_impl, . - mgos_nsleep100_impl
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the ""License"");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an ""AS IS"" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.arch armv7e-m
.syntax unified
.thumb
/* These are required to satisfy TI linker. */
.eabi_attribute Tag_ABI_align_needed, 1
.eabi_attribute Tag_ABI_align_preserved, 1
.global mgos_nsleep100_impl
.global mgos_nsleep100_loop_count
.section .iram.mgos_nsleep100_impl
.type mgos_nsleep100_impl, %function
.align 4
mgos_nsleep100_impl:
ldr r3, =mgos_nsleep100_loop_count
ldr r3, [r3]
/* Because of speculative fetch, the core loop only takes 1 cycle. */
muls r0, r3
cbz r0, xxx
lxx:
subs r0, #1
bne lxx
xxx:
bx lr
.align 4
.size mgos_nsleep100_impl, . - mgos_nsleep100_impl
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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
+10 -12
View File
@@ -1,20 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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"
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2017 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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"
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2017 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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
+11 -2
View File
@@ -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>
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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"
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+4 -3
View File
@@ -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
+14 -2
View File
@@ -1,13 +1,25 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -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>
+13 -1
View File
@@ -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>
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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"
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+37 -78
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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;
+95 -165
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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, \
+15 -3
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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 {
-197
View File
@@ -1,197 +0,0 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#if MG_ENABLE_SSL && MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
#include "common/mg_mem.h"
#include "common/cs_dbg.h"
#include <lwip/pbuf.h>
#include <lwip/tcp.h>
#ifndef MG_LWIP_SSL_IO_SIZE
#define MG_LWIP_SSL_IO_SIZE 1024
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
void mg_lwip_ssl_do_hs(struct mg_connection *nc) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
int server_side = (nc->listener != NULL);
enum mg_ssl_if_result res;
if (nc->flags & MG_F_CLOSE_IMMEDIATELY) return;
res = mg_ssl_if_handshake(nc);
DBG(("%p %lu %d %d", nc, nc->flags, server_side, res));
if (res != MG_SSL_OK) {
if (res == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
cs->err = 0;
} else if (res == MG_SSL_WANT_READ) {
/*
* Nothing to do in particular, we are callback-driven.
* What we definitely do not need anymore is SSL reading (nothing left).
*/
nc->flags &= ~MG_F_WANT_READ;
cs->err = 0;
} else {
cs->err = res;
if (server_side) {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
} else {
mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
}
}
} else {
cs->err = 0;
nc->flags &= ~MG_F_WANT_WRITE;
/*
* Handshake is done. Schedule a read immediately to consume app data
* which may already be waiting.
*/
nc->flags |= (MG_F_SSL_HANDSHAKE_DONE | MG_F_WANT_READ);
if (server_side) {
mg_lwip_accept_conn(nc, cs->pcb.tcp);
} else {
mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
}
}
}
void mg_lwip_ssl_send(struct mg_connection *nc) {
if (nc->sock == INVALID_SOCKET) {
DBG(("%p invalid socket", nc));
return;
}
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
/* It's ok if the buffer is empty. Return value of 0 may also be valid. */
int len = cs->last_ssl_write_size;
if (len == 0) {
len = MIN(MG_LWIP_SSL_IO_SIZE, nc->send_mbuf.len);
}
int ret = mg_ssl_if_write(nc, nc->send_mbuf.buf, len);
DBG(("%p SSL_write %u = %d", nc, len, ret));
if (ret > 0) {
mg_if_sent_cb(nc, ret);
cs->last_ssl_write_size = 0;
} else if (ret < 0) {
/* This is tricky. We must remember the exact data we were sending to retry
* exactly the same send next time. */
cs->last_ssl_write_size = len;
}
if (ret == len) {
nc->flags &= ~MG_F_WANT_WRITE;
} else if (ret == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
} else {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
}
}
void mg_lwip_ssl_recv(struct mg_connection *nc) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
/* Don't deliver data before connect callback */
if (nc->flags & MG_F_CONNECTING) return;
while (nc->recv_mbuf.len < nc->recv_mbuf_limit) {
char *buf = (char *) MG_MALLOC(MG_LWIP_SSL_IO_SIZE);
if (buf == NULL) return;
int ret = mg_ssl_if_read(nc, buf, MG_LWIP_SSL_IO_SIZE);
DBG(("%p %p SSL_read %u = %d", nc, cs->rx_chain, MG_LWIP_SSL_IO_SIZE, ret));
if (ret <= 0) {
MG_FREE(buf);
if (ret == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
return;
} else if (ret == MG_SSL_WANT_READ) {
/*
* Nothing to do in particular, we are callback-driven.
* What we definitely do not need anymore is SSL reading (nothing left).
*/
nc->flags &= ~MG_F_WANT_READ;
cs->err = 0;
return;
} else {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
return;
}
} else {
mg_if_recv_tcp_cb(nc, buf, ret, 1 /* own */);
}
}
}
#ifdef KR_VERSION
ssize_t kr_send(int fd, const void *buf, size_t len) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) fd;
int ret = mg_lwip_tcp_write(cs->nc, buf, len);
DBG(("%p mg_lwip_tcp_write %u = %d", cs->nc, len, ret));
if (ret == 0) ret = KR_IO_WOULDBLOCK;
return ret;
}
ssize_t kr_recv(int fd, void *buf, size_t len) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) fd;
struct pbuf *seg = cs->rx_chain;
if (seg == NULL) {
DBG(("%u - nothing to read", len));
return KR_IO_WOULDBLOCK;
}
size_t seg_len = (seg->len - cs->rx_offset);
DBG(("%u %u %u %u", len, cs->rx_chain->len, seg_len, cs->rx_chain->tot_len));
len = MIN(len, seg_len);
pbuf_copy_partial(seg, buf, len, cs->rx_offset);
cs->rx_offset += len;
tcp_recved(cs->pcb.tcp, len);
if (cs->rx_offset == cs->rx_chain->len) {
cs->rx_chain = pbuf_dechain(cs->rx_chain);
pbuf_free(seg);
cs->rx_offset = 0;
}
return len;
}
#elif MG_SSL_IF == MG_SSL_IF_MBEDTLS
int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len) {
struct mg_connection *nc = (struct mg_connection *) ctx;
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
int ret = mg_lwip_tcp_write(cs->nc, buf, len);
if (ret == 0) ret = MBEDTLS_ERR_SSL_WANT_WRITE;
LOG(LL_DEBUG, ("%p %d -> %d", nc, len, ret));
return ret;
}
int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len) {
struct mg_connection *nc = (struct mg_connection *) ctx;
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
struct pbuf *seg = cs->rx_chain;
if (seg == NULL) {
DBG(("%u - nothing to read", len));
return MBEDTLS_ERR_SSL_WANT_READ;
}
size_t seg_len = (seg->len - cs->rx_offset);
DBG(("%u %u %u %u", len, cs->rx_chain->len, seg_len, cs->rx_chain->tot_len));
mgos_lock();
len = MIN(len, seg_len);
pbuf_copy_partial(seg, buf, len, cs->rx_offset);
cs->rx_offset += len;
/* TCP PCB may be NULL if connection has already been closed
* but we still have data to deliver to SSL. */
if (cs->pcb.tcp != NULL) tcp_recved(cs->pcb.tcp, len);
if (cs->rx_offset == cs->rx_chain->len) {
cs->rx_chain = pbuf_dechain(cs->rx_chain);
pbuf_free(seg);
cs->rx_offset = 0;
}
mgos_unlock();
LOG(LL_DEBUG, ("%p <- %d", nc, (int) len));
return len;
}
#endif
#endif /* MG_ENABLE_SSL && MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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"
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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) && \
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+15 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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)
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -5
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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. */
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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 && \
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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. */
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+68 -116
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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, \
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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_
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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
+83 -43
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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;
}
+13 -1
View File
@@ -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
+13 -1
View File
@@ -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
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the ""License"");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an ""AS IS"" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "common/cs_dbg.h"
#include "common/test_main.h"
#include "common/test_util.h"
#if defined(_MSC_VER) && _MSC_VER >= 1900
#include <crtdbg.h>
int __cdecl CrtDbgHook(int nReportType, char *szMsg, int *pnRet) {
(void) nReportType;
(void) szMsg;
(void) pnRet;
fprintf(stderr, "CRT debug hook: type: %d, msg: %s\n", nReportType, szMsg);
/* Return true - Abort,Retry,Ignore dialog will *not* be displayed */
return 1;
}
#endif
#ifndef __cdecl
#define __cdecl
#endif
int g_num_tests = 0;
int g_num_checks = 0;
const char *g_argv_0 = NULL;
int __cdecl main(int argc, char *argv[]) {
const char *fail_msg;
const char *filter = argc > 1 ? argv[1] : "";
char *seed_str = getenv("TEST_SEED");
double started;
int seed = 0;
if (seed_str != NULL) {
seed = atoi(seed_str);
} else {
seed = (int) time(NULL);
}
printf("seed: %d\n", seed);
srand(seed);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
#if defined(_MSC_VER) && _MSC_VER >= 1900
/* NOTE: not available on wine/vc6 */
_CrtSetReportHook2(_CRT_RPTHOOK_INSTALL, CrtDbgHook);
#endif
g_argv_0 = argv[0];
tests_setup();
started = cs_time();
fail_msg = tests_run(filter);
printf("%s, ran %d tests (%d checks) in %.3lfs\n", fail_msg ? "FAIL" : "PASS",
g_num_tests, g_num_checks, cs_time() - started);
tests_teardown();
if (fail_msg != NULL) {
/* Prevent leak analyzer from running: there will be "leaks" because of
* premature return from the test, and in this case we don't care. */
_exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the ""License"");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an ""AS IS"" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CS_COMMON_TEST_MAIN_H_
#define CS_COMMON_TEST_MAIN_H_
#ifdef __cplusplus
extern "C" {
#endif
void tests_setup(void);
const char *tests_run(const char *filter);
void tests_teardown(void);
extern const char *g_argv_0;
#ifdef __cplusplus
}
#endif
#endif /* CS_COMMON_TEST_MAIN_H_ */
+13 -1
View File
@@ -1,6 +1,18 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* 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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -478,7 +478,6 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir,
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 {
+2 -2
View File
@@ -64,9 +64,9 @@ int mg_http_parse_header2(struct mg_str *hdr, const char *var_name, char **buf,
int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
size_t buf_size)
#ifdef __GNUC__
__attribute__((deprecated));
__attribute__((deprecated))
#endif
;
;
/*
* Gets and parses the Authorization: Basic header
+1 -1
View File
@@ -8,6 +8,7 @@ HEADERS = mg_common.h \
$(COMMON)/platforms/platform_esp8266.h \
$(COMMON)/platforms/platform_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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -148,7 +148,6 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
time_t now = (time_t) mg_time();
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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -196,10 +196,17 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
/*
* URL-escape the specified string.
* 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
View File
@@ -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
View File
@@ -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
View File
@@ -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):