LCOV - code coverage report
Current view: top level - progs - mongoose616.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 4094 0
Test Date: 2025-11-11 10:26:08 Functions: 0.0 % 343 0

            Line data    Source code
       1              : #include "mongoose616.h"
       2              : #include <string>
       3              : #include <regex>
       4              : #ifdef MG_MODULE_LINES
       5              : #line 1 "mongoose/src/mg_internal.h"
       6              : #endif
       7              : /*
       8              :  * Copyright (c) 2014 Cesanta Software Limited
       9              :  * All rights reserved
      10              :  */
      11              : 
      12              : #ifndef CS_MONGOOSE_SRC_INTERNAL_H_
      13              : #define CS_MONGOOSE_SRC_INTERNAL_H_
      14              : 
      15              : /* Amalgamated: #include "common/mg_mem.h" */
      16              : 
      17              : #ifndef MBUF_REALLOC
      18              : #define MBUF_REALLOC MG_REALLOC
      19              : #endif
      20              : 
      21              : #ifndef MBUF_FREE
      22              : #define MBUF_FREE MG_FREE
      23              : #endif
      24              : 
      25              : #define MG_SET_PTRPTR(_ptr, _v) \
      26              :   do {                          \
      27              :     if (_ptr) *(_ptr) = _v;     \
      28              :   } while (0)
      29              : 
      30              : #ifndef MG_INTERNAL
      31              : #define MG_INTERNAL static
      32              : #endif
      33              : 
      34              : #ifdef PICOTCP
      35              : #define NO_LIBC
      36              : #define MG_DISABLE_PFS
      37              : #endif
      38              : 
      39              : /* Amalgamated: #include "common/cs_dbg.h" */
      40              : /* Amalgamated: #include "mg_http.h" */
      41              : /* Amalgamated: #include "mg_net.h" */
      42              : 
      43              : #ifndef MG_CTL_MSG_MESSAGE_SIZE
      44              : #define MG_CTL_MSG_MESSAGE_SIZE 8192
      45              : #endif
      46              : 
      47              : /* internals that need to be accessible in unit tests */
      48              : MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc,
      49              :                                                 int proto,
      50              :                                                 union socket_address *sa);
      51              : 
      52              : MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa,
      53              :                                  int *proto, char *host, size_t host_len);
      54              : MG_INTERNAL void mg_call(struct mg_connection *nc,
      55              :                          mg_event_handler_t ev_handler, void *user_data, int ev,
      56              :                          void *ev_data);
      57              : void mg_forward(struct mg_connection *from, struct mg_connection *to);
      58              : MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c);
      59              : MG_INTERNAL void mg_remove_conn(struct mg_connection *c);
      60              : MG_INTERNAL struct mg_connection *mg_create_connection(
      61              :     struct mg_mgr *mgr, mg_event_handler_t callback,
      62              :     struct mg_add_sock_opts opts);
      63              : #ifdef _WIN32
      64              : /* Retur value is the same as for MultiByteToWideChar. */
      65              : int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len);
      66              : #endif
      67              : 
      68              : struct ctl_msg {
      69              :   mg_event_handler_t callback;
      70              :   char message[MG_CTL_MSG_MESSAGE_SIZE];
      71              : };
      72              : 
      73              : #if MG_ENABLE_MQTT
      74              : struct mg_mqtt_message;
      75              : 
      76              : #define MG_MQTT_ERROR_INCOMPLETE_MSG -1
      77              : #define MG_MQTT_ERROR_MALFORMED_MSG -2
      78              : 
      79              : MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm);
      80              : #endif
      81              : 
      82              : /* Forward declarations for testing. */
      83              : extern void *(*test_malloc)(size_t size);
      84              : extern void *(*test_calloc)(size_t count, size_t size);
      85              : 
      86              : #ifndef MIN
      87              : #define MIN(a, b) ((a) < (b) ? (a) : (b))
      88              : #endif
      89              : 
      90              : #if MG_ENABLE_HTTP
      91              : struct mg_serve_http_opts;
      92              : 
      93              : MG_INTERNAL struct mg_http_proto_data *mg_http_create_proto_data(
      94              :     struct mg_connection *c);
      95              : 
      96              : /*
      97              :  * Reassemble the content of the buffer (buf, blen) which should be
      98              :  * in the HTTP chunked encoding, by collapsing data chunks to the
      99              :  * beginning of the buffer.
     100              :  *
     101              :  * If chunks get reassembled, modify hm->body to point to the reassembled
     102              :  * body and fire MG_EV_HTTP_CHUNK event. If handler sets MG_F_DELETE_CHUNK
     103              :  * in nc->flags, delete reassembled body from the mbuf.
     104              :  *
     105              :  * Return reassembled body size.
     106              :  */
     107              : MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
     108              :                                      struct http_message *hm, char *buf,
     109              :                                      size_t blen);
     110              : 
     111              : #if MG_ENABLE_FILESYSTEM
     112              : MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
     113              :                                      const struct mg_serve_http_opts *opts,
     114              :                                      char **local_path,
     115              :                                      struct mg_str *remainder);
     116              : MG_INTERNAL time_t mg_parse_date_string(const char *datetime);
     117              : MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st);
     118              : #endif
     119              : #if MG_ENABLE_HTTP_CGI
     120              : MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
     121              :                                const struct mg_str *path_info,
     122              :                                const struct http_message *hm,
     123              :                                const struct mg_serve_http_opts *opts);
     124              : struct mg_http_proto_data_cgi;
     125              : MG_INTERNAL void mg_http_free_proto_data_cgi(struct mg_http_proto_data_cgi *d);
     126              : #endif
     127              : #if MG_ENABLE_HTTP_SSI
     128              : MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc,
     129              :                                        struct http_message *hm,
     130              :                                        const char *path,
     131              :                                        const struct mg_serve_http_opts *opts);
     132              : #endif
     133              : #if MG_ENABLE_HTTP_WEBDAV
     134              : MG_INTERNAL int mg_is_dav_request(const struct mg_str *s);
     135              : MG_INTERNAL void mg_handle_propfind(struct mg_connection *nc, const char *path,
     136              :                                     cs_stat_t *stp, struct http_message *hm,
     137              :                                     struct mg_serve_http_opts *opts);
     138              : MG_INTERNAL void mg_handle_lock(struct mg_connection *nc, const char *path);
     139              : MG_INTERNAL void mg_handle_mkcol(struct mg_connection *nc, const char *path,
     140              :                                  struct http_message *hm);
     141              : MG_INTERNAL void mg_handle_move(struct mg_connection *c,
     142              :                                 const struct mg_serve_http_opts *opts,
     143              :                                 const char *path, struct http_message *hm);
     144              : MG_INTERNAL void mg_handle_delete(struct mg_connection *nc,
     145              :                                   const struct mg_serve_http_opts *opts,
     146              :                                   const char *path);
     147              : MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path,
     148              :                                struct http_message *hm);
     149              : #endif
     150              : #if MG_ENABLE_HTTP_WEBSOCKET
     151              : MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev,
     152              :                                void *ev_data MG_UD_ARG(void *user_data));
     153              : MG_INTERNAL void mg_ws_handshake(struct mg_connection *nc,
     154              :                                  const struct mg_str *key,
     155              :                                  struct http_message *);
     156              : #endif
     157              : #endif /* MG_ENABLE_HTTP */
     158              : 
     159              : MG_INTERNAL int mg_get_errno(void);
     160              : 
     161              : MG_INTERNAL void mg_close_conn(struct mg_connection *conn);
     162              : 
     163              : #if MG_ENABLE_SNTP
     164              : MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len,
     165              :                                     struct mg_sntp_message *msg);
     166              : #endif
     167              : 
     168              : #endif /* CS_MONGOOSE_SRC_INTERNAL_H_ */
     169              : #ifdef MG_MODULE_LINES
     170              : #line 1 "common/mg_mem.h"
     171              : #endif
     172              : /*
     173              :  * Copyright (c) 2014-2018 Cesanta Software Limited
     174              :  * All rights reserved
     175              :  *
     176              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
     177              :  * you may not use this file except in compliance with the License.
     178              :  * You may obtain a copy of the License at
     179              :  *
     180              :  *     http://www.apache.org/licenses/LICENSE-2.0
     181              :  *
     182              :  * Unless required by applicable law or agreed to in writing, software
     183              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
     184              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     185              :  * See the License for the specific language governing permissions and
     186              :  * limitations under the License.
     187              :  */
     188              : 
     189              : #ifndef CS_COMMON_MG_MEM_H_
     190              : #define CS_COMMON_MG_MEM_H_
     191              : 
     192              : #ifdef __cplusplus
     193              : extern "C" {
     194              : #endif
     195              : 
     196              : #ifndef MG_MALLOC
     197              : #define MG_MALLOC malloc
     198              : #endif
     199              : 
     200              : #ifndef MG_CALLOC
     201              : #define MG_CALLOC calloc
     202              : #endif
     203              : 
     204              : #ifndef MG_REALLOC
     205              : #define MG_REALLOC realloc
     206              : #endif
     207              : 
     208              : #ifndef MG_FREE
     209              : #define MG_FREE free
     210              : #endif
     211              : 
     212              : #ifdef __cplusplus
     213              : }
     214              : #endif
     215              : 
     216              : #endif /* CS_COMMON_MG_MEM_H_ */
     217              : #ifdef MG_MODULE_LINES
     218              : #line 1 "common/cs_base64.c"
     219              : #endif
     220              : /*
     221              :  * Copyright (c) 2014-2018 Cesanta Software Limited
     222              :  * All rights reserved
     223              :  *
     224              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
     225              :  * you may not use this file except in compliance with the License.
     226              :  * You may obtain a copy of the License at
     227              :  *
     228              :  *     http://www.apache.org/licenses/LICENSE-2.0
     229              :  *
     230              :  * Unless required by applicable law or agreed to in writing, software
     231              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
     232              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     233              :  * See the License for the specific language governing permissions and
     234              :  * limitations under the License.
     235              :  */
     236              : 
     237              : #ifndef EXCLUDE_COMMON
     238              : 
     239              : /* Amalgamated: #include "common/cs_base64.h" */
     240              : 
     241              : #include <string.h>
     242              : 
     243              : /* Amalgamated: #include "common/cs_dbg.h" */
     244              : 
     245              : /* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ */
     246              : 
     247              : #define NUM_UPPERCASES ('Z' - 'A' + 1)
     248              : #define NUM_LETTERS (NUM_UPPERCASES * 2)
     249              : #define NUM_DIGITS ('9' - '0' + 1)
     250              : 
     251              : /*
     252              :  * Emit a base64 code char.
     253              :  *
     254              :  * Doesn't use memory, thus it's safe to use to safely dump memory in crashdumps
     255              :  */
     256            0 : static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v) {
     257            0 :   if (v < NUM_UPPERCASES) {
     258            0 :     ctx->b64_putc(v + 'A', ctx->user_data);
     259            0 :   } else if (v < (NUM_LETTERS)) {
     260            0 :     ctx->b64_putc(v - NUM_UPPERCASES + 'a', ctx->user_data);
     261            0 :   } else if (v < (NUM_LETTERS + NUM_DIGITS)) {
     262            0 :     ctx->b64_putc(v - NUM_LETTERS + '0', ctx->user_data);
     263              :   } else {
     264            0 :     ctx->b64_putc(v - NUM_LETTERS - NUM_DIGITS == 0 ? '+' : '/',
     265              :                   ctx->user_data);
     266              :   }
     267            0 : }
     268              : 
     269            0 : static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx) {
     270              :   int a, b, c;
     271              : 
     272            0 :   a = ctx->chunk[0];
     273            0 :   b = ctx->chunk[1];
     274            0 :   c = ctx->chunk[2];
     275              : 
     276            0 :   cs_base64_emit_code(ctx, a >> 2);
     277            0 :   cs_base64_emit_code(ctx, ((a & 3) << 4) | (b >> 4));
     278            0 :   if (ctx->chunk_size > 1) {
     279            0 :     cs_base64_emit_code(ctx, (b & 15) << 2 | (c >> 6));
     280              :   }
     281            0 :   if (ctx->chunk_size > 2) {
     282            0 :     cs_base64_emit_code(ctx, c & 63);
     283              :   }
     284            0 : }
     285              : 
     286            0 : void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc,
     287              :                     void *user_data) {
     288            0 :   ctx->chunk_size = 0;
     289            0 :   ctx->b64_putc = b64_putc;
     290            0 :   ctx->user_data = user_data;
     291            0 : }
     292              : 
     293            0 : void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len) {
     294            0 :   const unsigned char *src = (const unsigned char *) str;
     295              :   size_t i;
     296            0 :   for (i = 0; i < len; i++) {
     297            0 :     ctx->chunk[ctx->chunk_size++] = src[i];
     298            0 :     if (ctx->chunk_size == 3) {
     299            0 :       cs_base64_emit_chunk(ctx);
     300            0 :       ctx->chunk_size = 0;
     301              :     }
     302              :   }
     303            0 : }
     304              : 
     305            0 : void cs_base64_finish(struct cs_base64_ctx *ctx) {
     306            0 :   if (ctx->chunk_size > 0) {
     307              :     int i;
     308            0 :     memset(&ctx->chunk[ctx->chunk_size], 0, 3 - ctx->chunk_size);
     309            0 :     cs_base64_emit_chunk(ctx);
     310            0 :     for (i = 0; i < (3 - ctx->chunk_size); i++) {
     311            0 :       ctx->b64_putc('=', ctx->user_data);
     312              :     }
     313              :   }
     314            0 : }
     315              : 
     316              : #define BASE64_ENCODE_BODY                                                \
     317              :   static const char *b64 =                                                \
     318              :       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
     319              :   int i, j, a, b, c;                                                      \
     320              :                                                                           \
     321              :   for (i = j = 0; i < src_len; i += 3) {                                  \
     322              :     a = src[i];                                                           \
     323              :     b = i + 1 >= src_len ? 0 : src[i + 1];                                \
     324              :     c = i + 2 >= src_len ? 0 : src[i + 2];                                \
     325              :                                                                           \
     326              :     BASE64_OUT(b64[a >> 2]);                                              \
     327              :     BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]);                           \
     328              :     if (i + 1 < src_len) {                                                \
     329              :       BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]);                          \
     330              :     }                                                                     \
     331              :     if (i + 2 < src_len) {                                                \
     332              :       BASE64_OUT(b64[c & 63]);                                            \
     333              :     }                                                                     \
     334              :   }                                                                       \
     335              :                                                                           \
     336              :   while (j % 4 != 0) {                                                    \
     337              :     BASE64_OUT('=');                                                      \
     338              :   }                                                                       \
     339              :   BASE64_FLUSH()
     340              : 
     341              : #define BASE64_OUT(ch) \
     342              :   do {                 \
     343              :     dst[j++] = (ch);   \
     344              :   } while (0)
     345              : 
     346              : #define BASE64_FLUSH() \
     347              :   do {                 \
     348              :     dst[j++] = '\0';   \
     349              :   } while (0)
     350              : 
     351            0 : void cs_base64_encode(const unsigned char *src, int src_len, char *dst) {
     352            0 :   BASE64_ENCODE_BODY;
     353            0 : }
     354              : 
     355              : #undef BASE64_OUT
     356              : #undef BASE64_FLUSH
     357              : 
     358              : #if CS_ENABLE_STDIO
     359              : #define BASE64_OUT(ch)      \
     360              :   do {                      \
     361              :     fprintf(f, "%c", (ch)); \
     362              :     j++;                    \
     363              :   } while (0)
     364              : 
     365              : #define BASE64_FLUSH()
     366              : 
     367            0 : void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len) {
     368            0 :   BASE64_ENCODE_BODY;
     369            0 : }
     370              : 
     371              : #undef BASE64_OUT
     372              : #undef BASE64_FLUSH
     373              : #endif /* CS_ENABLE_STDIO */
     374              : 
     375              : /* Convert one byte of encoded base64 input stream to 6-bit chunk */
     376            0 : static unsigned char from_b64(unsigned char ch) {
     377              :   /* Inverse lookup map */
     378              :   static const unsigned char tab[128] = {
     379              :       255, 255, 255, 255,
     380              :       255, 255, 255, 255, /*  0 */
     381              :       255, 255, 255, 255,
     382              :       255, 255, 255, 255, /*  8 */
     383              :       255, 255, 255, 255,
     384              :       255, 255, 255, 255, /*  16 */
     385              :       255, 255, 255, 255,
     386              :       255, 255, 255, 255, /*  24 */
     387              :       255, 255, 255, 255,
     388              :       255, 255, 255, 255, /*  32 */
     389              :       255, 255, 255, 62,
     390              :       255, 255, 255, 63, /*  40 */
     391              :       52,  53,  54,  55,
     392              :       56,  57,  58,  59, /*  48 */
     393              :       60,  61,  255, 255,
     394              :       255, 200, 255, 255, /*  56   '=' is 200, on index 61 */
     395              :       255, 0,   1,   2,
     396              :       3,   4,   5,   6, /*  64 */
     397              :       7,   8,   9,   10,
     398              :       11,  12,  13,  14, /*  72 */
     399              :       15,  16,  17,  18,
     400              :       19,  20,  21,  22, /*  80 */
     401              :       23,  24,  25,  255,
     402              :       255, 255, 255, 255, /*  88 */
     403              :       255, 26,  27,  28,
     404              :       29,  30,  31,  32, /*  96 */
     405              :       33,  34,  35,  36,
     406              :       37,  38,  39,  40, /*  104 */
     407              :       41,  42,  43,  44,
     408              :       45,  46,  47,  48, /*  112 */
     409              :       49,  50,  51,  255,
     410              :       255, 255, 255, 255, /*  120 */
     411              :   };
     412            0 :   return tab[ch & 127];
     413              : }
     414              : 
     415            0 : int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len) {
     416              :   unsigned char a, b, c, d;
     417            0 :   int orig_len = len;
     418            0 :   char *orig_dst = dst;
     419            0 :   while (len >= 4 && (a = from_b64(s[0])) != 255 &&
     420            0 :          (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&
     421            0 :          (d = from_b64(s[3])) != 255) {
     422            0 :     s += 4;
     423            0 :     len -= 4;
     424            0 :     if (a == 200 || b == 200) break; /* '=' can't be there */
     425            0 :     *dst++ = a << 2 | b >> 4;
     426            0 :     if (c == 200) break;
     427            0 :     *dst++ = b << 4 | c >> 2;
     428            0 :     if (d == 200) break;
     429            0 :     *dst++ = c << 6 | d;
     430              :   }
     431            0 :   *dst = 0;
     432            0 :   if (dec_len != NULL) *dec_len = (dst - orig_dst);
     433            0 :   return orig_len - len;
     434              : }
     435              : 
     436              : #endif /* EXCLUDE_COMMON */
     437              : #ifdef MG_MODULE_LINES
     438              : #line 1 "common/cs_dbg.h"
     439              : #endif
     440              : /*
     441              :  * Copyright (c) 2014-2018 Cesanta Software Limited
     442              :  * All rights reserved
     443              :  *
     444              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
     445              :  * you may not use this file except in compliance with the License.
     446              :  * You may obtain a copy of the License at
     447              :  *
     448              :  *     http://www.apache.org/licenses/LICENSE-2.0
     449              :  *
     450              :  * Unless required by applicable law or agreed to in writing, software
     451              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
     452              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     453              :  * See the License for the specific language governing permissions and
     454              :  * limitations under the License.
     455              :  */
     456              : 
     457              : #ifndef CS_COMMON_CS_DBG_H_
     458              : #define CS_COMMON_CS_DBG_H_
     459              : 
     460              : /* Amalgamated: #include "common/platform.h" */
     461              : 
     462              : #if CS_ENABLE_STDIO
     463              : #include <stdio.h>
     464              : #endif
     465              : 
     466              : #ifndef CS_ENABLE_DEBUG
     467              : #define CS_ENABLE_DEBUG 0
     468              : #endif
     469              : 
     470              : #ifndef CS_LOG_PREFIX_LEN
     471              : #define CS_LOG_PREFIX_LEN 24
     472              : #endif
     473              : 
     474              : #ifndef CS_LOG_ENABLE_TS_DIFF
     475              : #define CS_LOG_ENABLE_TS_DIFF 0
     476              : #endif
     477              : 
     478              : #ifdef __cplusplus
     479              : extern "C" {
     480              : #endif /* __cplusplus */
     481              : 
     482              : /*
     483              :  * Log level; `LL_INFO` is the default. Use `cs_log_set_level()` to change it.
     484              :  */
     485              : enum cs_log_level {
     486              :   LL_NONE = -1,
     487              :   LL_ERROR = 0,
     488              :   LL_WARN = 1,
     489              :   LL_INFO = 2,
     490              :   LL_DEBUG = 3,
     491              :   LL_VERBOSE_DEBUG = 4,
     492              : 
     493              :   _LL_MIN = -2,
     494              :   _LL_MAX = 5,
     495              : };
     496              : 
     497              : /*
     498              :  * Set max log level to print; messages with the level above the given one will
     499              :  * not be printed.
     500              :  */
     501              : void cs_log_set_level(enum cs_log_level level);
     502              : 
     503              : /*
     504              :  * A comma-separated set of prefix=level.
     505              :  * prefix is matched against the log prefix exactly as printed, including line
     506              :  * number, but partial match is ok. Check stops on first matching entry.
     507              :  * If nothing matches, default level is used.
     508              :  *
     509              :  * Examples:
     510              :  *   main.c:=4 - everything from main C at verbose debug level.
     511              :  *   mongoose.c=1,mjs.c=1,=4 - everything at verbose debug except mg_* and mjs_*
     512              :  *
     513              :  */
     514              : void cs_log_set_file_level(const char *file_level);
     515              : 
     516              : /*
     517              :  * Helper function which prints message prefix with the given `level`.
     518              :  * If message should be printed (according to the current log level
     519              :  * and filter), prints the prefix and returns 1, otherwise returns 0.
     520              :  *
     521              :  * Clients should typically just use `LOG()` macro.
     522              :  */
     523              : int cs_log_print_prefix(enum cs_log_level level, const char *fname, int line);
     524              : 
     525              : extern enum cs_log_level cs_log_level;
     526              : 
     527              : #if CS_ENABLE_STDIO
     528              : 
     529              : /*
     530              :  * Set file to write logs into. If `NULL`, logs go to `stderr`.
     531              :  */
     532              : void cs_log_set_file(FILE *file);
     533              : 
     534              : /*
     535              :  * Prints log to the current log file, appends "\n" in the end and flushes the
     536              :  * stream.
     537              :  */
     538              : void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2);
     539              : 
     540              : #if CS_ENABLE_STDIO
     541              : 
     542              : /*
     543              :  * Format and print message `x` with the given level `l`. Example:
     544              :  *
     545              :  * ```c
     546              :  * LOG(LL_INFO, ("my info message: %d", 123));
     547              :  * LOG(LL_DEBUG, ("my debug message: %d", 123));
     548              :  * ```
     549              :  */
     550              : #define LOG(l, x)                                     \
     551              :   do {                                                \
     552              :     if (cs_log_print_prefix(l, __FILE__, __LINE__)) { \
     553              :       cs_log_printf x;                                \
     554              :     }                                                 \
     555              :   } while (0)
     556              : 
     557              : #else
     558              : 
     559              : #define LOG(l, x) ((void) l)
     560              : 
     561              : #endif
     562              : 
     563              : #ifndef CS_NDEBUG
     564              : 
     565              : /*
     566              :  * Shortcut for `LOG(LL_VERBOSE_DEBUG, (...))`
     567              :  */
     568              : #define DBG(x) LOG(LL_VERBOSE_DEBUG, x)
     569              : 
     570              : #else /* NDEBUG */
     571              : 
     572              : #define DBG(x)
     573              : 
     574              : #endif
     575              : 
     576              : #else /* CS_ENABLE_STDIO */
     577              : 
     578              : #define LOG(l, x)
     579              : #define DBG(x)
     580              : 
     581              : #endif
     582              : 
     583              : #ifdef __cplusplus
     584              : }
     585              : #endif /* __cplusplus */
     586              : 
     587              : #endif /* CS_COMMON_CS_DBG_H_ */
     588              : #ifdef MG_MODULE_LINES
     589              : #line 1 "common/cs_dbg.c"
     590              : #endif
     591              : /*
     592              :  * Copyright (c) 2014-2018 Cesanta Software Limited
     593              :  * All rights reserved
     594              :  *
     595              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
     596              :  * you may not use this file except in compliance with the License.
     597              :  * You may obtain a copy of the License at
     598              :  *
     599              :  *     http://www.apache.org/licenses/LICENSE-2.0
     600              :  *
     601              :  * Unless required by applicable law or agreed to in writing, software
     602              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
     603              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     604              :  * See the License for the specific language governing permissions and
     605              :  * limitations under the License.
     606              :  */
     607              : 
     608              : /* Amalgamated: #include "common/cs_dbg.h" */
     609              : 
     610              : #include <stdarg.h>
     611              : #include <stdio.h>
     612              : #include <string.h>
     613              : 
     614              : /* Amalgamated: #include "common/cs_time.h" */
     615              : /* Amalgamated: #include "common/str_util.h" */
     616              : 
     617              : enum cs_log_level cs_log_level WEAK =
     618              : #if CS_ENABLE_DEBUG
     619              :     LL_VERBOSE_DEBUG;
     620              : #else
     621              :     LL_ERROR;
     622              : #endif
     623              : 
     624              : #if CS_ENABLE_STDIO
     625              : static char *s_file_level = NULL;
     626              : 
     627              : void cs_log_set_file_level(const char *file_level) WEAK;
     628              : 
     629              : FILE *cs_log_file WEAK = NULL;
     630              : 
     631              : #if CS_LOG_ENABLE_TS_DIFF
     632              : double cs_log_ts WEAK;
     633              : #endif
     634              : 
     635              : enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE;
     636              : 
     637            0 : void cs_log_set_file_level(const char *file_level) {
     638            0 :   char *fl = s_file_level;
     639            0 :   if (file_level != NULL) {
     640            0 :     s_file_level = strdup(file_level);
     641              :   } else {
     642            0 :     s_file_level = NULL;
     643              :   }
     644            0 :   free(fl);
     645            0 : }
     646              : 
     647              : int cs_log_print_prefix(enum cs_log_level level, const char *file, int ln) WEAK;
     648            0 : int cs_log_print_prefix(enum cs_log_level level, const char *file, int ln) {
     649              :   char prefix[CS_LOG_PREFIX_LEN], *q;
     650              :   const char *p;
     651            0 :   size_t fl = 0, ll = 0, pl = 0;
     652              : 
     653            0 :   if (level > cs_log_level && s_file_level == NULL) return 0;
     654              : 
     655            0 :   p = file + strlen(file);
     656              : 
     657            0 :   while (p != file) {
     658            0 :     const char c = *(p - 1);
     659            0 :     if (c == '/' || c == '\\') break;
     660            0 :     p--;
     661            0 :     fl++;
     662              :   }
     663              : 
     664            0 :   ll = (ln < 10000 ? (ln < 1000 ? (ln < 100 ? (ln < 10 ? 1 : 2) : 3) : 4) : 5);
     665            0 :   if (fl > (sizeof(prefix) - ll - 2)) fl = (sizeof(prefix) - ll - 2);
     666              : 
     667            0 :   pl = fl + 1 + ll;
     668            0 :   memcpy(prefix, p, fl);
     669            0 :   q = prefix + pl;
     670            0 :   memset(q, ' ', sizeof(prefix) - pl);
     671              :   do {
     672            0 :     *(--q) = '0' + (ln % 10);
     673            0 :     ln /= 10;
     674            0 :   } while (ln > 0);
     675            0 :   *(--q) = ':';
     676              : 
     677            0 :   if (s_file_level != NULL) {
     678            0 :     enum cs_log_level pll = cs_log_level;
     679            0 :     struct mg_str fl = mg_mk_str(s_file_level), ps = MG_MK_STR_N(prefix, pl);
     680              :     struct mg_str k, v;
     681            0 :     while ((fl = mg_next_comma_list_entry_n(fl, &k, &v)).p != NULL) {
     682            0 :       bool yes = !(!mg_str_starts_with(ps, k) || v.len == 0);
     683            0 :       if (!yes) continue;
     684            0 :       pll = (enum cs_log_level)(*v.p - '0');
     685            0 :       break;
     686              :     }
     687            0 :     if (level > pll) return 0;
     688              :   }
     689              : 
     690            0 :   if (cs_log_file == NULL) cs_log_file = stderr;
     691            0 :   cs_log_cur_msg_level = level;
     692            0 :   fwrite(prefix, 1, sizeof(prefix), cs_log_file);
     693              : #if CS_LOG_ENABLE_TS_DIFF
     694              :   {
     695              :     double now = cs_time();
     696              :     fprintf(cs_log_file, "%7u ", (unsigned int) ((now - cs_log_ts) * 1000000));
     697              :     cs_log_ts = now;
     698              :   }
     699              : #endif
     700            0 :   return 1;
     701              : }
     702              : 
     703              : void cs_log_printf(const char *fmt, ...) WEAK;
     704            0 : void cs_log_printf(const char *fmt, ...) {
     705              :   va_list ap;
     706            0 :   va_start(ap, fmt);
     707            0 :   vfprintf(cs_log_file, fmt, ap);
     708            0 :   va_end(ap);
     709            0 :   fputc('\n', cs_log_file);
     710            0 :   fflush(cs_log_file);
     711            0 :   cs_log_cur_msg_level = LL_NONE;
     712            0 : }
     713              : 
     714              : void cs_log_set_file(FILE *file) WEAK;
     715            0 : void cs_log_set_file(FILE *file) {
     716            0 :   cs_log_file = file;
     717            0 : }
     718              : 
     719              : #else
     720              : 
     721              : void cs_log_set_file_level(const char *file_level) {
     722              :   (void) file_level;
     723              : }
     724              : 
     725              : #endif /* CS_ENABLE_STDIO */
     726              : 
     727              : void cs_log_set_level(enum cs_log_level level) WEAK;
     728            0 : void cs_log_set_level(enum cs_log_level level) {
     729            0 :   cs_log_level = level;
     730              : #if CS_LOG_ENABLE_TS_DIFF && CS_ENABLE_STDIO
     731              :   cs_log_ts = cs_time();
     732              : #endif
     733            0 : }
     734              : #ifdef MG_MODULE_LINES
     735              : #line 1 "common/cs_dirent.h"
     736              : #endif
     737              : /*
     738              :  * Copyright (c) 2014-2018 Cesanta Software Limited
     739              :  * All rights reserved
     740              :  *
     741              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
     742              :  * you may not use this file except in compliance with the License.
     743              :  * You may obtain a copy of the License at
     744              :  *
     745              :  *     http://www.apache.org/licenses/LICENSE-2.0
     746              :  *
     747              :  * Unless required by applicable law or agreed to in writing, software
     748              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
     749              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     750              :  * See the License for the specific language governing permissions and
     751              :  * limitations under the License.
     752              :  */
     753              : 
     754              : #ifndef CS_COMMON_CS_DIRENT_H_
     755              : #define CS_COMMON_CS_DIRENT_H_
     756              : 
     757              : #include <limits.h>
     758              : 
     759              : /* Amalgamated: #include "common/platform.h" */
     760              : 
     761              : #ifdef __cplusplus
     762              : extern "C" {
     763              : #endif /* __cplusplus */
     764              : 
     765              : #ifdef CS_DEFINE_DIRENT
     766              : typedef struct { int dummy; } DIR;
     767              : 
     768              : struct dirent {
     769              :   int d_ino;
     770              : #ifdef _WIN32
     771              :   char d_name[MAX_PATH];
     772              : #else
     773              :   /* TODO(rojer): Use PATH_MAX but make sure it's sane on every platform */
     774              :   char d_name[256];
     775              : #endif
     776              : };
     777              : 
     778              : DIR *opendir(const char *dir_name);
     779              : int closedir(DIR *dir);
     780              : struct dirent *readdir(DIR *dir);
     781              : #endif /* CS_DEFINE_DIRENT */
     782              : 
     783              : #ifdef __cplusplus
     784              : }
     785              : #endif /* __cplusplus */
     786              : 
     787              : #endif /* CS_COMMON_CS_DIRENT_H_ */
     788              : #ifdef MG_MODULE_LINES
     789              : #line 1 "common/cs_dirent.c"
     790              : #endif
     791              : /*
     792              :  * Copyright (c) 2014-2018 Cesanta Software Limited
     793              :  * All rights reserved
     794              :  *
     795              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
     796              :  * you may not use this file except in compliance with the License.
     797              :  * You may obtain a copy of the License at
     798              :  *
     799              :  *     http://www.apache.org/licenses/LICENSE-2.0
     800              :  *
     801              :  * Unless required by applicable law or agreed to in writing, software
     802              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
     803              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     804              :  * See the License for the specific language governing permissions and
     805              :  * limitations under the License.
     806              :  */
     807              : 
     808              : #ifndef EXCLUDE_COMMON
     809              : 
     810              : /* Amalgamated: #include "common/mg_mem.h" */
     811              : /* Amalgamated: #include "common/cs_dirent.h" */
     812              : 
     813              : /*
     814              :  * This file contains POSIX opendir/closedir/readdir API implementation
     815              :  * for systems which do not natively support it (e.g. Windows).
     816              :  */
     817              : 
     818              : #ifdef _WIN32
     819              : struct win32_dir {
     820              :   DIR d;
     821              :   HANDLE handle;
     822              :   WIN32_FIND_DATAW info;
     823              :   struct dirent result;
     824              : };
     825              : 
     826              : DIR *opendir(const char *name) {
     827              :   struct win32_dir *dir = NULL;
     828              :   wchar_t wpath[MAX_PATH];
     829              :   DWORD attrs;
     830              : 
     831              :   if (name == NULL) {
     832              :     SetLastError(ERROR_BAD_ARGUMENTS);
     833              :   } else if ((dir = (struct win32_dir *) MG_MALLOC(sizeof(*dir))) == NULL) {
     834              :     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
     835              :   } else {
     836              :     to_wchar(name, wpath, ARRAY_SIZE(wpath));
     837              :     attrs = GetFileAttributesW(wpath);
     838              :     if (attrs != 0xFFFFFFFF && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
     839              :       (void) wcscat(wpath, L"\\*");
     840              :       dir->handle = FindFirstFileW(wpath, &dir->info);
     841              :       dir->result.d_name[0] = '\0';
     842              :     } else {
     843              :       MG_FREE(dir);
     844              :       dir = NULL;
     845              :     }
     846              :   }
     847              : 
     848              :   return (DIR *) dir;
     849              : }
     850              : 
     851              : int closedir(DIR *d) {
     852              :   struct win32_dir *dir = (struct win32_dir *) d;
     853              :   int result = 0;
     854              : 
     855              :   if (dir != NULL) {
     856              :     if (dir->handle != INVALID_HANDLE_VALUE)
     857              :       result = FindClose(dir->handle) ? 0 : -1;
     858              :     MG_FREE(dir);
     859              :   } else {
     860              :     result = -1;
     861              :     SetLastError(ERROR_BAD_ARGUMENTS);
     862              :   }
     863              : 
     864              :   return result;
     865              : }
     866              : 
     867              : struct dirent *readdir(DIR *d) {
     868              :   struct win32_dir *dir = (struct win32_dir *) d;
     869              :   struct dirent *result = NULL;
     870              : 
     871              :   if (dir) {
     872              :     memset(&dir->result, 0, sizeof(dir->result));
     873              :     if (dir->handle != INVALID_HANDLE_VALUE) {
     874              :       result = &dir->result;
     875              :       (void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1,
     876              :                                  result->d_name, sizeof(result->d_name), NULL,
     877              :                                  NULL);
     878              : 
     879              :       if (!FindNextFileW(dir->handle, &dir->info)) {
     880              :         (void) FindClose(dir->handle);
     881              :         dir->handle = INVALID_HANDLE_VALUE;
     882              :       }
     883              : 
     884              :     } else {
     885              :       SetLastError(ERROR_FILE_NOT_FOUND);
     886              :     }
     887              :   } else {
     888              :     SetLastError(ERROR_BAD_ARGUMENTS);
     889              :   }
     890              : 
     891              :   return result;
     892              : }
     893              : #endif
     894              : 
     895              : #endif /* EXCLUDE_COMMON */
     896              : 
     897              : /* ISO C requires a translation unit to contain at least one declaration */
     898              : typedef int cs_dirent_dummy;
     899              : #ifdef MG_MODULE_LINES
     900              : #line 1 "common/cs_time.c"
     901              : #endif
     902              : /*
     903              :  * Copyright (c) 2014-2018 Cesanta Software Limited
     904              :  * All rights reserved
     905              :  *
     906              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
     907              :  * you may not use this file except in compliance with the License.
     908              :  * You may obtain a copy of the License at
     909              :  *
     910              :  *     http://www.apache.org/licenses/LICENSE-2.0
     911              :  *
     912              :  * Unless required by applicable law or agreed to in writing, software
     913              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
     914              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     915              :  * See the License for the specific language governing permissions and
     916              :  * limitations under the License.
     917              :  */
     918              : 
     919              : /* Amalgamated: #include "common/cs_time.h" */
     920              : 
     921              : #ifndef _WIN32
     922              : #include <stddef.h>
     923              : /*
     924              :  * There is no sys/time.h on ARMCC.
     925              :  */
     926              : #if !(defined(__ARMCC_VERSION) || defined(__ICCARM__)) && \
     927              :     !defined(__TI_COMPILER_VERSION__) &&                  \
     928              :     (!defined(CS_PLATFORM) || CS_PLATFORM != CS_P_NXP_LPC)
     929              : #include <sys/time.h>
     930              : #endif
     931              : #else
     932              : #include <windows.h>
     933              : #endif
     934              : 
     935              : double cs_time(void) WEAK;
     936            0 : double cs_time(void) {
     937              :   double now;
     938              : #ifndef _WIN32
     939              :   struct timeval tv;
     940            0 :   if (gettimeofday(&tv, NULL /* tz */) != 0) return 0;
     941            0 :   now = (double) tv.tv_sec + (((double) tv.tv_usec) / 1000000.0);
     942              : #else
     943              :   SYSTEMTIME sysnow;
     944              :   FILETIME ftime;
     945              :   GetLocalTime(&sysnow);
     946              :   SystemTimeToFileTime(&sysnow, &ftime);
     947              :   /*
     948              :    * 1. VC 6.0 doesn't support conversion uint64 -> double, so, using int64
     949              :    * This should not cause a problems in this (21th) century
     950              :    * 2. Windows FILETIME is a number of 100-nanosecond intervals since January
     951              :    * 1, 1601 while time_t is a number of _seconds_ since January 1, 1970 UTC,
     952              :    * thus, we need to convert to seconds and adjust amount (subtract 11644473600
     953              :    * seconds)
     954              :    */
     955              :   now = (double) (((int64_t) ftime.dwLowDateTime +
     956              :                    ((int64_t) ftime.dwHighDateTime << 32)) /
     957              :                   10000000.0) -
     958              :         11644473600;
     959              : #endif /* _WIN32 */
     960            0 :   return now;
     961              : }
     962              : 
     963            0 : double cs_timegm(const struct tm *tm) {
     964              :   /* Month-to-day offset for non-leap-years. */
     965              :   static const int month_day[12] = {0,   31,  59,  90,  120, 151,
     966              :                                     181, 212, 243, 273, 304, 334};
     967              : 
     968              :   /* Most of the calculation is easy; leap years are the main difficulty. */
     969            0 :   int month = tm->tm_mon % 12;
     970            0 :   int year = tm->tm_year + tm->tm_mon / 12;
     971              :   int year_for_leap;
     972              :   int64_t rt;
     973              : 
     974            0 :   if (month < 0) { /* Negative values % 12 are still negative. */
     975            0 :     month += 12;
     976            0 :     --year;
     977              :   }
     978              : 
     979              :   /* This is the number of Februaries since 1900. */
     980            0 :   year_for_leap = (month > 1) ? year + 1 : year;
     981              : 
     982            0 :   rt =
     983            0 :       tm->tm_sec /* Seconds */
     984            0 :       +
     985            0 :       60 *
     986            0 :           (tm->tm_min /* Minute = 60 seconds */
     987            0 :            +
     988            0 :            60 * (tm->tm_hour /* Hour = 60 minutes */
     989            0 :                  +
     990            0 :                  24 * (month_day[month] + tm->tm_mday - 1 /* Day = 24 hours */
     991            0 :                        + 365 * (year - 70)                /* Year = 365 days */
     992            0 :                        + (year_for_leap - 69) / 4 /* Every 4 years is leap... */
     993            0 :                        - (year_for_leap - 1) / 100 /* Except centuries... */
     994            0 :                        + (year_for_leap + 299) / 400))); /* Except 400s. */
     995            0 :   return rt < 0 ? -1 : (double) rt;
     996              : }
     997              : #ifdef MG_MODULE_LINES
     998              : #line 1 "common/cs_endian.h"
     999              : #endif
    1000              : /*
    1001              :  * Copyright (c) 2014-2018 Cesanta Software Limited
    1002              :  * All rights reserved
    1003              :  *
    1004              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
    1005              :  * you may not use this file except in compliance with the License.
    1006              :  * You may obtain a copy of the License at
    1007              :  *
    1008              :  *     http://www.apache.org/licenses/LICENSE-2.0
    1009              :  *
    1010              :  * Unless required by applicable law or agreed to in writing, software
    1011              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
    1012              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1013              :  * See the License for the specific language governing permissions and
    1014              :  * limitations under the License.
    1015              :  */
    1016              : 
    1017              : #ifndef CS_COMMON_CS_ENDIAN_H_
    1018              : #define CS_COMMON_CS_ENDIAN_H_
    1019              : 
    1020              : #ifdef __cplusplus
    1021              : extern "C" {
    1022              : #endif
    1023              : 
    1024              : /*
    1025              :  * clang with std=-c99 uses __LITTLE_ENDIAN, by default
    1026              :  * while for ex, RTOS gcc - LITTLE_ENDIAN, by default
    1027              :  * it depends on __USE_BSD, but let's have everything
    1028              :  */
    1029              : #if !defined(BYTE_ORDER) && defined(__BYTE_ORDER)
    1030              : #define BYTE_ORDER __BYTE_ORDER
    1031              : #ifndef LITTLE_ENDIAN
    1032              : #define LITTLE_ENDIAN __LITTLE_ENDIAN
    1033              : #endif /* LITTLE_ENDIAN */
    1034              : #ifndef BIG_ENDIAN
    1035              : #define BIG_ENDIAN __LITTLE_ENDIAN
    1036              : #endif /* BIG_ENDIAN */
    1037              : #endif /* BYTE_ORDER */
    1038              : 
    1039              : #ifdef __cplusplus
    1040              : }
    1041              : #endif
    1042              : 
    1043              : #endif /* CS_COMMON_CS_ENDIAN_H_ */
    1044              : #ifdef MG_MODULE_LINES
    1045              : #line 1 "common/cs_md5.c"
    1046              : #endif
    1047              : /*
    1048              :  * This code implements the MD5 message-digest algorithm.
    1049              :  * The algorithm is due to Ron Rivest.  This code was
    1050              :  * written by Colin Plumb in 1993, no copyright is claimed.
    1051              :  * This code is in the public domain; do with it what you wish.
    1052              :  *
    1053              :  * Equivalent code is available from RSA Data Security, Inc.
    1054              :  * This code has been tested against that, and is equivalent,
    1055              :  * except that you don't need to include two pages of legalese
    1056              :  * with every copy.
    1057              :  *
    1058              :  * To compute the message digest of a chunk of bytes, declare an
    1059              :  * MD5Context structure, pass it to MD5Init, call MD5Update as
    1060              :  * needed on buffers full of bytes, and then call MD5Final, which
    1061              :  * will fill a supplied 16-byte array with the digest.
    1062              :  */
    1063              : 
    1064              : /* Amalgamated: #include "common/cs_md5.h" */
    1065              : /* Amalgamated: #include "common/str_util.h" */
    1066              : 
    1067              : #if !defined(EXCLUDE_COMMON)
    1068              : #if !CS_DISABLE_MD5
    1069              : 
    1070              : /* Amalgamated: #include "common/cs_endian.h" */
    1071              : 
    1072            0 : static void byteReverse(unsigned char *buf, unsigned longs) {
    1073              : /* Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN */
    1074              : #if BYTE_ORDER == BIG_ENDIAN
    1075              :   do {
    1076              :     uint32_t t = (uint32_t)((unsigned) buf[3] << 8 | buf[2]) << 16 |
    1077              :                  ((unsigned) buf[1] << 8 | buf[0]);
    1078              :     *(uint32_t *) buf = t;
    1079              :     buf += 4;
    1080              :   } while (--longs);
    1081              : #else
    1082              :   (void) buf;
    1083              :   (void) longs;
    1084              : #endif
    1085            0 : }
    1086              : 
    1087              : #define F1(x, y, z) (z ^ (x & (y ^ z)))
    1088              : #define F2(x, y, z) F1(z, x, y)
    1089              : #define F3(x, y, z) (x ^ y ^ z)
    1090              : #define F4(x, y, z) (y ^ (x | ~z))
    1091              : 
    1092              : #define MD5STEP(f, w, x, y, z, data, s) \
    1093              :   (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
    1094              : 
    1095              : /*
    1096              :  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
    1097              :  * initialization constants.
    1098              :  */
    1099            0 : void cs_md5_init(cs_md5_ctx *ctx) {
    1100            0 :   ctx->buf[0] = 0x67452301;
    1101            0 :   ctx->buf[1] = 0xefcdab89;
    1102            0 :   ctx->buf[2] = 0x98badcfe;
    1103            0 :   ctx->buf[3] = 0x10325476;
    1104              : 
    1105            0 :   ctx->bits[0] = 0;
    1106            0 :   ctx->bits[1] = 0;
    1107            0 : }
    1108              : 
    1109            0 : static void cs_md5_transform(uint32_t buf[4], uint32_t const in[16]) {
    1110              :   uint32_t a, b, c, d;
    1111              : 
    1112            0 :   a = buf[0];
    1113            0 :   b = buf[1];
    1114            0 :   c = buf[2];
    1115            0 :   d = buf[3];
    1116              : 
    1117            0 :   MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
    1118            0 :   MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
    1119            0 :   MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
    1120            0 :   MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
    1121            0 :   MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
    1122            0 :   MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
    1123            0 :   MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
    1124            0 :   MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
    1125            0 :   MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
    1126            0 :   MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
    1127            0 :   MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
    1128            0 :   MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
    1129            0 :   MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
    1130            0 :   MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
    1131            0 :   MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
    1132            0 :   MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
    1133              : 
    1134            0 :   MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
    1135            0 :   MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
    1136            0 :   MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
    1137            0 :   MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
    1138            0 :   MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
    1139            0 :   MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
    1140            0 :   MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
    1141            0 :   MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
    1142            0 :   MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
    1143            0 :   MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
    1144            0 :   MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
    1145            0 :   MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
    1146            0 :   MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
    1147            0 :   MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
    1148            0 :   MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
    1149            0 :   MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
    1150              : 
    1151            0 :   MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
    1152            0 :   MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
    1153            0 :   MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
    1154            0 :   MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
    1155            0 :   MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
    1156            0 :   MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
    1157            0 :   MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
    1158            0 :   MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
    1159            0 :   MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
    1160            0 :   MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
    1161            0 :   MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
    1162            0 :   MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
    1163            0 :   MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
    1164            0 :   MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
    1165            0 :   MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
    1166            0 :   MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
    1167              : 
    1168            0 :   MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
    1169            0 :   MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
    1170            0 :   MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
    1171            0 :   MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
    1172            0 :   MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
    1173            0 :   MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
    1174            0 :   MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
    1175            0 :   MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
    1176            0 :   MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
    1177            0 :   MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
    1178            0 :   MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
    1179            0 :   MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
    1180            0 :   MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
    1181            0 :   MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
    1182            0 :   MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
    1183            0 :   MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
    1184              : 
    1185            0 :   buf[0] += a;
    1186            0 :   buf[1] += b;
    1187            0 :   buf[2] += c;
    1188            0 :   buf[3] += d;
    1189            0 : }
    1190              : 
    1191            0 : void cs_md5_update(cs_md5_ctx *ctx, const unsigned char *buf, size_t len) {
    1192              :   uint32_t t;
    1193              : 
    1194            0 :   t = ctx->bits[0];
    1195            0 :   if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
    1196            0 :   ctx->bits[1] += (uint32_t) len >> 29;
    1197              : 
    1198            0 :   t = (t >> 3) & 0x3f;
    1199              : 
    1200            0 :   if (t) {
    1201            0 :     unsigned char *p = (unsigned char *) ctx->in + t;
    1202              : 
    1203            0 :     t = 64 - t;
    1204            0 :     if (len < t) {
    1205            0 :       memcpy(p, buf, len);
    1206            0 :       return;
    1207              :     }
    1208            0 :     memcpy(p, buf, t);
    1209            0 :     byteReverse(ctx->in, 16);
    1210            0 :     cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
    1211            0 :     buf += t;
    1212            0 :     len -= t;
    1213              :   }
    1214              : 
    1215            0 :   while (len >= 64) {
    1216            0 :     memcpy(ctx->in, buf, 64);
    1217            0 :     byteReverse(ctx->in, 16);
    1218            0 :     cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
    1219            0 :     buf += 64;
    1220            0 :     len -= 64;
    1221              :   }
    1222              : 
    1223            0 :   memcpy(ctx->in, buf, len);
    1224              : }
    1225              : 
    1226            0 : void cs_md5_final(unsigned char digest[16], cs_md5_ctx *ctx) {
    1227              :   unsigned count;
    1228              :   unsigned char *p;
    1229              :   uint32_t *a;
    1230              : 
    1231            0 :   count = (ctx->bits[0] >> 3) & 0x3F;
    1232              : 
    1233            0 :   p = ctx->in + count;
    1234            0 :   *p++ = 0x80;
    1235            0 :   count = 64 - 1 - count;
    1236            0 :   if (count < 8) {
    1237            0 :     memset(p, 0, count);
    1238            0 :     byteReverse(ctx->in, 16);
    1239            0 :     cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
    1240            0 :     memset(ctx->in, 0, 56);
    1241              :   } else {
    1242            0 :     memset(p, 0, count - 8);
    1243              :   }
    1244            0 :   byteReverse(ctx->in, 14);
    1245              : 
    1246            0 :   a = (uint32_t *) ctx->in;
    1247            0 :   a[14] = ctx->bits[0];
    1248            0 :   a[15] = ctx->bits[1];
    1249              : 
    1250            0 :   cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
    1251            0 :   byteReverse((unsigned char *) ctx->buf, 4);
    1252            0 :   memcpy(digest, ctx->buf, 16);
    1253            0 :   memset((char *) ctx, 0, sizeof(*ctx));
    1254            0 : }
    1255              : 
    1256              : #endif /* CS_DISABLE_MD5 */
    1257              : #endif /* EXCLUDE_COMMON */
    1258              : #ifdef MG_MODULE_LINES
    1259              : #line 1 "common/cs_sha1.c"
    1260              : #endif
    1261              : /* Copyright(c) By Steve Reid <steve@edmweb.com> */
    1262              : /* 100% Public Domain */
    1263              : 
    1264              : /* Amalgamated: #include "common/cs_sha1.h" */
    1265              : 
    1266              : #if !CS_DISABLE_SHA1 && !defined(EXCLUDE_COMMON)
    1267              : 
    1268              : /* Amalgamated: #include "common/cs_endian.h" */
    1269              : 
    1270              : #define SHA1HANDSOFF
    1271              : #if defined(__sun)
    1272              : /* Amalgamated: #include "common/solarisfixes.h" */
    1273              : #endif
    1274              : 
    1275              : union char64long16 {
    1276              :   unsigned char c[64];
    1277              :   uint32_t l[16];
    1278              : };
    1279              : 
    1280              : #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
    1281              : 
    1282            0 : static uint32_t blk0(union char64long16 *block, int i) {
    1283              : /* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
    1284              : #if BYTE_ORDER == LITTLE_ENDIAN
    1285            0 :   block->l[i] =
    1286            0 :       (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF);
    1287              : #endif
    1288            0 :   return block->l[i];
    1289              : }
    1290              : 
    1291              : /* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
    1292              : #undef blk
    1293              : #undef R0
    1294              : #undef R1
    1295              : #undef R2
    1296              : #undef R3
    1297              : #undef R4
    1298              : 
    1299              : #define blk(i)                                                               \
    1300              :   (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
    1301              :                               block->l[(i + 2) & 15] ^ block->l[i & 15],     \
    1302              :                           1))
    1303              : #define R0(v, w, x, y, z, i)                                          \
    1304              :   z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
    1305              :   w = rol(w, 30);
    1306              : #define R1(v, w, x, y, z, i)                                  \
    1307              :   z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
    1308              :   w = rol(w, 30);
    1309              : #define R2(v, w, x, y, z, i)                          \
    1310              :   z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
    1311              :   w = rol(w, 30);
    1312              : #define R3(v, w, x, y, z, i)                                        \
    1313              :   z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
    1314              :   w = rol(w, 30);
    1315              : #define R4(v, w, x, y, z, i)                          \
    1316              :   z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
    1317              :   w = rol(w, 30);
    1318              : 
    1319            0 : void cs_sha1_transform(uint32_t state[5], const unsigned char buffer[64]) {
    1320              :   uint32_t a, b, c, d, e;
    1321              :   union char64long16 block[1];
    1322              : 
    1323            0 :   memcpy(block, buffer, 64);
    1324            0 :   a = state[0];
    1325            0 :   b = state[1];
    1326            0 :   c = state[2];
    1327            0 :   d = state[3];
    1328            0 :   e = state[4];
    1329            0 :   R0(a, b, c, d, e, 0);
    1330            0 :   R0(e, a, b, c, d, 1);
    1331            0 :   R0(d, e, a, b, c, 2);
    1332            0 :   R0(c, d, e, a, b, 3);
    1333            0 :   R0(b, c, d, e, a, 4);
    1334            0 :   R0(a, b, c, d, e, 5);
    1335            0 :   R0(e, a, b, c, d, 6);
    1336            0 :   R0(d, e, a, b, c, 7);
    1337            0 :   R0(c, d, e, a, b, 8);
    1338            0 :   R0(b, c, d, e, a, 9);
    1339            0 :   R0(a, b, c, d, e, 10);
    1340            0 :   R0(e, a, b, c, d, 11);
    1341            0 :   R0(d, e, a, b, c, 12);
    1342            0 :   R0(c, d, e, a, b, 13);
    1343            0 :   R0(b, c, d, e, a, 14);
    1344            0 :   R0(a, b, c, d, e, 15);
    1345            0 :   R1(e, a, b, c, d, 16);
    1346            0 :   R1(d, e, a, b, c, 17);
    1347            0 :   R1(c, d, e, a, b, 18);
    1348            0 :   R1(b, c, d, e, a, 19);
    1349            0 :   R2(a, b, c, d, e, 20);
    1350            0 :   R2(e, a, b, c, d, 21);
    1351            0 :   R2(d, e, a, b, c, 22);
    1352            0 :   R2(c, d, e, a, b, 23);
    1353            0 :   R2(b, c, d, e, a, 24);
    1354            0 :   R2(a, b, c, d, e, 25);
    1355            0 :   R2(e, a, b, c, d, 26);
    1356            0 :   R2(d, e, a, b, c, 27);
    1357            0 :   R2(c, d, e, a, b, 28);
    1358            0 :   R2(b, c, d, e, a, 29);
    1359            0 :   R2(a, b, c, d, e, 30);
    1360            0 :   R2(e, a, b, c, d, 31);
    1361            0 :   R2(d, e, a, b, c, 32);
    1362            0 :   R2(c, d, e, a, b, 33);
    1363            0 :   R2(b, c, d, e, a, 34);
    1364            0 :   R2(a, b, c, d, e, 35);
    1365            0 :   R2(e, a, b, c, d, 36);
    1366            0 :   R2(d, e, a, b, c, 37);
    1367            0 :   R2(c, d, e, a, b, 38);
    1368            0 :   R2(b, c, d, e, a, 39);
    1369            0 :   R3(a, b, c, d, e, 40);
    1370            0 :   R3(e, a, b, c, d, 41);
    1371            0 :   R3(d, e, a, b, c, 42);
    1372            0 :   R3(c, d, e, a, b, 43);
    1373            0 :   R3(b, c, d, e, a, 44);
    1374            0 :   R3(a, b, c, d, e, 45);
    1375            0 :   R3(e, a, b, c, d, 46);
    1376            0 :   R3(d, e, a, b, c, 47);
    1377            0 :   R3(c, d, e, a, b, 48);
    1378            0 :   R3(b, c, d, e, a, 49);
    1379            0 :   R3(a, b, c, d, e, 50);
    1380            0 :   R3(e, a, b, c, d, 51);
    1381            0 :   R3(d, e, a, b, c, 52);
    1382            0 :   R3(c, d, e, a, b, 53);
    1383            0 :   R3(b, c, d, e, a, 54);
    1384            0 :   R3(a, b, c, d, e, 55);
    1385            0 :   R3(e, a, b, c, d, 56);
    1386            0 :   R3(d, e, a, b, c, 57);
    1387            0 :   R3(c, d, e, a, b, 58);
    1388            0 :   R3(b, c, d, e, a, 59);
    1389            0 :   R4(a, b, c, d, e, 60);
    1390            0 :   R4(e, a, b, c, d, 61);
    1391            0 :   R4(d, e, a, b, c, 62);
    1392            0 :   R4(c, d, e, a, b, 63);
    1393            0 :   R4(b, c, d, e, a, 64);
    1394            0 :   R4(a, b, c, d, e, 65);
    1395            0 :   R4(e, a, b, c, d, 66);
    1396            0 :   R4(d, e, a, b, c, 67);
    1397            0 :   R4(c, d, e, a, b, 68);
    1398            0 :   R4(b, c, d, e, a, 69);
    1399            0 :   R4(a, b, c, d, e, 70);
    1400            0 :   R4(e, a, b, c, d, 71);
    1401            0 :   R4(d, e, a, b, c, 72);
    1402            0 :   R4(c, d, e, a, b, 73);
    1403            0 :   R4(b, c, d, e, a, 74);
    1404            0 :   R4(a, b, c, d, e, 75);
    1405            0 :   R4(e, a, b, c, d, 76);
    1406            0 :   R4(d, e, a, b, c, 77);
    1407            0 :   R4(c, d, e, a, b, 78);
    1408            0 :   R4(b, c, d, e, a, 79);
    1409            0 :   state[0] += a;
    1410            0 :   state[1] += b;
    1411            0 :   state[2] += c;
    1412            0 :   state[3] += d;
    1413            0 :   state[4] += e;
    1414              :   /* Erase working structures. The order of operations is important,
    1415              :    * used to ensure that compiler doesn't optimize those out. */
    1416            0 :   memset(block, 0, sizeof(block));
    1417            0 :   a = b = c = d = e = 0;
    1418              :   (void) a;
    1419              :   (void) b;
    1420              :   (void) c;
    1421              :   (void) d;
    1422              :   (void) e;
    1423            0 : }
    1424              : 
    1425            0 : void cs_sha1_init(cs_sha1_ctx *context) {
    1426            0 :   context->state[0] = 0x67452301;
    1427            0 :   context->state[1] = 0xEFCDAB89;
    1428            0 :   context->state[2] = 0x98BADCFE;
    1429            0 :   context->state[3] = 0x10325476;
    1430            0 :   context->state[4] = 0xC3D2E1F0;
    1431            0 :   context->count[0] = context->count[1] = 0;
    1432            0 : }
    1433              : 
    1434            0 : void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data,
    1435              :                     uint32_t len) {
    1436              :   uint32_t i, j;
    1437              : 
    1438            0 :   j = context->count[0];
    1439            0 :   if ((context->count[0] += len << 3) < j) context->count[1]++;
    1440            0 :   context->count[1] += (len >> 29);
    1441            0 :   j = (j >> 3) & 63;
    1442            0 :   if ((j + len) > 63) {
    1443            0 :     memcpy(&context->buffer[j], data, (i = 64 - j));
    1444            0 :     cs_sha1_transform(context->state, context->buffer);
    1445            0 :     for (; i + 63 < len; i += 64) {
    1446            0 :       cs_sha1_transform(context->state, &data[i]);
    1447              :     }
    1448            0 :     j = 0;
    1449              :   } else
    1450            0 :     i = 0;
    1451            0 :   memcpy(&context->buffer[j], &data[i], len - i);
    1452            0 : }
    1453              : 
    1454            0 : void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context) {
    1455              :   unsigned i;
    1456              :   unsigned char finalcount[8], c;
    1457              : 
    1458            0 :   for (i = 0; i < 8; i++) {
    1459            0 :     finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >>
    1460            0 :                                       ((3 - (i & 3)) * 8)) &
    1461              :                                      255);
    1462              :   }
    1463            0 :   c = 0200;
    1464            0 :   cs_sha1_update(context, &c, 1);
    1465            0 :   while ((context->count[0] & 504) != 448) {
    1466            0 :     c = 0000;
    1467            0 :     cs_sha1_update(context, &c, 1);
    1468              :   }
    1469            0 :   cs_sha1_update(context, finalcount, 8);
    1470            0 :   for (i = 0; i < 20; i++) {
    1471            0 :     digest[i] =
    1472            0 :         (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
    1473              :   }
    1474            0 :   memset(context, '\0', sizeof(*context));
    1475            0 :   memset(&finalcount, '\0', sizeof(finalcount));
    1476            0 : }
    1477              : 
    1478            0 : void cs_hmac_sha1(const unsigned char *key, size_t keylen,
    1479              :                   const unsigned char *data, size_t datalen,
    1480              :                   unsigned char out[20]) {
    1481              :   cs_sha1_ctx ctx;
    1482              :   unsigned char buf1[64], buf2[64], tmp_key[20], i;
    1483              : 
    1484            0 :   if (keylen > sizeof(buf1)) {
    1485            0 :     cs_sha1_init(&ctx);
    1486            0 :     cs_sha1_update(&ctx, key, keylen);
    1487            0 :     cs_sha1_final(tmp_key, &ctx);
    1488            0 :     key = tmp_key;
    1489            0 :     keylen = sizeof(tmp_key);
    1490              :   }
    1491              : 
    1492            0 :   memset(buf1, 0, sizeof(buf1));
    1493            0 :   memset(buf2, 0, sizeof(buf2));
    1494            0 :   memcpy(buf1, key, keylen);
    1495            0 :   memcpy(buf2, key, keylen);
    1496              : 
    1497            0 :   for (i = 0; i < sizeof(buf1); i++) {
    1498            0 :     buf1[i] ^= 0x36;
    1499            0 :     buf2[i] ^= 0x5c;
    1500              :   }
    1501              : 
    1502            0 :   cs_sha1_init(&ctx);
    1503            0 :   cs_sha1_update(&ctx, buf1, sizeof(buf1));
    1504            0 :   cs_sha1_update(&ctx, data, datalen);
    1505            0 :   cs_sha1_final(out, &ctx);
    1506              : 
    1507            0 :   cs_sha1_init(&ctx);
    1508            0 :   cs_sha1_update(&ctx, buf2, sizeof(buf2));
    1509            0 :   cs_sha1_update(&ctx, out, 20);
    1510            0 :   cs_sha1_final(out, &ctx);
    1511            0 : }
    1512              : 
    1513              : #endif /* EXCLUDE_COMMON */
    1514              : #ifdef MG_MODULE_LINES
    1515              : #line 1 "common/mbuf.c"
    1516              : #endif
    1517              : /*
    1518              :  * Copyright (c) 2014-2018 Cesanta Software Limited
    1519              :  * All rights reserved
    1520              :  *
    1521              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
    1522              :  * you may not use this file except in compliance with the License.
    1523              :  * You may obtain a copy of the License at
    1524              :  *
    1525              :  *     http://www.apache.org/licenses/LICENSE-2.0
    1526              :  *
    1527              :  * Unless required by applicable law or agreed to in writing, software
    1528              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
    1529              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1530              :  * See the License for the specific language governing permissions and
    1531              :  * limitations under the License.
    1532              :  */
    1533              : 
    1534              : #ifndef EXCLUDE_COMMON
    1535              : 
    1536              : #include <assert.h>
    1537              : #include <string.h>
    1538              : /* Amalgamated: #include "common/mbuf.h" */
    1539              : 
    1540              : #ifndef MBUF_REALLOC
    1541              : #define MBUF_REALLOC realloc
    1542              : #endif
    1543              : 
    1544              : #ifndef MBUF_FREE
    1545              : #define MBUF_FREE free
    1546              : #endif
    1547              : 
    1548              : void mbuf_init(struct mbuf *mbuf, size_t initial_size) WEAK;
    1549            0 : void mbuf_init(struct mbuf *mbuf, size_t initial_size) {
    1550            0 :   mbuf->len = mbuf->size = 0;
    1551            0 :   mbuf->buf = NULL;
    1552            0 :   mbuf_resize(mbuf, initial_size);
    1553            0 : }
    1554              : 
    1555              : void mbuf_free(struct mbuf *mbuf) WEAK;
    1556            0 : void mbuf_free(struct mbuf *mbuf) {
    1557            0 :   if (mbuf->buf != NULL) {
    1558            0 :     MBUF_FREE(mbuf->buf);
    1559            0 :     mbuf_init(mbuf, 0);
    1560              :   }
    1561            0 : }
    1562              : 
    1563              : void mbuf_resize(struct mbuf *a, size_t new_size) WEAK;
    1564            0 : void mbuf_resize(struct mbuf *a, size_t new_size) {
    1565            0 :   if (new_size > a->size || (new_size < a->size && new_size >= a->len)) {
    1566            0 :     char *buf = (char *) MBUF_REALLOC(a->buf, new_size);
    1567              :     /*
    1568              :      * In case realloc fails, there's not much we can do, except keep things as
    1569              :      * they are. Note that NULL is a valid return value from realloc when
    1570              :      * size == 0, but that is covered too.
    1571              :      */
    1572            0 :     if (buf == NULL && new_size != 0) return;
    1573            0 :     a->buf = buf;
    1574            0 :     a->size = new_size;
    1575              :   }
    1576              : }
    1577              : 
    1578              : void mbuf_trim(struct mbuf *mbuf) WEAK;
    1579            0 : void mbuf_trim(struct mbuf *mbuf) {
    1580            0 :   mbuf_resize(mbuf, mbuf->len);
    1581            0 : }
    1582              : 
    1583              : size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t) WEAK;
    1584            0 : size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) {
    1585            0 :   char *p = NULL;
    1586              : 
    1587            0 :   assert(a != NULL);
    1588            0 :   assert(a->len <= a->size);
    1589            0 :   assert(off <= a->len);
    1590              : 
    1591              :   /* check overflow */
    1592            0 :   if (~(size_t) 0 - (size_t) a->buf < len) return 0;
    1593              : 
    1594            0 :   if (a->len + len <= a->size) {
    1595            0 :     memmove(a->buf + off + len, a->buf + off, a->len - off);
    1596            0 :     if (buf != NULL) {
    1597            0 :       memcpy(a->buf + off, buf, len);
    1598              :     }
    1599            0 :     a->len += len;
    1600              :   } else {
    1601            0 :     size_t min_size = (a->len + len);
    1602            0 :     size_t new_size = (size_t)(min_size * MBUF_SIZE_MULTIPLIER);
    1603            0 :     if (new_size - min_size > MBUF_SIZE_MAX_HEADROOM) {
    1604            0 :       new_size = min_size + MBUF_SIZE_MAX_HEADROOM;
    1605              :     }
    1606            0 :     p = (char *) MBUF_REALLOC(a->buf, new_size);
    1607            0 :     if (p == NULL && new_size != min_size) {
    1608            0 :       new_size = min_size;
    1609            0 :       p = (char *) MBUF_REALLOC(a->buf, new_size);
    1610              :     }
    1611            0 :     if (p != NULL) {
    1612            0 :       a->buf = p;
    1613            0 :       if (off != a->len) {
    1614            0 :         memmove(a->buf + off + len, a->buf + off, a->len - off);
    1615              :       }
    1616            0 :       if (buf != NULL) memcpy(a->buf + off, buf, len);
    1617            0 :       a->len += len;
    1618            0 :       a->size = new_size;
    1619              :     } else {
    1620            0 :       len = 0;
    1621              :     }
    1622              :   }
    1623              : 
    1624            0 :   return len;
    1625              : }
    1626              : 
    1627              : size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) WEAK;
    1628            0 : size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) {
    1629            0 :   return mbuf_insert(a, a->len, buf, len);
    1630              : }
    1631              : 
    1632              : size_t mbuf_append_and_free(struct mbuf *a, void *buf, size_t len) WEAK;
    1633            0 : size_t mbuf_append_and_free(struct mbuf *a, void *data, size_t len) {
    1634              :   size_t ret;
    1635              :   /* Optimization: if the buffer is currently empty,
    1636              :    * take over the user-provided buffer. */
    1637            0 :   if (a->len == 0) {
    1638            0 :     if (a->buf != NULL) free(a->buf);
    1639            0 :     a->buf = (char *) data;
    1640            0 :     a->len = a->size = len;
    1641            0 :     return len;
    1642              :   }
    1643            0 :   ret = mbuf_insert(a, a->len, data, len);
    1644            0 :   free(data);
    1645            0 :   return ret;
    1646              : }
    1647              : 
    1648              : void mbuf_remove(struct mbuf *mb, size_t n) WEAK;
    1649            0 : void mbuf_remove(struct mbuf *mb, size_t n) {
    1650            0 :   if (n > 0 && n <= mb->len) {
    1651            0 :     memmove(mb->buf, mb->buf + n, mb->len - n);
    1652            0 :     mb->len -= n;
    1653              :   }
    1654            0 : }
    1655              : 
    1656              : void mbuf_clear(struct mbuf *mb) WEAK;
    1657            0 : void mbuf_clear(struct mbuf *mb) {
    1658            0 :   mb->len = 0;
    1659            0 : }
    1660              : 
    1661              : void mbuf_move(struct mbuf *from, struct mbuf *to) WEAK;
    1662            0 : void mbuf_move(struct mbuf *from, struct mbuf *to) {
    1663            0 :   memcpy(to, from, sizeof(*to));
    1664            0 :   memset(from, 0, sizeof(*from));
    1665            0 : }
    1666              : 
    1667              : #endif /* EXCLUDE_COMMON */
    1668              : #ifdef MG_MODULE_LINES
    1669              : #line 1 "common/mg_str.c"
    1670              : #endif
    1671              : /*
    1672              :  * Copyright (c) 2014-2018 Cesanta Software Limited
    1673              :  * All rights reserved
    1674              :  *
    1675              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
    1676              :  * you may not use this file except in compliance with the License.
    1677              :  * You may obtain a copy of the License at
    1678              :  *
    1679              :  *     http://www.apache.org/licenses/LICENSE-2.0
    1680              :  *
    1681              :  * Unless required by applicable law or agreed to in writing, software
    1682              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
    1683              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1684              :  * See the License for the specific language governing permissions and
    1685              :  * limitations under the License.
    1686              :  */
    1687              : 
    1688              : /* Amalgamated: #include "common/mg_mem.h" */
    1689              : /* Amalgamated: #include "common/mg_str.h" */
    1690              : /* Amalgamated: #include "common/platform.h" */
    1691              : 
    1692              : #include <ctype.h>
    1693              : #include <stdlib.h>
    1694              : #include <string.h>
    1695              : 
    1696              : int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK;
    1697              : 
    1698              : struct mg_str mg_mk_str(const char *s) WEAK;
    1699            0 : struct mg_str mg_mk_str(const char *s) {
    1700            0 :   struct mg_str ret = {s, 0};
    1701            0 :   if (s != NULL) ret.len = strlen(s);
    1702            0 :   return ret;
    1703              : }
    1704              : 
    1705              : struct mg_str mg_mk_str_n(const char *s, size_t len) WEAK;
    1706            0 : struct mg_str mg_mk_str_n(const char *s, size_t len) {
    1707            0 :   struct mg_str ret = {s, len};
    1708            0 :   return ret;
    1709              : }
    1710              : 
    1711              : int mg_vcmp(const struct mg_str *str1, const char *str2) WEAK;
    1712            0 : int mg_vcmp(const struct mg_str *str1, const char *str2) {
    1713            0 :   size_t n2 = strlen(str2), n1 = str1->len;
    1714            0 :   int r = strncmp(str1->p, str2, (n1 < n2) ? n1 : n2);
    1715            0 :   if (r == 0) {
    1716            0 :     return n1 - n2;
    1717              :   }
    1718            0 :   return r;
    1719              : }
    1720              : 
    1721              : int mg_vcasecmp(const struct mg_str *str1, const char *str2) WEAK;
    1722            0 : int mg_vcasecmp(const struct mg_str *str1, const char *str2) {
    1723            0 :   size_t n2 = strlen(str2), n1 = str1->len;
    1724            0 :   int r = mg_ncasecmp(str1->p, str2, (n1 < n2) ? n1 : n2);
    1725            0 :   if (r == 0) {
    1726            0 :     return n1 - n2;
    1727              :   }
    1728            0 :   return r;
    1729              : }
    1730              : 
    1731            0 : static struct mg_str mg_strdup_common(const struct mg_str s,
    1732              :                                       int nul_terminate) {
    1733            0 :   struct mg_str r = {NULL, 0};
    1734            0 :   if (s.len > 0 && s.p != NULL) {
    1735            0 :     char *sc = (char *) MG_MALLOC(s.len + (nul_terminate ? 1 : 0));
    1736            0 :     if (sc != NULL) {
    1737            0 :       memcpy(sc, s.p, s.len);
    1738            0 :       if (nul_terminate) sc[s.len] = '\0';
    1739            0 :       r.p = sc;
    1740            0 :       r.len = s.len;
    1741              :     }
    1742              :   }
    1743            0 :   return r;
    1744              : }
    1745              : 
    1746              : struct mg_str mg_strdup(const struct mg_str s) WEAK;
    1747            0 : struct mg_str mg_strdup(const struct mg_str s) {
    1748            0 :   return mg_strdup_common(s, 0 /* NUL-terminate */);
    1749              : }
    1750              : 
    1751              : struct mg_str mg_strdup_nul(const struct mg_str s) WEAK;
    1752            0 : struct mg_str mg_strdup_nul(const struct mg_str s) {
    1753            0 :   return mg_strdup_common(s, 1 /* NUL-terminate */);
    1754              : }
    1755              : 
    1756              : const char *mg_strchr(const struct mg_str s, int c) WEAK;
    1757            0 : const char *mg_strchr(const struct mg_str s, int c) {
    1758              :   size_t i;
    1759            0 :   for (i = 0; i < s.len; i++) {
    1760            0 :     if (s.p[i] == c) return &s.p[i];
    1761              :   }
    1762            0 :   return NULL;
    1763              : }
    1764              : 
    1765              : int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK;
    1766            0 : int mg_strcmp(const struct mg_str str1, const struct mg_str str2) {
    1767            0 :   size_t i = 0;
    1768            0 :   while (i < str1.len && i < str2.len) {
    1769            0 :     if (str1.p[i] < str2.p[i]) return -1;
    1770            0 :     if (str1.p[i] > str2.p[i]) return 1;
    1771            0 :     i++;
    1772              :   }
    1773            0 :   if (i < str1.len) return 1;
    1774            0 :   if (i < str2.len) return -1;
    1775            0 :   return 0;
    1776              : }
    1777              : 
    1778              : int mg_strncmp(const struct mg_str, const struct mg_str, size_t n) WEAK;
    1779            0 : int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n) {
    1780            0 :   struct mg_str s1 = str1;
    1781            0 :   struct mg_str s2 = str2;
    1782              : 
    1783            0 :   if (s1.len > n) {
    1784            0 :     s1.len = n;
    1785              :   }
    1786            0 :   if (s2.len > n) {
    1787            0 :     s2.len = n;
    1788              :   }
    1789            0 :   return mg_strcmp(s1, s2);
    1790              : }
    1791              : 
    1792              : void mg_strfree(struct mg_str *s) WEAK;
    1793            0 : void mg_strfree(struct mg_str *s) {
    1794            0 :   char *sp = (char *) s->p;
    1795            0 :   s->p = NULL;
    1796            0 :   s->len = 0;
    1797            0 :   if (sp != NULL) free(sp);
    1798            0 : }
    1799              : 
    1800              : const char *mg_strstr(const struct mg_str haystack,
    1801              :                       const struct mg_str needle) WEAK;
    1802            0 : const char *mg_strstr(const struct mg_str haystack,
    1803              :                       const struct mg_str needle) {
    1804              :   size_t i;
    1805            0 :   if (needle.len > haystack.len) return NULL;
    1806            0 :   for (i = 0; i <= haystack.len - needle.len; i++) {
    1807            0 :     if (memcmp(haystack.p + i, needle.p, needle.len) == 0) {
    1808            0 :       return haystack.p + i;
    1809              :     }
    1810              :   }
    1811            0 :   return NULL;
    1812              : }
    1813              : 
    1814              : struct mg_str mg_strstrip(struct mg_str s) WEAK;
    1815            0 : struct mg_str mg_strstrip(struct mg_str s) {
    1816            0 :   while (s.len > 0 && isspace((int) *s.p)) {
    1817            0 :     s.p++;
    1818            0 :     s.len--;
    1819              :   }
    1820            0 :   while (s.len > 0 && isspace((int) *(s.p + s.len - 1))) {
    1821            0 :     s.len--;
    1822              :   }
    1823            0 :   return s;
    1824              : }
    1825              : 
    1826              : int mg_str_starts_with(struct mg_str s, struct mg_str prefix) WEAK;
    1827            0 : int mg_str_starts_with(struct mg_str s, struct mg_str prefix) {
    1828            0 :   const struct mg_str sp = MG_MK_STR_N(s.p, prefix.len);
    1829            0 :   if (s.len < prefix.len) return 0;
    1830            0 :   return (mg_strcmp(sp, prefix) == 0);
    1831              : }
    1832              : #ifdef MG_MODULE_LINES
    1833              : #line 1 "common/str_util.c"
    1834              : #endif
    1835              : /*
    1836              :  * Copyright (c) 2014-2018 Cesanta Software Limited
    1837              :  * All rights reserved
    1838              :  *
    1839              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
    1840              :  * you may not use this file except in compliance with the License.
    1841              :  * You may obtain a copy of the License at
    1842              :  *
    1843              :  *     http://www.apache.org/licenses/LICENSE-2.0
    1844              :  *
    1845              :  * Unless required by applicable law or agreed to in writing, software
    1846              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
    1847              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1848              :  * See the License for the specific language governing permissions and
    1849              :  * limitations under the License.
    1850              :  */
    1851              : 
    1852              : #ifndef EXCLUDE_COMMON
    1853              : 
    1854              : /* Amalgamated: #include "common/str_util.h" */
    1855              : /* Amalgamated: #include "common/mg_mem.h" */
    1856              : /* Amalgamated: #include "common/platform.h" */
    1857              : 
    1858              : #ifndef C_DISABLE_BUILTIN_SNPRINTF
    1859              : #define C_DISABLE_BUILTIN_SNPRINTF 0
    1860              : #endif
    1861              : 
    1862              : /* Amalgamated: #include "common/mg_mem.h" */
    1863              : 
    1864              : size_t c_strnlen(const char *s, size_t maxlen) WEAK;
    1865            0 : size_t c_strnlen(const char *s, size_t maxlen) {
    1866            0 :   size_t l = 0;
    1867            0 :   for (; l < maxlen && s[l] != '\0'; l++) {
    1868              :   }
    1869            0 :   return l;
    1870              : }
    1871              : 
    1872              : #define C_SNPRINTF_APPEND_CHAR(ch)       \
    1873              :   do {                                   \
    1874              :     if (i < (int) buf_size) buf[i] = ch; \
    1875              :     i++;                                 \
    1876              :   } while (0)
    1877              : 
    1878              : #define C_SNPRINTF_FLAG_ZERO 1
    1879              : 
    1880              : #if C_DISABLE_BUILTIN_SNPRINTF
    1881              : int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) WEAK;
    1882              : int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
    1883              :   return vsnprintf(buf, buf_size, fmt, ap);
    1884              : }
    1885              : #else
    1886            0 : static int c_itoa(char *buf, size_t buf_size, int64_t num, int base, int flags,
    1887              :                   int field_width) {
    1888              :   char tmp[40];
    1889            0 :   int i = 0, k = 0, neg = 0;
    1890              : 
    1891            0 :   if (num < 0) {
    1892            0 :     neg++;
    1893            0 :     num = -num;
    1894              :   }
    1895              : 
    1896              :   /* Print into temporary buffer - in reverse order */
    1897              :   do {
    1898            0 :     int rem = num % base;
    1899            0 :     if (rem < 10) {
    1900            0 :       tmp[k++] = '0' + rem;
    1901              :     } else {
    1902            0 :       tmp[k++] = 'a' + (rem - 10);
    1903              :     }
    1904            0 :     num /= base;
    1905            0 :   } while (num > 0);
    1906              : 
    1907              :   /* Zero padding */
    1908            0 :   if (flags && C_SNPRINTF_FLAG_ZERO) {
    1909            0 :     while (k < field_width && k < (int) sizeof(tmp) - 1) {
    1910            0 :       tmp[k++] = '0';
    1911              :     }
    1912              :   }
    1913              : 
    1914              :   /* And sign */
    1915            0 :   if (neg) {
    1916            0 :     tmp[k++] = '-';
    1917              :   }
    1918              : 
    1919              :   /* Now output */
    1920            0 :   while (--k >= 0) {
    1921            0 :     C_SNPRINTF_APPEND_CHAR(tmp[k]);
    1922              :   }
    1923              : 
    1924            0 :   return i;
    1925              : }
    1926              : 
    1927              : int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) WEAK;
    1928            0 : int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
    1929            0 :   int ch, i = 0, len_mod, flags, precision, field_width;
    1930              : 
    1931            0 :   while ((ch = *fmt++) != '\0') {
    1932            0 :     if (ch != '%') {
    1933            0 :       C_SNPRINTF_APPEND_CHAR(ch);
    1934              :     } else {
    1935              :       /*
    1936              :        * Conversion specification:
    1937              :        *   zero or more flags (one of: # 0 - <space> + ')
    1938              :        *   an optional minimum  field  width (digits)
    1939              :        *   an  optional precision (. followed by digits, or *)
    1940              :        *   an optional length modifier (one of: hh h l ll L q j z t)
    1941              :        *   conversion specifier (one of: d i o u x X e E f F g G a A c s p n)
    1942              :        */
    1943            0 :       flags = field_width = precision = len_mod = 0;
    1944              : 
    1945              :       /* Flags. only zero-pad flag is supported. */
    1946            0 :       if (*fmt == '0') {
    1947            0 :         flags |= C_SNPRINTF_FLAG_ZERO;
    1948              :       }
    1949              : 
    1950              :       /* Field width */
    1951            0 :       while (*fmt >= '0' && *fmt <= '9') {
    1952            0 :         field_width *= 10;
    1953            0 :         field_width += *fmt++ - '0';
    1954              :       }
    1955              :       /* Dynamic field width */
    1956            0 :       if (*fmt == '*') {
    1957            0 :         field_width = va_arg(ap, int);
    1958            0 :         fmt++;
    1959              :       }
    1960              : 
    1961              :       /* Precision */
    1962            0 :       if (*fmt == '.') {
    1963            0 :         fmt++;
    1964            0 :         if (*fmt == '*') {
    1965            0 :           precision = va_arg(ap, int);
    1966            0 :           fmt++;
    1967              :         } else {
    1968            0 :           while (*fmt >= '0' && *fmt <= '9') {
    1969            0 :             precision *= 10;
    1970            0 :             precision += *fmt++ - '0';
    1971              :           }
    1972              :         }
    1973              :       }
    1974              : 
    1975              :       /* Length modifier */
    1976            0 :       switch (*fmt) {
    1977            0 :         case 'h':
    1978              :         case 'l':
    1979              :         case 'L':
    1980              :         case 'I':
    1981              :         case 'q':
    1982              :         case 'j':
    1983              :         case 'z':
    1984              :         case 't':
    1985            0 :           len_mod = *fmt++;
    1986            0 :           if (*fmt == 'h') {
    1987            0 :             len_mod = 'H';
    1988            0 :             fmt++;
    1989              :           }
    1990            0 :           if (*fmt == 'l') {
    1991            0 :             len_mod = 'q';
    1992            0 :             fmt++;
    1993              :           }
    1994            0 :           break;
    1995              :       }
    1996              : 
    1997            0 :       ch = *fmt++;
    1998            0 :       if (ch == 's') {
    1999            0 :         const char *s = va_arg(ap, const char *); /* Always fetch parameter */
    2000              :         int j;
    2001            0 :         int pad = field_width - (precision >= 0 ? c_strnlen(s, precision) : 0);
    2002            0 :         for (j = 0; j < pad; j++) {
    2003            0 :           C_SNPRINTF_APPEND_CHAR(' ');
    2004              :         }
    2005              : 
    2006              :         /* `s` may be NULL in case of %.*s */
    2007            0 :         if (s != NULL) {
    2008              :           /* Ignore negative and 0 precisions */
    2009            0 :           for (j = 0; (precision <= 0 || j < precision) && s[j] != '\0'; j++) {
    2010            0 :             C_SNPRINTF_APPEND_CHAR(s[j]);
    2011              :           }
    2012              :         }
    2013            0 :       } else if (ch == 'c') {
    2014            0 :         ch = va_arg(ap, int); /* Always fetch parameter */
    2015            0 :         C_SNPRINTF_APPEND_CHAR(ch);
    2016            0 :       } else if (ch == 'd' && len_mod == 0) {
    2017            0 :         i += c_itoa(buf + i, buf_size - i, va_arg(ap, int), 10, flags,
    2018              :                     field_width);
    2019            0 :       } else if (ch == 'd' && len_mod == 'l') {
    2020            0 :         i += c_itoa(buf + i, buf_size - i, va_arg(ap, long), 10, flags,
    2021              :                     field_width);
    2022              : #ifdef SSIZE_MAX
    2023            0 :       } else if (ch == 'd' && len_mod == 'z') {
    2024            0 :         i += c_itoa(buf + i, buf_size - i, va_arg(ap, ssize_t), 10, flags,
    2025              :                     field_width);
    2026              : #endif
    2027            0 :       } else if (ch == 'd' && len_mod == 'q') {
    2028            0 :         i += c_itoa(buf + i, buf_size - i, va_arg(ap, int64_t), 10, flags,
    2029              :                     field_width);
    2030            0 :       } else if ((ch == 'x' || ch == 'u') && len_mod == 0) {
    2031            0 :         i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned),
    2032              :                     ch == 'x' ? 16 : 10, flags, field_width);
    2033            0 :       } else if ((ch == 'x' || ch == 'u') && len_mod == 'l') {
    2034            0 :         i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned long),
    2035              :                     ch == 'x' ? 16 : 10, flags, field_width);
    2036            0 :       } else if ((ch == 'x' || ch == 'u') && len_mod == 'z') {
    2037            0 :         i += c_itoa(buf + i, buf_size - i, va_arg(ap, size_t),
    2038              :                     ch == 'x' ? 16 : 10, flags, field_width);
    2039            0 :       } else if (ch == 'p') {
    2040            0 :         unsigned long num = (unsigned long) (uintptr_t) va_arg(ap, void *);
    2041            0 :         C_SNPRINTF_APPEND_CHAR('0');
    2042            0 :         C_SNPRINTF_APPEND_CHAR('x');
    2043            0 :         i += c_itoa(buf + i, buf_size - i, num, 16, flags, 0);
    2044              :       } else {
    2045              : #ifndef NO_LIBC
    2046              :         /*
    2047              :          * TODO(lsm): abort is not nice in a library, remove it
    2048              :          * Also, ESP8266 SDK doesn't have it
    2049              :          */
    2050            0 :         abort();
    2051              : #endif
    2052              :       }
    2053              :     }
    2054              :   }
    2055              : 
    2056              :   /* Zero-terminate the result */
    2057            0 :   if (buf_size > 0) {
    2058            0 :     buf[i < (int) buf_size ? i : (int) buf_size - 1] = '\0';
    2059              :   }
    2060              : 
    2061            0 :   return i;
    2062              : }
    2063              : #endif
    2064              : 
    2065              : int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) WEAK;
    2066            0 : int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) {
    2067              :   int result;
    2068              :   va_list ap;
    2069            0 :   va_start(ap, fmt);
    2070            0 :   result = c_vsnprintf(buf, buf_size, fmt, ap);
    2071            0 :   va_end(ap);
    2072            0 :   return result;
    2073              : }
    2074              : 
    2075              : #ifdef _WIN32
    2076              : int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
    2077              :   int ret;
    2078              :   char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p;
    2079              : 
    2080              :   strncpy(buf, path, sizeof(buf));
    2081              :   buf[sizeof(buf) - 1] = '\0';
    2082              : 
    2083              :   /* Trim trailing slashes. Leave backslash for paths like "X:\" */
    2084              :   p = buf + strlen(buf) - 1;
    2085              :   while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
    2086              : 
    2087              :   memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
    2088              :   ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
    2089              : 
    2090              :   /*
    2091              :    * Convert back to Unicode. If doubly-converted string does not match the
    2092              :    * original, something is fishy, reject.
    2093              :    */
    2094              :   WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
    2095              :                       NULL, NULL);
    2096              :   if (strcmp(buf, buf2) != 0) {
    2097              :     wbuf[0] = L'\0';
    2098              :     ret = 0;
    2099              :   }
    2100              : 
    2101              :   return ret;
    2102              : }
    2103              : #endif /* _WIN32 */
    2104              : 
    2105              : /* The simplest O(mn) algorithm. Better implementation are GPLed */
    2106              : const char *c_strnstr(const char *s, const char *find, size_t slen) WEAK;
    2107            0 : const char *c_strnstr(const char *s, const char *find, size_t slen) {
    2108            0 :   size_t find_length = strlen(find);
    2109              :   size_t i;
    2110              : 
    2111            0 :   for (i = 0; i < slen; i++) {
    2112            0 :     if (i + find_length > slen) {
    2113            0 :       return NULL;
    2114              :     }
    2115              : 
    2116            0 :     if (strncmp(&s[i], find, find_length) == 0) {
    2117            0 :       return &s[i];
    2118              :     }
    2119              :   }
    2120              : 
    2121            0 :   return NULL;
    2122              : }
    2123              : 
    2124              : #if CS_ENABLE_STRDUP
    2125              : char *strdup(const char *src) WEAK;
    2126              : char *strdup(const char *src) {
    2127              :   size_t len = strlen(src) + 1;
    2128              :   char *ret = MG_MALLOC(len);
    2129              :   if (ret != NULL) {
    2130              :     strcpy(ret, src);
    2131              :   }
    2132              :   return ret;
    2133              : }
    2134              : #endif
    2135              : 
    2136              : void cs_to_hex(char *to, const unsigned char *p, size_t len) WEAK;
    2137            0 : void cs_to_hex(char *to, const unsigned char *p, size_t len) {
    2138              :   static const char *hex = "0123456789abcdef";
    2139              : 
    2140            0 :   for (; len--; p++) {
    2141            0 :     *to++ = hex[p[0] >> 4];
    2142            0 :     *to++ = hex[p[0] & 0x0f];
    2143              :   }
    2144            0 :   *to = '\0';
    2145            0 : }
    2146              : 
    2147            0 : static int fourbit(int ch) {
    2148            0 :   if (ch >= '0' && ch <= '9') {
    2149            0 :     return ch - '0';
    2150            0 :   } else if (ch >= 'a' && ch <= 'f') {
    2151            0 :     return ch - 'a' + 10;
    2152            0 :   } else if (ch >= 'A' && ch <= 'F') {
    2153            0 :     return ch - 'A' + 10;
    2154              :   }
    2155            0 :   return 0;
    2156              : }
    2157              : 
    2158              : void cs_from_hex(char *to, const char *p, size_t len) WEAK;
    2159            0 : void cs_from_hex(char *to, const char *p, size_t len) {
    2160              :   size_t i;
    2161              : 
    2162            0 :   for (i = 0; i < len; i += 2) {
    2163            0 :     *to++ = (fourbit(p[i]) << 4) + fourbit(p[i + 1]);
    2164              :   }
    2165            0 :   *to = '\0';
    2166            0 : }
    2167              : 
    2168              : #if CS_ENABLE_TO64
    2169              : int64_t cs_to64(const char *s) WEAK;
    2170              : int64_t cs_to64(const char *s) {
    2171              :   int64_t result = 0;
    2172              :   int64_t neg = 1;
    2173              :   while (*s && isspace((unsigned char) *s)) s++;
    2174              :   if (*s == '-') {
    2175              :     neg = -1;
    2176              :     s++;
    2177              :   }
    2178              :   while (isdigit((unsigned char) *s)) {
    2179              :     result *= 10;
    2180              :     result += (*s - '0');
    2181              :     s++;
    2182              :   }
    2183              :   return result * neg;
    2184              : }
    2185              : #endif
    2186              : 
    2187            0 : static int str_util_lowercase(const char *s) {
    2188            0 :   return tolower(*(const unsigned char *) s);
    2189              : }
    2190              : 
    2191              : int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK;
    2192            0 : int mg_ncasecmp(const char *s1, const char *s2, size_t len) {
    2193            0 :   int diff = 0;
    2194              : 
    2195            0 :   if (len > 0) do {
    2196            0 :       diff = str_util_lowercase(s1++) - str_util_lowercase(s2++);
    2197            0 :     } while (diff == 0 && s1[-1] != '\0' && --len > 0);
    2198              : 
    2199            0 :   return diff;
    2200              : }
    2201              : 
    2202              : int mg_casecmp(const char *s1, const char *s2) WEAK;
    2203            0 : int mg_casecmp(const char *s1, const char *s2) {
    2204            0 :   return mg_ncasecmp(s1, s2, (size_t) ~0);
    2205              : }
    2206              : 
    2207              : int mg_asprintf(char **buf, size_t size, const char *fmt, ...) WEAK;
    2208            0 : int mg_asprintf(char **buf, size_t size, const char *fmt, ...) {
    2209              :   int ret;
    2210              :   va_list ap;
    2211            0 :   va_start(ap, fmt);
    2212            0 :   ret = mg_avprintf(buf, size, fmt, ap);
    2213            0 :   va_end(ap);
    2214            0 :   return ret;
    2215              : }
    2216              : 
    2217              : int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) WEAK;
    2218            0 : int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
    2219              :   va_list ap_copy;
    2220              :   int len;
    2221              : 
    2222            0 :   va_copy(ap_copy, ap);
    2223            0 :   len = vsnprintf(*buf, size, fmt, ap_copy);
    2224            0 :   va_end(ap_copy);
    2225              : 
    2226            0 :   if (len < 0) {
    2227              :     /* eCos and Windows are not standard-compliant and return -1 when
    2228              :      * the buffer is too small. Keep allocating larger buffers until we
    2229              :      * succeed or out of memory. */
    2230              :     *buf = NULL; /* LCOV_EXCL_START */
    2231              :     while (len < 0) {
    2232              :       MG_FREE(*buf);
    2233              :       if (size == 0) {
    2234              :         size = 5;
    2235              :       }
    2236              :       size *= 2;
    2237              :       if ((*buf = (char *) MG_MALLOC(size)) == NULL) {
    2238              :         len = -1;
    2239              :         break;
    2240              :       }
    2241              :       va_copy(ap_copy, ap);
    2242              :       len = vsnprintf(*buf, size - 1, fmt, ap_copy);
    2243              :       va_end(ap_copy);
    2244              :     }
    2245              : 
    2246              :     /*
    2247              :      * Microsoft version of vsnprintf() is not always null-terminated, so put
    2248              :      * the terminator manually
    2249              :      */
    2250              :     (*buf)[len] = 0;
    2251              :     /* LCOV_EXCL_STOP */
    2252            0 :   } else if (len >= (int) size) {
    2253              :     /* Standard-compliant code path. Allocate a buffer that is large enough. */
    2254            0 :     if ((*buf = (char *) MG_MALLOC(len + 1)) == NULL) {
    2255              :       len = -1; /* LCOV_EXCL_LINE */
    2256              :     } else {    /* LCOV_EXCL_LINE */
    2257            0 :       va_copy(ap_copy, ap);
    2258            0 :       len = vsnprintf(*buf, len + 1, fmt, ap_copy);
    2259            0 :       va_end(ap_copy);
    2260              :     }
    2261              :   }
    2262              : 
    2263            0 :   return len;
    2264              : }
    2265              : 
    2266              : const char *mg_next_comma_list_entry(const char *, struct mg_str *,
    2267              :                                      struct mg_str *) WEAK;
    2268            0 : const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
    2269              :                                      struct mg_str *eq_val) {
    2270            0 :   struct mg_str ret = mg_next_comma_list_entry_n(mg_mk_str(list), val, eq_val);
    2271            0 :   return ret.p;
    2272              : }
    2273              : 
    2274              : struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
    2275              :                                          struct mg_str *eq_val) WEAK;
    2276            0 : struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
    2277              :                                          struct mg_str *eq_val) {
    2278            0 :   if (list.len == 0) {
    2279              :     /* End of the list */
    2280            0 :     list = mg_mk_str(NULL);
    2281              :   } else {
    2282            0 :     const char *chr = NULL;
    2283            0 :     *val = list;
    2284              : 
    2285            0 :     if ((chr = mg_strchr(*val, ',')) != NULL) {
    2286              :       /* Comma found. Store length and shift the list ptr */
    2287            0 :       val->len = chr - val->p;
    2288            0 :       chr++;
    2289            0 :       list.len -= (chr - list.p);
    2290            0 :       list.p = chr;
    2291              :     } else {
    2292              :       /* This value is the last one */
    2293            0 :       list = mg_mk_str_n(list.p + list.len, 0);
    2294              :     }
    2295              : 
    2296            0 :     if (eq_val != NULL) {
    2297              :       /* Value has form "x=y", adjust pointers and lengths */
    2298              :       /* so that val points to "x", and eq_val points to "y". */
    2299            0 :       eq_val->len = 0;
    2300            0 :       eq_val->p = (const char *) memchr(val->p, '=', val->len);
    2301            0 :       if (eq_val->p != NULL) {
    2302            0 :         eq_val->p++; /* Skip over '=' character */
    2303            0 :         eq_val->len = val->p + val->len - eq_val->p;
    2304            0 :         val->len = (eq_val->p - val->p) - 1;
    2305              :       }
    2306              :     }
    2307              :   }
    2308              : 
    2309            0 :   return list;
    2310              : }
    2311              : 
    2312              : size_t mg_match_prefix_n(const struct mg_str, const struct mg_str) WEAK;
    2313            0 : size_t mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str) {
    2314              :   const char *or_str;
    2315            0 :   size_t res = 0, len = 0, i = 0, j = 0;
    2316              : 
    2317            0 :   if ((or_str = (const char *) memchr(pattern.p, '|', pattern.len)) != NULL ||
    2318            0 :       (or_str = (const char *) memchr(pattern.p, ',', pattern.len)) != NULL) {
    2319            0 :     struct mg_str pstr = {pattern.p, (size_t)(or_str - pattern.p)};
    2320            0 :     res = mg_match_prefix_n(pstr, str);
    2321            0 :     if (res > 0) return res;
    2322            0 :     pstr.p = or_str + 1;
    2323            0 :     pstr.len = (pattern.p + pattern.len) - (or_str + 1);
    2324            0 :     return mg_match_prefix_n(pstr, str);
    2325              :   }
    2326              : 
    2327            0 :   for (; i < pattern.len && j < str.len; i++, j++) {
    2328            0 :     if (pattern.p[i] == '?') {
    2329            0 :       continue;
    2330            0 :     } else if (pattern.p[i] == '*') {
    2331            0 :       i++;
    2332            0 :       if (i < pattern.len && pattern.p[i] == '*') {
    2333            0 :         i++;
    2334            0 :         len = str.len - j;
    2335              :       } else {
    2336            0 :         len = 0;
    2337            0 :         while (j + len < str.len && str.p[j + len] != '/') len++;
    2338              :       }
    2339            0 :       if (i == pattern.len || (pattern.p[i] == '$' && i == pattern.len - 1))
    2340            0 :         return j + len;
    2341              :       do {
    2342            0 :         const struct mg_str pstr = {pattern.p + i, pattern.len - i};
    2343            0 :         const struct mg_str sstr = {str.p + j + len, str.len - j - len};
    2344            0 :         res = mg_match_prefix_n(pstr, sstr);
    2345            0 :       } while (res == 0 && len != 0 && len-- > 0);
    2346            0 :       return res == 0 ? 0 : j + res + len;
    2347            0 :     } else if (str_util_lowercase(&pattern.p[i]) !=
    2348            0 :                str_util_lowercase(&str.p[j])) {
    2349            0 :       break;
    2350              :     }
    2351              :   }
    2352            0 :   if (i < pattern.len && pattern.p[i] == '$') {
    2353            0 :     return j == str.len ? str.len : 0;
    2354              :   }
    2355            0 :   return i == pattern.len ? j : 0;
    2356              : }
    2357              : 
    2358              : size_t mg_match_prefix(const char *, int, const char *) WEAK;
    2359            0 : size_t mg_match_prefix(const char *pattern, int pattern_len, const char *str) {
    2360            0 :   const struct mg_str pstr = {pattern, (size_t) pattern_len};
    2361            0 :   struct mg_str s = {str, 0};
    2362            0 :   if (str != NULL) s.len = strlen(str);
    2363            0 :   return mg_match_prefix_n(pstr, s);
    2364              : }
    2365              : 
    2366              : #endif /* EXCLUDE_COMMON */
    2367              : #ifdef MG_MODULE_LINES
    2368              : #line 1 "mongoose/src/mg_net.c"
    2369              : #endif
    2370              : /*
    2371              :  * Copyright (c) 2014 Cesanta Software Limited
    2372              :  * All rights reserved
    2373              :  *
    2374              :  * This software is dual-licensed: you can redistribute it and/or modify
    2375              :  * it under the terms of the GNU General Public License version 2 as
    2376              :  * published by the Free Software Foundation. For the terms of this
    2377              :  * license, see <http://www.gnu.org/licenses/>.
    2378              :  *
    2379              :  * You are free to use this software under the terms of the GNU General
    2380              :  * Public License, but WITHOUT ANY WARRANTY; without even the implied
    2381              :  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    2382              :  * See the GNU General Public License for more details.
    2383              :  *
    2384              :  * Alternatively, you can license this software under a commercial
    2385              :  * license, as set out in <https://www.cesanta.com/license>.
    2386              :  */
    2387              : 
    2388              : /* Amalgamated: #include "common/cs_time.h" */
    2389              : /* Amalgamated: #include "mg_dns.h" */
    2390              : /* Amalgamated: #include "mg_internal.h" */
    2391              : /* Amalgamated: #include "mg_resolv.h" */
    2392              : /* Amalgamated: #include "mg_util.h" */
    2393              : 
    2394              : #define MG_MAX_HOST_LEN 200
    2395              : 
    2396              : #ifndef MG_TCP_IO_SIZE
    2397              : //#define MG_TCP_IO_SIZE 1460
    2398              : #define MG_TCP_IO_SIZE 1460000
    2399              : #endif
    2400              : #ifndef MG_UDP_IO_SIZE
    2401              : #define MG_UDP_IO_SIZE 1460
    2402              : #endif
    2403              : 
    2404              : #define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src) \
    2405              :   memcpy(dst, src, sizeof(*dst));
    2406              : 
    2407              : /* Which flags can be pre-set by the user at connection creation time. */
    2408              : #define _MG_ALLOWED_CONNECT_FLAGS_MASK                                   \
    2409              :   (MG_F_USER_1 | MG_F_USER_2 | MG_F_USER_3 | MG_F_USER_4 | MG_F_USER_5 | \
    2410              :    MG_F_USER_6 | MG_F_WEBSOCKET_NO_DEFRAG | MG_F_ENABLE_BROADCAST)
    2411              : /* Which flags should be modifiable by user's callbacks. */
    2412              : #define _MG_CALLBACK_MODIFIABLE_FLAGS_MASK                               \
    2413              :   (MG_F_USER_1 | MG_F_USER_2 | MG_F_USER_3 | MG_F_USER_4 | MG_F_USER_5 | \
    2414              :    MG_F_USER_6 | MG_F_WEBSOCKET_NO_DEFRAG | MG_F_SEND_AND_CLOSE |        \
    2415              :    MG_F_CLOSE_IMMEDIATELY | MG_F_IS_WEBSOCKET | MG_F_DELETE_CHUNK)
    2416              : 
    2417              : #ifndef intptr_t
    2418              : #define intptr_t long
    2419              : #endif
    2420              : 
    2421            0 : MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c) {
    2422            0 :   DBG(("%p %p", mgr, c));
    2423            0 :   c->mgr = mgr;
    2424            0 :   c->next = mgr->active_connections;
    2425            0 :   mgr->active_connections = c;
    2426            0 :   c->prev = NULL;
    2427            0 :   if (c->next != NULL) c->next->prev = c;
    2428            0 :   if (c->sock != INVALID_SOCKET) {
    2429            0 :     c->iface->vtable->add_conn(c);
    2430              :   }
    2431            0 : }
    2432              : 
    2433            0 : MG_INTERNAL void mg_remove_conn(struct mg_connection *conn) {
    2434            0 :   if (conn->prev == NULL) conn->mgr->active_connections = conn->next;
    2435            0 :   if (conn->prev) conn->prev->next = conn->next;
    2436            0 :   if (conn->next) conn->next->prev = conn->prev;
    2437            0 :   conn->prev = conn->next = NULL;
    2438            0 :   conn->iface->vtable->remove_conn(conn);
    2439            0 : }
    2440              : 
    2441            0 : MG_INTERNAL void mg_call(struct mg_connection *nc,
    2442              :                          mg_event_handler_t ev_handler, void *user_data, int ev,
    2443              :                          void *ev_data) {
    2444            0 :   if (ev_handler == NULL) {
    2445              :     /*
    2446              :      * If protocol handler is specified, call it. Otherwise, call user-specified
    2447              :      * event handler.
    2448              :      */
    2449            0 :     ev_handler = nc->proto_handler ? nc->proto_handler : nc->handler;
    2450              :   }
    2451            0 :   if (ev != MG_EV_POLL) {
    2452            0 :     DBG(("%p %s ev=%d ev_data=%p flags=0x%lx rmbl=%d smbl=%d", nc,
    2453              :          ev_handler == nc->handler ? "user" : "proto", ev, ev_data, nc->flags,
    2454              :          (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
    2455              :   }
    2456              : 
    2457              : #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
    2458            0 :   if (nc->mgr->hexdump_file != NULL && ev != MG_EV_POLL && ev != MG_EV_RECV &&
    2459              :       ev != MG_EV_SEND /* handled separately */) {
    2460            0 :     mg_hexdump_connection(nc, nc->mgr->hexdump_file, NULL, 0, ev);
    2461              :   }
    2462              : #endif
    2463            0 :   if (ev_handler != NULL) {
    2464            0 :     unsigned long flags_before = nc->flags;
    2465            0 :     ev_handler(nc, ev, ev_data MG_UD_ARG(user_data));
    2466              :     /* Prevent user handler from fiddling with system flags. */
    2467            0 :     if (ev_handler == nc->handler && nc->flags != flags_before) {
    2468            0 :       nc->flags = (flags_before & ~_MG_CALLBACK_MODIFIABLE_FLAGS_MASK) |
    2469            0 :                   (nc->flags & _MG_CALLBACK_MODIFIABLE_FLAGS_MASK);
    2470              :     }
    2471              :   }
    2472            0 :   if (ev != MG_EV_POLL) nc->mgr->num_calls++;
    2473            0 :   if (ev != MG_EV_POLL) {
    2474            0 :     DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc,
    2475              :          ev_handler == nc->handler ? "user" : "proto", nc->flags,
    2476              :          (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
    2477              :   }
    2478              : #if !MG_ENABLE_CALLBACK_USERDATA
    2479              :   (void) user_data;
    2480              : #endif
    2481            0 : }
    2482              : 
    2483            0 : MG_INTERNAL void mg_timer(struct mg_connection *c, double now) {
    2484            0 :   if (c->ev_timer_time > 0 && now >= c->ev_timer_time) {
    2485            0 :     double old_value = c->ev_timer_time;
    2486            0 :     c->ev_timer_time = 0;
    2487            0 :     mg_call(c, NULL, c->user_data, MG_EV_TIMER, &old_value);
    2488              :   }
    2489            0 : }
    2490              : 
    2491            0 : MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) {
    2492              :   size_t avail;
    2493            0 :   if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0;
    2494            0 :   avail = conn->recv_mbuf_limit - conn->recv_mbuf.len;
    2495            0 :   return avail > max ? max : avail;
    2496              : }
    2497              : 
    2498              : static int mg_do_recv(struct mg_connection *nc);
    2499              : 
    2500            0 : int mg_if_poll(struct mg_connection *nc, double now) {
    2501            0 :   if (nc->flags & MG_F_CLOSE_IMMEDIATELY) {
    2502            0 :     mg_close_conn(nc);
    2503            0 :     return 0;
    2504            0 :   } else if (nc->flags & MG_F_SEND_AND_CLOSE) {
    2505            0 :     if (nc->send_mbuf.len == 0) {
    2506            0 :       nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    2507            0 :       mg_close_conn(nc);
    2508            0 :       return 0;
    2509              :     }
    2510            0 :   } else if (nc->flags & MG_F_RECV_AND_CLOSE) {
    2511            0 :     mg_close_conn(nc);
    2512            0 :     return 0;
    2513              :   }
    2514              : #if MG_ENABLE_SSL
    2515              :   if ((nc->flags & (MG_F_SSL | MG_F_LISTENING | MG_F_CONNECTING)) == MG_F_SSL) {
    2516              :     /* SSL library may have data to be delivered to the app in its buffers,
    2517              :      * drain them. */
    2518              :     int recved = 0;
    2519              :     do {
    2520              :       if (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE)) break;
    2521              :       if (recv_avail_size(nc, MG_TCP_IO_SIZE) <= 0) break;
    2522              :       recved = mg_do_recv(nc);
    2523              :     } while (recved > 0);
    2524              :   }
    2525              : #endif /* MG_ENABLE_SSL */
    2526            0 :   mg_timer(nc, now);
    2527              :   {
    2528            0 :     time_t now_t = (time_t) now;
    2529            0 :     mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now_t);
    2530              :   }
    2531            0 :   return 1;
    2532              : }
    2533              : 
    2534            0 : void mg_destroy_conn(struct mg_connection *conn, int destroy_if) {
    2535            0 :   if (conn->sock != INVALID_SOCKET) { /* Don't print timer-only conns */
    2536            0 :     LOG(LL_DEBUG, ("%p 0x%lx %d", conn, conn->flags, destroy_if));
    2537              :   }
    2538            0 :   if (destroy_if) conn->iface->vtable->destroy_conn(conn);
    2539            0 :   if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) {
    2540            0 :     conn->proto_data_destructor(conn->proto_data);
    2541              :   }
    2542              : #if MG_ENABLE_SSL
    2543              :   mg_ssl_if_conn_free(conn);
    2544              : #endif
    2545            0 :   mbuf_free(&conn->recv_mbuf);
    2546            0 :   mbuf_free(&conn->send_mbuf);
    2547              : 
    2548            0 :   memset(conn, 0, sizeof(*conn));
    2549            0 :   MG_FREE(conn);
    2550            0 : }
    2551              : 
    2552            0 : void mg_close_conn(struct mg_connection *conn) {
    2553              :   /* See if there's any remaining data to deliver. Skip if user completely
    2554              :    * throttled the connection there will be no progress anyway. */
    2555            0 :   if (conn->sock != INVALID_SOCKET && mg_do_recv(conn) == -2) {
    2556              :     /* Receive is throttled, wait. */
    2557            0 :     conn->flags |= MG_F_RECV_AND_CLOSE;
    2558            0 :     return;
    2559              :   }
    2560              : #if MG_ENABLE_SSL
    2561              :   if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) {
    2562              :     mg_ssl_if_conn_close_notify(conn);
    2563              :   }
    2564              : #endif
    2565              :   /*
    2566              :    * Clearly mark the connection as going away (if not already).
    2567              :    * Some net_if impls (LwIP) need this for cleanly handling half-dead conns.
    2568              :    */
    2569            0 :   conn->flags |= MG_F_CLOSE_IMMEDIATELY;
    2570            0 :   mg_remove_conn(conn);
    2571            0 :   conn->iface->vtable->destroy_conn(conn);
    2572            0 :   mg_call(conn, NULL, conn->user_data, MG_EV_CLOSE, NULL);
    2573            0 :   mg_destroy_conn(conn, 0 /* destroy_if */);
    2574              : }
    2575              : 
    2576            0 : void mg_mgr_init(struct mg_mgr *m, void *user_data) {
    2577              :   struct mg_mgr_init_opts opts;
    2578            0 :   memset(&opts, 0, sizeof(opts));
    2579            0 :   mg_mgr_init_opt(m, user_data, opts);
    2580            0 : }
    2581              : 
    2582            0 : void mg_mgr_init_opt(struct mg_mgr *m, void *user_data,
    2583              :                      struct mg_mgr_init_opts opts) {
    2584            0 :   memset(m, 0, sizeof(*m));
    2585              : #if MG_ENABLE_BROADCAST
    2586            0 :   m->ctl[0] = m->ctl[1] = INVALID_SOCKET;
    2587              : #endif
    2588            0 :   m->user_data = user_data;
    2589              : 
    2590              : #ifdef _WIN32
    2591              :   {
    2592              :     WSADATA data;
    2593              :     WSAStartup(MAKEWORD(2, 2), &data);
    2594              :   }
    2595              : #elif defined(__unix__)
    2596              :   /* Ignore SIGPIPE signal, so if client cancels the request, it
    2597              :    * won't kill the whole process. */
    2598            0 :   signal(SIGPIPE, SIG_IGN);
    2599              : #endif
    2600              : 
    2601              :   {
    2602              :     int i;
    2603            0 :     if (opts.num_ifaces == 0) {
    2604            0 :       opts.num_ifaces = mg_num_ifaces;
    2605            0 :       opts.ifaces = mg_ifaces;
    2606              :     }
    2607            0 :     if (opts.main_iface != NULL) {
    2608            0 :       opts.ifaces[MG_MAIN_IFACE] = opts.main_iface;
    2609              :     }
    2610            0 :     m->num_ifaces = opts.num_ifaces;
    2611            0 :     m->ifaces =
    2612            0 :         (struct mg_iface **) MG_MALLOC(sizeof(*m->ifaces) * opts.num_ifaces);
    2613            0 :     for (i = 0; i < opts.num_ifaces; i++) {
    2614            0 :       m->ifaces[i] = mg_if_create_iface(opts.ifaces[i], m);
    2615            0 :       m->ifaces[i]->vtable->init(m->ifaces[i]);
    2616              :     }
    2617              :   }
    2618            0 :   if (opts.nameserver != NULL) {
    2619            0 :     m->nameserver = strdup(opts.nameserver);
    2620              :   }
    2621            0 :   DBG(("=================================="));
    2622            0 :   DBG(("init mgr=%p", m));
    2623              : #if MG_ENABLE_SSL
    2624              :   {
    2625              :     static int init_done;
    2626              :     if (!init_done) {
    2627              :       mg_ssl_if_init();
    2628              :       init_done++;
    2629              :     }
    2630              :   }
    2631              : #endif
    2632            0 : }
    2633              : 
    2634            0 : void mg_mgr_free(struct mg_mgr *m) {
    2635              :   struct mg_connection *conn, *tmp_conn;
    2636              : 
    2637            0 :   DBG(("%p", m));
    2638            0 :   if (m == NULL) return;
    2639              :   /* Do one last poll, see https://github.com/cesanta/mongoose/issues/286 */
    2640            0 :   mg_mgr_poll(m, 0);
    2641              : 
    2642              : #if MG_ENABLE_BROADCAST
    2643            0 :   if (m->ctl[0] != INVALID_SOCKET) closesocket(m->ctl[0]);
    2644            0 :   if (m->ctl[1] != INVALID_SOCKET) closesocket(m->ctl[1]);
    2645            0 :   m->ctl[0] = m->ctl[1] = INVALID_SOCKET;
    2646              : #endif
    2647              : 
    2648            0 :   for (conn = m->active_connections; conn != NULL; conn = tmp_conn) {
    2649            0 :     tmp_conn = conn->next;
    2650            0 :     conn->flags |= MG_F_CLOSE_IMMEDIATELY;
    2651            0 :     mg_close_conn(conn);
    2652              :   }
    2653              : 
    2654              :   {
    2655              :     int i;
    2656            0 :     for (i = 0; i < m->num_ifaces; i++) {
    2657            0 :       m->ifaces[i]->vtable->free(m->ifaces[i]);
    2658            0 :       MG_FREE(m->ifaces[i]);
    2659              :     }
    2660            0 :     MG_FREE(m->ifaces);
    2661              :   }
    2662              : 
    2663            0 :   MG_FREE((char *) m->nameserver);
    2664              : }
    2665              : 
    2666            0 : int mg_mgr_poll(struct mg_mgr *m, int timeout_ms) {
    2667            0 :   int i, num_calls_before = m->num_calls;
    2668              : 
    2669            0 :   for (i = 0; i < m->num_ifaces; i++) {
    2670            0 :     m->ifaces[i]->vtable->poll(m->ifaces[i], timeout_ms);
    2671              :   }
    2672              : 
    2673            0 :   return (m->num_calls - num_calls_before);
    2674              : }
    2675              : 
    2676            0 : int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap) {
    2677            0 :   char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
    2678              :   int len;
    2679              : 
    2680            0 :   if ((len = mg_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
    2681            0 :     mg_send(nc, buf, len);
    2682              :   }
    2683            0 :   if (buf != mem && buf != NULL) {
    2684              :     MG_FREE(buf); /* LCOV_EXCL_LINE */
    2685              :   }               /* LCOV_EXCL_LINE */
    2686              : 
    2687            0 :   return len;
    2688              : }
    2689              : 
    2690            0 : int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
    2691              :   int len;
    2692              :   va_list ap;
    2693            0 :   va_start(ap, fmt);
    2694            0 :   len = mg_vprintf(conn, fmt, ap);
    2695            0 :   va_end(ap);
    2696            0 :   return len;
    2697              : }
    2698              : 
    2699              : #if MG_ENABLE_SYNC_RESOLVER
    2700              : /* TODO(lsm): use non-blocking resolver */
    2701              : static int mg_resolve2(const char *host, struct in_addr *ina) {
    2702              : #if MG_ENABLE_GETADDRINFO
    2703              :   int rv = 0;
    2704              :   struct addrinfo hints, *servinfo, *p;
    2705              :   struct sockaddr_in *h = NULL;
    2706              :   memset(&hints, 0, sizeof hints);
    2707              :   hints.ai_family = AF_INET;
    2708              :   hints.ai_socktype = SOCK_STREAM;
    2709              :   if ((rv = getaddrinfo(host, NULL, NULL, &servinfo)) != 0) {
    2710              :     DBG(("getaddrinfo(%s) failed: %s", host, strerror(mg_get_errno())));
    2711              :     return 0;
    2712              :   }
    2713              :   for (p = servinfo; p != NULL; p = p->ai_next) {
    2714              :     memcpy(&h, &p->ai_addr, sizeof(h));
    2715              :     memcpy(ina, &h->sin_addr, sizeof(*ina));
    2716              :   }
    2717              :   freeaddrinfo(servinfo);
    2718              :   return 1;
    2719              : #else
    2720              :   struct hostent *he;
    2721              :   if ((he = gethostbyname(host)) == NULL) {
    2722              :     DBG(("gethostbyname(%s) failed: %s", host, strerror(mg_get_errno())));
    2723              :   } else {
    2724              :     memcpy(ina, he->h_addr_list[0], sizeof(*ina));
    2725              :     return 1;
    2726              :   }
    2727              :   return 0;
    2728              : #endif /* MG_ENABLE_GETADDRINFO */
    2729              : }
    2730              : 
    2731              : int mg_resolve(const char *host, char *buf, size_t n) {
    2732              :   struct in_addr ad;
    2733              :   return mg_resolve2(host, &ad) ? snprintf(buf, n, "%s", inet_ntoa(ad)) : 0;
    2734              : }
    2735              : #endif /* MG_ENABLE_SYNC_RESOLVER */
    2736              : 
    2737            0 : MG_INTERNAL struct mg_connection *mg_create_connection_base(
    2738              :     struct mg_mgr *mgr, mg_event_handler_t callback,
    2739              :     struct mg_add_sock_opts opts) {
    2740              :   struct mg_connection *conn;
    2741              : 
    2742            0 :   if ((conn = (struct mg_connection *) MG_CALLOC(1, sizeof(*conn))) != NULL) {
    2743            0 :     conn->sock = INVALID_SOCKET;
    2744            0 :     conn->handler = callback;
    2745            0 :     conn->mgr = mgr;
    2746            0 :     conn->last_io_time = (time_t) mg_time();
    2747            0 :     conn->iface =
    2748            0 :         (opts.iface != NULL ? opts.iface : mgr->ifaces[MG_MAIN_IFACE]);
    2749            0 :     conn->flags = opts.flags & _MG_ALLOWED_CONNECT_FLAGS_MASK;
    2750            0 :     conn->user_data = opts.user_data;
    2751              :     /*
    2752              :      * SIZE_MAX is defined as a long long constant in
    2753              :      * system headers on some platforms and so it
    2754              :      * doesn't compile with pedantic ansi flags.
    2755              :      */
    2756            0 :     conn->recv_mbuf_limit = ~0;
    2757              :   } else {
    2758            0 :     MG_SET_PTRPTR(opts.error_string, "failed to create connection");
    2759              :   }
    2760              : 
    2761            0 :   return conn;
    2762              : }
    2763              : 
    2764            0 : MG_INTERNAL struct mg_connection *mg_create_connection(
    2765              :     struct mg_mgr *mgr, mg_event_handler_t callback,
    2766              :     struct mg_add_sock_opts opts) {
    2767            0 :   struct mg_connection *conn = mg_create_connection_base(mgr, callback, opts);
    2768              : 
    2769            0 :   if (conn != NULL && !conn->iface->vtable->create_conn(conn)) {
    2770            0 :     MG_FREE(conn);
    2771            0 :     conn = NULL;
    2772              :   }
    2773            0 :   if (conn == NULL) {
    2774            0 :     MG_SET_PTRPTR(opts.error_string, "failed to init connection");
    2775              :   }
    2776              : 
    2777            0 :   return conn;
    2778              : }
    2779              : 
    2780              : /*
    2781              :  * Address format: [PROTO://][HOST]:PORT
    2782              :  *
    2783              :  * HOST could be IPv4/IPv6 address or a host name.
    2784              :  * `host` is a destination buffer to hold parsed HOST part. Should be at least
    2785              :  * MG_MAX_HOST_LEN bytes long.
    2786              :  * `proto` is a returned socket type, either SOCK_STREAM or SOCK_DGRAM
    2787              :  *
    2788              :  * Return:
    2789              :  *   -1   on parse error
    2790              :  *    0   if HOST needs DNS lookup
    2791              :  *   >0   length of the address string
    2792              :  */
    2793            0 : MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa,
    2794              :                                  int *proto, char *host, size_t host_len) {
    2795            0 :   unsigned int a, b, c, d, port = 0;
    2796            0 :   int ch, len = 0;
    2797              : #if MG_ENABLE_IPV6
    2798              :   char buf[100];
    2799              : #endif
    2800              : 
    2801              :   /*
    2802              :    * MacOS needs that. If we do not zero it, subsequent bind() will fail.
    2803              :    * Also, all-zeroes in the socket address means binding to all addresses
    2804              :    * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
    2805              :    */
    2806            0 :   memset(sa, 0, sizeof(*sa));
    2807            0 :   sa->sin.sin_family = AF_INET;
    2808              : 
    2809            0 :   *proto = SOCK_STREAM;
    2810              : 
    2811            0 :   if (strncmp(str, "udp://", 6) == 0) {
    2812            0 :     str += 6;
    2813            0 :     *proto = SOCK_DGRAM;
    2814            0 :   } else if (strncmp(str, "tcp://", 6) == 0) {
    2815            0 :     str += 6;
    2816              :   }
    2817              : 
    2818            0 :   if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
    2819              :     /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
    2820            0 :     sa->sin.sin_addr.s_addr =
    2821            0 :         htonl(((uint32_t) a << 24) | ((uint32_t) b << 16) | c << 8 | d);
    2822            0 :     sa->sin.sin_port = htons((uint16_t) port);
    2823              : #if MG_ENABLE_IPV6
    2824            0 :   } else if (sscanf(str, "[%99[^]]]:%u%n", buf, &port, &len) == 2 &&
    2825            0 :              inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) {
    2826              :     /* IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080 */
    2827            0 :     sa->sin6.sin6_family = AF_INET6;
    2828            0 :     sa->sin.sin_port = htons((uint16_t) port);
    2829              : #endif
    2830              : #if MG_ENABLE_ASYNC_RESOLVER
    2831            0 :   } else if (strlen(str) < host_len &&
    2832            0 :              sscanf(str, "%[^ :]:%u%n", host, &port, &len) == 2) {
    2833            0 :     sa->sin.sin_port = htons((uint16_t) port);
    2834            0 :     if (mg_resolve_from_hosts_file(host, sa) != 0) {
    2835              :       /*
    2836              :        * if resolving from hosts file failed and the host
    2837              :        * we are trying to resolve is `localhost` - we should
    2838              :        * try to resolve it using `gethostbyname` and do not try
    2839              :        * to resolve it via DNS server if gethostbyname has failed too
    2840              :        */
    2841            0 :       if (mg_ncasecmp(host, "localhost", 9) != 0) {
    2842            0 :         return 0;
    2843              :       }
    2844              : 
    2845              : #if MG_ENABLE_SYNC_RESOLVER
    2846              :       if (!mg_resolve2(host, &sa->sin.sin_addr)) {
    2847              :         return -1;
    2848              :       }
    2849              : #else
    2850            0 :       return -1;
    2851              : #endif
    2852              :     }
    2853              : #endif
    2854            0 :   } else if (sscanf(str, ":%u%n", &port, &len) == 1 ||
    2855            0 :              sscanf(str, "%u%n", &port, &len) == 1) {
    2856              :     /* If only port is specified, bind to IPv4, INADDR_ANY */
    2857            0 :     sa->sin.sin_port = htons((uint16_t) port);
    2858              :   } else {
    2859            0 :     return -1;
    2860              :   }
    2861              : 
    2862              :   /* Required for MG_ENABLE_ASYNC_RESOLVER=0 */
    2863              :   (void) host;
    2864              :   (void) host_len;
    2865              : 
    2866            0 :   ch = str[len]; /* Character that follows the address */
    2867            0 :   return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1;
    2868              : }
    2869              : 
    2870              : #if MG_ENABLE_SSL
    2871              : MG_INTERNAL void mg_ssl_handshake(struct mg_connection *nc) {
    2872              :   int err = 0;
    2873              :   int server_side = (nc->listener != NULL);
    2874              :   enum mg_ssl_if_result res;
    2875              :   if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return;
    2876              :   res = mg_ssl_if_handshake(nc);
    2877              : 
    2878              :   if (res == MG_SSL_OK) {
    2879              :     nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
    2880              :     nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE);
    2881              :     if (server_side) {
    2882              :       mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
    2883              :     } else {
    2884              :       mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
    2885              :     }
    2886              :   } else if (res == MG_SSL_WANT_READ) {
    2887              :     nc->flags |= MG_F_WANT_READ;
    2888              :   } else if (res == MG_SSL_WANT_WRITE) {
    2889              :     nc->flags |= MG_F_WANT_WRITE;
    2890              :   } else {
    2891              :     if (!server_side) {
    2892              :       err = res;
    2893              :       mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
    2894              :     }
    2895              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    2896              :   }
    2897              : }
    2898              : #endif /* MG_ENABLE_SSL */
    2899              : 
    2900            0 : struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) {
    2901              :   struct mg_add_sock_opts opts;
    2902              :   struct mg_connection *nc;
    2903            0 :   memset(&opts, 0, sizeof(opts));
    2904            0 :   nc = mg_create_connection(lc->mgr, lc->handler, opts);
    2905            0 :   if (nc == NULL) return NULL;
    2906            0 :   nc->listener = lc;
    2907            0 :   nc->proto_handler = lc->proto_handler;
    2908            0 :   nc->user_data = lc->user_data;
    2909            0 :   nc->recv_mbuf_limit = lc->recv_mbuf_limit;
    2910            0 :   nc->iface = lc->iface;
    2911            0 :   if (lc->flags & MG_F_SSL) nc->flags |= MG_F_SSL;
    2912            0 :   mg_add_conn(nc->mgr, nc);
    2913            0 :   LOG(LL_DEBUG, ("%p %p %d %d", lc, nc, nc->sock, (int) nc->flags));
    2914            0 :   return nc;
    2915              : }
    2916              : 
    2917            0 : void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa,
    2918              :                          size_t sa_len) {
    2919            0 :   LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"),
    2920              :                  inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
    2921            0 :   nc->sa = *sa;
    2922              : #if MG_ENABLE_SSL
    2923              :   if (nc->listener->flags & MG_F_SSL) {
    2924              :     nc->flags |= MG_F_SSL;
    2925              :     if (mg_ssl_if_conn_accept(nc, nc->listener) == MG_SSL_OK) {
    2926              :       mg_ssl_handshake(nc);
    2927              :     } else {
    2928              :       mg_close_conn(nc);
    2929              :     }
    2930              :   } else
    2931              : #endif
    2932              :   {
    2933            0 :     mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
    2934              :   }
    2935              :   (void) sa_len;
    2936            0 : }
    2937              : 
    2938            0 : void mg_send(struct mg_connection *nc, const void *buf, int len) {
    2939            0 :   nc->last_io_time = (time_t) mg_time();
    2940            0 :   mbuf_append(&nc->send_mbuf, buf, len);
    2941            0 : }
    2942              : 
    2943              : static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len);
    2944              : static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len);
    2945              : 
    2946            0 : static int mg_do_recv(struct mg_connection *nc) {
    2947            0 :   int res = 0;
    2948            0 :   char *buf = NULL;
    2949            0 :   size_t len = (nc->flags & MG_F_UDP ? MG_UDP_IO_SIZE : MG_TCP_IO_SIZE);
    2950            0 :   if ((nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_CONNECTING)) ||
    2951            0 :       ((nc->flags & MG_F_LISTENING) && !(nc->flags & MG_F_UDP))) {
    2952            0 :     return -1;
    2953              :   }
    2954              :   do {
    2955            0 :     len = recv_avail_size(nc, len);
    2956            0 :     if (len == 0) {
    2957            0 :       res = -2;
    2958            0 :       break;
    2959              :     }
    2960            0 :     if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) {
    2961            0 :       mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len);
    2962              :     }
    2963            0 :     buf = nc->recv_mbuf.buf + nc->recv_mbuf.len;
    2964            0 :     len = nc->recv_mbuf.size - nc->recv_mbuf.len;
    2965            0 :     if (nc->flags & MG_F_UDP) {
    2966            0 :       res = mg_recv_udp(nc, buf, len);
    2967              :     } else {
    2968            0 :       res = mg_recv_tcp(nc, buf, len);
    2969              :     }
    2970            0 :   } while (res > 0 && !(nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_UDP)));
    2971            0 :   return res;
    2972              : }
    2973              : 
    2974            0 : void mg_if_can_recv_cb(struct mg_connection *nc) {
    2975            0 :   mg_do_recv(nc);
    2976            0 : }
    2977              : 
    2978            0 : static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) {
    2979            0 :   int n = 0;
    2980              : #if MG_ENABLE_SSL
    2981              :   if (nc->flags & MG_F_SSL) {
    2982              :     if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
    2983              :       n = mg_ssl_if_read(nc, buf, len);
    2984              :       DBG(("%p <- %d bytes (SSL)", nc, n));
    2985              :       if (n < 0) {
    2986              :         if (n == MG_SSL_WANT_READ) {
    2987              :           nc->flags |= MG_F_WANT_READ;
    2988              :           n = 0;
    2989              :         } else {
    2990              :           nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    2991              :         }
    2992              :       } else if (n > 0) {
    2993              :         nc->flags &= ~MG_F_WANT_READ;
    2994              :       }
    2995              :     } else {
    2996              :       mg_ssl_handshake(nc);
    2997              :     }
    2998              :   } else
    2999              : #endif
    3000              :   {
    3001            0 :     n = nc->iface->vtable->tcp_recv(nc, buf, len);
    3002            0 :     DBG(("%p <- %d bytes", nc, n));
    3003              :   }
    3004            0 :   if (n > 0) {
    3005            0 :     nc->recv_mbuf.len += n;
    3006            0 :     nc->last_io_time = (time_t) mg_time();
    3007              : #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
    3008            0 :     if (nc->mgr && nc->mgr->hexdump_file != NULL) {
    3009            0 :       mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
    3010              :     }
    3011              : #endif
    3012            0 :     mbuf_trim(&nc->recv_mbuf);
    3013            0 :     mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
    3014            0 :   } else if (n < 0) {
    3015            0 :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    3016              :   }
    3017            0 :   mbuf_trim(&nc->recv_mbuf);
    3018            0 :   return n;
    3019              : }
    3020              : 
    3021            0 : static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
    3022            0 :   int n = 0;
    3023            0 :   struct mg_connection *lc = nc;
    3024              :   union socket_address sa;
    3025            0 :   size_t sa_len = sizeof(sa);
    3026            0 :   n = nc->iface->vtable->udp_recv(lc, buf, len, &sa, &sa_len);
    3027            0 :   if (n < 0) {
    3028            0 :     lc->flags |= MG_F_CLOSE_IMMEDIATELY;
    3029            0 :     goto out;
    3030              :   }
    3031            0 :   if (nc->flags & MG_F_LISTENING) {
    3032              :     /*
    3033              :      * Do we have an existing connection for this source?
    3034              :      * This is very inefficient for long connection lists.
    3035              :      */
    3036            0 :     lc = nc;
    3037            0 :     for (nc = mg_next(lc->mgr, NULL); nc != NULL; nc = mg_next(lc->mgr, nc)) {
    3038            0 :       if (memcmp(&nc->sa.sa, &sa.sa, sa_len) == 0 && nc->listener == lc) {
    3039            0 :         break;
    3040              :       }
    3041              :     }
    3042            0 :     if (nc == NULL) {
    3043              :       struct mg_add_sock_opts opts;
    3044            0 :       memset(&opts, 0, sizeof(opts));
    3045              :       /* Create fake connection w/out sock initialization */
    3046            0 :       nc = mg_create_connection_base(lc->mgr, lc->handler, opts);
    3047            0 :       if (nc != NULL) {
    3048            0 :         nc->sock = lc->sock;
    3049            0 :         nc->listener = lc;
    3050            0 :         nc->sa = sa;
    3051            0 :         nc->proto_handler = lc->proto_handler;
    3052            0 :         nc->user_data = lc->user_data;
    3053            0 :         nc->recv_mbuf_limit = lc->recv_mbuf_limit;
    3054            0 :         nc->flags = MG_F_UDP;
    3055              :         /*
    3056              :          * Long-lived UDP "connections" i.e. interactions that involve more
    3057              :          * than one request and response are rare, most are transactional:
    3058              :          * response is sent and the "connection" is closed. Or - should be.
    3059              :          * But users (including ourselves) tend to forget about that part,
    3060              :          * because UDP is connectionless and one does not think about
    3061              :          * processing a UDP request as handling a connection that needs to be
    3062              :          * closed. Thus, we begin with SEND_AND_CLOSE flag set, which should
    3063              :          * be a reasonable default for most use cases, but it is possible to
    3064              :          * turn it off the connection should be kept alive after processing.
    3065              :          */
    3066            0 :         nc->flags |= MG_F_SEND_AND_CLOSE;
    3067            0 :         mg_add_conn(lc->mgr, nc);
    3068            0 :         mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
    3069              :       }
    3070              :     }
    3071              :   }
    3072            0 :   if (nc != NULL) {
    3073            0 :     DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
    3074              :          ntohs(nc->sa.sin.sin_port)));
    3075            0 :     if (nc == lc) {
    3076            0 :       nc->recv_mbuf.len += n;
    3077              :     } else {
    3078            0 :       mbuf_append(&nc->recv_mbuf, buf, n);
    3079              :     }
    3080            0 :     mbuf_trim(&lc->recv_mbuf);
    3081            0 :     lc->last_io_time = nc->last_io_time = (time_t) mg_time();
    3082              : #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
    3083            0 :     if (nc->mgr && nc->mgr->hexdump_file != NULL) {
    3084            0 :       mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
    3085              :     }
    3086              : #endif
    3087            0 :     if (n != 0) {
    3088            0 :       mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
    3089              :     }
    3090              :   }
    3091              : 
    3092            0 : out:
    3093            0 :   mbuf_free(&lc->recv_mbuf);
    3094            0 :   return n;
    3095              : }
    3096              : 
    3097            0 : void mg_if_can_send_cb(struct mg_connection *nc) {
    3098            0 :   int n = 0;
    3099            0 :   const char *buf = nc->send_mbuf.buf;
    3100            0 :   size_t len = nc->send_mbuf.len;
    3101              : 
    3102            0 :   if (nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_CONNECTING)) {
    3103            0 :     return;
    3104              :   }
    3105            0 :   if (!(nc->flags & MG_F_UDP)) {
    3106            0 :     if (nc->flags & MG_F_LISTENING) return;
    3107            0 :     if (len > MG_TCP_IO_SIZE) len = MG_TCP_IO_SIZE;
    3108              :   }
    3109              : #if MG_ENABLE_SSL
    3110              :   if (nc->flags & MG_F_SSL) {
    3111              :     if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
    3112              :       if (len > 0) {
    3113              :         n = mg_ssl_if_write(nc, buf, len);
    3114              :         DBG(("%p -> %d bytes (SSL)", nc, n));
    3115              :       }
    3116              :       if (n < 0) {
    3117              :         if (n == MG_SSL_WANT_WRITE) {
    3118              :           nc->flags |= MG_F_WANT_WRITE;
    3119              :           n = 0;
    3120              :         } else {
    3121              :           nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    3122              :         }
    3123              :       } else {
    3124              :         nc->flags &= ~MG_F_WANT_WRITE;
    3125              :       }
    3126              :     } else {
    3127              :       mg_ssl_handshake(nc);
    3128              :     }
    3129              :   } else
    3130              : #endif
    3131            0 :       if (len > 0) {
    3132            0 :     if (nc->flags & MG_F_UDP) {
    3133            0 :       n = nc->iface->vtable->udp_send(nc, buf, len);
    3134              :     } else {
    3135            0 :       n = nc->iface->vtable->tcp_send(nc, buf, len);
    3136              :     }
    3137            0 :     DBG(("%p -> %d bytes", nc, n));
    3138              :   }
    3139              : 
    3140              : #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
    3141            0 :   if (n > 0 && nc->mgr && nc->mgr->hexdump_file != NULL) {
    3142            0 :     mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_SEND);
    3143              :   }
    3144              : #endif
    3145            0 :   if (n < 0) {
    3146            0 :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    3147            0 :   } else if (n > 0) {
    3148            0 :     nc->last_io_time = (time_t) mg_time();
    3149            0 :     mbuf_remove(&nc->send_mbuf, n);
    3150            0 :     mbuf_trim(&nc->send_mbuf);
    3151              :   }
    3152            0 :   if (n != 0) mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &n);
    3153              : }
    3154              : 
    3155              : /*
    3156              :  * Schedules an async connect for a resolved address and proto.
    3157              :  * Called from two places: `mg_connect_opt()` and from async resolver.
    3158              :  * When called from the async resolver, it must trigger `MG_EV_CONNECT` event
    3159              :  * with a failure flag to indicate connection failure.
    3160              :  */
    3161            0 : MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc,
    3162              :                                                 int proto,
    3163              :                                                 union socket_address *sa) {
    3164            0 :   LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp",
    3165              :                  inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
    3166              : 
    3167            0 :   nc->flags |= MG_F_CONNECTING;
    3168            0 :   if (proto == SOCK_DGRAM) {
    3169            0 :     nc->iface->vtable->connect_udp(nc);
    3170              :   } else {
    3171            0 :     nc->iface->vtable->connect_tcp(nc, sa);
    3172              :   }
    3173            0 :   mg_add_conn(nc->mgr, nc);
    3174            0 :   return nc;
    3175              : }
    3176              : 
    3177            0 : void mg_if_connect_cb(struct mg_connection *nc, int err) {
    3178            0 :   LOG(LL_DEBUG,
    3179              :       ("%p %s://%s:%hu -> %d", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"),
    3180              :        inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port), err));
    3181            0 :   nc->flags &= ~MG_F_CONNECTING;
    3182            0 :   if (err != 0) {
    3183            0 :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    3184              :   }
    3185              : #if MG_ENABLE_SSL
    3186              :   if (err == 0 && (nc->flags & MG_F_SSL)) {
    3187              :     mg_ssl_handshake(nc);
    3188              :   } else
    3189              : #endif
    3190              :   {
    3191            0 :     mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
    3192              :   }
    3193            0 : }
    3194              : 
    3195              : #if MG_ENABLE_ASYNC_RESOLVER
    3196              : /*
    3197              :  * Callback for the async resolver on mg_connect_opt() call.
    3198              :  * Main task of this function is to trigger MG_EV_CONNECT event with
    3199              :  *    either failure (and dealloc the connection)
    3200              :  *    or success (and proceed with connect()
    3201              :  */
    3202            0 : static void resolve_cb(struct mg_dns_message *msg, void *data,
    3203              :                        enum mg_resolve_err e) {
    3204            0 :   struct mg_connection *nc = (struct mg_connection *) data;
    3205              :   int i;
    3206            0 :   int failure = -1;
    3207              : 
    3208            0 :   nc->flags &= ~MG_F_RESOLVING;
    3209            0 :   if (msg != NULL) {
    3210              :     /*
    3211              :      * Take the first DNS A answer and run...
    3212              :      */
    3213            0 :     for (i = 0; i < msg->num_answers; i++) {
    3214            0 :       if (msg->answers[i].rtype == MG_DNS_A_RECORD) {
    3215              :         /*
    3216              :          * Async resolver guarantees that there is at least one answer.
    3217              :          * TODO(lsm): handle IPv6 answers too
    3218              :          */
    3219            0 :         mg_dns_parse_record_data(msg, &msg->answers[i], &nc->sa.sin.sin_addr,
    3220              :                                  4);
    3221            0 :         mg_do_connect(nc, nc->flags & MG_F_UDP ? SOCK_DGRAM : SOCK_STREAM,
    3222              :                       &nc->sa);
    3223            0 :         return;
    3224              :       }
    3225              :     }
    3226              :   }
    3227              : 
    3228            0 :   if (e == MG_RESOLVE_TIMEOUT) {
    3229            0 :     double now = mg_time();
    3230            0 :     mg_call(nc, NULL, nc->user_data, MG_EV_TIMER, &now);
    3231              :   }
    3232              : 
    3233              :   /*
    3234              :    * If we get there was no MG_DNS_A_RECORD in the answer
    3235              :    */
    3236            0 :   mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &failure);
    3237            0 :   mg_call(nc, NULL, nc->user_data, MG_EV_CLOSE, NULL);
    3238            0 :   mg_destroy_conn(nc, 1 /* destroy_if */);
    3239              : }
    3240              : #endif
    3241              : 
    3242            0 : struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address,
    3243              :                                  MG_CB(mg_event_handler_t callback,
    3244              :                                        void *user_data)) {
    3245              :   struct mg_connect_opts opts;
    3246            0 :   memset(&opts, 0, sizeof(opts));
    3247            0 :   return mg_connect_opt(mgr, address, MG_CB(callback, user_data), opts);
    3248              : }
    3249              : 
    3250            0 : void mg_ev_handler_empty(struct mg_connection *c, int ev,
    3251              :                          void *ev_data MG_UD_ARG(void *user_data)) {
    3252              :   (void) c;
    3253              :   (void) ev;
    3254              :   (void) ev_data;
    3255              : #if MG_ENABLE_CALLBACK_USERDATA
    3256              :   (void) user_data;
    3257              : #endif
    3258            0 : }
    3259              : 
    3260            0 : struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address,
    3261              :                                      MG_CB(mg_event_handler_t callback,
    3262              :                                            void *user_data),
    3263              :                                      struct mg_connect_opts opts) {
    3264            0 :   struct mg_connection *nc = NULL;
    3265              :   int proto, rc;
    3266              :   struct mg_add_sock_opts add_sock_opts;
    3267              :   char host[MG_MAX_HOST_LEN];
    3268              : 
    3269            0 :   MG_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts);
    3270              : 
    3271            0 :   if (callback == NULL) callback = mg_ev_handler_empty;
    3272              : 
    3273            0 :   if ((nc = mg_create_connection(mgr, callback, add_sock_opts)) == NULL) {
    3274            0 :     return NULL;
    3275              :   }
    3276              : 
    3277            0 :   if ((rc = mg_parse_address(address, &nc->sa, &proto, host, sizeof(host))) <
    3278              :       0) {
    3279              :     /* Address is malformed */
    3280            0 :     MG_SET_PTRPTR(opts.error_string, "cannot parse address");
    3281            0 :     mg_destroy_conn(nc, 1 /* destroy_if */);
    3282            0 :     return NULL;
    3283              :   }
    3284              : 
    3285            0 :   nc->flags |= opts.flags & _MG_ALLOWED_CONNECT_FLAGS_MASK;
    3286            0 :   nc->flags |= (proto == SOCK_DGRAM) ? MG_F_UDP : 0;
    3287              : #if MG_ENABLE_CALLBACK_USERDATA
    3288              :   nc->user_data = user_data;
    3289              : #else
    3290            0 :   nc->user_data = opts.user_data;
    3291              : #endif
    3292              : 
    3293              : #if MG_ENABLE_SSL
    3294              :   LOG(LL_DEBUG,
    3295              :       ("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
    3296              :        (opts.ssl_key ? opts.ssl_key : "-"),
    3297              :        (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-")));
    3298              : 
    3299              :   if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL ||
    3300              :       opts.ssl_psk_identity != NULL) {
    3301              :     const char *err_msg = NULL;
    3302              :     struct mg_ssl_if_conn_params params;
    3303              :     if (nc->flags & MG_F_UDP) {
    3304              :       MG_SET_PTRPTR(opts.error_string, "SSL for UDP is not supported");
    3305              :       mg_destroy_conn(nc, 1 /* destroy_if */);
    3306              :       return NULL;
    3307              :     }
    3308              :     memset(&params, 0, sizeof(params));
    3309              :     params.cert = opts.ssl_cert;
    3310              :     params.key = opts.ssl_key;
    3311              :     params.ca_cert = opts.ssl_ca_cert;
    3312              :     params.cipher_suites = opts.ssl_cipher_suites;
    3313              :     params.psk_identity = opts.ssl_psk_identity;
    3314              :     params.psk_key = opts.ssl_psk_key;
    3315              :     if (opts.ssl_ca_cert != NULL) {
    3316              :       if (opts.ssl_server_name != NULL) {
    3317              :         if (strcmp(opts.ssl_server_name, "*") != 0) {
    3318              :           params.server_name = opts.ssl_server_name;
    3319              :         }
    3320              :       } else if (rc == 0) { /* If it's a DNS name, use host. */
    3321              :         params.server_name = host;
    3322              :       }
    3323              :     }
    3324              :     if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
    3325              :       MG_SET_PTRPTR(opts.error_string, err_msg);
    3326              :       mg_destroy_conn(nc, 1 /* destroy_if */);
    3327              :       return NULL;
    3328              :     }
    3329              :     nc->flags |= MG_F_SSL;
    3330              :   }
    3331              : #endif /* MG_ENABLE_SSL */
    3332              : 
    3333            0 :   if (rc == 0) {
    3334              : #if MG_ENABLE_ASYNC_RESOLVER
    3335              :     /*
    3336              :      * DNS resolution is required for host.
    3337              :      * mg_parse_address() fills port in nc->sa, which we pass to resolve_cb()
    3338              :      */
    3339            0 :     struct mg_connection *dns_conn = NULL;
    3340              :     struct mg_resolve_async_opts o;
    3341            0 :     memset(&o, 0, sizeof(o));
    3342            0 :     o.dns_conn = &dns_conn;
    3343            0 :     o.nameserver = opts.nameserver;
    3344            0 :     if (mg_resolve_async_opt(nc->mgr, host, MG_DNS_A_RECORD, resolve_cb, nc,
    3345            0 :                              o) != 0) {
    3346            0 :       MG_SET_PTRPTR(opts.error_string, "cannot schedule DNS lookup");
    3347            0 :       mg_destroy_conn(nc, 1 /* destroy_if */);
    3348            0 :       return NULL;
    3349              :     }
    3350            0 :     nc->priv_2 = dns_conn;
    3351            0 :     nc->flags |= MG_F_RESOLVING;
    3352            0 :     return nc;
    3353              : #else
    3354              :     MG_SET_PTRPTR(opts.error_string, "Resolver is disabled");
    3355              :     mg_destroy_conn(nc, 1 /* destroy_if */);
    3356              :     return NULL;
    3357              : #endif
    3358              :   } else {
    3359              :     /* Address is parsed and resolved to IP. proceed with connect() */
    3360            0 :     return mg_do_connect(nc, proto, &nc->sa);
    3361              :   }
    3362              : }
    3363              : 
    3364            0 : struct mg_connection *mg_bind(struct mg_mgr *srv, const char *address,
    3365              :                               MG_CB(mg_event_handler_t event_handler,
    3366              :                                     void *user_data)) {
    3367              :   struct mg_bind_opts opts;
    3368            0 :   memset(&opts, 0, sizeof(opts));
    3369            0 :   return mg_bind_opt(srv, address, MG_CB(event_handler, user_data), opts);
    3370              : }
    3371              : 
    3372            0 : struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address,
    3373              :                                   MG_CB(mg_event_handler_t callback,
    3374              :                                         void *user_data),
    3375              :                                   struct mg_bind_opts opts) {
    3376              :   union socket_address sa;
    3377            0 :   struct mg_connection *nc = NULL;
    3378              :   int proto, rc;
    3379              :   struct mg_add_sock_opts add_sock_opts;
    3380              :   char host[MG_MAX_HOST_LEN];
    3381              : 
    3382              : #if MG_ENABLE_CALLBACK_USERDATA
    3383              :   opts.user_data = user_data;
    3384              : #endif
    3385              : 
    3386            0 :   if (callback == NULL) callback = mg_ev_handler_empty;
    3387              : 
    3388            0 :   MG_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts);
    3389              : 
    3390            0 :   if (mg_parse_address(address, &sa, &proto, host, sizeof(host)) <= 0) {
    3391            0 :     MG_SET_PTRPTR(opts.error_string, "cannot parse address");
    3392            0 :     return NULL;
    3393              :   }
    3394              : 
    3395            0 :   nc = mg_create_connection(mgr, callback, add_sock_opts);
    3396            0 :   if (nc == NULL) {
    3397            0 :     return NULL;
    3398              :   }
    3399              : 
    3400            0 :   nc->sa = sa;
    3401            0 :   nc->flags |= MG_F_LISTENING;
    3402            0 :   if (proto == SOCK_DGRAM) nc->flags |= MG_F_UDP;
    3403              : 
    3404              : #if MG_ENABLE_SSL
    3405              :   DBG(("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
    3406              :        (opts.ssl_key ? opts.ssl_key : "-"),
    3407              :        (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-")));
    3408              : 
    3409              :   if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
    3410              :     const char *err_msg = NULL;
    3411              :     struct mg_ssl_if_conn_params params;
    3412              :     if (nc->flags & MG_F_UDP) {
    3413              :       MG_SET_PTRPTR(opts.error_string, "SSL for UDP is not supported");
    3414              :       mg_destroy_conn(nc, 1 /* destroy_if */);
    3415              :       return NULL;
    3416              :     }
    3417              :     memset(&params, 0, sizeof(params));
    3418              :     params.cert = opts.ssl_cert;
    3419              :     params.key = opts.ssl_key;
    3420              :     params.ca_cert = opts.ssl_ca_cert;
    3421              :     params.cipher_suites = opts.ssl_cipher_suites;
    3422              :     if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
    3423              :       MG_SET_PTRPTR(opts.error_string, err_msg);
    3424              :       mg_destroy_conn(nc, 1 /* destroy_if */);
    3425              :       return NULL;
    3426              :     }
    3427              :     nc->flags |= MG_F_SSL;
    3428              :   }
    3429              : #endif /* MG_ENABLE_SSL */
    3430              : 
    3431            0 :   if (nc->flags & MG_F_UDP) {
    3432            0 :     rc = nc->iface->vtable->listen_udp(nc, &nc->sa);
    3433              :   } else {
    3434            0 :     rc = nc->iface->vtable->listen_tcp(nc, &nc->sa);
    3435              :   }
    3436            0 :   if (rc != 0) {
    3437            0 :     DBG(("Failed to open listener: %d", rc));
    3438            0 :     MG_SET_PTRPTR(opts.error_string, "failed to open listener");
    3439            0 :     mg_destroy_conn(nc, 1 /* destroy_if */);
    3440            0 :     return NULL;
    3441              :   }
    3442            0 :   mg_add_conn(nc->mgr, nc);
    3443              : 
    3444            0 :   return nc;
    3445              : }
    3446              : 
    3447            0 : struct mg_connection *mg_next(struct mg_mgr *s, struct mg_connection *conn) {
    3448            0 :   return conn == NULL ? s->active_connections : conn->next;
    3449              : }
    3450              : 
    3451              : #if MG_ENABLE_BROADCAST
    3452            0 : void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data,
    3453              :                   size_t len) {
    3454              :   struct ctl_msg ctl_msg;
    3455              : 
    3456              :   /*
    3457              :    * Mongoose manager has a socketpair, `struct mg_mgr::ctl`,
    3458              :    * where `mg_broadcast()` pushes the message.
    3459              :    * `mg_mgr_poll()` wakes up, reads a message from the socket pair, and calls
    3460              :    * specified callback for each connection. Thus the callback function executes
    3461              :    * in event manager thread.
    3462              :    */
    3463            0 :   if (mgr->ctl[0] != INVALID_SOCKET && data != NULL &&
    3464            0 :       len < sizeof(ctl_msg.message)) {
    3465              :     size_t dummy;
    3466              : 
    3467            0 :     ctl_msg.callback = cb;
    3468            0 :     memcpy(ctl_msg.message, data, len);
    3469            0 :     dummy = MG_SEND_FUNC(mgr->ctl[0], (char *) &ctl_msg,
    3470              :                          offsetof(struct ctl_msg, message) + len, 0);
    3471            0 :     dummy = MG_RECV_FUNC(mgr->ctl[0], (char *) &len, 1, 0);
    3472              :     (void) dummy; /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 */
    3473              :   }
    3474            0 : }
    3475              : #endif /* MG_ENABLE_BROADCAST */
    3476              : 
    3477            0 : static int isbyte(int n) {
    3478            0 :   return n >= 0 && n <= 255;
    3479              : }
    3480              : 
    3481            0 : static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
    3482            0 :   int n, a, b, c, d, slash = 32, len = 0;
    3483              : 
    3484            0 :   if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
    3485            0 :        sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
    3486            0 :       isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0 &&
    3487            0 :       slash < 33) {
    3488            0 :     len = n;
    3489            0 :     *net =
    3490            0 :         ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t) c << 8) | d;
    3491            0 :     *mask = slash ? 0xffffffffU << (32 - slash) : 0;
    3492              :   }
    3493              : 
    3494            0 :   return len;
    3495              : }
    3496              : 
    3497            0 : int mg_check_ip_acl(const char *acl, uint32_t remote_ip) {
    3498              :   int allowed, flag;
    3499              :   uint32_t net, mask;
    3500              :   struct mg_str vec;
    3501              : 
    3502              :   /* If any ACL is set, deny by default */
    3503            0 :   allowed = (acl == NULL || *acl == '\0') ? '+' : '-';
    3504              : 
    3505            0 :   while ((acl = mg_next_comma_list_entry(acl, &vec, NULL)) != NULL) {
    3506            0 :     flag = vec.p[0];
    3507            0 :     if ((flag != '+' && flag != '-') ||
    3508            0 :         parse_net(&vec.p[1], &net, &mask) == 0) {
    3509            0 :       return -1;
    3510              :     }
    3511              : 
    3512            0 :     if (net == (remote_ip & mask)) {
    3513            0 :       allowed = flag;
    3514              :     }
    3515              :   }
    3516              : 
    3517            0 :   DBG(("%08x %c", (unsigned int) remote_ip, allowed));
    3518            0 :   return allowed == '+';
    3519              : }
    3520              : 
    3521              : /* Move data from one connection to another */
    3522            0 : void mg_forward(struct mg_connection *from, struct mg_connection *to) {
    3523            0 :   mg_send(to, from->recv_mbuf.buf, from->recv_mbuf.len);
    3524            0 :   mbuf_remove(&from->recv_mbuf, from->recv_mbuf.len);
    3525            0 : }
    3526              : 
    3527            0 : double mg_set_timer(struct mg_connection *c, double timestamp) {
    3528            0 :   double result = c->ev_timer_time;
    3529            0 :   c->ev_timer_time = timestamp;
    3530              :   /*
    3531              :    * If this connection is resolving, it's not in the list of active
    3532              :    * connections, so not processed yet. It has a DNS resolver connection
    3533              :    * linked to it. Set up a timer for the DNS connection.
    3534              :    */
    3535            0 :   DBG(("%p %p %d -> %lu", c, c->priv_2, (c->flags & MG_F_RESOLVING ? 1 : 0),
    3536              :        (unsigned long) timestamp));
    3537            0 :   if ((c->flags & MG_F_RESOLVING) && c->priv_2 != NULL) {
    3538            0 :     mg_set_timer((struct mg_connection *) c->priv_2, timestamp);
    3539              :   }
    3540            0 :   return result;
    3541              : }
    3542              : 
    3543            0 : void mg_sock_set(struct mg_connection *nc, sock_t sock) {
    3544            0 :   if (sock != INVALID_SOCKET) {
    3545            0 :     nc->iface->vtable->sock_set(nc, sock);
    3546              :   }
    3547            0 : }
    3548              : 
    3549            0 : void mg_if_get_conn_addr(struct mg_connection *nc, int remote,
    3550              :                          union socket_address *sa) {
    3551            0 :   nc->iface->vtable->get_conn_addr(nc, remote, sa);
    3552            0 : }
    3553              : 
    3554            0 : struct mg_connection *mg_add_sock_opt(struct mg_mgr *s, sock_t sock,
    3555              :                                       MG_CB(mg_event_handler_t callback,
    3556              :                                             void *user_data),
    3557              :                                       struct mg_add_sock_opts opts) {
    3558              : #if MG_ENABLE_CALLBACK_USERDATA
    3559              :   opts.user_data = user_data;
    3560              : #endif
    3561              : 
    3562            0 :   struct mg_connection *nc = mg_create_connection_base(s, callback, opts);
    3563            0 :   if (nc != NULL) {
    3564            0 :     mg_sock_set(nc, sock);
    3565            0 :     mg_add_conn(nc->mgr, nc);
    3566              :   }
    3567            0 :   return nc;
    3568              : }
    3569              : 
    3570            0 : struct mg_connection *mg_add_sock(struct mg_mgr *s, sock_t sock,
    3571              :                                   MG_CB(mg_event_handler_t callback,
    3572              :                                         void *user_data)) {
    3573              :   struct mg_add_sock_opts opts;
    3574            0 :   memset(&opts, 0, sizeof(opts));
    3575            0 :   return mg_add_sock_opt(s, sock, MG_CB(callback, user_data), opts);
    3576              : }
    3577              : 
    3578            0 : double mg_time(void) {
    3579            0 :   return cs_time();
    3580              : }
    3581              : #ifdef MG_MODULE_LINES
    3582              : #line 1 "mongoose/src/mg_net_if_socket.h"
    3583              : #endif
    3584              : /*
    3585              :  * Copyright (c) 2014-2016 Cesanta Software Limited
    3586              :  * All rights reserved
    3587              :  */
    3588              : 
    3589              : #ifndef CS_MONGOOSE_SRC_NET_IF_SOCKET_H_
    3590              : #define CS_MONGOOSE_SRC_NET_IF_SOCKET_H_
    3591              : 
    3592              : /* Amalgamated: #include "mg_net_if.h" */
    3593              : 
    3594              : #ifdef __cplusplus
    3595              : extern "C" {
    3596              : #endif /* __cplusplus */
    3597              : 
    3598              : #ifndef MG_ENABLE_NET_IF_SOCKET
    3599              : #define MG_ENABLE_NET_IF_SOCKET MG_NET_IF == MG_NET_IF_SOCKET
    3600              : #endif
    3601              : 
    3602              : extern const struct mg_iface_vtable mg_socket_iface_vtable;
    3603              : 
    3604              : #ifdef __cplusplus
    3605              : }
    3606              : #endif /* __cplusplus */
    3607              : 
    3608              : #endif /* CS_MONGOOSE_SRC_NET_IF_SOCKET_H_ */
    3609              : #ifdef MG_MODULE_LINES
    3610              : #line 1 "mongoose/src/mg_net_if_socks.h"
    3611              : #endif
    3612              : /*
    3613              : * Copyright (c) 2014-2017 Cesanta Software Limited
    3614              : * All rights reserved
    3615              : */
    3616              : 
    3617              : #ifndef CS_MONGOOSE_SRC_NET_IF_SOCKS_H_
    3618              : #define CS_MONGOOSE_SRC_NET_IF_SOCKS_H_
    3619              : 
    3620              : #if MG_ENABLE_SOCKS
    3621              : /* Amalgamated: #include "mg_net_if.h" */
    3622              : 
    3623              : #ifdef __cplusplus
    3624              : extern "C" {
    3625              : #endif /* __cplusplus */
    3626              : 
    3627              : extern const struct mg_iface_vtable mg_socks_iface_vtable;
    3628              : 
    3629              : #ifdef __cplusplus
    3630              : }
    3631              : #endif /* __cplusplus */
    3632              : #endif /* MG_ENABLE_SOCKS */
    3633              : #endif /* CS_MONGOOSE_SRC_NET_IF_SOCKS_H_ */
    3634              : #ifdef MG_MODULE_LINES
    3635              : #line 1 "mongoose/src/mg_net_if.c"
    3636              : #endif
    3637              : /* Amalgamated: #include "mg_net_if.h" */
    3638              : /* Amalgamated: #include "mg_internal.h" */
    3639              : /* Amalgamated: #include "mg_net_if_socket.h" */
    3640              : 
    3641              : extern const struct mg_iface_vtable mg_default_iface_vtable;
    3642              : 
    3643              : const struct mg_iface_vtable *mg_ifaces[] = {
    3644              :     &mg_default_iface_vtable,
    3645              : };
    3646              : 
    3647              : int mg_num_ifaces = (int) (sizeof(mg_ifaces) / sizeof(mg_ifaces[0]));
    3648              : 
    3649            0 : struct mg_iface *mg_if_create_iface(const struct mg_iface_vtable *vtable,
    3650              :                                     struct mg_mgr *mgr) {
    3651            0 :   struct mg_iface *iface = (struct mg_iface *) MG_CALLOC(1, sizeof(*iface));
    3652            0 :   iface->mgr = mgr;
    3653            0 :   iface->data = NULL;
    3654            0 :   iface->vtable = vtable;
    3655            0 :   return iface;
    3656              : }
    3657              : 
    3658            0 : struct mg_iface *mg_find_iface(struct mg_mgr *mgr,
    3659              :                                const struct mg_iface_vtable *vtable,
    3660              :                                struct mg_iface *from) {
    3661            0 :   int i = 0;
    3662            0 :   if (from != NULL) {
    3663            0 :     for (i = 0; i < mgr->num_ifaces; i++) {
    3664            0 :       if (mgr->ifaces[i] == from) {
    3665            0 :         i++;
    3666            0 :         break;
    3667              :       }
    3668              :     }
    3669              :   }
    3670              : 
    3671            0 :   for (; i < mgr->num_ifaces; i++) {
    3672            0 :     if (mgr->ifaces[i]->vtable == vtable) {
    3673            0 :       return mgr->ifaces[i];
    3674              :     }
    3675              :   }
    3676            0 :   return NULL;
    3677              : }
    3678              : 
    3679            0 : double mg_mgr_min_timer(const struct mg_mgr *mgr) {
    3680            0 :   double min_timer = 0;
    3681              :   struct mg_connection *nc;
    3682            0 :   for (nc = mgr->active_connections; nc != NULL; nc = nc->next) {
    3683            0 :     if (nc->ev_timer_time <= 0) continue;
    3684            0 :     if (min_timer == 0 || nc->ev_timer_time < min_timer) {
    3685            0 :       min_timer = nc->ev_timer_time;
    3686              :     }
    3687              :   }
    3688            0 :   return min_timer;
    3689              : }
    3690              : #ifdef MG_MODULE_LINES
    3691              : #line 1 "mongoose/src/mg_net_if_null.c"
    3692              : #endif
    3693              : /*
    3694              :  * Copyright (c) 2018 Cesanta Software Limited
    3695              :  * All rights reserved
    3696              :  *
    3697              :  * This software is dual-licensed: you can redistribute it and/or modify
    3698              :  * it under the terms of the GNU General Public License version 2 as
    3699              :  * published by the Free Software Foundation. For the terms of this
    3700              :  * license, see <http://www.gnu.org/licenses/>.
    3701              :  *
    3702              :  * You are free to use this software under the terms of the GNU General
    3703              :  * Public License, but WITHOUT ANY WARRANTY; without even the implied
    3704              :  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    3705              :  * See the GNU General Public License for more details.
    3706              :  *
    3707              :  * Alternatively, you can license this software under a commercial
    3708              :  * license, as set out in <https://www.cesanta.com/license>.
    3709              :  */
    3710              : 
    3711            0 : static void mg_null_if_connect_tcp(struct mg_connection *c,
    3712              :                                    const union socket_address *sa) {
    3713            0 :   c->flags |= MG_F_CLOSE_IMMEDIATELY;
    3714              :   (void) sa;
    3715            0 : }
    3716              : 
    3717            0 : static void mg_null_if_connect_udp(struct mg_connection *c) {
    3718            0 :   c->flags |= MG_F_CLOSE_IMMEDIATELY;
    3719            0 : }
    3720              : 
    3721            0 : static int mg_null_if_listen_tcp(struct mg_connection *c,
    3722              :                                  union socket_address *sa) {
    3723              :   (void) c;
    3724              :   (void) sa;
    3725            0 :   return -1;
    3726              : }
    3727              : 
    3728            0 : static int mg_null_if_listen_udp(struct mg_connection *c,
    3729              :                                  union socket_address *sa) {
    3730              :   (void) c;
    3731              :   (void) sa;
    3732            0 :   return -1;
    3733              : }
    3734              : 
    3735            0 : static int mg_null_if_tcp_send(struct mg_connection *c, const void *buf,
    3736              :                                size_t len) {
    3737              :   (void) c;
    3738              :   (void) buf;
    3739              :   (void) len;
    3740            0 :   return -1;
    3741              : }
    3742              : 
    3743            0 : static int mg_null_if_udp_send(struct mg_connection *c, const void *buf,
    3744              :                                size_t len) {
    3745              :   (void) c;
    3746              :   (void) buf;
    3747              :   (void) len;
    3748            0 :   return -1;
    3749              : }
    3750              : 
    3751            0 : int mg_null_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
    3752              :   (void) c;
    3753              :   (void) buf;
    3754              :   (void) len;
    3755            0 :   return -1;
    3756              : }
    3757              : 
    3758            0 : int mg_null_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
    3759              :                         union socket_address *sa, size_t *sa_len) {
    3760              :   (void) c;
    3761              :   (void) buf;
    3762              :   (void) len;
    3763              :   (void) sa;
    3764              :   (void) sa_len;
    3765            0 :   return -1;
    3766              : }
    3767              : 
    3768            0 : static int mg_null_if_create_conn(struct mg_connection *c) {
    3769              :   (void) c;
    3770            0 :   return 1;
    3771              : }
    3772              : 
    3773            0 : static void mg_null_if_destroy_conn(struct mg_connection *c) {
    3774              :   (void) c;
    3775            0 : }
    3776              : 
    3777            0 : static void mg_null_if_sock_set(struct mg_connection *c, sock_t sock) {
    3778              :   (void) c;
    3779              :   (void) sock;
    3780            0 : }
    3781              : 
    3782            0 : static void mg_null_if_init(struct mg_iface *iface) {
    3783              :   (void) iface;
    3784            0 : }
    3785              : 
    3786            0 : static void mg_null_if_free(struct mg_iface *iface) {
    3787              :   (void) iface;
    3788            0 : }
    3789              : 
    3790            0 : static void mg_null_if_add_conn(struct mg_connection *c) {
    3791            0 :   c->sock = INVALID_SOCKET;
    3792            0 :   c->flags |= MG_F_CLOSE_IMMEDIATELY;
    3793            0 : }
    3794              : 
    3795            0 : static void mg_null_if_remove_conn(struct mg_connection *c) {
    3796              :   (void) c;
    3797            0 : }
    3798              : 
    3799            0 : static time_t mg_null_if_poll(struct mg_iface *iface, int timeout_ms) {
    3800            0 :   struct mg_mgr *mgr = iface->mgr;
    3801              :   struct mg_connection *nc, *tmp;
    3802            0 :   double now = mg_time();
    3803              :   /* We basically just run timers and poll. */
    3804            0 :   for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
    3805            0 :     tmp = nc->next;
    3806            0 :     mg_if_poll(nc, now);
    3807              :   }
    3808              :   (void) timeout_ms;
    3809            0 :   return (time_t) now;
    3810              : }
    3811              : 
    3812            0 : static void mg_null_if_get_conn_addr(struct mg_connection *c, int remote,
    3813              :                                      union socket_address *sa) {
    3814              :   (void) c;
    3815              :   (void) remote;
    3816              :   (void) sa;
    3817            0 : }
    3818              : 
    3819              : #define MG_NULL_IFACE_VTABLE                                                   \
    3820              :   {                                                                            \
    3821              :     mg_null_if_init, mg_null_if_free, mg_null_if_add_conn,                     \
    3822              :         mg_null_if_remove_conn, mg_null_if_poll, mg_null_if_listen_tcp,        \
    3823              :         mg_null_if_listen_udp, mg_null_if_connect_tcp, mg_null_if_connect_udp, \
    3824              :         mg_null_if_tcp_send, mg_null_if_udp_send, mg_null_if_tcp_recv,         \
    3825              :         mg_null_if_udp_recv, mg_null_if_create_conn, mg_null_if_destroy_conn,  \
    3826              :         mg_null_if_sock_set, mg_null_if_get_conn_addr,                         \
    3827              :   }
    3828              : 
    3829              : //const struct mg_iface_vtable mg_null_iface_vtable = MG_NULL_IFACE_VTABLE;
    3830              : 
    3831              : #if MG_NET_IF == MG_NET_IF_NULL
    3832              : const struct mg_iface_vtable mg_default_iface_vtable = MG_NULL_IFACE_VTABLE;
    3833              : #endif /* MG_NET_IF == MG_NET_IF_NULL */
    3834              : #ifdef MG_MODULE_LINES
    3835              : #line 1 "mongoose/src/mg_net_if_socket.c"
    3836              : #endif
    3837              : /*
    3838              :  * Copyright (c) 2014-2016 Cesanta Software Limited
    3839              :  * All rights reserved
    3840              :  */
    3841              : 
    3842              : #if MG_ENABLE_NET_IF_SOCKET
    3843              : 
    3844              : /* Amalgamated: #include "mg_net_if_socket.h" */
    3845              : /* Amalgamated: #include "mg_internal.h" */
    3846              : /* Amalgamated: #include "mg_util.h" */
    3847              : 
    3848              : static sock_t mg_open_listening_socket(union socket_address *sa, int type,
    3849              :                                        int proto);
    3850              : 
    3851            0 : void mg_set_non_blocking_mode(sock_t sock) {
    3852              : #ifdef _WIN32
    3853              :   unsigned long on = 1;
    3854              :   ioctlsocket(sock, FIONBIO, &on);
    3855              : #else
    3856            0 :   int flags = fcntl(sock, F_GETFL, 0);
    3857            0 :   fcntl(sock, F_SETFL, flags | O_NONBLOCK);
    3858              : #endif
    3859            0 : }
    3860              : 
    3861            0 : static int mg_is_error(void) {
    3862            0 :   int err = mg_get_errno();
    3863            0 :   return err != EINPROGRESS && err != EWOULDBLOCK
    3864              : #ifndef WINCE
    3865            0 :          && err != EAGAIN && err != EINTR
    3866              : #endif
    3867              : #ifdef _WIN32
    3868              :          && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK
    3869              : #endif
    3870              :       ;
    3871              : }
    3872              : 
    3873            0 : void mg_socket_if_connect_tcp(struct mg_connection *nc,
    3874              :                               const union socket_address *sa) {
    3875            0 :   int rc, proto = 0;
    3876            0 :   nc->sock = socket(AF_INET, SOCK_STREAM, proto);
    3877            0 :   if (nc->sock == INVALID_SOCKET) {
    3878            0 :     nc->err = mg_get_errno() ? mg_get_errno() : 1;
    3879            0 :     return;
    3880              :   }
    3881              : #if !defined(MG_ESP8266)
    3882            0 :   mg_set_non_blocking_mode(nc->sock);
    3883              : #endif
    3884            0 :   rc = connect(nc->sock, &sa->sa, sizeof(sa->sin));
    3885            0 :   nc->err = rc < 0 && mg_is_error() ? mg_get_errno() : 0;
    3886            0 :   DBG(("%p sock %d rc %d errno %d err %d", nc, nc->sock, rc, mg_get_errno(),
    3887              :        nc->err));
    3888              : }
    3889              : 
    3890            0 : void mg_socket_if_connect_udp(struct mg_connection *nc) {
    3891            0 :   nc->sock = socket(AF_INET, SOCK_DGRAM, 0);
    3892            0 :   if (nc->sock == INVALID_SOCKET) {
    3893            0 :     nc->err = mg_get_errno() ? mg_get_errno() : 1;
    3894            0 :     return;
    3895              :   }
    3896            0 :   if (nc->flags & MG_F_ENABLE_BROADCAST) {
    3897            0 :     int optval = 1;
    3898            0 :     if (setsockopt(nc->sock, SOL_SOCKET, SO_BROADCAST, (const char *) &optval,
    3899            0 :                    sizeof(optval)) < 0) {
    3900            0 :       nc->err = mg_get_errno() ? mg_get_errno() : 1;
    3901            0 :       return;
    3902              :     }
    3903              :   }
    3904            0 :   nc->err = 0;
    3905              : }
    3906              : 
    3907            0 : int mg_socket_if_listen_tcp(struct mg_connection *nc,
    3908              :                             union socket_address *sa) {
    3909            0 :   int proto = 0;
    3910            0 :   sock_t sock = mg_open_listening_socket(sa, SOCK_STREAM, proto);
    3911            0 :   if (sock == INVALID_SOCKET) {
    3912            0 :     return (mg_get_errno() ? mg_get_errno() : 1);
    3913              :   }
    3914            0 :   mg_sock_set(nc, sock);
    3915            0 :   return 0;
    3916              : }
    3917              : 
    3918            0 : static int mg_socket_if_listen_udp(struct mg_connection *nc,
    3919              :                                    union socket_address *sa) {
    3920            0 :   sock_t sock = mg_open_listening_socket(sa, SOCK_DGRAM, 0);
    3921            0 :   if (sock == INVALID_SOCKET) return (mg_get_errno() ? mg_get_errno() : 1);
    3922            0 :   mg_sock_set(nc, sock);
    3923            0 :   return 0;
    3924              : }
    3925              : 
    3926            0 : static int mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf,
    3927              :                                  size_t len) {
    3928            0 :   int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0);
    3929            0 :   if (n < 0 && !mg_is_error()) n = 0;
    3930            0 :   return n;
    3931              : }
    3932              : 
    3933            0 : static int mg_socket_if_udp_send(struct mg_connection *nc, const void *buf,
    3934              :                                  size_t len) {
    3935            0 :   int n = sendto(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
    3936            0 :   if (n < 0 && !mg_is_error()) n = 0;
    3937            0 :   return n;
    3938              : }
    3939              : 
    3940            0 : static int mg_socket_if_tcp_recv(struct mg_connection *nc, void *buf,
    3941              :                                  size_t len) {
    3942            0 :   int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0);
    3943            0 :   if (n == 0) {
    3944              :     /* Orderly shutdown of the socket, try flushing output. */
    3945            0 :     nc->flags |= MG_F_SEND_AND_CLOSE;
    3946            0 :   } else if (n < 0 && !mg_is_error()) {
    3947            0 :     n = 0;
    3948              :   }
    3949            0 :   return n;
    3950              : }
    3951              : 
    3952            0 : static int mg_socket_if_udp_recv(struct mg_connection *nc, void *buf,
    3953              :                                  size_t len, union socket_address *sa,
    3954              :                                  size_t *sa_len) {
    3955            0 :   socklen_t sa_len_st = *sa_len;
    3956            0 :   int n = recvfrom(nc->sock, buf, len, 0, &sa->sa, &sa_len_st);
    3957            0 :   *sa_len = sa_len_st;
    3958            0 :   if (n < 0 && !mg_is_error()) n = 0;
    3959            0 :   return n;
    3960              : }
    3961              : 
    3962            0 : int mg_socket_if_create_conn(struct mg_connection *nc) {
    3963              :   (void) nc;
    3964            0 :   return 1;
    3965              : }
    3966              : 
    3967            0 : void mg_socket_if_destroy_conn(struct mg_connection *nc) {
    3968            0 :   if (nc->sock == INVALID_SOCKET) return;
    3969            0 :   if (!(nc->flags & MG_F_UDP)) {
    3970            0 :     closesocket(nc->sock);
    3971              :   } else {
    3972              :     /* Only close outgoing UDP sockets or listeners. */
    3973            0 :     if (nc->listener == NULL) closesocket(nc->sock);
    3974              :   }
    3975            0 :   nc->sock = INVALID_SOCKET;
    3976              : }
    3977              : 
    3978            0 : static int mg_accept_conn(struct mg_connection *lc) {
    3979              :   struct mg_connection *nc;
    3980              :   union socket_address sa;
    3981            0 :   socklen_t sa_len = sizeof(sa);
    3982              :   /* NOTE(lsm): on Windows, sock is always > FD_SETSIZE */
    3983            0 :   sock_t sock = accept(lc->sock, &sa.sa, &sa_len);
    3984            0 :   if (sock == INVALID_SOCKET) {
    3985            0 :     if (mg_is_error()) {
    3986            0 :       DBG(("%p: failed to accept: %d", lc, mg_get_errno()));
    3987              :     }
    3988            0 :     return 0;
    3989              :   }
    3990            0 :   nc = mg_if_accept_new_conn(lc);
    3991            0 :   if (nc == NULL) {
    3992            0 :     closesocket(sock);
    3993            0 :     return 0;
    3994              :   }
    3995            0 :   DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
    3996              :        ntohs(sa.sin.sin_port)));
    3997            0 :   mg_sock_set(nc, sock);
    3998            0 :   mg_if_accept_tcp_cb(nc, &sa, sa_len);
    3999            0 :   return 1;
    4000              : }
    4001              : 
    4002              : /* 'sa' must be an initialized address to bind to */
    4003            0 : static sock_t mg_open_listening_socket(union socket_address *sa, int type,
    4004              :                                        int proto) {
    4005            0 :   socklen_t sa_len =
    4006            0 :       (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
    4007            0 :   sock_t sock = INVALID_SOCKET;
    4008              : #if !MG_LWIP
    4009            0 :   int on = 1;
    4010              : #endif
    4011              : 
    4012            0 :   if ((sock = socket(sa->sa.sa_family, type, proto)) != INVALID_SOCKET &&
    4013              : #if !MG_LWIP /* LWIP doesn't support either */
    4014              : #if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
    4015              :       /* "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" http://goo.gl/RmrFTm */
    4016              :       !setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
    4017              :                   sizeof(on)) &&
    4018              : #endif
    4019              : 
    4020              : #if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
    4021              :       /*
    4022              :        * SO_RESUSEADDR is not enabled on Windows because the semantics of
    4023              :        * SO_REUSEADDR on UNIX and Windows is different. On Windows,
    4024              :        * SO_REUSEADDR allows to bind a socket to a port without error even if
    4025              :        * the port is already open by another program. This is not the behavior
    4026              :        * SO_REUSEADDR was designed for, and leads to hard-to-track failure
    4027              :        * scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
    4028              :        * SO_EXCLUSIVEADDRUSE is supported and set on a socket.
    4029              :        */
    4030            0 :       !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
    4031              : #endif
    4032              : #endif /* !MG_LWIP */
    4033              : 
    4034            0 :       !bind(sock, &sa->sa, sa_len) &&
    4035            0 :       (type == SOCK_DGRAM || listen(sock, SOMAXCONN) == 0)) {
    4036              : #if !MG_LWIP
    4037            0 :     mg_set_non_blocking_mode(sock);
    4038              :     /* In case port was set to 0, get the real port number */
    4039            0 :     (void) getsockname(sock, &sa->sa, &sa_len);
    4040              : #endif
    4041            0 :   } else if (sock != INVALID_SOCKET) {
    4042            0 :     closesocket(sock);
    4043            0 :     sock = INVALID_SOCKET;
    4044              :   }
    4045              : 
    4046            0 :   return sock;
    4047              : }
    4048              : 
    4049              : #define _MG_F_FD_CAN_READ 1
    4050              : #define _MG_F_FD_CAN_WRITE 1 << 1
    4051              : #define _MG_F_FD_ERROR 1 << 2
    4052              : 
    4053            0 : void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
    4054            0 :   int worth_logging =
    4055            0 :       fd_flags != 0 || (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE));
    4056            0 :   if (worth_logging) {
    4057            0 :     DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
    4058              :          fd_flags, nc->flags, (int) nc->recv_mbuf.len,
    4059              :          (int) nc->send_mbuf.len));
    4060              :   }
    4061              : 
    4062            0 :   if (!mg_if_poll(nc, now)) return;
    4063              : 
    4064            0 :   if (nc->flags & MG_F_CONNECTING) {
    4065            0 :     if (fd_flags != 0) {
    4066            0 :       int err = 0;
    4067              : #if !defined(MG_ESP8266)
    4068            0 :       if (!(nc->flags & MG_F_UDP)) {
    4069            0 :         socklen_t len = sizeof(err);
    4070              :         int ret =
    4071            0 :             getsockopt(nc->sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len);
    4072            0 :         if (ret != 0) {
    4073            0 :           err = 1;
    4074            0 :         } else if (err == EAGAIN || err == EWOULDBLOCK) {
    4075            0 :           err = 0;
    4076              :         }
    4077              :       }
    4078              : #else
    4079              :       /*
    4080              :        * On ESP8266 we use blocking connect.
    4081              :        */
    4082              :       err = nc->err;
    4083              : #endif
    4084            0 :       mg_if_connect_cb(nc, err);
    4085            0 :     } else if (nc->err != 0) {
    4086            0 :       mg_if_connect_cb(nc, nc->err);
    4087              :     }
    4088              :   }
    4089              : 
    4090            0 :   if (fd_flags & _MG_F_FD_CAN_READ) {
    4091            0 :     if (nc->flags & MG_F_UDP) {
    4092            0 :       mg_if_can_recv_cb(nc);
    4093              :     } else {
    4094            0 :       if (nc->flags & MG_F_LISTENING) {
    4095              :         /*
    4096              :          * We're not looping here, and accepting just one connection at
    4097              :          * a time. The reason is that eCos does not respect non-blocking
    4098              :          * flag on a listening socket and hangs in a loop.
    4099              :          */
    4100            0 :         mg_accept_conn(nc);
    4101              :       } else {
    4102            0 :         mg_if_can_recv_cb(nc);
    4103              :       }
    4104              :     }
    4105              :   }
    4106              : 
    4107            0 :   if (fd_flags & _MG_F_FD_CAN_WRITE) mg_if_can_send_cb(nc);
    4108              : 
    4109            0 :   if (worth_logging) {
    4110            0 :     DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
    4111              :          nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
    4112              :   }
    4113              : }
    4114              : 
    4115              : #if MG_ENABLE_BROADCAST
    4116            0 : static void mg_mgr_handle_ctl_sock(struct mg_mgr *mgr) {
    4117              :   struct ctl_msg ctl_msg;
    4118              :   int len =
    4119            0 :       (int) MG_RECV_FUNC(mgr->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0);
    4120            0 :   DBG(("read %d from ctl socket", len));
    4121            0 :   if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) {
    4122              :     struct mg_connection *nc;
    4123            0 :     for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
    4124            0 :       ctl_msg.callback(nc, MG_EV_POLL,
    4125              :                        ctl_msg.message MG_UD_ARG(nc->user_data));
    4126              :     }
    4127              :   }
    4128              :   // change from original mongoose code: send the reply message
    4129              :   // after we finished processing the broadcast message. K.O.
    4130            0 :   size_t dummy = MG_SEND_FUNC(mgr->ctl[1], ctl_msg.message, 1, 0);
    4131              :   (void) dummy; /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 */
    4132            0 : }
    4133              : #endif
    4134              : 
    4135              : /* Associate a socket to a connection. */
    4136            0 : void mg_socket_if_sock_set(struct mg_connection *nc, sock_t sock) {
    4137            0 :   mg_set_non_blocking_mode(sock);
    4138            0 :   mg_set_close_on_exec(sock);
    4139            0 :   nc->sock = sock;
    4140            0 :   DBG(("%p %d", nc, sock));
    4141            0 : }
    4142              : 
    4143            0 : void mg_socket_if_init(struct mg_iface *iface) {
    4144              :   (void) iface;
    4145            0 :   DBG(("%p using select()", iface->mgr));
    4146              : #if MG_ENABLE_BROADCAST
    4147            0 :   mg_socketpair(iface->mgr->ctl, SOCK_DGRAM);
    4148              : #endif
    4149            0 : }
    4150              : 
    4151            0 : void mg_socket_if_free(struct mg_iface *iface) {
    4152              :   (void) iface;
    4153            0 : }
    4154              : 
    4155            0 : void mg_socket_if_add_conn(struct mg_connection *nc) {
    4156              :   (void) nc;
    4157            0 : }
    4158              : 
    4159            0 : void mg_socket_if_remove_conn(struct mg_connection *nc) {
    4160              :   (void) nc;
    4161            0 : }
    4162              : 
    4163            0 : void mg_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
    4164            0 :   if (sock != INVALID_SOCKET
    4165              : #ifdef __unix__
    4166            0 :       && sock < (sock_t) FD_SETSIZE
    4167              : #endif
    4168              :       ) {
    4169            0 :     FD_SET(sock, set);
    4170            0 :     if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
    4171            0 :       *max_fd = sock;
    4172              :     }
    4173              :   }
    4174            0 : }
    4175              : 
    4176            0 : time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) {
    4177            0 :   struct mg_mgr *mgr = iface->mgr;
    4178            0 :   double now = mg_time();
    4179              :   double min_timer;
    4180              :   struct mg_connection *nc, *tmp;
    4181              :   struct timeval tv;
    4182              :   fd_set read_set, write_set, err_set;
    4183            0 :   sock_t max_fd = INVALID_SOCKET;
    4184            0 :   int num_fds, num_ev, num_timers = 0;
    4185              : #ifdef __unix__
    4186            0 :   int try_dup = 1;
    4187              : #endif
    4188              : 
    4189            0 :   FD_ZERO(&read_set);
    4190            0 :   FD_ZERO(&write_set);
    4191            0 :   FD_ZERO(&err_set);
    4192              : #if MG_ENABLE_BROADCAST
    4193            0 :   mg_add_to_set(mgr->ctl[1], &read_set, &max_fd);
    4194              : #endif
    4195              : 
    4196              :   /*
    4197              :    * Note: it is ok to have connections with sock == INVALID_SOCKET in the list,
    4198              :    * e.g. timer-only "connections".
    4199              :    */
    4200            0 :   min_timer = 0;
    4201            0 :   for (nc = mgr->active_connections, num_fds = 0; nc != NULL; nc = tmp) {
    4202            0 :     tmp = nc->next;
    4203              : 
    4204            0 :     if (nc->sock != INVALID_SOCKET) {
    4205            0 :       num_fds++;
    4206              : 
    4207              : #ifdef __unix__
    4208              :       /* A hack to make sure all our file descriptos fit into FD_SETSIZE. */
    4209            0 :       if (nc->sock >= (sock_t) FD_SETSIZE && try_dup) {
    4210            0 :         int new_sock = dup(nc->sock);
    4211            0 :         if (new_sock >= 0) {
    4212            0 :           if (new_sock < (sock_t) FD_SETSIZE) {
    4213            0 :             closesocket(nc->sock);
    4214            0 :             DBG(("new sock %d -> %d", nc->sock, new_sock));
    4215            0 :             nc->sock = new_sock;
    4216              :           } else {
    4217            0 :             closesocket(new_sock);
    4218            0 :             DBG(("new sock is still larger than FD_SETSIZE, disregard"));
    4219            0 :             try_dup = 0;
    4220              :           }
    4221              :         } else {
    4222            0 :           try_dup = 0;
    4223              :         }
    4224              :       }
    4225              : #endif
    4226              : 
    4227            0 :       if (nc->recv_mbuf.len < nc->recv_mbuf_limit &&
    4228            0 :           (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
    4229            0 :         mg_add_to_set(nc->sock, &read_set, &max_fd);
    4230              :       }
    4231              : 
    4232            0 :       if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) ||
    4233            0 :           (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) {
    4234            0 :         mg_add_to_set(nc->sock, &write_set, &max_fd);
    4235            0 :         mg_add_to_set(nc->sock, &err_set, &max_fd);
    4236              :       }
    4237              :     }
    4238              : 
    4239            0 :     if (nc->ev_timer_time > 0) {
    4240            0 :       if (num_timers == 0 || nc->ev_timer_time < min_timer) {
    4241            0 :         min_timer = nc->ev_timer_time;
    4242              :       }
    4243            0 :       num_timers++;
    4244              :     }
    4245              :   }
    4246              : 
    4247              :   /*
    4248              :    * If there is a timer to be fired earlier than the requested timeout,
    4249              :    * adjust the timeout.
    4250              :    */
    4251            0 :   if (num_timers > 0) {
    4252            0 :     double timer_timeout_ms = (min_timer - mg_time()) * 1000 + 1 /* rounding */;
    4253            0 :     if (timer_timeout_ms < timeout_ms) {
    4254            0 :       timeout_ms = (int) timer_timeout_ms;
    4255              :     }
    4256              :   }
    4257            0 :   if (timeout_ms < 0) timeout_ms = 0;
    4258              : 
    4259            0 :   tv.tv_sec = timeout_ms / 1000;
    4260            0 :   tv.tv_usec = (timeout_ms % 1000) * 1000;
    4261              : 
    4262            0 :   num_ev = select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv);
    4263            0 :   now = mg_time();
    4264              : #if 0
    4265              :   DBG(("select @ %ld num_ev=%d of %d, timeout=%d", (long) now, num_ev, num_fds,
    4266              :        timeout_ms));
    4267              : #endif
    4268              : 
    4269              : #if MG_ENABLE_BROADCAST
    4270            0 :   if (num_ev > 0 && mgr->ctl[1] != INVALID_SOCKET &&
    4271            0 :       FD_ISSET(mgr->ctl[1], &read_set)) {
    4272            0 :     mg_mgr_handle_ctl_sock(mgr);
    4273              :   }
    4274              : #endif
    4275              : 
    4276            0 :   for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
    4277            0 :     int fd_flags = 0;
    4278            0 :     if (nc->sock != INVALID_SOCKET) {
    4279            0 :       if (num_ev > 0) {
    4280            0 :         fd_flags = (FD_ISSET(nc->sock, &read_set) &&
    4281            0 :                             (!(nc->flags & MG_F_UDP) || nc->listener == NULL)
    4282            0 :                         ? _MG_F_FD_CAN_READ
    4283            0 :                         : 0) |
    4284            0 :                    (FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE : 0) |
    4285            0 :                    (FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0);
    4286              :       }
    4287              : #if MG_LWIP
    4288              :       /* With LWIP socket emulation layer, we don't get write events for UDP */
    4289              :       if ((nc->flags & MG_F_UDP) && nc->listener == NULL) {
    4290              :         fd_flags |= _MG_F_FD_CAN_WRITE;
    4291              :       }
    4292              : #endif
    4293              :     }
    4294            0 :     tmp = nc->next;
    4295            0 :     mg_mgr_handle_conn(nc, fd_flags, now);
    4296              :   }
    4297              : 
    4298            0 :   return (time_t) now;
    4299              : }
    4300              : 
    4301              : #if MG_ENABLE_BROADCAST
    4302            0 : MG_INTERNAL void mg_socketpair_close(sock_t *sock) {
    4303              :   while (1) {
    4304            0 :     if (closesocket(*sock) == -1 && errno == EINTR) continue;
    4305            0 :     break;
    4306              :   }
    4307            0 :   *sock = INVALID_SOCKET;
    4308            0 : }
    4309              : 
    4310              : MG_INTERNAL sock_t
    4311            0 : mg_socketpair_accept(sock_t sock, union socket_address *sa, socklen_t sa_len) {
    4312              :   sock_t rc;
    4313              :   while (1) {
    4314            0 :     if ((rc = accept(sock, &sa->sa, &sa_len)) == INVALID_SOCKET &&
    4315            0 :         errno == EINTR)
    4316            0 :       continue;
    4317            0 :     break;
    4318              :   }
    4319            0 :   return rc;
    4320              : }
    4321              : 
    4322            0 : int mg_socketpair(sock_t sp[2], int sock_type) {
    4323              :   union socket_address sa, sa2;
    4324              :   sock_t sock;
    4325            0 :   socklen_t len = sizeof(sa.sin);
    4326            0 :   int ret = 0;
    4327              : 
    4328            0 :   sock = sp[0] = sp[1] = INVALID_SOCKET;
    4329              : 
    4330            0 :   (void) memset(&sa, 0, sizeof(sa));
    4331            0 :   sa.sin.sin_family = AF_INET;
    4332            0 :   sa.sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
    4333            0 :   sa2 = sa;
    4334              : 
    4335            0 :   if ((sock = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
    4336            0 :   } else if (bind(sock, &sa.sa, len) != 0) {
    4337            0 :   } else if (sock_type == SOCK_STREAM && listen(sock, 1) != 0) {
    4338            0 :   } else if (getsockname(sock, &sa.sa, &len) != 0) {
    4339            0 :   } else if ((sp[0] = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
    4340            0 :   } else if (sock_type == SOCK_STREAM && connect(sp[0], &sa.sa, len) != 0) {
    4341            0 :   } else if (sock_type == SOCK_DGRAM &&
    4342            0 :              (bind(sp[0], &sa2.sa, len) != 0 ||
    4343            0 :               getsockname(sp[0], &sa2.sa, &len) != 0 ||
    4344            0 :               connect(sp[0], &sa.sa, len) != 0 ||
    4345            0 :               connect(sock, &sa2.sa, len) != 0)) {
    4346            0 :   } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock : mg_socketpair_accept(
    4347            0 :                                                             sock, &sa, len))) ==
    4348              :              INVALID_SOCKET) {
    4349              :   } else {
    4350            0 :     mg_set_close_on_exec(sp[0]);
    4351            0 :     mg_set_close_on_exec(sp[1]);
    4352            0 :     if (sock_type == SOCK_STREAM) mg_socketpair_close(&sock);
    4353            0 :     ret = 1;
    4354              :   }
    4355              : 
    4356            0 :   if (!ret) {
    4357            0 :     if (sp[0] != INVALID_SOCKET) mg_socketpair_close(&sp[0]);
    4358            0 :     if (sp[1] != INVALID_SOCKET) mg_socketpair_close(&sp[1]);
    4359            0 :     if (sock != INVALID_SOCKET) mg_socketpair_close(&sock);
    4360              :   }
    4361              : 
    4362            0 :   return ret;
    4363              : }
    4364              : #endif /* MG_ENABLE_BROADCAST */
    4365              : 
    4366            0 : static void mg_sock_get_addr(sock_t sock, int remote,
    4367              :                              union socket_address *sa) {
    4368            0 :   socklen_t slen = sizeof(*sa);
    4369            0 :   memset(sa, 0, slen);
    4370            0 :   if (remote) {
    4371            0 :     getpeername(sock, &sa->sa, &slen);
    4372              :   } else {
    4373            0 :     getsockname(sock, &sa->sa, &slen);
    4374              :   }
    4375            0 : }
    4376              : 
    4377            0 : void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags) {
    4378              :   union socket_address sa;
    4379            0 :   mg_sock_get_addr(sock, flags & MG_SOCK_STRINGIFY_REMOTE, &sa);
    4380            0 :   mg_sock_addr_to_str(&sa, buf, len, flags);
    4381            0 : }
    4382              : 
    4383            0 : void mg_socket_if_get_conn_addr(struct mg_connection *nc, int remote,
    4384              :                                 union socket_address *sa) {
    4385            0 :   if ((nc->flags & MG_F_UDP) && remote) {
    4386            0 :     memcpy(sa, &nc->sa, sizeof(*sa));
    4387            0 :     return;
    4388              :   }
    4389            0 :   mg_sock_get_addr(nc->sock, remote, sa);
    4390              : }
    4391              : 
    4392              : /* clang-format off */
    4393              : #define MG_SOCKET_IFACE_VTABLE                                          \
    4394              :   {                                                                     \
    4395              :     mg_socket_if_init,                                                  \
    4396              :     mg_socket_if_free,                                                  \
    4397              :     mg_socket_if_add_conn,                                              \
    4398              :     mg_socket_if_remove_conn,                                           \
    4399              :     mg_socket_if_poll,                                                  \
    4400              :     mg_socket_if_listen_tcp,                                            \
    4401              :     mg_socket_if_listen_udp,                                            \
    4402              :     mg_socket_if_connect_tcp,                                           \
    4403              :     mg_socket_if_connect_udp,                                           \
    4404              :     mg_socket_if_tcp_send,                                              \
    4405              :     mg_socket_if_udp_send,                                              \
    4406              :     mg_socket_if_tcp_recv,                                              \
    4407              :     mg_socket_if_udp_recv,                                              \
    4408              :     mg_socket_if_create_conn,                                           \
    4409              :     mg_socket_if_destroy_conn,                                          \
    4410              :     mg_socket_if_sock_set,                                              \
    4411              :     mg_socket_if_get_conn_addr,                                         \
    4412              :   }
    4413              : /* clang-format on */
    4414              : 
    4415              : const struct mg_iface_vtable mg_socket_iface_vtable = MG_SOCKET_IFACE_VTABLE;
    4416              : #if MG_NET_IF == MG_NET_IF_SOCKET
    4417              : const struct mg_iface_vtable mg_default_iface_vtable = MG_SOCKET_IFACE_VTABLE;
    4418              : #endif
    4419              : 
    4420              : #endif /* MG_ENABLE_NET_IF_SOCKET */
    4421              : #ifdef MG_MODULE_LINES
    4422              : #line 1 "mongoose/src/mg_net_if_socks.c"
    4423              : #endif
    4424              : /*
    4425              :  * Copyright (c) 2014-2016 Cesanta Software Limited
    4426              :  * All rights reserved
    4427              :  */
    4428              : 
    4429              : #if MG_ENABLE_SOCKS
    4430              : 
    4431              : struct socksdata {
    4432              :   char *proxy_addr;        /* HOST:PORT of the socks5 proxy server */
    4433              :   struct mg_connection *s; /* Respective connection to the server */
    4434              :   struct mg_connection *c; /* Connection to the client */
    4435              : };
    4436              : 
    4437              : static void socks_if_disband(struct socksdata *d) {
    4438              :   LOG(LL_DEBUG, ("disbanding proxy %p %p", d->c, d->s));
    4439              :   if (d->c) {
    4440              :     d->c->flags |= MG_F_SEND_AND_CLOSE;
    4441              :     d->c->user_data = NULL;
    4442              :     d->c = NULL;
    4443              :   }
    4444              :   if (d->s) {
    4445              :     d->s->flags |= MG_F_SEND_AND_CLOSE;
    4446              :     d->s->user_data = NULL;
    4447              :     d->s = NULL;
    4448              :   }
    4449              : }
    4450              : 
    4451              : static void socks_if_relay(struct mg_connection *s) {
    4452              :   struct socksdata *d = (struct socksdata *) s->user_data;
    4453              :   if (d == NULL || d->c == NULL || !(s->flags & MG_SOCKS_CONNECT_DONE) ||
    4454              :       d->s == NULL) {
    4455              :     return;
    4456              :   }
    4457              :   if (s->recv_mbuf.len > 0) mg_if_can_recv_cb(d->c);
    4458              :   if (d->c->send_mbuf.len > 0 && s->send_mbuf.len == 0) mg_if_can_send_cb(d->c);
    4459              : }
    4460              : 
    4461              : static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) {
    4462              :   struct socksdata *d = (struct socksdata *) c->user_data;
    4463              :   if (d == NULL) return;
    4464              :   if (ev == MG_EV_CONNECT) {
    4465              :     int res = *(int *) ev_data;
    4466              :     if (res == 0) {
    4467              :       /* Send handshake to the proxy server */
    4468              :       unsigned char buf[] = {MG_SOCKS_VERSION, 1, MG_SOCKS_HANDSHAKE_NOAUTH};
    4469              :       mg_send(d->s, buf, sizeof(buf));
    4470              :       LOG(LL_DEBUG, ("Sent handshake to %s", d->proxy_addr));
    4471              :     } else {
    4472              :       LOG(LL_ERROR, ("Cannot connect to %s: %d", d->proxy_addr, res));
    4473              :       d->c->flags |= MG_F_CLOSE_IMMEDIATELY;
    4474              :     }
    4475              :   } else if (ev == MG_EV_CLOSE) {
    4476              :     socks_if_disband(d);
    4477              :   } else if (ev == MG_EV_RECV) {
    4478              :     /* Handle handshake reply */
    4479              :     if (!(c->flags & MG_SOCKS_HANDSHAKE_DONE)) {
    4480              :       /* TODO(lsm): process IPv6 too */
    4481              :       unsigned char buf[10] = {MG_SOCKS_VERSION, MG_SOCKS_CMD_CONNECT, 0,
    4482              :                                MG_SOCKS_ADDR_IPV4};
    4483              :       if (c->recv_mbuf.len < 2) return;
    4484              :       if ((unsigned char) c->recv_mbuf.buf[1] == MG_SOCKS_HANDSHAKE_FAILURE) {
    4485              :         LOG(LL_ERROR, ("Server kicked us out"));
    4486              :         socks_if_disband(d);
    4487              :         return;
    4488              :       }
    4489              :       mbuf_remove(&c->recv_mbuf, 2);
    4490              :       c->flags |= MG_SOCKS_HANDSHAKE_DONE;
    4491              : 
    4492              :       /* Send connect request */
    4493              :       memcpy(buf + 4, &d->c->sa.sin.sin_addr, 4);
    4494              :       memcpy(buf + 8, &d->c->sa.sin.sin_port, 2);
    4495              :       mg_send(c, buf, sizeof(buf));
    4496              :       LOG(LL_DEBUG, ("%p Sent connect request", c));
    4497              :     }
    4498              :     /* Process connect request */
    4499              :     if ((c->flags & MG_SOCKS_HANDSHAKE_DONE) &&
    4500              :         !(c->flags & MG_SOCKS_CONNECT_DONE)) {
    4501              :       if (c->recv_mbuf.len < 10) return;
    4502              :       if (c->recv_mbuf.buf[1] != MG_SOCKS_SUCCESS) {
    4503              :         LOG(LL_ERROR, ("Socks connection error: %d", c->recv_mbuf.buf[1]));
    4504              :         socks_if_disband(d);
    4505              :         return;
    4506              :       }
    4507              :       mbuf_remove(&c->recv_mbuf, 10);
    4508              :       c->flags |= MG_SOCKS_CONNECT_DONE;
    4509              :       LOG(LL_DEBUG, ("%p Connect done %p", c, d->c));
    4510              :       mg_if_connect_cb(d->c, 0);
    4511              :     }
    4512              :     socks_if_relay(c);
    4513              :   } else if (ev == MG_EV_SEND || ev == MG_EV_POLL) {
    4514              :     socks_if_relay(c);
    4515              :   }
    4516              : }
    4517              : 
    4518              : static void mg_socks_if_connect_tcp(struct mg_connection *c,
    4519              :                                     const union socket_address *sa) {
    4520              :   struct socksdata *d = (struct socksdata *) c->iface->data;
    4521              :   d->c = c;
    4522              :   d->s = mg_connect(c->mgr, d->proxy_addr, socks_if_handler);
    4523              :   d->s->user_data = d;
    4524              :   LOG(LL_DEBUG, ("%p %s %p %p", c, d->proxy_addr, d, d->s));
    4525              :   (void) sa;
    4526              : }
    4527              : 
    4528              : static void mg_socks_if_connect_udp(struct mg_connection *c) {
    4529              :   (void) c;
    4530              : }
    4531              : 
    4532              : static int mg_socks_if_listen_tcp(struct mg_connection *c,
    4533              :                                   union socket_address *sa) {
    4534              :   (void) c;
    4535              :   (void) sa;
    4536              :   return 0;
    4537              : }
    4538              : 
    4539              : static int mg_socks_if_listen_udp(struct mg_connection *c,
    4540              :                                   union socket_address *sa) {
    4541              :   (void) c;
    4542              :   (void) sa;
    4543              :   return -1;
    4544              : }
    4545              : 
    4546              : static int mg_socks_if_tcp_send(struct mg_connection *c, const void *buf,
    4547              :                                 size_t len) {
    4548              :   int res;
    4549              :   struct socksdata *d = (struct socksdata *) c->iface->data;
    4550              :   if (d->s == NULL) return -1;
    4551              :   res = (int) mbuf_append(&d->s->send_mbuf, buf, len);
    4552              :   DBG(("%p -> %d -> %p", c, res, d->s));
    4553              :   return res;
    4554              : }
    4555              : 
    4556              : static int mg_socks_if_udp_send(struct mg_connection *c, const void *buf,
    4557              :                                 size_t len) {
    4558              :   (void) c;
    4559              :   (void) buf;
    4560              :   (void) len;
    4561              :   return -1;
    4562              : }
    4563              : 
    4564              : int mg_socks_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
    4565              :   struct socksdata *d = (struct socksdata *) c->iface->data;
    4566              :   if (d->s == NULL) return -1;
    4567              :   if (len > d->s->recv_mbuf.len) len = d->s->recv_mbuf.len;
    4568              :   if (len > 0) {
    4569              :     memcpy(buf, d->s->recv_mbuf.buf, len);
    4570              :     mbuf_remove(&d->s->recv_mbuf, len);
    4571              :   }
    4572              :   DBG(("%p <- %d <- %p", c, (int) len, d->s));
    4573              :   return len;
    4574              : }
    4575              : 
    4576              : int mg_socks_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
    4577              :                          union socket_address *sa, size_t *sa_len) {
    4578              :   (void) c;
    4579              :   (void) buf;
    4580              :   (void) len;
    4581              :   (void) sa;
    4582              :   (void) sa_len;
    4583              :   return -1;
    4584              : }
    4585              : 
    4586              : static int mg_socks_if_create_conn(struct mg_connection *c) {
    4587              :   (void) c;
    4588              :   return 1;
    4589              : }
    4590              : 
    4591              : static void mg_socks_if_destroy_conn(struct mg_connection *c) {
    4592              :   c->iface->vtable->free(c->iface);
    4593              :   MG_FREE(c->iface);
    4594              :   c->iface = NULL;
    4595              :   LOG(LL_DEBUG, ("%p", c));
    4596              : }
    4597              : 
    4598              : static void mg_socks_if_sock_set(struct mg_connection *c, sock_t sock) {
    4599              :   (void) c;
    4600              :   (void) sock;
    4601              : }
    4602              : 
    4603              : static void mg_socks_if_init(struct mg_iface *iface) {
    4604              :   (void) iface;
    4605              : }
    4606              : 
    4607              : static void mg_socks_if_free(struct mg_iface *iface) {
    4608              :   struct socksdata *d = (struct socksdata *) iface->data;
    4609              :   LOG(LL_DEBUG, ("%p", iface));
    4610              :   if (d != NULL) {
    4611              :     socks_if_disband(d);
    4612              :     MG_FREE(d->proxy_addr);
    4613              :     MG_FREE(d);
    4614              :     iface->data = NULL;
    4615              :   }
    4616              : }
    4617              : 
    4618              : static void mg_socks_if_add_conn(struct mg_connection *c) {
    4619              :   c->sock = INVALID_SOCKET;
    4620              : }
    4621              : 
    4622              : static void mg_socks_if_remove_conn(struct mg_connection *c) {
    4623              :   (void) c;
    4624              : }
    4625              : 
    4626              : static time_t mg_socks_if_poll(struct mg_iface *iface, int timeout_ms) {
    4627              :   LOG(LL_DEBUG, ("%p", iface));
    4628              :   (void) iface;
    4629              :   (void) timeout_ms;
    4630              :   return (time_t) cs_time();
    4631              : }
    4632              : 
    4633              : static void mg_socks_if_get_conn_addr(struct mg_connection *c, int remote,
    4634              :                                       union socket_address *sa) {
    4635              :   LOG(LL_DEBUG, ("%p", c));
    4636              :   (void) c;
    4637              :   (void) remote;
    4638              :   (void) sa;
    4639              : }
    4640              : 
    4641              : const struct mg_iface_vtable mg_socks_iface_vtable = {
    4642              :     mg_socks_if_init,          mg_socks_if_free,
    4643              :     mg_socks_if_add_conn,      mg_socks_if_remove_conn,
    4644              :     mg_socks_if_poll,          mg_socks_if_listen_tcp,
    4645              :     mg_socks_if_listen_udp,    mg_socks_if_connect_tcp,
    4646              :     mg_socks_if_connect_udp,   mg_socks_if_tcp_send,
    4647              :     mg_socks_if_udp_send,      mg_socks_if_tcp_recv,
    4648              :     mg_socks_if_udp_recv,      mg_socks_if_create_conn,
    4649              :     mg_socks_if_destroy_conn,  mg_socks_if_sock_set,
    4650              :     mg_socks_if_get_conn_addr,
    4651              : };
    4652              : 
    4653              : struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) {
    4654              :   struct mg_iface *iface = mg_if_create_iface(&mg_socks_iface_vtable, mgr);
    4655              :   iface->data = MG_CALLOC(1, sizeof(struct socksdata));
    4656              :   ((struct socksdata *) iface->data)->proxy_addr = strdup(proxy_addr);
    4657              :   return iface;
    4658              : }
    4659              : 
    4660              : #endif
    4661              : #ifdef MG_MODULE_LINES
    4662              : #line 1 "mongoose/src/mg_ssl_if_openssl.c"
    4663              : #endif
    4664              : /*
    4665              :  * Copyright (c) 2014-2016 Cesanta Software Limited
    4666              :  * All rights reserved
    4667              :  */
    4668              : 
    4669              : #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_OPENSSL
    4670              : 
    4671              : #ifdef __APPLE__
    4672              : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    4673              : #endif
    4674              : 
    4675              : #include <openssl/ssl.h>
    4676              : #ifndef KR_VERSION
    4677              : #include <openssl/tls1.h>
    4678              : #endif
    4679              : 
    4680              : struct mg_ssl_if_ctx {
    4681              :   SSL *ssl;
    4682              :   SSL_CTX *ssl_ctx;
    4683              :   struct mbuf psk;
    4684              :   size_t identity_len;
    4685              : };
    4686              : 
    4687              : void mg_ssl_if_init() {
    4688              :   SSL_library_init();
    4689              : }
    4690              : 
    4691              : enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc,
    4692              :                                             struct mg_connection *lc) {
    4693              :   struct mg_ssl_if_ctx *ctx =
    4694              :       (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
    4695              :   struct mg_ssl_if_ctx *lc_ctx = (struct mg_ssl_if_ctx *) lc->ssl_if_data;
    4696              :   nc->ssl_if_data = ctx;
    4697              :   if (ctx == NULL || lc_ctx == NULL) return MG_SSL_ERROR;
    4698              :   ctx->ssl_ctx = lc_ctx->ssl_ctx;
    4699              :   if ((ctx->ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
    4700              :     return MG_SSL_ERROR;
    4701              :   }
    4702              :   return MG_SSL_OK;
    4703              : }
    4704              : 
    4705              : static enum mg_ssl_if_result mg_use_cert(SSL_CTX *ctx, const char *cert,
    4706              :                                          const char *key, const char **err_msg);
    4707              : static enum mg_ssl_if_result mg_use_ca_cert(SSL_CTX *ctx, const char *cert);
    4708              : static enum mg_ssl_if_result mg_set_cipher_list(SSL_CTX *ctx, const char *cl);
    4709              : static enum mg_ssl_if_result mg_ssl_if_ossl_set_psk(struct mg_ssl_if_ctx *ctx,
    4710              :                                                     const char *identity,
    4711              :                                                     const char *key_str);
    4712              : 
    4713              : enum mg_ssl_if_result mg_ssl_if_conn_init(
    4714              :     struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
    4715              :     const char **err_msg) {
    4716              :   struct mg_ssl_if_ctx *ctx =
    4717              :       (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
    4718              :   DBG(("%p %s,%s,%s", nc, (params->cert ? params->cert : ""),
    4719              :        (params->key ? params->key : ""),
    4720              :        (params->ca_cert ? params->ca_cert : "")));
    4721              :   if (ctx == NULL) {
    4722              :     MG_SET_PTRPTR(err_msg, "Out of memory");
    4723              :     return MG_SSL_ERROR;
    4724              :   }
    4725              :   nc->ssl_if_data = ctx;
    4726              :   if (nc->flags & MG_F_LISTENING) {
    4727              :     ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
    4728              :   } else {
    4729              :     ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
    4730              :   }
    4731              :   if (ctx->ssl_ctx == NULL) {
    4732              :     MG_SET_PTRPTR(err_msg, "Failed to create SSL context");
    4733              :     return MG_SSL_ERROR;
    4734              :   }
    4735              : 
    4736              : #ifndef KR_VERSION
    4737              :   /* Disable deprecated protocols. */
    4738              :   SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
    4739              :   SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3);
    4740              :   SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
    4741              : #ifdef MG_SSL_OPENSSL_NO_COMPRESSION
    4742              :   SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_COMPRESSION);
    4743              : #endif
    4744              : #ifdef MG_SSL_OPENSSL_CIPHER_SERVER_PREFERENCE
    4745              :   SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
    4746              : #endif
    4747              : #else
    4748              : /* Krypton only supports TLSv1.2 anyway. */
    4749              : #endif
    4750              : 
    4751              :   if (params->cert != NULL &&
    4752              :       mg_use_cert(ctx->ssl_ctx, params->cert, params->key, err_msg) !=
    4753              :           MG_SSL_OK) {
    4754              :     return MG_SSL_ERROR;
    4755              :   }
    4756              : 
    4757              :   if (params->ca_cert != NULL &&
    4758              :       mg_use_ca_cert(ctx->ssl_ctx, params->ca_cert) != MG_SSL_OK) {
    4759              :     MG_SET_PTRPTR(err_msg, "Invalid SSL CA cert");
    4760              :     return MG_SSL_ERROR;
    4761              :   }
    4762              : 
    4763              :   if (mg_set_cipher_list(ctx->ssl_ctx, params->cipher_suites) != MG_SSL_OK) {
    4764              :     MG_SET_PTRPTR(err_msg, "Invalid cipher suite list");
    4765              :     return MG_SSL_ERROR;
    4766              :   }
    4767              : 
    4768              :   mbuf_init(&ctx->psk, 0);
    4769              :   if (mg_ssl_if_ossl_set_psk(ctx, params->psk_identity, params->psk_key) !=
    4770              :       MG_SSL_OK) {
    4771              :     MG_SET_PTRPTR(err_msg, "Invalid PSK settings");
    4772              :     return MG_SSL_ERROR;
    4773              :   }
    4774              : 
    4775              :   if (!(nc->flags & MG_F_LISTENING) &&
    4776              :       (ctx->ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
    4777              :     MG_SET_PTRPTR(err_msg, "Failed to create SSL session");
    4778              :     return MG_SSL_ERROR;
    4779              :   }
    4780              : 
    4781              :   if (params->server_name != NULL) {
    4782              : #ifdef KR_VERSION
    4783              :     SSL_CTX_kr_set_verify_name(ctx->ssl_ctx, params->server_name);
    4784              : #else
    4785              :     SSL_set_tlsext_host_name(ctx->ssl, params->server_name);
    4786              : #endif
    4787              :   }
    4788              : 
    4789              :   nc->flags |= MG_F_SSL;
    4790              : 
    4791              :   return MG_SSL_OK;
    4792              : }
    4793              : 
    4794              : static enum mg_ssl_if_result mg_ssl_if_ssl_err(struct mg_connection *nc,
    4795              :                                                int res) {
    4796              :   struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
    4797              :   int err = SSL_get_error(ctx->ssl, res);
    4798              :   if (err == SSL_ERROR_WANT_READ) return MG_SSL_WANT_READ;
    4799              :   if (err == SSL_ERROR_WANT_WRITE) return MG_SSL_WANT_WRITE;
    4800              :   DBG(("%p %p SSL error: %d %d", nc, ctx->ssl_ctx, res, err));
    4801              :   nc->err = err;
    4802              :   return MG_SSL_ERROR;
    4803              : }
    4804              : 
    4805              : enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
    4806              :   struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
    4807              :   int server_side = (nc->listener != NULL);
    4808              :   int res;
    4809              :   /* If descriptor is not yet set, do it now. */
    4810              :   if (SSL_get_fd(ctx->ssl) < 0) {
    4811              :     if (SSL_set_fd(ctx->ssl, nc->sock) != 1) return MG_SSL_ERROR;
    4812              :   }
    4813              :   res = server_side ? SSL_accept(ctx->ssl) : SSL_connect(ctx->ssl);
    4814              :   if (res != 1) return mg_ssl_if_ssl_err(nc, res);
    4815              :   return MG_SSL_OK;
    4816              : }
    4817              : 
    4818              : int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t buf_size) {
    4819              :   struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
    4820              :   int n = SSL_read(ctx->ssl, buf, buf_size);
    4821              :   DBG(("%p %d -> %d", nc, (int) buf_size, n));
    4822              :   if (n < 0) return mg_ssl_if_ssl_err(nc, n);
    4823              :   if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    4824              :   return n;
    4825              : }
    4826              : 
    4827              : int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len) {
    4828              :   struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
    4829              :   int n = SSL_write(ctx->ssl, data, len);
    4830              :   DBG(("%p %d -> %d", nc, (int) len, n));
    4831              :   if (n <= 0) return mg_ssl_if_ssl_err(nc, n);
    4832              :   return n;
    4833              : }
    4834              : 
    4835              : void mg_ssl_if_conn_close_notify(struct mg_connection *nc) {
    4836              :   struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
    4837              :   if (ctx == NULL) return;
    4838              :   SSL_shutdown(ctx->ssl);
    4839              : }
    4840              : 
    4841              : void mg_ssl_if_conn_free(struct mg_connection *nc) {
    4842              :   struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
    4843              :   if (ctx == NULL) return;
    4844              :   nc->ssl_if_data = NULL;
    4845              :   if (ctx->ssl != NULL) SSL_free(ctx->ssl);
    4846              :   if (ctx->ssl_ctx != NULL && nc->listener == NULL) SSL_CTX_free(ctx->ssl_ctx);
    4847              :   mbuf_free(&ctx->psk);
    4848              :   memset(ctx, 0, sizeof(*ctx));
    4849              :   MG_FREE(ctx);
    4850              : }
    4851              : 
    4852              : /*
    4853              :  * Cipher suite options used for TLS negotiation.
    4854              :  * https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations
    4855              :  */
    4856              : static const char mg_s_cipher_list[] =
    4857              : #if defined(MG_SSL_CRYPTO_MODERN)
    4858              :     "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:"
    4859              :     "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:"
    4860              :     "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
    4861              :     "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
    4862              :     "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
    4863              :     "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
    4864              :     "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
    4865              :     "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:"
    4866              :     "!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
    4867              : #elif defined(MG_SSL_CRYPTO_OLD)
    4868              :     "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
    4869              :     "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
    4870              :     "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
    4871              :     "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
    4872              :     "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
    4873              :     "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
    4874              :     "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
    4875              :     "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:"
    4876              :     "ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
    4877              :     "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:"
    4878              :     "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
    4879              :     "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
    4880              : #else /* Default - intermediate. */
    4881              :     "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
    4882              :     "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
    4883              :     "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
    4884              :     "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
    4885              :     "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
    4886              :     "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
    4887              :     "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
    4888              :     "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
    4889              :     "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:"
    4890              :     "DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
    4891              :     "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:"
    4892              :     "!CAMELLIA:"
    4893              :     "!RSA:"
    4894              :     "!DES:"
    4895              :     "!3DES"
    4896              :     //TLS_RSA_WITH_AES_128_CBC_SHA256
    4897              : #endif
    4898              :     ;
    4899              : 
    4900              : /*
    4901              :  * Default DH params for PFS cipher negotiation. This is a 2048-bit group.
    4902              :  * Will be used if none are provided by the user in the certificate file.
    4903              :  */
    4904              : #if !MG_DISABLE_PFS && !defined(KR_VERSION)
    4905              : static const char mg_s_default_dh_params[] =
    4906              :     "\
    4907              : -----BEGIN DH PARAMETERS-----\n\
    4908              : MIIBCAKCAQEAlvbgD/qh9znWIlGFcV0zdltD7rq8FeShIqIhkQ0C7hYFThrBvF2E\n\
    4909              : Z9bmgaP+sfQwGpVlv9mtaWjvERbu6mEG7JTkgmVUJrUt/wiRzwTaCXBqZkdUO8Tq\n\
    4910              : +E6VOEQAilstG90ikN1Tfo+K6+X68XkRUIlgawBTKuvKVwBhuvlqTGerOtnXWnrt\n\
    4911              : ym//hd3cd5PBYGBix0i7oR4xdghvfR2WLVu0LgdThTBb6XP7gLd19cQ1JuBtAajZ\n\
    4912              : wMuPn7qlUkEFDIkAZy59/Hue/H2Q2vU/JsvVhHWCQBL4F1ofEAt50il6ZxR1QfFK\n\
    4913              : 9VGKDC4oOgm9DlxwwBoC2FjqmvQlqVV3kwIBAg==\n\
    4914              : -----END DH PARAMETERS-----\n";
    4915              : #endif
    4916              : 
    4917              : static enum mg_ssl_if_result mg_use_ca_cert(SSL_CTX *ctx, const char *cert) {
    4918              :   if (cert == NULL || strcmp(cert, "*") == 0) {
    4919              :     return MG_SSL_OK;
    4920              :   }
    4921              :   SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
    4922              :   return SSL_CTX_load_verify_locations(ctx, cert, NULL) == 1 ? MG_SSL_OK
    4923              :                                                              : MG_SSL_ERROR;
    4924              : }
    4925              : 
    4926              : static enum mg_ssl_if_result mg_use_cert(SSL_CTX *ctx, const char *cert,
    4927              :                                          const char *key,
    4928              :                                          const char **err_msg) {
    4929              :   if (key == NULL) key = cert;
    4930              :   if (cert == NULL || cert[0] == '\0' || key == NULL || key[0] == '\0') {
    4931              :     return MG_SSL_OK;
    4932              :   } else if (SSL_CTX_use_certificate_file(ctx, cert, 1) == 0) {
    4933              :     MG_SET_PTRPTR(err_msg, "Invalid SSL cert");
    4934              :     return MG_SSL_ERROR;
    4935              :   } else if (SSL_CTX_use_PrivateKey_file(ctx, key, 1) == 0) {
    4936              :     MG_SET_PTRPTR(err_msg, "Invalid SSL key");
    4937              :     return MG_SSL_ERROR;
    4938              :   } else if (SSL_CTX_use_certificate_chain_file(ctx, cert) == 0) {
    4939              :     MG_SET_PTRPTR(err_msg, "Invalid CA bundle");
    4940              :     return MG_SSL_ERROR;
    4941              :   } else {
    4942              :     SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
    4943              : #if !MG_DISABLE_PFS && !defined(KR_VERSION)
    4944              :     BIO *bio = NULL;
    4945              :     DH *dh = NULL;
    4946              : 
    4947              :     /* Try to read DH parameters from the cert/key file. */
    4948              :     bio = BIO_new_file(cert, "r");
    4949              :     if (bio != NULL) {
    4950              :       dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
    4951              :       BIO_free(bio);
    4952              :     }
    4953              :     /*
    4954              :      * If there are no DH params in the file, fall back to hard-coded ones.
    4955              :      * Not ideal, but better than nothing.
    4956              :      */
    4957              :     if (dh == NULL) {
    4958              :       bio = BIO_new_mem_buf((void *) mg_s_default_dh_params, -1);
    4959              :       dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
    4960              :       BIO_free(bio);
    4961              :     }
    4962              :     if (dh != NULL) {
    4963              :       SSL_CTX_set_tmp_dh(ctx, dh);
    4964              :       SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
    4965              :       DH_free(dh);
    4966              :     }
    4967              : #if OPENSSL_VERSION_NUMBER > 0x10002000L
    4968              :     SSL_CTX_set_ecdh_auto(ctx, 1);
    4969              : #endif
    4970              : #endif
    4971              :   }
    4972              :   return MG_SSL_OK;
    4973              : }
    4974              : 
    4975              : static enum mg_ssl_if_result mg_set_cipher_list(SSL_CTX *ctx, const char *cl) {
    4976              :   return (SSL_CTX_set_cipher_list(ctx, cl ? cl : mg_s_cipher_list) == 1
    4977              :               ? MG_SSL_OK
    4978              :               : MG_SSL_ERROR);
    4979              : }
    4980              : 
    4981              : #if !defined(KR_VERSION) && !defined(LIBRESSL_VERSION_NUMBER)
    4982              : static unsigned int mg_ssl_if_ossl_psk_cb(SSL *ssl, const char *hint,
    4983              :                                           char *identity,
    4984              :                                           unsigned int max_identity_len,
    4985              :                                           unsigned char *psk,
    4986              :                                           unsigned int max_psk_len) {
    4987              :   struct mg_ssl_if_ctx *ctx =
    4988              :       (struct mg_ssl_if_ctx *) SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl));
    4989              :   size_t key_len = ctx->psk.len - ctx->identity_len - 1;
    4990              :   DBG(("hint: '%s'", (hint ? hint : "")));
    4991              :   if (ctx->identity_len + 1 > max_identity_len) {
    4992              :     DBG(("identity too long"));
    4993              :     return 0;
    4994              :   }
    4995              :   if (key_len > max_psk_len) {
    4996              :     DBG(("key too long"));
    4997              :     return 0;
    4998              :   }
    4999              :   memcpy(identity, ctx->psk.buf, ctx->identity_len + 1);
    5000              :   memcpy(psk, ctx->psk.buf + ctx->identity_len + 1, key_len);
    5001              :   (void) ssl;
    5002              :   return key_len;
    5003              : }
    5004              : 
    5005              : static enum mg_ssl_if_result mg_ssl_if_ossl_set_psk(struct mg_ssl_if_ctx *ctx,
    5006              :                                                     const char *identity,
    5007              :                                                     const char *key_str) {
    5008              :   unsigned char key[32];
    5009              :   size_t key_len;
    5010              :   size_t i = 0;
    5011              :   if (identity == NULL && key_str == NULL) return MG_SSL_OK;
    5012              :   if (identity == NULL || key_str == NULL) return MG_SSL_ERROR;
    5013              :   key_len = strlen(key_str);
    5014              :   if (key_len != 32 && key_len != 64) return MG_SSL_ERROR;
    5015              :   memset(key, 0, sizeof(key));
    5016              :   key_len = 0;
    5017              :   for (i = 0; key_str[i] != '\0'; i++) {
    5018              :     unsigned char c;
    5019              :     char hc = tolower((int) key_str[i]);
    5020              :     if (hc >= '0' && hc <= '9') {
    5021              :       c = hc - '0';
    5022              :     } else if (hc >= 'a' && hc <= 'f') {
    5023              :       c = hc - 'a' + 0xa;
    5024              :     } else {
    5025              :       return MG_SSL_ERROR;
    5026              :     }
    5027              :     key_len = i / 2;
    5028              :     key[key_len] <<= 4;
    5029              :     key[key_len] |= c;
    5030              :   }
    5031              :   key_len++;
    5032              :   DBG(("identity = '%s', key = (%u)", identity, (unsigned int) key_len));
    5033              :   ctx->identity_len = strlen(identity);
    5034              :   mbuf_append(&ctx->psk, identity, ctx->identity_len + 1);
    5035              :   mbuf_append(&ctx->psk, key, key_len);
    5036              :   SSL_CTX_set_psk_client_callback(ctx->ssl_ctx, mg_ssl_if_ossl_psk_cb);
    5037              :   SSL_CTX_set_app_data(ctx->ssl_ctx, ctx);
    5038              :   return MG_SSL_OK;
    5039              : }
    5040              : #else
    5041              : static enum mg_ssl_if_result mg_ssl_if_ossl_set_psk(struct mg_ssl_if_ctx *ctx,
    5042              :                                                     const char *identity,
    5043              :                                                     const char *key_str) {
    5044              :   (void) ctx;
    5045              :   (void) identity;
    5046              :   (void) key_str;
    5047              :   /* Krypton / LibreSSL does not support PSK. */
    5048              :   return MG_SSL_ERROR;
    5049              : }
    5050              : #endif /* !defined(KR_VERSION) && !defined(LIBRESSL_VERSION_NUMBER) */
    5051              : 
    5052              : const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
    5053              :                        const char *ca_cert) {
    5054              :   const char *err_msg = NULL;
    5055              :   struct mg_ssl_if_conn_params params;
    5056              :   memset(&params, 0, sizeof(params));
    5057              :   params.cert = cert;
    5058              :   params.ca_cert = ca_cert;
    5059              :   if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
    5060              :     return err_msg;
    5061              :   }
    5062              :   return NULL;
    5063              : }
    5064              : 
    5065              : #endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_OPENSSL */
    5066              : #ifdef MG_MODULE_LINES
    5067              : #line 1 "mongoose/src/mg_ssl_if_mbedtls.c"
    5068              : #endif
    5069              : /*
    5070              :  * Copyright (c) 2014-2016 Cesanta Software Limited
    5071              :  * All rights reserved
    5072              :  */
    5073              : 
    5074              : #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_MBEDTLS
    5075              : 
    5076              : #include <mbedtls/debug.h>
    5077              : #include <mbedtls/ecp.h>
    5078              : #include <mbedtls/net.h>
    5079              : #include <mbedtls/platform.h>
    5080              : #include <mbedtls/ssl.h>
    5081              : #include <mbedtls/ssl_internal.h>
    5082              : #include <mbedtls/x509_crt.h>
    5083              : #include <mbedtls/version.h>
    5084              : 
    5085              : static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line,
    5086              :                             const char *str) {
    5087              :   enum cs_log_level cs_level;
    5088              :   switch (level) {
    5089              :     case 1:
    5090              :       cs_level = LL_ERROR;
    5091              :       break;
    5092              :     case 2:
    5093              :       cs_level = LL_INFO;
    5094              :       break;
    5095              :     case 3:
    5096              :       cs_level = LL_DEBUG;
    5097              :       break;
    5098              :     default:
    5099              :       cs_level = LL_VERBOSE_DEBUG;
    5100              :   }
    5101              :   /* mbedTLS passes strings with \n at the end, strip it. */
    5102              :   LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str));
    5103              :   (void) ctx;
    5104              :   (void) str;
    5105              :   (void) file;
    5106              :   (void) line;
    5107              :   (void) cs_level;
    5108              : }
    5109              : 
    5110              : struct mg_ssl_if_ctx {
    5111              :   mbedtls_ssl_config *conf;
    5112              :   mbedtls_ssl_context *ssl;
    5113              :   mbedtls_x509_crt *cert;
    5114              :   mbedtls_pk_context *key;
    5115              :   mbedtls_x509_crt *ca_cert;
    5116              :   struct mbuf cipher_suites;
    5117              :   size_t saved_len;
    5118              : };
    5119              : 
    5120              : /* Must be provided by the platform. ctx is struct mg_connection. */
    5121              : extern int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len);
    5122              : 
    5123              : void mg_ssl_if_init() {
    5124              :   LOG(LL_INFO, ("%s", MBEDTLS_VERSION_STRING_FULL));
    5125              : }
    5126              : 
    5127              : enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc,
    5128              :                                             struct mg_connection *lc) {
    5129              :   struct mg_ssl_if_ctx *ctx =
    5130              :       (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
    5131              :   struct mg_ssl_if_ctx *lc_ctx = (struct mg_ssl_if_ctx *) lc->ssl_if_data;
    5132              :   nc->ssl_if_data = ctx;
    5133              :   if (ctx == NULL || lc_ctx == NULL) return MG_SSL_ERROR;
    5134              :   ctx->ssl = (mbedtls_ssl_context *) MG_CALLOC(1, sizeof(*ctx->ssl));
    5135              :   if (mbedtls_ssl_setup(ctx->ssl, lc_ctx->conf) != 0) {
    5136              :     return MG_SSL_ERROR;
    5137              :   }
    5138              :   return MG_SSL_OK;
    5139              : }
    5140              : 
    5141              : static enum mg_ssl_if_result mg_use_cert(struct mg_ssl_if_ctx *ctx,
    5142              :                                          const char *cert, const char *key,
    5143              :                                          const char **err_msg);
    5144              : static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
    5145              :                                             const char *cert);
    5146              : static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx,
    5147              :                                                 const char *ciphers);
    5148              : #ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
    5149              : static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx,
    5150              :                                                     const char *identity,
    5151              :                                                     const char *key);
    5152              : #endif
    5153              : 
    5154              : enum mg_ssl_if_result mg_ssl_if_conn_init(
    5155              :     struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
    5156              :     const char **err_msg) {
    5157              :   struct mg_ssl_if_ctx *ctx =
    5158              :       (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
    5159              :   DBG(("%p %s,%s,%s", nc, (params->cert ? params->cert : ""),
    5160              :        (params->key ? params->key : ""),
    5161              :        (params->ca_cert ? params->ca_cert : "")));
    5162              : 
    5163              :   if (ctx == NULL) {
    5164              :     MG_SET_PTRPTR(err_msg, "Out of memory");
    5165              :     return MG_SSL_ERROR;
    5166              :   }
    5167              :   nc->ssl_if_data = ctx;
    5168              :   ctx->conf = (mbedtls_ssl_config *) MG_CALLOC(1, sizeof(*ctx->conf));
    5169              :   mbuf_init(&ctx->cipher_suites, 0);
    5170              :   mbedtls_ssl_config_init(ctx->conf);
    5171              :   mbedtls_ssl_conf_dbg(ctx->conf, mg_ssl_mbed_log, nc);
    5172              :   if (mbedtls_ssl_config_defaults(
    5173              :           ctx->conf, (nc->flags & MG_F_LISTENING ? MBEDTLS_SSL_IS_SERVER
    5174              :                                                  : MBEDTLS_SSL_IS_CLIENT),
    5175              :           MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT) != 0) {
    5176              :     MG_SET_PTRPTR(err_msg, "Failed to init SSL config");
    5177              :     return MG_SSL_ERROR;
    5178              :   }
    5179              : 
    5180              :   /* TLS 1.2 and up */
    5181              :   mbedtls_ssl_conf_min_version(ctx->conf, MBEDTLS_SSL_MAJOR_VERSION_3,
    5182              :                                MBEDTLS_SSL_MINOR_VERSION_3);
    5183              :   mbedtls_ssl_conf_rng(ctx->conf, mg_ssl_if_mbed_random, nc);
    5184              : 
    5185              :   if (params->cert != NULL &&
    5186              :       mg_use_cert(ctx, params->cert, params->key, err_msg) != MG_SSL_OK) {
    5187              :     return MG_SSL_ERROR;
    5188              :   }
    5189              : 
    5190              :   if (params->ca_cert != NULL &&
    5191              :       mg_use_ca_cert(ctx, params->ca_cert) != MG_SSL_OK) {
    5192              :     MG_SET_PTRPTR(err_msg, "Invalid SSL CA cert");
    5193              :     return MG_SSL_ERROR;
    5194              :   }
    5195              : 
    5196              :   if (mg_set_cipher_list(ctx, params->cipher_suites) != MG_SSL_OK) {
    5197              :     MG_SET_PTRPTR(err_msg, "Invalid cipher suite list");
    5198              :     return MG_SSL_ERROR;
    5199              :   }
    5200              : 
    5201              : #ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
    5202              :   if (mg_ssl_if_mbed_set_psk(ctx, params->psk_identity, params->psk_key) !=
    5203              :       MG_SSL_OK) {
    5204              :     MG_SET_PTRPTR(err_msg, "Invalid PSK settings");
    5205              :     return MG_SSL_ERROR;
    5206              :   }
    5207              : #endif
    5208              : 
    5209              :   if (!(nc->flags & MG_F_LISTENING)) {
    5210              :     ctx->ssl = (mbedtls_ssl_context *) MG_CALLOC(1, sizeof(*ctx->ssl));
    5211              :     mbedtls_ssl_init(ctx->ssl);
    5212              :     if (mbedtls_ssl_setup(ctx->ssl, ctx->conf) != 0) {
    5213              :       MG_SET_PTRPTR(err_msg, "Failed to create SSL session");
    5214              :       return MG_SSL_ERROR;
    5215              :     }
    5216              :     if (params->server_name != NULL &&
    5217              :         mbedtls_ssl_set_hostname(ctx->ssl, params->server_name) != 0) {
    5218              :       return MG_SSL_ERROR;
    5219              :     }
    5220              :   }
    5221              : 
    5222              : #ifdef MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN
    5223              :   if (mbedtls_ssl_conf_max_frag_len(ctx->conf,
    5224              : #if MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN == 512
    5225              :                                     MBEDTLS_SSL_MAX_FRAG_LEN_512
    5226              : #elif MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN == 1024
    5227              :                                     MBEDTLS_SSL_MAX_FRAG_LEN_1024
    5228              : #elif MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN == 2048
    5229              :                                     MBEDTLS_SSL_MAX_FRAG_LEN_2048
    5230              : #elif MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN == 4096
    5231              :                                     MBEDTLS_SSL_MAX_FRAG_LEN_4096
    5232              : #else
    5233              : #error Invalid MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN
    5234              : #endif
    5235              :                                     ) != 0) {
    5236              :     return MG_SSL_ERROR;
    5237              :   }
    5238              : #endif
    5239              : 
    5240              :   nc->flags |= MG_F_SSL;
    5241              : 
    5242              :   return MG_SSL_OK;
    5243              : }
    5244              : 
    5245              : static int mg_ssl_if_mbed_send(void *ctx, const unsigned char *buf,
    5246              :                                size_t len) {
    5247              :   struct mg_connection *nc = (struct mg_connection *) ctx;
    5248              :   int n = nc->iface->vtable->tcp_send(nc, buf, len);
    5249              :   if (n > 0) return n;
    5250              :   if (n == 0) return MBEDTLS_ERR_SSL_WANT_WRITE;
    5251              :   return MBEDTLS_ERR_NET_SEND_FAILED;
    5252              : }
    5253              : 
    5254              : static int mg_ssl_if_mbed_recv(void *ctx, unsigned char *buf, size_t len) {
    5255              :   struct mg_connection *nc = (struct mg_connection *) ctx;
    5256              :   int n = nc->iface->vtable->tcp_recv(nc, buf, len);
    5257              :   if (n > 0) return n;
    5258              :   if (n == 0) return MBEDTLS_ERR_SSL_WANT_READ;
    5259              :   return MBEDTLS_ERR_NET_RECV_FAILED;
    5260              : }
    5261              : 
    5262              : static enum mg_ssl_if_result mg_ssl_if_mbed_err(struct mg_connection *nc,
    5263              :                                                 int ret) {
    5264              :   enum mg_ssl_if_result res = MG_SSL_OK;
    5265              :   if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
    5266              :     res = MG_SSL_WANT_READ;
    5267              :   } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
    5268              :     res = MG_SSL_WANT_WRITE;
    5269              :   } else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
    5270              :     LOG(LL_DEBUG, ("%p TLS connection closed by peer", nc));
    5271              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    5272              :     res = MG_SSL_OK;
    5273              :   } else if (ret == MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE) {
    5274              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    5275              :     res = MG_SSL_ERROR;
    5276              :   } else if (ret == MBEDTLS_ERR_SSL_INVALID_MAC) {
    5277              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    5278              :     res = MG_SSL_ERROR;
    5279              :   } else if (ret == MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION) {
    5280              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    5281              :     res = MG_SSL_ERROR;
    5282              :   } else if (ret == MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE) {
    5283              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    5284              :     res = MG_SSL_ERROR;
    5285              :   } else if (ret == MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN) {
    5286              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    5287              :     res = MG_SSL_ERROR;
    5288              :   } else if (ret == MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) {
    5289              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    5290              :     res = MG_SSL_ERROR;
    5291              :   } else if (ret == MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO) {
    5292              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    5293              :     res = MG_SSL_ERROR;
    5294              :   } else if (ret == MBEDTLS_ERR_NET_RECV_FAILED) {
    5295              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    5296              :     res = MG_SSL_ERROR;
    5297              :   } else {
    5298              :     LOG(LL_ERROR, ("%p mbedTLS error: -0x%04x", nc, -ret));
    5299              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    5300              :     res = MG_SSL_ERROR;
    5301              :   }
    5302              :   nc->err = ret;
    5303              :   return res;
    5304              : }
    5305              : 
    5306              : static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) {
    5307              :   if (ctx->cert != NULL) {
    5308              :     mbedtls_x509_crt_free(ctx->cert);
    5309              :     MG_FREE(ctx->cert);
    5310              :     ctx->cert = NULL;
    5311              :     mbedtls_pk_free(ctx->key);
    5312              :     MG_FREE(ctx->key);
    5313              :     ctx->key = NULL;
    5314              :   }
    5315              :   if (ctx->ca_cert != NULL) {
    5316              :     mbedtls_ssl_conf_ca_chain(ctx->conf, NULL, NULL);
    5317              : #ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
    5318              :     if (ctx->conf->ca_chain_file != NULL) {
    5319              :       MG_FREE((void *) ctx->conf->ca_chain_file);
    5320              :       ctx->conf->ca_chain_file = NULL;
    5321              :     }
    5322              : #endif
    5323              :     mbedtls_x509_crt_free(ctx->ca_cert);
    5324              :     MG_FREE(ctx->ca_cert);
    5325              :     ctx->ca_cert = NULL;
    5326              :   }
    5327              : }
    5328              : 
    5329              : enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
    5330              :   struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
    5331              :   int err;
    5332              :   /* If bio is not yet set, do it now. */
    5333              :   if (ctx->ssl->p_bio == NULL) {
    5334              :     mbedtls_ssl_set_bio(ctx->ssl, nc, mg_ssl_if_mbed_send, mg_ssl_if_mbed_recv,
    5335              :                         NULL);
    5336              :   }
    5337              :   err = mbedtls_ssl_handshake(ctx->ssl);
    5338              :   if (err != 0) return mg_ssl_if_mbed_err(nc, err);
    5339              : #ifdef MG_SSL_IF_MBEDTLS_FREE_CERTS
    5340              :   /*
    5341              :    * Free the peer certificate, we don't need it after handshake.
    5342              :    * Note that this effectively disables renegotiation.
    5343              :    */
    5344              :   mbedtls_x509_crt_free(ctx->ssl->session->peer_cert);
    5345              :   mbedtls_free(ctx->ssl->session->peer_cert);
    5346              :   ctx->ssl->session->peer_cert = NULL;
    5347              :   /* On a client connection we can also free our own and CA certs. */
    5348              :   if (nc->listener == NULL) {
    5349              :     if (ctx->conf->key_cert != NULL) {
    5350              :       /* Note that this assumes one key_cert entry, which matches our init. */
    5351              :       MG_FREE(ctx->conf->key_cert);
    5352              :       ctx->conf->key_cert = NULL;
    5353              :     }
    5354              :     mbedtls_ssl_conf_ca_chain(ctx->conf, NULL, NULL);
    5355              :     mg_ssl_if_mbed_free_certs_and_keys(ctx);
    5356              :   }
    5357              : #endif
    5358              :   return MG_SSL_OK;
    5359              : }
    5360              : 
    5361              : int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
    5362              :   struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
    5363              :   int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, len);
    5364              :   DBG(("%p %d -> %d", nc, (int) len, n));
    5365              :   if (n < 0) return mg_ssl_if_mbed_err(nc, n);
    5366              :   if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    5367              :   return n;
    5368              : }
    5369              : 
    5370              : int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
    5371              :   struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
    5372              :   /* Per mbedTLS docs, if write returns WANT_READ or WANT_WRITE, the operation
    5373              :    * should be retried with the same data and length.
    5374              :    * Here we assume that the data being pushed will remain the same but the
    5375              :    * amount may grow between calls so we save the length that was used and
    5376              :    * retry. The assumption being that the data itself won't change and won't
    5377              :    * be removed. */
    5378              :   size_t l = len;
    5379              :   if (ctx->saved_len > 0 && ctx->saved_len < l) l = ctx->saved_len;
    5380              :   int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) buf, l);
    5381              :   DBG(("%p %d,%d,%d -> %d", nc, (int) len, (int) ctx->saved_len, (int) l, n));
    5382              :   if (n < 0) {
    5383              :     if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) {
    5384              :       ctx->saved_len = len;
    5385              :     }
    5386              :     return mg_ssl_if_mbed_err(nc, n);
    5387              :   } else if (n > 0) {
    5388              :     ctx->saved_len = 0;
    5389              :   }
    5390              :   return n;
    5391              : }
    5392              : 
    5393              : void mg_ssl_if_conn_close_notify(struct mg_connection *nc) {
    5394              :   struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
    5395              :   if (ctx == NULL) return;
    5396              :   mbedtls_ssl_close_notify(ctx->ssl);
    5397              : }
    5398              : 
    5399              : void mg_ssl_if_conn_free(struct mg_connection *nc) {
    5400              :   struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
    5401              :   if (ctx == NULL) return;
    5402              :   nc->ssl_if_data = NULL;
    5403              :   if (ctx->ssl != NULL) {
    5404              :     mbedtls_ssl_free(ctx->ssl);
    5405              :     MG_FREE(ctx->ssl);
    5406              :   }
    5407              :   mg_ssl_if_mbed_free_certs_and_keys(ctx);
    5408              :   if (ctx->conf != NULL) {
    5409              :     mbedtls_ssl_config_free(ctx->conf);
    5410              :     MG_FREE(ctx->conf);
    5411              :   }
    5412              :   mbuf_free(&ctx->cipher_suites);
    5413              :   memset(ctx, 0, sizeof(*ctx));
    5414              :   MG_FREE(ctx);
    5415              : }
    5416              : 
    5417              : static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
    5418              :                                             const char *ca_cert) {
    5419              :   if (ca_cert == NULL || strcmp(ca_cert, "*") == 0) {
    5420              :     mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_NONE);
    5421              :     return MG_SSL_OK;
    5422              :   }
    5423              :   ctx->ca_cert = (mbedtls_x509_crt *) MG_CALLOC(1, sizeof(*ctx->ca_cert));
    5424              :   mbedtls_x509_crt_init(ctx->ca_cert);
    5425              : #ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
    5426              :   ca_cert = strdup(ca_cert);
    5427              :   mbedtls_ssl_conf_ca_chain_file(ctx->conf, ca_cert, NULL);
    5428              : #else
    5429              :   if (mbedtls_x509_crt_parse_file(ctx->ca_cert, ca_cert) != 0) {
    5430              :     return MG_SSL_ERROR;
    5431              :   }
    5432              :   mbedtls_ssl_conf_ca_chain(ctx->conf, ctx->ca_cert, NULL);
    5433              : #endif
    5434              :   mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
    5435              :   return MG_SSL_OK;
    5436              : }
    5437              : 
    5438              : static enum mg_ssl_if_result mg_use_cert(struct mg_ssl_if_ctx *ctx,
    5439              :                                          const char *cert, const char *key,
    5440              :                                          const char **err_msg) {
    5441              :   if (key == NULL) key = cert;
    5442              :   if (cert == NULL || cert[0] == '\0' || key == NULL || key[0] == '\0') {
    5443              :     return MG_SSL_OK;
    5444              :   }
    5445              :   ctx->cert = (mbedtls_x509_crt *) MG_CALLOC(1, sizeof(*ctx->cert));
    5446              :   mbedtls_x509_crt_init(ctx->cert);
    5447              :   ctx->key = (mbedtls_pk_context *) MG_CALLOC(1, sizeof(*ctx->key));
    5448              :   mbedtls_pk_init(ctx->key);
    5449              :   if (mbedtls_x509_crt_parse_file(ctx->cert, cert) != 0) {
    5450              :     MG_SET_PTRPTR(err_msg, "Invalid SSL cert");
    5451              :     return MG_SSL_ERROR;
    5452              :   }
    5453              :   if (mbedtls_pk_parse_keyfile(ctx->key, key, NULL) != 0) {
    5454              :     MG_SET_PTRPTR(err_msg, "Invalid SSL key");
    5455              :     return MG_SSL_ERROR;
    5456              :   }
    5457              :   if (mbedtls_ssl_conf_own_cert(ctx->conf, ctx->cert, ctx->key) != 0) {
    5458              :     MG_SET_PTRPTR(err_msg, "Invalid SSL key or cert");
    5459              :     return MG_SSL_ERROR;
    5460              :   }
    5461              :   return MG_SSL_OK;
    5462              : }
    5463              : 
    5464              : static const int mg_s_cipher_list[] = {
    5465              : #if CS_PLATFORM != CS_P_ESP8266
    5466              :     MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
    5467              :     MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
    5468              :     MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
    5469              :     MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
    5470              :     MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
    5471              :     MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
    5472              :     MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
    5473              :     MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
    5474              :     MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
    5475              :     MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
    5476              :     MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
    5477              :     MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
    5478              :     MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256,
    5479              :     MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256,
    5480              :     MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA,
    5481              : #else
    5482              :     /*
    5483              :      * ECDHE is way too slow on ESP8266 w/o cryptochip, this sometimes results
    5484              :      * in WiFi STA deauths. Use weaker but faster cipher suites. Sad but true.
    5485              :      * Disable DHE completely because it's just hopelessly slow.
    5486              :      */
    5487              :     MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256,
    5488              :     MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256,
    5489              :     MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
    5490              :     MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
    5491              :     MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
    5492              :     MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
    5493              :     MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
    5494              :     MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
    5495              :     MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
    5496              :     MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
    5497              :     MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
    5498              :     MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
    5499              :     MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA,
    5500              : #endif /* CS_PLATFORM != CS_P_ESP8266 */
    5501              :     0,
    5502              : };
    5503              : 
    5504              : /*
    5505              :  * Ciphers can be specified as a colon-separated list of cipher suite names.
    5506              :  * These can be found in
    5507              :  * https://github.com/ARMmbed/mbedtls/blob/development/library/ssl_ciphersuites.c#L267
    5508              :  * E.g.: TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CCM
    5509              :  */
    5510              : static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx,
    5511              :                                                 const char *ciphers) {
    5512              :   if (ciphers != NULL) {
    5513              :     int l, id;
    5514              :     const char *s = ciphers, *e;
    5515              :     char tmp[50];
    5516              :     while (s != NULL) {
    5517              :       e = strchr(s, ':');
    5518              :       l = (e != NULL ? (e - s) : (int) strlen(s));
    5519              :       strncpy(tmp, s, l);
    5520              :       tmp[l] = '\0';
    5521              :       id = mbedtls_ssl_get_ciphersuite_id(tmp);
    5522              :       DBG(("%s -> %04x", tmp, id));
    5523              :       if (id != 0) {
    5524              :         mbuf_append(&ctx->cipher_suites, &id, sizeof(id));
    5525              :       }
    5526              :       s = (e != NULL ? e + 1 : NULL);
    5527              :     }
    5528              :     if (ctx->cipher_suites.len == 0) return MG_SSL_ERROR;
    5529              :     id = 0;
    5530              :     mbuf_append(&ctx->cipher_suites, &id, sizeof(id));
    5531              :     mbuf_trim(&ctx->cipher_suites);
    5532              :     mbedtls_ssl_conf_ciphersuites(ctx->conf,
    5533              :                                   (const int *) ctx->cipher_suites.buf);
    5534              :   } else {
    5535              :     mbedtls_ssl_conf_ciphersuites(ctx->conf, mg_s_cipher_list);
    5536              :   }
    5537              :   return MG_SSL_OK;
    5538              : }
    5539              : 
    5540              : #ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
    5541              : static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx,
    5542              :                                                     const char *identity,
    5543              :                                                     const char *key_str) {
    5544              :   unsigned char key[32];
    5545              :   size_t key_len;
    5546              :   if (identity == NULL && key_str == NULL) return MG_SSL_OK;
    5547              :   if (identity == NULL || key_str == NULL) return MG_SSL_ERROR;
    5548              :   key_len = strlen(key_str);
    5549              :   if (key_len != 32 && key_len != 64) return MG_SSL_ERROR;
    5550              :   size_t i = 0;
    5551              :   memset(key, 0, sizeof(key));
    5552              :   key_len = 0;
    5553              :   for (i = 0; key_str[i] != '\0'; i++) {
    5554              :     unsigned char c;
    5555              :     char hc = tolower((int) key_str[i]);
    5556              :     if (hc >= '0' && hc <= '9') {
    5557              :       c = hc - '0';
    5558              :     } else if (hc >= 'a' && hc <= 'f') {
    5559              :       c = hc - 'a' + 0xa;
    5560              :     } else {
    5561              :       return MG_SSL_ERROR;
    5562              :     }
    5563              :     key_len = i / 2;
    5564              :     key[key_len] <<= 4;
    5565              :     key[key_len] |= c;
    5566              :   }
    5567              :   key_len++;
    5568              :   DBG(("identity = '%s', key = (%u)", identity, (unsigned int) key_len));
    5569              :   /* mbedTLS makes copies of psk and identity. */
    5570              :   if (mbedtls_ssl_conf_psk(ctx->conf, (const unsigned char *) key, key_len,
    5571              :                            (const unsigned char *) identity,
    5572              :                            strlen(identity)) != 0) {
    5573              :     return MG_SSL_ERROR;
    5574              :   }
    5575              :   return MG_SSL_OK;
    5576              : }
    5577              : #endif
    5578              : 
    5579              : const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
    5580              :                        const char *ca_cert) {
    5581              :   const char *err_msg = NULL;
    5582              :   struct mg_ssl_if_conn_params params;
    5583              :   memset(&params, 0, sizeof(params));
    5584              :   params.cert = cert;
    5585              :   params.ca_cert = ca_cert;
    5586              :   if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
    5587              :     return err_msg;
    5588              :   }
    5589              :   return NULL;
    5590              : }
    5591              : 
    5592              : /* Lazy RNG. Warning: it would be a bad idea to do this in production! */
    5593              : #ifdef MG_SSL_MBED_DUMMY_RANDOM
    5594              : int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len) {
    5595              :   (void) ctx;
    5596              :   while (len--) *buf++ = rand();
    5597              :   return 0;
    5598              : }
    5599              : #endif
    5600              : 
    5601              : #endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_MBEDTLS */
    5602              : #ifdef MG_MODULE_LINES
    5603              : #line 1 "mongoose/src/mg_uri.c"
    5604              : #endif
    5605              : /*
    5606              :  * Copyright (c) 2014 Cesanta Software Limited
    5607              :  * All rights reserved
    5608              :  */
    5609              : 
    5610              : /* Amalgamated: #include "mg_internal.h" */
    5611              : /* Amalgamated: #include "mg_uri.h" */
    5612              : 
    5613              : /*
    5614              :  * scan string until encountering one of `seps`, keeping track of component
    5615              :  * boundaries in `res`.
    5616              :  *
    5617              :  * `p` will point to the char after the separator or it will be `end`.
    5618              :  */
    5619            0 : static void parse_uri_component(const char **p, const char *end,
    5620              :                                 const char *seps, struct mg_str *res) {
    5621              :   const char *q;
    5622            0 :   res->p = *p;
    5623            0 :   for (; *p < end; (*p)++) {
    5624            0 :     for (q = seps; *q != '\0'; q++) {
    5625            0 :       if (**p == *q) break;
    5626              :     }
    5627            0 :     if (*q != '\0') break;
    5628              :   }
    5629            0 :   res->len = (*p) - res->p;
    5630            0 :   if (*p < end) (*p)++;
    5631            0 : }
    5632              : 
    5633            0 : int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme,
    5634              :                  struct mg_str *user_info, struct mg_str *host,
    5635              :                  unsigned int *port, struct mg_str *path, struct mg_str *query,
    5636              :                  struct mg_str *fragment) {
    5637            0 :   struct mg_str rscheme = {0, 0}, ruser_info = {0, 0}, rhost = {0, 0},
    5638            0 :                 rpath = {0, 0}, rquery = {0, 0}, rfragment = {0, 0};
    5639            0 :   unsigned int rport = 0;
    5640              :   enum {
    5641              :     P_START,
    5642              :     P_SCHEME_OR_PORT,
    5643              :     P_USER_INFO,
    5644              :     P_HOST,
    5645              :     P_PORT,
    5646              :     P_REST
    5647            0 :   } state = P_START;
    5648              : 
    5649            0 :   const char *p = uri.p, *end = p + uri.len;
    5650            0 :   while (p < end) {
    5651            0 :     switch (state) {
    5652            0 :       case P_START:
    5653              :         /*
    5654              :          * expecting on of:
    5655              :          * - `scheme://xxxx`
    5656              :          * - `xxxx:port`
    5657              :          * - `[a:b:c]:port`
    5658              :          * - `xxxx/path`
    5659              :          */
    5660            0 :         if (*p == '[') {
    5661            0 :           state = P_HOST;
    5662            0 :           break;
    5663              :         }
    5664            0 :         for (; p < end; p++) {
    5665            0 :           if (*p == ':') {
    5666            0 :             state = P_SCHEME_OR_PORT;
    5667            0 :             break;
    5668            0 :           } else if (*p == '/') {
    5669            0 :             state = P_REST;
    5670            0 :             break;
    5671              :           }
    5672              :         }
    5673            0 :         if (state == P_START || state == P_REST) {
    5674            0 :           rhost.p = uri.p;
    5675            0 :           rhost.len = p - uri.p;
    5676              :         }
    5677            0 :         break;
    5678            0 :       case P_SCHEME_OR_PORT:
    5679            0 :         if (end - p >= 3 && strncmp(p, "://", 3) == 0) {
    5680            0 :           rscheme.p = uri.p;
    5681            0 :           rscheme.len = p - uri.p;
    5682            0 :           state = P_USER_INFO;
    5683            0 :           p += 3;
    5684              :         } else {
    5685            0 :           rhost.p = uri.p;
    5686            0 :           rhost.len = p - uri.p;
    5687            0 :           state = P_PORT;
    5688              :         }
    5689            0 :         break;
    5690            0 :       case P_USER_INFO:
    5691            0 :         ruser_info.p = p;
    5692            0 :         for (; p < end; p++) {
    5693            0 :           if (*p == '@' || *p == '[' || *p == '/') {
    5694              :             break;
    5695              :           }
    5696              :         }
    5697            0 :         if (p == end || *p == '/' || *p == '[') {
    5698              :           /* backtrack and parse as host */
    5699            0 :           p = ruser_info.p;
    5700              :         }
    5701            0 :         ruser_info.len = p - ruser_info.p;
    5702            0 :         state = P_HOST;
    5703            0 :         break;
    5704            0 :       case P_HOST:
    5705            0 :         if (*p == '@') p++;
    5706            0 :         rhost.p = p;
    5707            0 :         if (*p == '[') {
    5708            0 :           int found = 0;
    5709            0 :           for (; !found && p < end; p++) {
    5710            0 :             found = (*p == ']');
    5711              :           }
    5712            0 :           if (!found) return -1;
    5713              :         } else {
    5714            0 :           for (; p < end; p++) {
    5715            0 :             if (*p == ':' || *p == '/') break;
    5716              :           }
    5717              :         }
    5718            0 :         rhost.len = p - rhost.p;
    5719            0 :         if (p < end) {
    5720            0 :           if (*p == ':') {
    5721            0 :             state = P_PORT;
    5722            0 :             break;
    5723            0 :           } else if (*p == '/') {
    5724            0 :             state = P_REST;
    5725            0 :             break;
    5726              :           }
    5727              :         }
    5728            0 :         break;
    5729            0 :       case P_PORT:
    5730            0 :         p++;
    5731            0 :         for (; p < end; p++) {
    5732            0 :           if (*p == '/') {
    5733            0 :             state = P_REST;
    5734            0 :             break;
    5735              :           }
    5736            0 :           rport *= 10;
    5737            0 :           rport += *p - '0';
    5738              :         }
    5739            0 :         break;
    5740            0 :       case P_REST:
    5741              :         /* `p` points to separator. `path` includes the separator */
    5742            0 :         parse_uri_component(&p, end, "?#", &rpath);
    5743            0 :         if (p < end && *(p - 1) == '?') {
    5744            0 :           parse_uri_component(&p, end, "#", &rquery);
    5745              :         }
    5746            0 :         parse_uri_component(&p, end, "", &rfragment);
    5747            0 :         break;
    5748              :     }
    5749              :   }
    5750              : 
    5751            0 :   if (scheme != 0) *scheme = rscheme;
    5752            0 :   if (user_info != 0) *user_info = ruser_info;
    5753            0 :   if (host != 0) *host = rhost;
    5754            0 :   if (port != 0) *port = rport;
    5755            0 :   if (path != 0) *path = rpath;
    5756            0 :   if (query != 0) *query = rquery;
    5757            0 :   if (fragment != 0) *fragment = rfragment;
    5758              : 
    5759            0 :   return 0;
    5760              : }
    5761              : 
    5762              : /* Normalize the URI path. Remove/resolve "." and "..". */
    5763            0 : int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out) {
    5764            0 :   const char *s = in->p, *se = s + in->len;
    5765            0 :   char *cp = (char *) out->p, *d;
    5766              : 
    5767            0 :   if (in->len == 0 || *s != '/') {
    5768            0 :     out->len = 0;
    5769            0 :     return 0;
    5770              :   }
    5771              : 
    5772            0 :   d = cp;
    5773              : 
    5774            0 :   while (s < se) {
    5775            0 :     const char *next = s;
    5776              :     struct mg_str component;
    5777            0 :     parse_uri_component(&next, se, "/", &component);
    5778            0 :     if (mg_vcmp(&component, ".") == 0) {
    5779              :       /* Yum. */
    5780            0 :     } else if (mg_vcmp(&component, "..") == 0) {
    5781              :       /* Backtrack to previous slash. */
    5782            0 :       if (d > cp + 1 && *(d - 1) == '/') d--;
    5783            0 :       while (d > cp && *(d - 1) != '/') d--;
    5784              :     } else {
    5785            0 :       memmove(d, s, next - s);
    5786            0 :       d += next - s;
    5787              :     }
    5788            0 :     s = next;
    5789              :   }
    5790            0 :   if (d == cp) *d++ = '/';
    5791              : 
    5792            0 :   out->p = cp;
    5793            0 :   out->len = d - cp;
    5794            0 :   return 1;
    5795              : }
    5796              : 
    5797            0 : int mg_assemble_uri(const struct mg_str *scheme, const struct mg_str *user_info,
    5798              :                     const struct mg_str *host, unsigned int port,
    5799              :                     const struct mg_str *path, const struct mg_str *query,
    5800              :                     const struct mg_str *fragment, int normalize_path,
    5801              :                     struct mg_str *uri) {
    5802            0 :   int result = -1;
    5803              :   struct mbuf out;
    5804            0 :   mbuf_init(&out, 0);
    5805              : 
    5806            0 :   if (scheme != NULL && scheme->len > 0) {
    5807            0 :     mbuf_append(&out, scheme->p, scheme->len);
    5808            0 :     mbuf_append(&out, "://", 3);
    5809              :   }
    5810              : 
    5811            0 :   if (user_info != NULL && user_info->len > 0) {
    5812            0 :     mbuf_append(&out, user_info->p, user_info->len);
    5813            0 :     mbuf_append(&out, "@", 1);
    5814              :   }
    5815              : 
    5816            0 :   if (host != NULL && host->len > 0) {
    5817            0 :     mbuf_append(&out, host->p, host->len);
    5818              :   }
    5819              : 
    5820            0 :   if (port != 0) {
    5821              :     char port_str[20];
    5822            0 :     int port_str_len = sprintf(port_str, ":%u", port);
    5823            0 :     mbuf_append(&out, port_str, port_str_len);
    5824              :   }
    5825              : 
    5826            0 :   if (path != NULL && path->len > 0) {
    5827            0 :     if (normalize_path) {
    5828            0 :       struct mg_str npath = mg_strdup(*path);
    5829            0 :       if (npath.len != path->len) goto out;
    5830            0 :       if (!mg_normalize_uri_path(path, &npath)) {
    5831            0 :         free((void *) npath.p);
    5832            0 :         goto out;
    5833              :       }
    5834            0 :       mbuf_append(&out, npath.p, npath.len);
    5835            0 :       free((void *) npath.p);
    5836              :     } else {
    5837            0 :       mbuf_append(&out, path->p, path->len);
    5838              :     }
    5839            0 :   } else if (normalize_path) {
    5840            0 :     mbuf_append(&out, "/", 1);
    5841              :   }
    5842              : 
    5843            0 :   if (query != NULL && query->len > 0) {
    5844            0 :     mbuf_append(&out, "?", 1);
    5845            0 :     mbuf_append(&out, query->p, query->len);
    5846              :   }
    5847              : 
    5848            0 :   if (fragment != NULL && fragment->len > 0) {
    5849            0 :     mbuf_append(&out, "#", 1);
    5850            0 :     mbuf_append(&out, fragment->p, fragment->len);
    5851              :   }
    5852              : 
    5853            0 :   result = 0;
    5854              : 
    5855            0 : out:
    5856            0 :   if (result == 0) {
    5857            0 :     uri->p = out.buf;
    5858            0 :     uri->len = out.len;
    5859              :   } else {
    5860            0 :     mbuf_free(&out);
    5861            0 :     uri->p = NULL;
    5862            0 :     uri->len = 0;
    5863              :   }
    5864            0 :   return result;
    5865              : }
    5866              : #ifdef MG_MODULE_LINES
    5867              : #line 1 "mongoose/src/mg_http.c"
    5868              : #endif
    5869              : /*
    5870              :  * Copyright (c) 2014 Cesanta Software Limited
    5871              :  * All rights reserved
    5872              :  */
    5873              : 
    5874              : #if MG_ENABLE_HTTP
    5875              : 
    5876              : /* Amalgamated: #include "common/cs_md5.h" */
    5877              : /* Amalgamated: #include "mg_internal.h" */
    5878              : /* Amalgamated: #include "mg_util.h" */
    5879              : 
    5880              : /* altbuf {{{ */
    5881              : 
    5882              : /*
    5883              :  * Alternate buffer: fills the client-provided buffer with data; and if it's
    5884              :  * not large enough, allocates another buffer (via mbuf), similar to asprintf.
    5885              :  */
    5886              : struct altbuf {
    5887              :   struct mbuf m;
    5888              :   char *user_buf;
    5889              :   size_t len;
    5890              :   size_t user_buf_size;
    5891              : };
    5892              : 
    5893              : /*
    5894              :  * Initializes altbuf; `buf`, `buf_size` is the client-provided buffer.
    5895              :  */
    5896            0 : MG_INTERNAL void altbuf_init(struct altbuf *ab, char *buf, size_t buf_size) {
    5897            0 :   mbuf_init(&ab->m, 0);
    5898            0 :   ab->user_buf = buf;
    5899            0 :   ab->user_buf_size = buf_size;
    5900            0 :   ab->len = 0;
    5901            0 : }
    5902              : 
    5903              : /*
    5904              :  * Appends a single char to the altbuf.
    5905              :  */
    5906            0 : MG_INTERNAL void altbuf_append(struct altbuf *ab, char c) {
    5907            0 :   if (ab->len < ab->user_buf_size) {
    5908              :     /* The data fits into the original buffer */
    5909            0 :     ab->user_buf[ab->len++] = c;
    5910              :   } else {
    5911              :     /* The data can't fit into the original buffer, so write it to mbuf.  */
    5912              : 
    5913              :     /*
    5914              :      * First of all, see if that's the first byte which overflows the original
    5915              :      * buffer: if so, copy the existing data from there to a newly allocated
    5916              :      * mbuf.
    5917              :      */
    5918            0 :     if (ab->len > 0 && ab->m.len == 0) {
    5919            0 :       mbuf_append(&ab->m, ab->user_buf, ab->len);
    5920              :     }
    5921              : 
    5922            0 :     mbuf_append(&ab->m, &c, 1);
    5923            0 :     ab->len = ab->m.len;
    5924              :   }
    5925            0 : }
    5926              : 
    5927              : /*
    5928              :  * Resets any data previously appended to altbuf.
    5929              :  */
    5930            0 : MG_INTERNAL void altbuf_reset(struct altbuf *ab) {
    5931            0 :   mbuf_free(&ab->m);
    5932            0 :   ab->len = 0;
    5933            0 : }
    5934              : 
    5935              : /*
    5936              :  * Returns whether the additional buffer was allocated (and thus the data
    5937              :  * is in the mbuf, not the client-provided buffer)
    5938              :  */
    5939            0 : MG_INTERNAL int altbuf_reallocated(struct altbuf *ab) {
    5940            0 :   return ab->len > ab->user_buf_size;
    5941              : }
    5942              : 
    5943              : /*
    5944              :  * Returns the actual buffer with data, either the client-provided or a newly
    5945              :  * allocated one. If `trim` is non-zero, mbuf-backed buffer is trimmed first.
    5946              :  */
    5947            0 : MG_INTERNAL char *altbuf_get_buf(struct altbuf *ab, int trim) {
    5948            0 :   if (altbuf_reallocated(ab)) {
    5949            0 :     if (trim) {
    5950            0 :       mbuf_trim(&ab->m);
    5951              :     }
    5952            0 :     return ab->m.buf;
    5953              :   } else {
    5954            0 :     return ab->user_buf;
    5955              :   }
    5956              : }
    5957              : 
    5958              : /* }}} */
    5959              : 
    5960              : static const char *mg_version_header = "Mongoose/" MG_VERSION;
    5961              : 
    5962              : enum mg_http_proto_data_type { DATA_NONE, DATA_FILE, DATA_PUT };
    5963              : 
    5964              : struct mg_http_proto_data_file {
    5965              :   FILE *fp;      /* Opened file. */
    5966              :   int64_t cl;    /* Content-Length. How many bytes to send. */
    5967              :   int64_t sent;  /* How many bytes have been already sent. */
    5968              :   int keepalive; /* Keep connection open after sending. */
    5969              :   enum mg_http_proto_data_type type;
    5970              : };
    5971              : 
    5972              : #if MG_ENABLE_HTTP_CGI
    5973              : struct mg_http_proto_data_cgi {
    5974              :   struct mg_connection *cgi_nc;
    5975              : };
    5976              : #endif
    5977              : 
    5978              : struct mg_http_proto_data_chuncked {
    5979              :   int64_t body_len; /* How many bytes of chunked body was reassembled. */
    5980              : };
    5981              : 
    5982              : struct mg_http_endpoint {
    5983              :   struct mg_http_endpoint *next;
    5984              :   struct mg_str uri_pattern; /* owned */
    5985              :   char *auth_domain;         /* owned */
    5986              :   char *auth_file;           /* owned */
    5987              : 
    5988              :   mg_event_handler_t handler;
    5989              : #if MG_ENABLE_CALLBACK_USERDATA
    5990              :   void *user_data;
    5991              : #endif
    5992              : };
    5993              : 
    5994              : enum mg_http_multipart_stream_state {
    5995              :   MPS_BEGIN,
    5996              :   MPS_WAITING_FOR_BOUNDARY,
    5997              :   MPS_WAITING_FOR_CHUNK,
    5998              :   MPS_GOT_BOUNDARY,
    5999              :   MPS_FINALIZE,
    6000              :   MPS_FINISHED
    6001              : };
    6002              : 
    6003              : struct mg_http_multipart_stream {
    6004              :   const char *boundary;
    6005              :   int boundary_len;
    6006              :   const char *var_name;
    6007              :   const char *file_name;
    6008              :   void *user_data;
    6009              :   enum mg_http_multipart_stream_state state;
    6010              :   int processing_part;
    6011              :   int data_avail;
    6012              : };
    6013              : 
    6014              : struct mg_reverse_proxy_data {
    6015              :   struct mg_connection *linked_conn;
    6016              : };
    6017              : 
    6018              : struct mg_ws_proto_data {
    6019              :   /*
    6020              :    * Defragmented size of the frame so far.
    6021              :    *
    6022              :    * First byte of nc->recv_mbuf.buf is an op, the rest of the data is
    6023              :    * defragmented data.
    6024              :    */
    6025              :   size_t reass_len;
    6026              : };
    6027              : 
    6028              : struct mg_http_proto_data {
    6029              : #if MG_ENABLE_FILESYSTEM
    6030              :   struct mg_http_proto_data_file file;
    6031              : #endif
    6032              : #if MG_ENABLE_HTTP_CGI
    6033              :   struct mg_http_proto_data_cgi cgi;
    6034              : #endif
    6035              : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
    6036              :   struct mg_http_multipart_stream mp_stream;
    6037              : #endif
    6038              : #if MG_ENABLE_HTTP_WEBSOCKET
    6039              :   struct mg_ws_proto_data ws_data;
    6040              : #endif
    6041              :   struct mg_http_proto_data_chuncked chunk;
    6042              :   struct mg_http_endpoint *endpoints;
    6043              :   mg_event_handler_t endpoint_handler;
    6044              :   struct mg_reverse_proxy_data reverse_proxy_data;
    6045              :   size_t rcvd; /* How many bytes we have received. */
    6046              : };
    6047              : 
    6048              : static void mg_http_proto_data_destructor(void *proto_data);
    6049              : 
    6050              : struct mg_connection *mg_connect_http_base(
    6051              :     struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
    6052              :     struct mg_connect_opts opts, const char *scheme1, const char *scheme2,
    6053              :     const char *scheme_ssl1, const char *scheme_ssl2, const char *url,
    6054              :     struct mg_str *path, struct mg_str *user_info, struct mg_str *host);
    6055              : 
    6056            0 : MG_INTERNAL struct mg_http_proto_data *mg_http_create_proto_data(
    6057              :     struct mg_connection *c) {
    6058              :   /* If we have proto data from previous connection, flush it. */
    6059            0 :   if (c->proto_data != NULL) {
    6060            0 :     void *pd = c->proto_data;
    6061            0 :     c->proto_data = NULL;
    6062            0 :     mg_http_proto_data_destructor(pd);
    6063              :   }
    6064            0 :   c->proto_data = MG_CALLOC(1, sizeof(struct mg_http_proto_data));
    6065            0 :   c->proto_data_destructor = mg_http_proto_data_destructor;
    6066            0 :   return (struct mg_http_proto_data *) c->proto_data;
    6067              : }
    6068              : 
    6069            0 : static struct mg_http_proto_data *mg_http_get_proto_data(
    6070              :     struct mg_connection *c) {
    6071            0 :   return (struct mg_http_proto_data *) c->proto_data;
    6072              : }
    6073              : 
    6074              : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
    6075              : static void mg_http_free_proto_data_mp_stream(
    6076              :     struct mg_http_multipart_stream *mp) {
    6077              :   MG_FREE((void *) mp->boundary);
    6078              :   MG_FREE((void *) mp->var_name);
    6079              :   MG_FREE((void *) mp->file_name);
    6080              :   memset(mp, 0, sizeof(*mp));
    6081              : }
    6082              : #endif
    6083              : 
    6084              : #if MG_ENABLE_FILESYSTEM
    6085            0 : static void mg_http_free_proto_data_file(struct mg_http_proto_data_file *d) {
    6086            0 :   if (d != NULL) {
    6087            0 :     if (d->fp != NULL) {
    6088            0 :       fclose(d->fp);
    6089              :     }
    6090            0 :     memset(d, 0, sizeof(struct mg_http_proto_data_file));
    6091              :   }
    6092            0 : }
    6093              : #endif
    6094              : 
    6095            0 : static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep) {
    6096            0 :   struct mg_http_endpoint *current = *ep;
    6097              : 
    6098            0 :   while (current != NULL) {
    6099            0 :     struct mg_http_endpoint *tmp = current->next;
    6100            0 :     MG_FREE((void *) current->uri_pattern.p);
    6101            0 :     MG_FREE((void *) current->auth_domain);
    6102            0 :     MG_FREE((void *) current->auth_file);
    6103            0 :     MG_FREE(current);
    6104            0 :     current = tmp;
    6105              :   }
    6106              : 
    6107            0 :   ep = NULL;
    6108            0 : }
    6109              : 
    6110            0 : static void mg_http_free_reverse_proxy_data(struct mg_reverse_proxy_data *rpd) {
    6111            0 :   if (rpd->linked_conn != NULL) {
    6112              :     /*
    6113              :      * Connection has linked one, we have to unlink & close it
    6114              :      * since _this_ connection is going to die and
    6115              :      * it doesn't make sense to keep another one
    6116              :      */
    6117            0 :     struct mg_http_proto_data *pd = mg_http_get_proto_data(rpd->linked_conn);
    6118            0 :     if (pd->reverse_proxy_data.linked_conn != NULL) {
    6119            0 :       pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE;
    6120            0 :       pd->reverse_proxy_data.linked_conn = NULL;
    6121              :     }
    6122            0 :     rpd->linked_conn = NULL;
    6123              :   }
    6124            0 : }
    6125              : 
    6126            0 : static void mg_http_proto_data_destructor(void *proto_data) {
    6127            0 :   struct mg_http_proto_data *pd = (struct mg_http_proto_data *) proto_data;
    6128              : #if MG_ENABLE_FILESYSTEM
    6129            0 :   mg_http_free_proto_data_file(&pd->file);
    6130              : #endif
    6131              : #if MG_ENABLE_HTTP_CGI
    6132            0 :   mg_http_free_proto_data_cgi(&pd->cgi);
    6133              : #endif
    6134              : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
    6135              :   mg_http_free_proto_data_mp_stream(&pd->mp_stream);
    6136              : #endif
    6137            0 :   mg_http_free_proto_data_endpoints(&pd->endpoints);
    6138            0 :   mg_http_free_reverse_proxy_data(&pd->reverse_proxy_data);
    6139            0 :   MG_FREE(proto_data);
    6140            0 : }
    6141              : 
    6142              : #if MG_ENABLE_FILESYSTEM
    6143              : 
    6144              : #define MIME_ENTRY(_ext, _type) \
    6145              :   { _ext, sizeof(_ext) - 1, _type }
    6146              : static const struct {
    6147              :   const char *extension;
    6148              :   size_t ext_len;
    6149              :   const char *mime_type;
    6150              : } mg_static_builtin_mime_types[] = {
    6151              :     MIME_ENTRY("html", "text/html"),
    6152              :     MIME_ENTRY("html", "text/html"),
    6153              :     MIME_ENTRY("htm", "text/html"),
    6154              :     MIME_ENTRY("shtm", "text/html"),
    6155              :     MIME_ENTRY("shtml", "text/html"),
    6156              :     MIME_ENTRY("css", "text/css"),
    6157              :     MIME_ENTRY("js", "application/x-javascript"),
    6158              :     MIME_ENTRY("ico", "image/x-icon"),
    6159              :     MIME_ENTRY("gif", "image/gif"),
    6160              :     MIME_ENTRY("jpg", "image/jpeg"),
    6161              :     MIME_ENTRY("jpeg", "image/jpeg"),
    6162              :     MIME_ENTRY("png", "image/png"),
    6163              :     MIME_ENTRY("svg", "image/svg+xml"),
    6164              :     MIME_ENTRY("txt", "text/plain"),
    6165              :     MIME_ENTRY("torrent", "application/x-bittorrent"),
    6166              :     MIME_ENTRY("wav", "audio/x-wav"),
    6167              :     MIME_ENTRY("mp3", "audio/x-mp3"),
    6168              :     MIME_ENTRY("mid", "audio/mid"),
    6169              :     MIME_ENTRY("m3u", "audio/x-mpegurl"),
    6170              :     MIME_ENTRY("ogg", "application/ogg"),
    6171              :     MIME_ENTRY("ram", "audio/x-pn-realaudio"),
    6172              :     MIME_ENTRY("xml", "text/xml"),
    6173              :     MIME_ENTRY("ttf", "application/x-font-ttf"),
    6174              :     MIME_ENTRY("json", "application/json"),
    6175              :     MIME_ENTRY("xslt", "application/xml"),
    6176              :     MIME_ENTRY("xsl", "application/xml"),
    6177              :     MIME_ENTRY("ra", "audio/x-pn-realaudio"),
    6178              :     MIME_ENTRY("doc", "application/msword"),
    6179              :     MIME_ENTRY("exe", "application/octet-stream"),
    6180              :     MIME_ENTRY("zip", "application/x-zip-compressed"),
    6181              :     MIME_ENTRY("xls", "application/excel"),
    6182              :     MIME_ENTRY("tgz", "application/x-tar-gz"),
    6183              :     MIME_ENTRY("tar", "application/x-tar"),
    6184              :     MIME_ENTRY("gz", "application/x-gunzip"),
    6185              :     MIME_ENTRY("arj", "application/x-arj-compressed"),
    6186              :     MIME_ENTRY("rar", "application/x-rar-compressed"),
    6187              :     MIME_ENTRY("rtf", "application/rtf"),
    6188              :     MIME_ENTRY("pdf", "application/pdf"),
    6189              :     MIME_ENTRY("swf", "application/x-shockwave-flash"),
    6190              :     MIME_ENTRY("mpg", "video/mpeg"),
    6191              :     MIME_ENTRY("webm", "video/webm"),
    6192              :     MIME_ENTRY("mpeg", "video/mpeg"),
    6193              :     MIME_ENTRY("mov", "video/quicktime"),
    6194              :     MIME_ENTRY("mp4", "video/mp4"),
    6195              :     MIME_ENTRY("m4v", "video/x-m4v"),
    6196              :     MIME_ENTRY("asf", "video/x-ms-asf"),
    6197              :     MIME_ENTRY("avi", "video/x-msvideo"),
    6198              :     MIME_ENTRY("bmp", "image/bmp"),
    6199              :     {NULL, 0, NULL}};
    6200              : 
    6201            0 : static struct mg_str mg_get_mime_type(const char *path, const char *dflt,
    6202              :                                       const struct mg_serve_http_opts *opts) {
    6203              :   const char *ext, *overrides;
    6204              :   size_t i, path_len;
    6205              :   struct mg_str r, k, v;
    6206              : 
    6207            0 :   path_len = strlen(path);
    6208              : 
    6209            0 :   overrides = opts->custom_mime_types;
    6210            0 :   while ((overrides = mg_next_comma_list_entry(overrides, &k, &v)) != NULL) {
    6211            0 :     ext = path + (path_len - k.len);
    6212            0 :     if (path_len > k.len && mg_vcasecmp(&k, ext) == 0) {
    6213            0 :       return v;
    6214              :     }
    6215              :   }
    6216              : 
    6217            0 :   for (i = 0; mg_static_builtin_mime_types[i].extension != NULL; i++) {
    6218            0 :     ext = path + (path_len - mg_static_builtin_mime_types[i].ext_len);
    6219            0 :     if (path_len > mg_static_builtin_mime_types[i].ext_len && ext[-1] == '.' &&
    6220            0 :         mg_casecmp(ext, mg_static_builtin_mime_types[i].extension) == 0) {
    6221            0 :       r.p = mg_static_builtin_mime_types[i].mime_type;
    6222            0 :       r.len = strlen(r.p);
    6223            0 :       return r;
    6224              :     }
    6225              :   }
    6226              : 
    6227            0 :   r.p = dflt;
    6228            0 :   r.len = strlen(r.p);
    6229            0 :   return r;
    6230              : }
    6231              : #endif
    6232              : 
    6233              : /*
    6234              :  * Check whether full request is buffered. Return:
    6235              :  *   -1  if request is malformed
    6236              :  *    0  if request is not yet fully buffered
    6237              :  *   >0  actual request length, including last \r\n\r\n
    6238              :  */
    6239            0 : static int mg_http_get_request_len(const char *s, int buf_len) {
    6240            0 :   const unsigned char *buf = (unsigned char *) s;
    6241              :   int i;
    6242              : 
    6243            0 :   for (i = 0; i < buf_len; i++) {
    6244            0 :     if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128) {
    6245            0 :       return -1;
    6246            0 :     } else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') {
    6247            0 :       return i + 2;
    6248            0 :     } else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' &&
    6249            0 :                buf[i + 2] == '\n') {
    6250            0 :       return i + 3;
    6251              :     }
    6252              :   }
    6253              : 
    6254            0 :   return 0;
    6255              : }
    6256              : 
    6257            0 : static const char *mg_http_parse_headers(const char *s, const char *end,
    6258              :                                          int len, struct http_message *req) {
    6259            0 :   int i = 0;
    6260            0 :   while (i < (int) ARRAY_SIZE(req->header_names) - 1) {
    6261            0 :     struct mg_str *k = &req->header_names[i], *v = &req->header_values[i];
    6262              : 
    6263            0 :     s = mg_skip(s, end, ": ", k);
    6264            0 :     s = mg_skip(s, end, "\r\n", v);
    6265              : 
    6266            0 :     while (v->len > 0 && v->p[v->len - 1] == ' ') {
    6267            0 :       v->len--; /* Trim trailing spaces in header value */
    6268              :     }
    6269              : 
    6270              :     /*
    6271              :      * If header value is empty - skip it and go to next (if any).
    6272              :      * NOTE: Do not add it to headers_values because such addition changes API
    6273              :      * behaviour
    6274              :      */
    6275            0 :     if (k->len != 0 && v->len == 0) {
    6276            0 :       continue;
    6277              :     }
    6278              : 
    6279            0 :     if (k->len == 0 || v->len == 0) {
    6280            0 :       k->p = v->p = NULL;
    6281            0 :       k->len = v->len = 0;
    6282            0 :       break;
    6283              :     }
    6284              : 
    6285            0 :     if (!mg_ncasecmp(k->p, "Content-Length", 14)) {
    6286            0 :       req->body.len = (size_t) to64(v->p);
    6287            0 :       req->message.len = len + req->body.len;
    6288              :     }
    6289              : 
    6290            0 :     i++;
    6291              :   }
    6292              : 
    6293            0 :   return s;
    6294              : }
    6295              : 
    6296            0 : int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req) {
    6297              :   const char *end, *qs;
    6298            0 :   int len = mg_http_get_request_len(s, n);
    6299              : 
    6300            0 :   if (len <= 0) return len;
    6301              : 
    6302            0 :   memset(hm, 0, sizeof(*hm));
    6303            0 :   hm->message.p = s;
    6304            0 :   hm->body.p = s + len;
    6305            0 :   hm->message.len = hm->body.len = (size_t) ~0;
    6306            0 :   end = s + len;
    6307              : 
    6308              :   /* Request is fully buffered. Skip leading whitespaces. */
    6309            0 :   while (s < end && isspace(*(unsigned char *) s)) s++;
    6310              : 
    6311            0 :   if (is_req) {
    6312              :     /* Parse request line: method, URI, proto */
    6313            0 :     s = mg_skip(s, end, " ", &hm->method);
    6314            0 :     s = mg_skip(s, end, " ", &hm->uri);
    6315            0 :     s = mg_skip(s, end, "\r\n", &hm->proto);
    6316            0 :     if (hm->uri.p <= hm->method.p || hm->proto.p <= hm->uri.p) return -1;
    6317              : 
    6318              :     /* If URI contains '?' character, initialize query_string */
    6319            0 :     if ((qs = (char *) memchr(hm->uri.p, '?', hm->uri.len)) != NULL) {
    6320            0 :       hm->query_string.p = qs + 1;
    6321            0 :       hm->query_string.len = &hm->uri.p[hm->uri.len] - (qs + 1);
    6322            0 :       hm->uri.len = qs - hm->uri.p;
    6323              :     }
    6324              :   } else {
    6325            0 :     s = mg_skip(s, end, " ", &hm->proto);
    6326            0 :     if (end - s < 4 || s[0] < '0' || s[0] > '9' || s[3] != ' ') return -1;
    6327            0 :     hm->resp_code = atoi(s);
    6328            0 :     if (hm->resp_code < 100 || hm->resp_code >= 600) return -1;
    6329            0 :     s += 4;
    6330            0 :     s = mg_skip(s, end, "\r\n", &hm->resp_status_msg);
    6331              :   }
    6332              : 
    6333            0 :   s = mg_http_parse_headers(s, end, len, hm);
    6334              : 
    6335              :   /*
    6336              :    * mg_parse_http() is used to parse both HTTP requests and HTTP
    6337              :    * responses. If HTTP response does not have Content-Length set, then
    6338              :    * body is read until socket is closed, i.e. body.len is infinite (~0).
    6339              :    *
    6340              :    * For HTTP requests though, according to
    6341              :    * http://tools.ietf.org/html/rfc7231#section-8.1.3,
    6342              :    * only POST and PUT methods have defined body semantics.
    6343              :    * Therefore, if Content-Length is not specified and methods are
    6344              :    * not one of PUT or POST, set body length to 0.
    6345              :    *
    6346              :    * So,
    6347              :    * if it is HTTP request, and Content-Length is not set,
    6348              :    * and method is not (PUT or POST) then reset body length to zero.
    6349              :    */
    6350            0 :   if (hm->body.len == (size_t) ~0 && is_req &&
    6351            0 :       mg_vcasecmp(&hm->method, "PUT") != 0 &&
    6352            0 :       mg_vcasecmp(&hm->method, "POST") != 0) {
    6353            0 :     hm->body.len = 0;
    6354            0 :     hm->message.len = len;
    6355              :   }
    6356              : 
    6357            0 :   return len;
    6358              : }
    6359              : 
    6360            0 : struct mg_str *mg_get_http_header(struct http_message *hm, const char *name) {
    6361            0 :   size_t i, len = strlen(name);
    6362              : 
    6363            0 :   for (i = 0; hm->header_names[i].len > 0; i++) {
    6364            0 :     struct mg_str *h = &hm->header_names[i], *v = &hm->header_values[i];
    6365            0 :     if (h->p != NULL && h->len == len && !mg_ncasecmp(h->p, name, len))
    6366            0 :       return v;
    6367              :   }
    6368              : 
    6369            0 :   return NULL;
    6370              : }
    6371              : 
    6372              : #if MG_ENABLE_FILESYSTEM
    6373            0 : static void mg_http_transfer_file_data(struct mg_connection *nc) {
    6374            0 :   struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
    6375              :   char buf[MG_MAX_HTTP_SEND_MBUF];
    6376            0 :   size_t n = 0, to_read = 0, left = (size_t)(pd->file.cl - pd->file.sent);
    6377              : 
    6378            0 :   if (pd->file.type == DATA_FILE) {
    6379            0 :     struct mbuf *io = &nc->send_mbuf;
    6380            0 :     if (io->len >= MG_MAX_HTTP_SEND_MBUF) {
    6381            0 :       to_read = 0;
    6382              :     } else {
    6383            0 :       to_read = MG_MAX_HTTP_SEND_MBUF - io->len;
    6384              :     }
    6385            0 :     if (to_read > left) {
    6386            0 :       to_read = left;
    6387              :     }
    6388            0 :     if (to_read > 0) {
    6389            0 :       n = mg_fread(buf, 1, to_read, pd->file.fp);
    6390            0 :       if (n > 0) {
    6391            0 :         mg_send(nc, buf, n);
    6392            0 :         pd->file.sent += n;
    6393            0 :         DBG(("%p sent %d (total %d)", nc, (int) n, (int) pd->file.sent));
    6394              :       }
    6395              :     } else {
    6396              :       /* Rate-limited */
    6397              :     }
    6398            0 :     if (pd->file.sent >= pd->file.cl) {
    6399            0 :       LOG(LL_DEBUG, ("%p done, %d bytes, ka %d", nc, (int) pd->file.sent,
    6400              :                      pd->file.keepalive));
    6401            0 :       if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
    6402            0 :       mg_http_free_proto_data_file(&pd->file);
    6403              :     }
    6404            0 :   } else if (pd->file.type == DATA_PUT) {
    6405            0 :     struct mbuf *io = &nc->recv_mbuf;
    6406            0 :     size_t to_write = left <= 0 ? 0 : left < io->len ? (size_t) left : io->len;
    6407            0 :     size_t n = mg_fwrite(io->buf, 1, to_write, pd->file.fp);
    6408            0 :     if (n > 0) {
    6409            0 :       mbuf_remove(io, n);
    6410            0 :       pd->file.sent += n;
    6411              :     }
    6412            0 :     if (n == 0 || pd->file.sent >= pd->file.cl) {
    6413            0 :       if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
    6414            0 :       mg_http_free_proto_data_file(&pd->file);
    6415              :     }
    6416              :   }
    6417              : #if MG_ENABLE_HTTP_CGI
    6418            0 :   else if (pd->cgi.cgi_nc != NULL) {
    6419              :     /* This is POST data that needs to be forwarded to the CGI process */
    6420            0 :     if (pd->cgi.cgi_nc != NULL) {
    6421            0 :       mg_forward(nc, pd->cgi.cgi_nc);
    6422              :     } else {
    6423            0 :       nc->flags |= MG_F_SEND_AND_CLOSE;
    6424              :     }
    6425              :   }
    6426              : #endif
    6427            0 : }
    6428              : #endif /* MG_ENABLE_FILESYSTEM */
    6429              : 
    6430              : /*
    6431              :  * Parse chunked-encoded buffer. Return 0 if the buffer is not encoded, or
    6432              :  * if it's incomplete. If the chunk is fully buffered, return total number of
    6433              :  * bytes in a chunk, and store data in `data`, `data_len`.
    6434              :  */
    6435            0 : static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data,
    6436              :                                   size_t *chunk_len) {
    6437            0 :   unsigned char *s = (unsigned char *) buf;
    6438            0 :   size_t n = 0; /* scanned chunk length */
    6439            0 :   size_t i = 0; /* index in s */
    6440              : 
    6441              :   /* Scan chunk length. That should be a hexadecimal number. */
    6442            0 :   while (i < len && isxdigit(s[i])) {
    6443            0 :     n *= 16;
    6444            0 :     n += (s[i] >= '0' && s[i] <= '9') ? s[i] - '0' : tolower(s[i]) - 'a' + 10;
    6445            0 :     i++;
    6446            0 :     if (i > 6) {
    6447              :       /* Chunk size is unreasonable. */
    6448            0 :       return 0;
    6449              :     }
    6450              :   }
    6451              : 
    6452              :   /* Skip new line */
    6453            0 :   if (i == 0 || i + 2 > len || s[i] != '\r' || s[i + 1] != '\n') {
    6454            0 :     return 0;
    6455              :   }
    6456            0 :   i += 2;
    6457              : 
    6458              :   /* Record where the data is */
    6459            0 :   *chunk_data = (char *) s + i;
    6460            0 :   *chunk_len = n;
    6461              : 
    6462              :   /* Skip data */
    6463            0 :   i += n;
    6464              : 
    6465              :   /* Skip new line */
    6466            0 :   if (i == 0 || i + 2 > len || s[i] != '\r' || s[i + 1] != '\n') {
    6467            0 :     return 0;
    6468              :   }
    6469            0 :   return i + 2;
    6470              : }
    6471              : 
    6472            0 : MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
    6473              :                                      struct http_message *hm, char *buf,
    6474              :                                      size_t blen) {
    6475            0 :   struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
    6476              :   char *data;
    6477            0 :   size_t i, n, data_len, body_len, zero_chunk_received = 0;
    6478              :   /* Find out piece of received data that is not yet reassembled */
    6479            0 :   body_len = (size_t) pd->chunk.body_len;
    6480            0 :   assert(blen >= body_len);
    6481              : 
    6482              :   /* Traverse all fully buffered chunks */
    6483            0 :   for (i = body_len;
    6484            0 :        (n = mg_http_parse_chunk(buf + i, blen - i, &data, &data_len)) > 0;
    6485            0 :        i += n) {
    6486              :     /* Collapse chunk data to the rest of HTTP body */
    6487            0 :     memmove(buf + body_len, data, data_len);
    6488            0 :     body_len += data_len;
    6489            0 :     hm->body.len = body_len;
    6490              : 
    6491            0 :     if (data_len == 0) {
    6492            0 :       zero_chunk_received = 1;
    6493            0 :       i += n;
    6494            0 :       break;
    6495              :     }
    6496              :   }
    6497              : 
    6498            0 :   if (i > body_len) {
    6499              :     /* Shift unparsed content to the parsed body */
    6500            0 :     assert(i <= blen);
    6501            0 :     memmove(buf + body_len, buf + i, blen - i);
    6502            0 :     memset(buf + body_len + blen - i, 0, i - body_len);
    6503            0 :     nc->recv_mbuf.len -= i - body_len;
    6504            0 :     pd->chunk.body_len = body_len;
    6505              : 
    6506              :     /* Send MG_EV_HTTP_CHUNK event */
    6507            0 :     nc->flags &= ~MG_F_DELETE_CHUNK;
    6508            0 :     mg_call(nc, nc->handler, nc->user_data, MG_EV_HTTP_CHUNK, hm);
    6509              : 
    6510              :     /* Delete processed data if user set MG_F_DELETE_CHUNK flag */
    6511            0 :     if (nc->flags & MG_F_DELETE_CHUNK) {
    6512            0 :       memset(buf, 0, body_len);
    6513            0 :       memmove(buf, buf + body_len, blen - i);
    6514            0 :       nc->recv_mbuf.len -= body_len;
    6515            0 :       hm->body.len = 0;
    6516            0 :       pd->chunk.body_len = 0;
    6517              :     }
    6518              : 
    6519            0 :     if (zero_chunk_received) {
    6520              :       /* Total message size is len(body) + len(headers) */
    6521            0 :       hm->message.len =
    6522            0 :           (size_t) pd->chunk.body_len + blen - i + (hm->body.p - hm->message.p);
    6523              :     }
    6524              :   }
    6525              : 
    6526            0 :   return body_len;
    6527              : }
    6528              : 
    6529            0 : struct mg_http_endpoint *mg_http_get_endpoint_handler(struct mg_connection *nc,
    6530              :                                                       struct mg_str *uri_path) {
    6531              :   struct mg_http_proto_data *pd;
    6532            0 :   struct mg_http_endpoint *ret = NULL;
    6533            0 :   int matched, matched_max = 0;
    6534              :   struct mg_http_endpoint *ep;
    6535              : 
    6536            0 :   if (nc == NULL) return NULL;
    6537              : 
    6538            0 :   pd = mg_http_get_proto_data(nc);
    6539              : 
    6540            0 :   if (pd == NULL) return NULL;
    6541              : 
    6542            0 :   ep = pd->endpoints;
    6543            0 :   while (ep != NULL) {
    6544            0 :     if ((matched = mg_match_prefix_n(ep->uri_pattern, *uri_path)) > 0) {
    6545            0 :       if (matched > matched_max) {
    6546              :         /* Looking for the longest suitable handler */
    6547            0 :         ret = ep;
    6548            0 :         matched_max = matched;
    6549              :       }
    6550              :     }
    6551              : 
    6552            0 :     ep = ep->next;
    6553              :   }
    6554              : 
    6555            0 :   return ret;
    6556              : }
    6557              : 
    6558              : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
    6559              : static void mg_http_multipart_continue(struct mg_connection *nc);
    6560              : 
    6561              : static void mg_http_multipart_begin(struct mg_connection *nc,
    6562              :                                     struct http_message *hm, int req_len);
    6563              : 
    6564              : #endif
    6565              : 
    6566              : static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
    6567              :                                           struct http_message *hm);
    6568              : 
    6569            0 : static void deliver_chunk(struct mg_connection *c, struct http_message *hm,
    6570              :                           int req_len) {
    6571              :   /* Incomplete message received. Send MG_EV_HTTP_CHUNK event */
    6572            0 :   hm->body.len = c->recv_mbuf.len - req_len;
    6573            0 :   c->flags &= ~MG_F_DELETE_CHUNK;
    6574            0 :   mg_call(c, c->handler, c->user_data, MG_EV_HTTP_CHUNK, hm);
    6575              :   /* Delete processed data if user set MG_F_DELETE_CHUNK flag */
    6576            0 :   if (c->flags & MG_F_DELETE_CHUNK) c->recv_mbuf.len = req_len;
    6577            0 : }
    6578              : 
    6579              : /*
    6580              :  * lx106 compiler has a bug (TODO(mkm) report and insert tracking bug here)
    6581              :  * If a big structure is declared in a big function, lx106 gcc will make it
    6582              :  * even bigger (round up to 4k, from 700 bytes of actual size).
    6583              :  */
    6584              : #ifdef __xtensa__
    6585              : static void mg_http_handler2(struct mg_connection *nc, int ev,
    6586              :                              void *ev_data MG_UD_ARG(void *user_data),
    6587              :                              struct http_message *hm) __attribute__((noinline));
    6588              : 
    6589              : void mg_http_handler(struct mg_connection *nc, int ev,
    6590              :                      void *ev_data MG_UD_ARG(void *user_data)) {
    6591              :   struct http_message hm;
    6592              :   mg_http_handler2(nc, ev, ev_data MG_UD_ARG(user_data), &hm);
    6593              : }
    6594              : 
    6595              : static void mg_http_handler2(struct mg_connection *nc, int ev,
    6596              :                              void *ev_data MG_UD_ARG(void *user_data),
    6597              :                              struct http_message *hm) {
    6598              : #else  /* !__XTENSA__ */
    6599            0 : void mg_http_handler(struct mg_connection *nc, int ev,
    6600              :                      void *ev_data MG_UD_ARG(void *user_data)) {
    6601            0 :   struct http_message shm, *hm = &shm;
    6602              : #endif /* __XTENSA__ */
    6603            0 :   struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
    6604            0 :   struct mbuf *io = &nc->recv_mbuf;
    6605              :   int req_len;
    6606            0 :   const int is_req = (nc->listener != NULL);
    6607              : #if MG_ENABLE_HTTP_WEBSOCKET
    6608              :   struct mg_str *vec;
    6609              : #endif
    6610            0 :   if (ev == MG_EV_CLOSE) {
    6611              : #if MG_ENABLE_HTTP_CGI
    6612              :     /* Close associated CGI forwarder connection */
    6613            0 :     if (pd != NULL && pd->cgi.cgi_nc != NULL) {
    6614            0 :       pd->cgi.cgi_nc->user_data = NULL;
    6615            0 :       pd->cgi.cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    6616              :     }
    6617              : #endif
    6618              : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
    6619              :     if (pd != NULL && pd->mp_stream.boundary != NULL) {
    6620              :       /*
    6621              :        * Multipart message is in progress, but connection is closed.
    6622              :        * Finish part and request with an error flag.
    6623              :        */
    6624              :       struct mg_http_multipart_part mp;
    6625              :       memset(&mp, 0, sizeof(mp));
    6626              :       mp.status = -1;
    6627              :       mp.user_data = pd->mp_stream.user_data;
    6628              :       mp.var_name = pd->mp_stream.var_name;
    6629              :       mp.file_name = pd->mp_stream.file_name;
    6630              :       mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler),
    6631              :               nc->user_data, MG_EV_HTTP_PART_END, &mp);
    6632              :       mp.var_name = NULL;
    6633              :       mp.file_name = NULL;
    6634              :       mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler),
    6635              :               nc->user_data, MG_EV_HTTP_MULTIPART_REQUEST_END, &mp);
    6636              :     } else
    6637              : #endif
    6638            0 :         if (io->len > 0 &&
    6639            0 :             (req_len = mg_parse_http(io->buf, io->len, hm, is_req)) > 0) {
    6640              :       /*
    6641              :        * For HTTP messages without Content-Length, always send HTTP message
    6642              :        * before MG_EV_CLOSE message.
    6643              :        */
    6644            0 :       int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
    6645            0 :       hm->message.len = io->len;
    6646            0 :       hm->body.len = io->buf + io->len - hm->body.p;
    6647            0 :       deliver_chunk(nc, hm, req_len);
    6648            0 :       mg_http_call_endpoint_handler(nc, ev2, hm);
    6649              :     }
    6650            0 :     if (pd != NULL && pd->endpoint_handler != NULL &&
    6651            0 :         pd->endpoint_handler != nc->handler) {
    6652            0 :       mg_call(nc, pd->endpoint_handler, nc->user_data, ev, NULL);
    6653              :     }
    6654              :   }
    6655              : 
    6656              : #if MG_ENABLE_FILESYSTEM
    6657            0 :   if (pd != NULL && pd->file.fp != NULL) {
    6658            0 :     mg_http_transfer_file_data(nc);
    6659              :   }
    6660              : #endif
    6661              : 
    6662            0 :   mg_call(nc, nc->handler, nc->user_data, ev, ev_data);
    6663              : 
    6664              : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
    6665              :   if (pd != NULL && pd->mp_stream.boundary != NULL &&
    6666              :       (ev == MG_EV_RECV || ev == MG_EV_POLL)) {
    6667              :     if (ev == MG_EV_RECV) {
    6668              :       pd->rcvd += *(int *) ev_data;
    6669              :       mg_http_multipart_continue(nc);
    6670              :     } else if (pd->mp_stream.data_avail) {
    6671              :       /* Try re-delivering the data. */
    6672              :       mg_http_multipart_continue(nc);
    6673              :     }
    6674              :     return;
    6675              :   }
    6676              : #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
    6677              : 
    6678            0 :   if (ev == MG_EV_RECV) {
    6679              :     struct mg_str *s;
    6680              : 
    6681            0 :   again:
    6682            0 :     req_len = mg_parse_http(io->buf, io->len, hm, is_req);
    6683              : 
    6684            0 :     if (req_len > 0) {
    6685              :       /* New request - new proto data */
    6686            0 :       if (!pd) {
    6687            0 :         pd = mg_http_create_proto_data(nc);
    6688              :       }
    6689            0 :       pd->rcvd = io->len;
    6690              :     }
    6691              : 
    6692            0 :     if (req_len > 0 &&
    6693            0 :         (s = mg_get_http_header(hm, "Transfer-Encoding")) != NULL &&
    6694            0 :         mg_vcasecmp(s, "chunked") == 0) {
    6695            0 :       mg_handle_chunked(nc, hm, io->buf + req_len, io->len - req_len);
    6696              :     }
    6697              : 
    6698              : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
    6699              :     if (req_len > 0 && (s = mg_get_http_header(hm, "Content-Type")) != NULL &&
    6700              :         s->len >= 9 && strncmp(s->p, "multipart", 9) == 0) {
    6701              :       mg_http_multipart_begin(nc, hm, req_len);
    6702              :       mg_http_multipart_continue(nc);
    6703              :       return;
    6704              :     }
    6705              : #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
    6706              : 
    6707              :     /* TODO(alashkin): refactor this ifelseifelseifelseifelse */
    6708            0 :     if ((req_len < 0 ||
    6709            0 :          (req_len == 0 && io->len >= MG_MAX_HTTP_REQUEST_SIZE))) {
    6710            0 :       DBG(("invalid request"));
    6711            0 :       nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    6712            0 :     } else if (req_len == 0) {
    6713              :       /* Do nothing, request is not yet fully buffered */
    6714              :     }
    6715              : #if MG_ENABLE_HTTP_WEBSOCKET
    6716            0 :     else if (nc->listener == NULL && (nc->flags & MG_F_IS_WEBSOCKET)) {
    6717              :       /* We're websocket client, got handshake response from server. */
    6718            0 :       DBG(("%p WebSocket upgrade code %d", nc, hm->resp_code));
    6719            0 :       if (hm->resp_code == 101 &&
    6720            0 :           mg_get_http_header(hm, "Sec-WebSocket-Accept")) {
    6721              :         /* TODO(lsm): check the validity of accept Sec-WebSocket-Accept */
    6722            0 :         mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE,
    6723              :                 hm);
    6724            0 :         mbuf_remove(io, req_len);
    6725            0 :         nc->proto_handler = mg_ws_handler;
    6726            0 :         mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data));
    6727              :       } else {
    6728            0 :         mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE,
    6729              :                 hm);
    6730            0 :         nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    6731            0 :         mbuf_remove(io, req_len);
    6732              :       }
    6733            0 :     } else if (nc->listener != NULL &&
    6734            0 :                (vec = mg_get_http_header(hm, "Sec-WebSocket-Key")) != NULL) {
    6735              :       struct mg_http_endpoint *ep;
    6736              : 
    6737              :       /* This is a websocket request. Switch protocol handlers. */
    6738            0 :       mbuf_remove(io, req_len);
    6739            0 :       nc->proto_handler = mg_ws_handler;
    6740            0 :       nc->flags |= MG_F_IS_WEBSOCKET;
    6741              : 
    6742              :       /*
    6743              :        * If we have a handler set up with mg_register_http_endpoint(),
    6744              :        * deliver subsequent websocket events to this handler after the
    6745              :        * protocol switch.
    6746              :        */
    6747            0 :       ep = mg_http_get_endpoint_handler(nc->listener, &hm->uri);
    6748            0 :       if (ep != NULL) {
    6749            0 :         nc->handler = ep->handler;
    6750              : #if MG_ENABLE_CALLBACK_USERDATA
    6751              :         nc->user_data = ep->user_data;
    6752              : #endif
    6753              :       }
    6754              : 
    6755              :       /* Send handshake */
    6756            0 :       mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_REQUEST,
    6757              :               hm);
    6758            0 :       if (!(nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_SEND_AND_CLOSE))) {
    6759            0 :         if (nc->send_mbuf.len == 0) {
    6760            0 :           mg_ws_handshake(nc, vec, hm);
    6761              :         }
    6762            0 :         mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE,
    6763              :                 hm);
    6764            0 :         mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data));
    6765              :       }
    6766              :     }
    6767              : #endif /* MG_ENABLE_HTTP_WEBSOCKET */
    6768            0 :     else if (hm->message.len > pd->rcvd) {
    6769              :       /* Not yet received all HTTP body, deliver MG_EV_HTTP_CHUNK */
    6770            0 :       deliver_chunk(nc, hm, req_len);
    6771            0 :       if (nc->recv_mbuf_limit > 0 && nc->recv_mbuf.len >= nc->recv_mbuf_limit) {
    6772            0 :         LOG(LL_ERROR, ("%p recv buffer (%lu bytes) exceeds the limit "
    6773              :                        "%lu bytes, and not drained, closing",
    6774              :                        nc, (unsigned long) nc->recv_mbuf.len,
    6775              :                        (unsigned long) nc->recv_mbuf_limit));
    6776            0 :         nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    6777              :       }
    6778              :     } else {
    6779              :       /* We did receive all HTTP body. */
    6780            0 :       int request_done = 1;
    6781            0 :       int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
    6782              :       char addr[32];
    6783            0 :       mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
    6784              :                           MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
    6785            0 :       DBG(("%p %s %.*s %.*s", nc, addr, (int) hm->method.len, hm->method.p,
    6786              :            (int) hm->uri.len, hm->uri.p));
    6787            0 :       deliver_chunk(nc, hm, req_len);
    6788              :       /* Whole HTTP message is fully buffered, call event handler */
    6789            0 :       mg_http_call_endpoint_handler(nc, trigger_ev, hm);
    6790            0 :       mbuf_remove(io, hm->message.len);
    6791            0 :       pd->rcvd -= hm->message.len;
    6792              : #if MG_ENABLE_FILESYSTEM
    6793              :       /* We don't have a generic mechanism of communicating that we are done
    6794              :        * responding to a request (should probably add one). But if we are
    6795              :        * serving
    6796              :        * a file, we are definitely not done. */
    6797            0 :       if (pd->file.fp != NULL) request_done = 0;
    6798              : #endif
    6799              : #if MG_ENABLE_HTTP_CGI
    6800              :       /* If this is a CGI request, we are not done either. */
    6801            0 :       if (pd->cgi.cgi_nc != NULL) request_done = 0;
    6802              : #endif
    6803            0 :       if (request_done && io->len > 0) goto again;
    6804              :     }
    6805              :   }
    6806            0 : }
    6807              : 
    6808            0 : static size_t mg_get_line_len(const char *buf, size_t buf_len) {
    6809            0 :   size_t len = 0;
    6810            0 :   while (len < buf_len && buf[len] != '\n') len++;
    6811            0 :   return len == buf_len ? 0 : len + 1;
    6812              : }
    6813              : 
    6814              : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
    6815              : static void mg_http_multipart_begin(struct mg_connection *nc,
    6816              :                                     struct http_message *hm, int req_len) {
    6817              :   struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
    6818              :   struct mg_str *ct;
    6819              :   struct mbuf *io = &nc->recv_mbuf;
    6820              : 
    6821              :   char boundary_buf[100];
    6822              :   char *boundary = boundary_buf;
    6823              :   int boundary_len;
    6824              : 
    6825              :   ct = mg_get_http_header(hm, "Content-Type");
    6826              :   if (ct == NULL) {
    6827              :     /* We need more data - or it isn't multipart mesage */
    6828              :     goto exit_mp;
    6829              :   }
    6830              : 
    6831              :   /* Content-type should start with "multipart" */
    6832              :   if (ct->len < 9 || strncmp(ct->p, "multipart", 9) != 0) {
    6833              :     goto exit_mp;
    6834              :   }
    6835              : 
    6836              :   boundary_len =
    6837              :       mg_http_parse_header2(ct, "boundary", &boundary, sizeof(boundary_buf));
    6838              :   if (boundary_len == 0) {
    6839              :     /*
    6840              :      * Content type is multipart, but there is no boundary,
    6841              :      * probably malformed request
    6842              :      */
    6843              :     nc->flags = MG_F_CLOSE_IMMEDIATELY;
    6844              :     DBG(("invalid request"));
    6845              :     goto exit_mp;
    6846              :   }
    6847              : 
    6848              :   /* If we reach this place - that is multipart request */
    6849              : 
    6850              :   if (pd->mp_stream.boundary != NULL) {
    6851              :     /*
    6852              :      * Another streaming request was in progress,
    6853              :      * looks like protocol error
    6854              :      */
    6855              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    6856              :   } else {
    6857              :     struct mg_http_endpoint *ep = NULL;
    6858              :     pd->mp_stream.state = MPS_BEGIN;
    6859              :     pd->mp_stream.boundary = strdup(boundary);
    6860              :     pd->mp_stream.boundary_len = strlen(boundary);
    6861              :     pd->mp_stream.var_name = pd->mp_stream.file_name = NULL;
    6862              :     pd->endpoint_handler = nc->handler;
    6863              : 
    6864              :     ep = mg_http_get_endpoint_handler(nc->listener, &hm->uri);
    6865              :     if (ep != NULL) {
    6866              :       pd->endpoint_handler = ep->handler;
    6867              :     }
    6868              : 
    6869              :     mg_http_call_endpoint_handler(nc, MG_EV_HTTP_MULTIPART_REQUEST, hm);
    6870              : 
    6871              :     mbuf_remove(io, req_len);
    6872              :   }
    6873              : exit_mp:
    6874              :   if (boundary != boundary_buf) MG_FREE(boundary);
    6875              : }
    6876              : 
    6877              : #define CONTENT_DISPOSITION "Content-Disposition: "
    6878              : 
    6879              : static size_t mg_http_multipart_call_handler(struct mg_connection *c, int ev,
    6880              :                                              const char *data,
    6881              :                                              size_t data_len) {
    6882              :   struct mg_http_multipart_part mp;
    6883              :   struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
    6884              :   memset(&mp, 0, sizeof(mp));
    6885              : 
    6886              :   mp.var_name = pd->mp_stream.var_name;
    6887              :   mp.file_name = pd->mp_stream.file_name;
    6888              :   mp.user_data = pd->mp_stream.user_data;
    6889              :   mp.data.p = data;
    6890              :   mp.data.len = data_len;
    6891              :   mp.num_data_consumed = data_len;
    6892              :   mg_call(c, pd->endpoint_handler, c->user_data, ev, &mp);
    6893              :   pd->mp_stream.user_data = mp.user_data;
    6894              :   pd->mp_stream.data_avail = (mp.num_data_consumed != data_len);
    6895              :   return mp.num_data_consumed;
    6896              : }
    6897              : 
    6898              : static int mg_http_multipart_finalize(struct mg_connection *c) {
    6899              :   struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
    6900              : 
    6901              :   mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0);
    6902              :   MG_FREE((void *) pd->mp_stream.file_name);
    6903              :   pd->mp_stream.file_name = NULL;
    6904              :   MG_FREE((void *) pd->mp_stream.var_name);
    6905              :   pd->mp_stream.var_name = NULL;
    6906              :   mg_http_multipart_call_handler(c, MG_EV_HTTP_MULTIPART_REQUEST_END, NULL, 0);
    6907              :   mg_http_free_proto_data_mp_stream(&pd->mp_stream);
    6908              :   pd->mp_stream.state = MPS_FINISHED;
    6909              : 
    6910              :   return 1;
    6911              : }
    6912              : 
    6913              : static int mg_http_multipart_wait_for_boundary(struct mg_connection *c) {
    6914              :   const char *boundary;
    6915              :   struct mbuf *io = &c->recv_mbuf;
    6916              :   struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
    6917              : 
    6918              :   if (pd->mp_stream.boundary == NULL) {
    6919              :     pd->mp_stream.state = MPS_FINALIZE;
    6920              :     DBG(("Invalid request: boundary not initialized"));
    6921              :     return 0;
    6922              :   }
    6923              : 
    6924              :   if ((int) io->len < pd->mp_stream.boundary_len + 2) {
    6925              :     return 0;
    6926              :   }
    6927              : 
    6928              :   boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
    6929              :   if (boundary != NULL) {
    6930              :     const char *boundary_end = (boundary + pd->mp_stream.boundary_len);
    6931              :     if (io->len - (boundary_end - io->buf) < 4) {
    6932              :       return 0;
    6933              :     }
    6934              :     if (strncmp(boundary_end, "--\r\n", 4) == 0) {
    6935              :       pd->mp_stream.state = MPS_FINALIZE;
    6936              :       mbuf_remove(io, (boundary_end - io->buf) + 4);
    6937              :     } else {
    6938              :       pd->mp_stream.state = MPS_GOT_BOUNDARY;
    6939              :     }
    6940              :   } else {
    6941              :     return 0;
    6942              :   }
    6943              : 
    6944              :   return 1;
    6945              : }
    6946              : 
    6947              : static void mg_http_parse_header_internal(struct mg_str *hdr,
    6948              :                                           const char *var_name,
    6949              :                                           struct altbuf *ab);
    6950              : 
    6951              : static int mg_http_multipart_process_boundary(struct mg_connection *c) {
    6952              :   int data_size;
    6953              :   const char *boundary, *block_begin;
    6954              :   struct mbuf *io = &c->recv_mbuf;
    6955              :   struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
    6956              :   struct altbuf ab_file_name, ab_var_name;
    6957              :   int line_len;
    6958              :   boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
    6959              :   block_begin = boundary + pd->mp_stream.boundary_len + 2;
    6960              :   data_size = io->len - (block_begin - io->buf);
    6961              : 
    6962              :   altbuf_init(&ab_file_name, NULL, 0);
    6963              :   altbuf_init(&ab_var_name, NULL, 0);
    6964              : 
    6965              :   while (data_size > 0 &&
    6966              :          (line_len = mg_get_line_len(block_begin, data_size)) != 0) {
    6967              :     if (line_len > (int) sizeof(CONTENT_DISPOSITION) &&
    6968              :         mg_ncasecmp(block_begin, CONTENT_DISPOSITION,
    6969              :                     sizeof(CONTENT_DISPOSITION) - 1) == 0) {
    6970              :       struct mg_str header;
    6971              : 
    6972              :       header.p = block_begin + sizeof(CONTENT_DISPOSITION) - 1;
    6973              :       header.len = line_len - sizeof(CONTENT_DISPOSITION) - 1;
    6974              : 
    6975              :       altbuf_reset(&ab_var_name);
    6976              :       mg_http_parse_header_internal(&header, "name", &ab_var_name);
    6977              : 
    6978              :       altbuf_reset(&ab_file_name);
    6979              :       mg_http_parse_header_internal(&header, "filename", &ab_file_name);
    6980              : 
    6981              :       block_begin += line_len;
    6982              :       data_size -= line_len;
    6983              : 
    6984              :       continue;
    6985              :     }
    6986              : 
    6987              :     if (line_len == 2 && mg_ncasecmp(block_begin, "\r\n", 2) == 0) {
    6988              :       mbuf_remove(io, block_begin - io->buf + 2);
    6989              : 
    6990              :       if (pd->mp_stream.processing_part != 0) {
    6991              :         mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0);
    6992              :       }
    6993              : 
    6994              :       /* Reserve 2 bytes for "\r\n" in file_name and var_name */
    6995              :       altbuf_append(&ab_file_name, '\0');
    6996              :       altbuf_append(&ab_file_name, '\0');
    6997              :       altbuf_append(&ab_var_name, '\0');
    6998              :       altbuf_append(&ab_var_name, '\0');
    6999              : 
    7000              :       MG_FREE((void *) pd->mp_stream.file_name);
    7001              :       pd->mp_stream.file_name = altbuf_get_buf(&ab_file_name, 1 /* trim */);
    7002              :       MG_FREE((void *) pd->mp_stream.var_name);
    7003              :       pd->mp_stream.var_name = altbuf_get_buf(&ab_var_name, 1 /* trim */);
    7004              : 
    7005              :       mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_BEGIN, NULL, 0);
    7006              :       pd->mp_stream.state = MPS_WAITING_FOR_CHUNK;
    7007              :       pd->mp_stream.processing_part++;
    7008              :       return 1;
    7009              :     }
    7010              : 
    7011              :     block_begin += line_len;
    7012              :   }
    7013              : 
    7014              :   pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
    7015              : 
    7016              :   altbuf_reset(&ab_var_name);
    7017              :   altbuf_reset(&ab_file_name);
    7018              : 
    7019              :   return 0;
    7020              : }
    7021              : 
    7022              : static int mg_http_multipart_continue_wait_for_chunk(struct mg_connection *c) {
    7023              :   struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
    7024              :   struct mbuf *io = &c->recv_mbuf;
    7025              : 
    7026              :   const char *boundary;
    7027              :   if ((int) io->len < pd->mp_stream.boundary_len + 6 /* \r\n, --, -- */) {
    7028              :     return 0;
    7029              :   }
    7030              : 
    7031              :   boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
    7032              :   if (boundary == NULL) {
    7033              :     int data_len = (io->len - (pd->mp_stream.boundary_len + 6));
    7034              :     if (data_len > 0) {
    7035              :       size_t consumed = mg_http_multipart_call_handler(
    7036              :           c, MG_EV_HTTP_PART_DATA, io->buf, (size_t) data_len);
    7037              :       mbuf_remove(io, consumed);
    7038              :     }
    7039              :     return 0;
    7040              :   } else if (boundary != NULL) {
    7041              :     size_t data_len = ((size_t)(boundary - io->buf) - 4);
    7042              :     size_t consumed = mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA,
    7043              :                                                      io->buf, data_len);
    7044              :     mbuf_remove(io, consumed);
    7045              :     if (consumed == data_len) {
    7046              :       mbuf_remove(io, 4);
    7047              :       pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
    7048              :       return 1;
    7049              :     } else {
    7050              :       return 0;
    7051              :     }
    7052              :   } else {
    7053              :     return 0;
    7054              :   }
    7055              : }
    7056              : 
    7057              : static void mg_http_multipart_continue(struct mg_connection *c) {
    7058              :   struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
    7059              :   while (1) {
    7060              :     switch (pd->mp_stream.state) {
    7061              :       case MPS_BEGIN: {
    7062              :         pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
    7063              :         break;
    7064              :       }
    7065              :       case MPS_WAITING_FOR_BOUNDARY: {
    7066              :         if (mg_http_multipart_wait_for_boundary(c) == 0) {
    7067              :           return;
    7068              :         }
    7069              :         break;
    7070              :       }
    7071              :       case MPS_GOT_BOUNDARY: {
    7072              :         if (mg_http_multipart_process_boundary(c) == 0) {
    7073              :           return;
    7074              :         }
    7075              :         break;
    7076              :       }
    7077              :       case MPS_WAITING_FOR_CHUNK: {
    7078              :         if (mg_http_multipart_continue_wait_for_chunk(c) == 0) {
    7079              :           return;
    7080              :         }
    7081              :         break;
    7082              :       }
    7083              :       case MPS_FINALIZE: {
    7084              :         if (mg_http_multipart_finalize(c) == 0) {
    7085              :           return;
    7086              :         }
    7087              :         break;
    7088              :       }
    7089              :       case MPS_FINISHED: {
    7090              :         return;
    7091              :       }
    7092              :     }
    7093              :   }
    7094              : }
    7095              : 
    7096              : struct file_upload_state {
    7097              :   char *lfn;
    7098              :   size_t num_recd;
    7099              :   FILE *fp;
    7100              : };
    7101              : 
    7102              : #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
    7103              : 
    7104            0 : void mg_set_protocol_http_websocket(struct mg_connection *nc) {
    7105            0 :   nc->proto_handler = mg_http_handler;
    7106            0 : }
    7107              : 
    7108            0 : const char *mg_status_message(int status_code) {
    7109            0 :   switch (status_code) {
    7110            0 :     case 206:
    7111            0 :       return "Partial Content";
    7112            0 :     case 301:
    7113            0 :       return "Moved";
    7114            0 :     case 302:
    7115            0 :       return "Found";
    7116            0 :     case 400:
    7117            0 :       return "Bad Request";
    7118            0 :     case 401:
    7119            0 :       return "Unauthorized";
    7120            0 :     case 403:
    7121            0 :       return "Forbidden";
    7122            0 :     case 404:
    7123            0 :       return "Not Found";
    7124            0 :     case 416:
    7125            0 :       return "Requested Range Not Satisfiable";
    7126            0 :     case 418:
    7127            0 :       return "I'm a teapot";
    7128            0 :     case 500:
    7129            0 :       return "Internal Server Error";
    7130            0 :     case 502:
    7131            0 :       return "Bad Gateway";
    7132            0 :     case 503:
    7133            0 :       return "Service Unavailable";
    7134              : 
    7135              : #if MG_ENABLE_EXTRA_ERRORS_DESC
    7136            0 :     case 100:
    7137            0 :       return "Continue";
    7138            0 :     case 101:
    7139            0 :       return "Switching Protocols";
    7140            0 :     case 102:
    7141            0 :       return "Processing";
    7142            0 :     case 200:
    7143            0 :       return "OK";
    7144            0 :     case 201:
    7145            0 :       return "Created";
    7146            0 :     case 202:
    7147            0 :       return "Accepted";
    7148            0 :     case 203:
    7149            0 :       return "Non-Authoritative Information";
    7150            0 :     case 204:
    7151            0 :       return "No Content";
    7152            0 :     case 205:
    7153            0 :       return "Reset Content";
    7154            0 :     case 207:
    7155            0 :       return "Multi-Status";
    7156            0 :     case 208:
    7157            0 :       return "Already Reported";
    7158            0 :     case 226:
    7159            0 :       return "IM Used";
    7160            0 :     case 300:
    7161            0 :       return "Multiple Choices";
    7162            0 :     case 303:
    7163            0 :       return "See Other";
    7164            0 :     case 304:
    7165            0 :       return "Not Modified";
    7166            0 :     case 305:
    7167            0 :       return "Use Proxy";
    7168            0 :     case 306:
    7169            0 :       return "Switch Proxy";
    7170            0 :     case 307:
    7171            0 :       return "Temporary Redirect";
    7172            0 :     case 308:
    7173            0 :       return "Permanent Redirect";
    7174            0 :     case 402:
    7175            0 :       return "Payment Required";
    7176            0 :     case 405:
    7177            0 :       return "Method Not Allowed";
    7178            0 :     case 406:
    7179            0 :       return "Not Acceptable";
    7180            0 :     case 407:
    7181            0 :       return "Proxy Authentication Required";
    7182            0 :     case 408:
    7183            0 :       return "Request Timeout";
    7184            0 :     case 409:
    7185            0 :       return "Conflict";
    7186            0 :     case 410:
    7187            0 :       return "Gone";
    7188            0 :     case 411:
    7189            0 :       return "Length Required";
    7190            0 :     case 412:
    7191            0 :       return "Precondition Failed";
    7192            0 :     case 413:
    7193            0 :       return "Payload Too Large";
    7194            0 :     case 414:
    7195            0 :       return "URI Too Long";
    7196            0 :     case 415:
    7197            0 :       return "Unsupported Media Type";
    7198            0 :     case 417:
    7199            0 :       return "Expectation Failed";
    7200            0 :     case 422:
    7201            0 :       return "Unprocessable Entity";
    7202            0 :     case 423:
    7203            0 :       return "Locked";
    7204            0 :     case 424:
    7205            0 :       return "Failed Dependency";
    7206            0 :     case 426:
    7207            0 :       return "Upgrade Required";
    7208            0 :     case 428:
    7209            0 :       return "Precondition Required";
    7210            0 :     case 429:
    7211            0 :       return "Too Many Requests";
    7212            0 :     case 431:
    7213            0 :       return "Request Header Fields Too Large";
    7214            0 :     case 451:
    7215            0 :       return "Unavailable For Legal Reasons";
    7216            0 :     case 501:
    7217            0 :       return "Not Implemented";
    7218            0 :     case 504:
    7219            0 :       return "Gateway Timeout";
    7220            0 :     case 505:
    7221            0 :       return "HTTP Version Not Supported";
    7222            0 :     case 506:
    7223            0 :       return "Variant Also Negotiates";
    7224            0 :     case 507:
    7225            0 :       return "Insufficient Storage";
    7226            0 :     case 508:
    7227            0 :       return "Loop Detected";
    7228            0 :     case 510:
    7229            0 :       return "Not Extended";
    7230            0 :     case 511:
    7231            0 :       return "Network Authentication Required";
    7232              : #endif /* MG_ENABLE_EXTRA_ERRORS_DESC */
    7233              : 
    7234            0 :     default:
    7235            0 :       return "OK";
    7236              :   }
    7237              : }
    7238              : 
    7239            0 : void mg_send_response_line_s(struct mg_connection *nc, int status_code,
    7240              :                              const struct mg_str extra_headers) {
    7241            0 :   mg_printf(nc, "HTTP/1.1 %d %s\r\n", status_code,
    7242              :             mg_status_message(status_code));
    7243              : #ifndef MG_HIDE_SERVER_INFO
    7244            0 :   mg_printf(nc, "Server: %s\r\n", mg_version_header);
    7245              : #endif
    7246            0 :   if (extra_headers.len > 0) {
    7247            0 :     mg_printf(nc, "%.*s\r\n", (int) extra_headers.len, extra_headers.p);
    7248              :   }
    7249            0 : }
    7250              : 
    7251            0 : void mg_send_response_line(struct mg_connection *nc, int status_code,
    7252              :                            const char *extra_headers) {
    7253            0 :   mg_send_response_line_s(nc, status_code, mg_mk_str(extra_headers));
    7254            0 : }
    7255              : 
    7256            0 : void mg_http_send_redirect(struct mg_connection *nc, int status_code,
    7257              :                            const struct mg_str location,
    7258              :                            const struct mg_str extra_headers) {
    7259            0 :   char bbody[100], *pbody = bbody;
    7260            0 :   int bl = mg_asprintf(&pbody, sizeof(bbody),
    7261              :                        "<p>Moved <a href='%.*s'>here</a>.\r\n",
    7262            0 :                        (int) location.len, location.p);
    7263            0 :   char bhead[150], *phead = bhead;
    7264            0 :   mg_asprintf(&phead, sizeof(bhead),
    7265              :               "Location: %.*s\r\n"
    7266              :               "Content-Type: text/html\r\n"
    7267              :               "Content-Length: %d\r\n"
    7268              :               "Cache-Control: no-cache\r\n"
    7269              :               "%.*s%s",
    7270            0 :               (int) location.len, location.p, bl, (int) extra_headers.len,
    7271            0 :               extra_headers.p, (extra_headers.len > 0 ? "\r\n" : ""));
    7272            0 :   mg_send_response_line(nc, status_code, phead);
    7273            0 :   if (phead != bhead) MG_FREE(phead);
    7274            0 :   mg_send(nc, pbody, bl);
    7275            0 :   if (pbody != bbody) MG_FREE(pbody);
    7276            0 : }
    7277              : 
    7278            0 : void mg_send_head(struct mg_connection *c, int status_code,
    7279              :                   int64_t content_length, const char *extra_headers) {
    7280            0 :   mg_send_response_line(c, status_code, extra_headers);
    7281            0 :   if (content_length < 0) {
    7282            0 :     mg_printf(c, "%s", "Transfer-Encoding: chunked\r\n");
    7283              :   } else {
    7284            0 :     mg_printf(c, "Content-Length: %" INT64_FMT "\r\n", content_length);
    7285              :   }
    7286            0 :   mg_send(c, "\r\n", 2);
    7287            0 : }
    7288              : 
    7289            0 : void mg_http_send_error(struct mg_connection *nc, int code,
    7290              :                         const char *reason) {
    7291            0 :   if (!reason) reason = mg_status_message(code);
    7292            0 :   LOG(LL_DEBUG, ("%p %d %s", nc, code, reason));
    7293            0 :   mg_send_head(nc, code, strlen(reason),
    7294              :                "Content-Type: text/plain\r\nConnection: close");
    7295            0 :   mg_send(nc, reason, strlen(reason));
    7296            0 :   nc->flags |= MG_F_SEND_AND_CLOSE;
    7297            0 : }
    7298              : 
    7299              : #if MG_ENABLE_FILESYSTEM
    7300            0 : static void mg_http_construct_etag(char *buf, size_t buf_len,
    7301              :                                    const cs_stat_t *st) {
    7302            0 :   snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"", (unsigned long) st->st_mtime,
    7303            0 :            (int64_t) st->st_size);
    7304            0 : }
    7305              : 
    7306              : #ifndef WINCE
    7307            0 : static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t) {
    7308            0 :   strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
    7309            0 : }
    7310              : #else
    7311              : /* Look wince_lib.c for WindowsCE implementation */
    7312              : static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t);
    7313              : #endif
    7314              : 
    7315            0 : static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a,
    7316              :                                       int64_t *b) {
    7317              :   /*
    7318              :    * There is no snscanf. Headers are not guaranteed to be NUL-terminated,
    7319              :    * so we have this. Ugh.
    7320              :    */
    7321              :   int result;
    7322            0 :   char *p = (char *) MG_MALLOC(header->len + 1);
    7323            0 :   if (p == NULL) return 0;
    7324            0 :   memcpy(p, header->p, header->len);
    7325            0 :   p[header->len] = '\0';
    7326            0 :   result = sscanf(p, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
    7327            0 :   MG_FREE(p);
    7328            0 :   return result;
    7329              : }
    7330              : 
    7331            0 : void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
    7332              :                         const char *path, const struct mg_str mime_type,
    7333              :                         const struct mg_str extra_headers) {
    7334            0 :   struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
    7335              :   cs_stat_t st;
    7336            0 :   LOG(LL_DEBUG, ("%p [%s] %.*s", nc, path, (int) mime_type.len, mime_type.p));
    7337            0 :   if (mg_stat(path, &st) != 0 || (pd->file.fp = mg_fopen(path, "rb")) == NULL) {
    7338            0 :     int code, err = mg_get_errno();
    7339            0 :     switch (err) {
    7340            0 :       case EACCES:
    7341            0 :         code = 403;
    7342            0 :         break;
    7343            0 :       case ENOENT:
    7344            0 :         code = 404;
    7345            0 :         break;
    7346            0 :       default:
    7347            0 :         code = 500;
    7348              :     };
    7349            0 :     mg_http_send_error(nc, code, "Open failed");
    7350              :   } else {
    7351              :     char etag[50], current_time[50], last_modified[50], range[70];
    7352            0 :     time_t t = (time_t) mg_time();
    7353            0 :     int64_t r1 = 0, r2 = 0, cl = st.st_size;
    7354            0 :     struct mg_str *range_hdr = mg_get_http_header(hm, "Range");
    7355            0 :     int n, status_code = 200;
    7356              : 
    7357              :     /* Handle Range header */
    7358            0 :     range[0] = '\0';
    7359            0 :     if (range_hdr != NULL &&
    7360            0 :         (n = mg_http_parse_range_header(range_hdr, &r1, &r2)) > 0 && r1 >= 0 &&
    7361            0 :         r2 >= 0) {
    7362              :       /* If range is specified like "400-", set second limit to content len */
    7363            0 :       if (n == 1) {
    7364            0 :         r2 = cl - 1;
    7365              :       }
    7366            0 :       if (r1 > r2 || r2 >= cl) {
    7367            0 :         status_code = 416;
    7368            0 :         cl = 0;
    7369            0 :         snprintf(range, sizeof(range),
    7370              :                  "Content-Range: bytes */%" INT64_FMT "\r\n",
    7371            0 :                  (int64_t) st.st_size);
    7372              :       } else {
    7373            0 :         status_code = 206;
    7374            0 :         cl = r2 - r1 + 1;
    7375            0 :         snprintf(range, sizeof(range), "Content-Range: bytes %" INT64_FMT
    7376              :                                        "-%" INT64_FMT "/%" INT64_FMT "\r\n",
    7377            0 :                  r1, r1 + cl - 1, (int64_t) st.st_size);
    7378              : #if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \
    7379              :     _XOPEN_SOURCE >= 600
    7380            0 :         fseeko(pd->file.fp, r1, SEEK_SET);
    7381              : #else
    7382              :         fseek(pd->file.fp, (long) r1, SEEK_SET);
    7383              : #endif
    7384              :       }
    7385              :     }
    7386              : 
    7387              : #if !MG_DISABLE_HTTP_KEEP_ALIVE
    7388              :     {
    7389            0 :       struct mg_str *conn_hdr = mg_get_http_header(hm, "Connection");
    7390            0 :       if (conn_hdr != NULL) {
    7391            0 :         pd->file.keepalive = (mg_vcasecmp(conn_hdr, "keep-alive") == 0);
    7392              :       } else {
    7393            0 :         pd->file.keepalive = (mg_vcmp(&hm->proto, "HTTP/1.1") == 0);
    7394              :       }
    7395              :     }
    7396              : #endif
    7397              : 
    7398            0 :     mg_http_construct_etag(etag, sizeof(etag), &st);
    7399            0 :     mg_gmt_time_string(current_time, sizeof(current_time), &t);
    7400            0 :     mg_gmt_time_string(last_modified, sizeof(last_modified), &st.st_mtime);
    7401              :     /*
    7402              :      * Content length casted to size_t because:
    7403              :      * 1) that's the maximum buffer size anyway
    7404              :      * 2) ESP8266 RTOS SDK newlib vprintf cannot contain a 64bit arg at non-last
    7405              :      *    position
    7406              :      * TODO(mkm): fix ESP8266 RTOS SDK
    7407              :      */
    7408            0 :     mg_send_response_line_s(nc, status_code, extra_headers);
    7409            0 :     mg_printf(nc,
    7410              :               "Date: %s\r\n"
    7411              :               "Last-Modified: %s\r\n"
    7412              :               "Accept-Ranges: bytes\r\n"
    7413              :               "Content-Type: %.*s\r\n"
    7414              :               "Connection: %s\r\n"
    7415              :               "Content-Length: %" SIZE_T_FMT
    7416              :               "\r\n"
    7417              :               "%sEtag: %s\r\n\r\n",
    7418            0 :               current_time, last_modified, (int) mime_type.len, mime_type.p,
    7419            0 :               (pd->file.keepalive ? "keep-alive" : "close"), (size_t) cl, range,
    7420              :               etag);
    7421              : 
    7422            0 :     pd->file.cl = cl;
    7423            0 :     pd->file.type = DATA_FILE;
    7424            0 :     mg_http_transfer_file_data(nc);
    7425              :   }
    7426            0 : }
    7427              : 
    7428            0 : static void mg_http_serve_file2(struct mg_connection *nc, const char *path,
    7429              :                                 struct http_message *hm,
    7430              :                                 struct mg_serve_http_opts *opts) {
    7431              : #if MG_ENABLE_HTTP_SSI
    7432              :   if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern), path) > 0) {
    7433              :     mg_handle_ssi_request(nc, hm, path, opts);
    7434              :     return;
    7435              :   }
    7436              : #endif
    7437            0 :   mg_http_serve_file(nc, hm, path, mg_get_mime_type(path, "text/plain", opts),
    7438              :                      mg_mk_str(opts->extra_headers));
    7439            0 : }
    7440              : 
    7441              : #endif
    7442              : 
    7443            0 : int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
    7444              :                   int is_form_url_encoded) {
    7445              :   int i, j, a, b;
    7446              : #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
    7447              : 
    7448            0 :   for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
    7449            0 :     if (src[i] == '%') {
    7450            0 :       if (i < src_len - 2 && isxdigit(*(const unsigned char *) (src + i + 1)) &&
    7451            0 :           isxdigit(*(const unsigned char *) (src + i + 2))) {
    7452            0 :         a = tolower(*(const unsigned char *) (src + i + 1));
    7453            0 :         b = tolower(*(const unsigned char *) (src + i + 2));
    7454            0 :         dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
    7455            0 :         i += 2;
    7456              :       } else {
    7457            0 :         return -1;
    7458              :       }
    7459            0 :     } else if (is_form_url_encoded && src[i] == '+') {
    7460            0 :       dst[j] = ' ';
    7461              :     } else {
    7462            0 :       dst[j] = src[i];
    7463              :     }
    7464              :   }
    7465              : 
    7466            0 :   dst[j] = '\0'; /* Null-terminate the destination */
    7467              : 
    7468            0 :   return i >= src_len ? j : -1;
    7469              : }
    7470              : 
    7471            0 : int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst,
    7472              :                     size_t dst_len) {
    7473              :   const char *p, *e, *s;
    7474              :   size_t name_len;
    7475              :   int len;
    7476              : 
    7477              :   /*
    7478              :    * According to the documentation function returns negative
    7479              :    * value in case of error. For debug purposes it returns:
    7480              :    * -1 - src is wrong (NUUL)
    7481              :    * -2 - dst is wrong (NULL)
    7482              :    * -3 - failed to decode url or dst is to small
    7483              :    * -4 - name does not exist
    7484              :    */
    7485            0 :   if (dst == NULL || dst_len == 0) {
    7486            0 :     len = -2;
    7487            0 :   } else if (buf->p == NULL || name == NULL || buf->len == 0) {
    7488            0 :     len = -1;
    7489            0 :     dst[0] = '\0';
    7490              :   } else {
    7491            0 :     name_len = strlen(name);
    7492            0 :     e = buf->p + buf->len;
    7493            0 :     len = -4;
    7494            0 :     dst[0] = '\0';
    7495              : 
    7496            0 :     for (p = buf->p; p + name_len < e; p++) {
    7497            0 :       if ((p == buf->p || p[-1] == '&') && p[name_len] == '=' &&
    7498            0 :           !mg_ncasecmp(name, p, name_len)) {
    7499            0 :         p += name_len + 1;
    7500            0 :         s = (const char *) memchr(p, '&', (size_t)(e - p));
    7501            0 :         if (s == NULL) {
    7502            0 :           s = e;
    7503              :         }
    7504            0 :         len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
    7505              :         /* -1 means: failed to decode or dst is too small */
    7506            0 :         if (len == -1) {
    7507            0 :           len = -3;
    7508              :         }
    7509            0 :         break;
    7510              :       }
    7511              :     }
    7512              :   }
    7513              : 
    7514            0 :   return len;
    7515              : }
    7516              : 
    7517            0 : void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len) {
    7518              :   char chunk_size[50];
    7519              :   int n;
    7520              : 
    7521            0 :   n = snprintf(chunk_size, sizeof(chunk_size), "%lX\r\n", (unsigned long) len);
    7522            0 :   mg_send(nc, chunk_size, n);
    7523            0 :   mg_send(nc, buf, len);
    7524            0 :   mg_send(nc, "\r\n", 2);
    7525            0 : }
    7526              : 
    7527            0 : void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...) {
    7528            0 :   char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
    7529              :   int len;
    7530              :   va_list ap;
    7531              : 
    7532            0 :   va_start(ap, fmt);
    7533            0 :   len = mg_avprintf(&buf, sizeof(mem), fmt, ap);
    7534            0 :   va_end(ap);
    7535              : 
    7536            0 :   if (len >= 0) {
    7537            0 :     mg_send_http_chunk(nc, buf, len);
    7538              :   }
    7539              : 
    7540              :   /* LCOV_EXCL_START */
    7541              :   if (buf != mem && buf != NULL) {
    7542              :     MG_FREE(buf);
    7543              :   }
    7544              :   /* LCOV_EXCL_STOP */
    7545            0 : }
    7546              : 
    7547            0 : void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...) {
    7548            0 :   char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
    7549              :   int i, j, len;
    7550              :   va_list ap;
    7551              : 
    7552            0 :   va_start(ap, fmt);
    7553            0 :   len = mg_avprintf(&buf, sizeof(mem), fmt, ap);
    7554            0 :   va_end(ap);
    7555              : 
    7556            0 :   if (len >= 0) {
    7557            0 :     for (i = j = 0; i < len; i++) {
    7558            0 :       if (buf[i] == '<' || buf[i] == '>') {
    7559            0 :         mg_send(nc, buf + j, i - j);
    7560            0 :         mg_send(nc, buf[i] == '<' ? "&lt;" : "&gt;", 4);
    7561            0 :         j = i + 1;
    7562              :       }
    7563              :     }
    7564            0 :     mg_send(nc, buf + j, i - j);
    7565              :   }
    7566              : 
    7567              :   /* LCOV_EXCL_START */
    7568              :   if (buf != mem && buf != NULL) {
    7569              :     MG_FREE(buf);
    7570              :   }
    7571              :   /* LCOV_EXCL_STOP */
    7572            0 : }
    7573              : 
    7574            0 : static void mg_http_parse_header_internal(struct mg_str *hdr,
    7575              :                                           const char *var_name,
    7576              :                                           struct altbuf *ab) {
    7577            0 :   int ch = ' ', ch1 = ',', ch2 = ';', n = strlen(var_name);
    7578            0 :   const char *p, *end = hdr ? hdr->p + hdr->len : NULL, *s = NULL;
    7579              : 
    7580              :   /* Find where variable starts */
    7581            0 :   for (s = hdr->p; s != NULL && s + n < end; s++) {
    7582            0 :     if ((s == hdr->p || s[-1] == ch || s[-1] == ch1 || s[-1] == ';') &&
    7583            0 :         s[n] == '=' && !strncmp(s, var_name, n))
    7584            0 :       break;
    7585              :   }
    7586              : 
    7587            0 :   if (s != NULL && &s[n + 1] < end) {
    7588            0 :     s += n + 1;
    7589            0 :     if (*s == '"' || *s == '\'') {
    7590            0 :       ch = ch1 = ch2 = *s++;
    7591              :     }
    7592            0 :     p = s;
    7593            0 :     while (p < end && p[0] != ch && p[0] != ch1 && p[0] != ch2) {
    7594            0 :       if (ch != ' ' && p[0] == '\\' && p[1] == ch) p++;
    7595            0 :       altbuf_append(ab, *p++);
    7596              :     }
    7597              : 
    7598            0 :     if (ch != ' ' && *p != ch) {
    7599            0 :       altbuf_reset(ab);
    7600              :     }
    7601              :   }
    7602              : 
    7603              :   /* If there is some data, append a NUL. */
    7604            0 :   if (ab->len > 0) {
    7605            0 :     altbuf_append(ab, '\0');
    7606              :   }
    7607            0 : }
    7608              : 
    7609            0 : int mg_http_parse_header2(struct mg_str *hdr, const char *var_name, char **buf,
    7610              :                           size_t buf_size) {
    7611              :   struct altbuf ab;
    7612            0 :   altbuf_init(&ab, *buf, buf_size);
    7613            0 :   if (hdr == NULL) return 0;
    7614            0 :   if (*buf != NULL && buf_size > 0) *buf[0] = '\0';
    7615              : 
    7616            0 :   mg_http_parse_header_internal(hdr, var_name, &ab);
    7617              : 
    7618              :   /*
    7619              :    * Get a (trimmed) buffer, and return a len without a NUL byte which might
    7620              :    * have been added.
    7621              :    */
    7622            0 :   *buf = altbuf_get_buf(&ab, 1 /* trim */);
    7623            0 :   return ab.len > 0 ? ab.len - 1 : 0;
    7624              : }
    7625              : 
    7626            0 : int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
    7627              :                          size_t buf_size) {
    7628            0 :   char *buf2 = buf;
    7629              : 
    7630            0 :   int len = mg_http_parse_header2(hdr, var_name, &buf2, buf_size);
    7631              : 
    7632            0 :   if (buf2 != buf) {
    7633              :     /* Buffer was not enough and was reallocated: free it and just return 0 */
    7634            0 :     MG_FREE(buf2);
    7635            0 :     return 0;
    7636              :   }
    7637              : 
    7638            0 :   return len;
    7639              : }
    7640              : 
    7641            0 : int mg_get_http_basic_auth(struct http_message *hm, char *user, size_t user_len,
    7642              :                            char *pass, size_t pass_len) {
    7643            0 :   struct mg_str *hdr = mg_get_http_header(hm, "Authorization");
    7644            0 :   if (hdr == NULL) return -1;
    7645            0 :   return mg_parse_http_basic_auth(hdr, user, user_len, pass, pass_len);
    7646              : }
    7647              : 
    7648            0 : int mg_parse_http_basic_auth(struct mg_str *hdr, char *user, size_t user_len,
    7649              :                              char *pass, size_t pass_len) {
    7650            0 :   char *buf = NULL;
    7651              :   char fmt[64];
    7652            0 :   int res = 0;
    7653              : 
    7654            0 :   if (mg_strncmp(*hdr, mg_mk_str("Basic "), 6) != 0) return -1;
    7655              : 
    7656            0 :   buf = (char *) MG_MALLOC(hdr->len);
    7657            0 :   cs_base64_decode((unsigned char *) hdr->p + 6, hdr->len, buf, NULL);
    7658              : 
    7659              :   /* e.g. "%123[^:]:%321[^\n]" */
    7660            0 :   snprintf(fmt, sizeof(fmt), "%%%" SIZE_T_FMT "[^:]:%%%" SIZE_T_FMT "[^\n]",
    7661              :            user_len - 1, pass_len - 1);
    7662            0 :   if (sscanf(buf, fmt, user, pass) == 0) {
    7663            0 :     res = -1;
    7664              :   }
    7665              : 
    7666            0 :   MG_FREE(buf);
    7667            0 :   return res;
    7668              : }
    7669              : 
    7670              : #if MG_ENABLE_FILESYSTEM
    7671            0 : static int mg_is_file_hidden(const char *path,
    7672              :                              const struct mg_serve_http_opts *opts,
    7673              :                              int exclude_specials) {
    7674            0 :   const char *p1 = opts->per_directory_auth_file;
    7675            0 :   const char *p2 = opts->hidden_file_pattern;
    7676              : 
    7677              :   /* Strip directory path from the file name */
    7678            0 :   const char *pdir = strrchr(path, DIRSEP);
    7679            0 :   if (pdir != NULL) {
    7680            0 :     path = pdir + 1;
    7681              :   }
    7682              : 
    7683            0 :   return (exclude_specials && (!strcmp(path, ".") || !strcmp(path, ".."))) ||
    7684            0 :          (p1 != NULL && mg_match_prefix(p1, strlen(p1), path) == strlen(p1)) ||
    7685            0 :          (p2 != NULL && mg_match_prefix(p2, strlen(p2), path) > 0);
    7686              : }
    7687              : 
    7688              : #if !MG_DISABLE_HTTP_DIGEST_AUTH
    7689              : 
    7690              : #ifndef MG_EXT_MD5
    7691            0 : void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[],
    7692              :                    const size_t *msg_lens, uint8_t *digest) {
    7693              :   size_t i;
    7694              :   cs_md5_ctx md5_ctx;
    7695            0 :   cs_md5_init(&md5_ctx);
    7696            0 :   for (i = 0; i < num_msgs; i++) {
    7697            0 :     cs_md5_update(&md5_ctx, msgs[i], msg_lens[i]);
    7698              :   }
    7699            0 :   cs_md5_final(digest, &md5_ctx);
    7700            0 : }
    7701              : #else
    7702              : extern void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[],
    7703              :                           const size_t *msg_lens, uint8_t *digest);
    7704              : #endif
    7705              : 
    7706            0 : void cs_md5(char buf[33], ...) {
    7707              :   unsigned char hash[16];
    7708              :   const uint8_t *msgs[20], *p;
    7709              :   size_t msg_lens[20];
    7710            0 :   size_t num_msgs = 0;
    7711              :   va_list ap;
    7712              : 
    7713            0 :   va_start(ap, buf);
    7714            0 :   while ((p = va_arg(ap, const unsigned char *) ) != NULL) {
    7715            0 :     msgs[num_msgs] = p;
    7716            0 :     msg_lens[num_msgs] = va_arg(ap, size_t);
    7717            0 :     num_msgs++;
    7718              :   }
    7719            0 :   va_end(ap);
    7720              : 
    7721            0 :   mg_hash_md5_v(num_msgs, msgs, msg_lens, hash);
    7722            0 :   cs_to_hex(buf, hash, sizeof(hash));
    7723            0 : }
    7724              : 
    7725            0 : static void mg_mkmd5resp(const char *method, size_t method_len, const char *uri,
    7726              :                          size_t uri_len, const char *ha1, size_t ha1_len,
    7727              :                          const char *nonce, size_t nonce_len, const char *nc,
    7728              :                          size_t nc_len, const char *cnonce, size_t cnonce_len,
    7729              :                          const char *qop, size_t qop_len, char *resp) {
    7730              :   static const char colon[] = ":";
    7731              :   static const size_t one = 1;
    7732              :   char ha2[33];
    7733            0 :   cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL);
    7734            0 :   cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc,
    7735              :          nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len,
    7736              :          colon, one, ha2, sizeof(ha2) - 1, NULL);
    7737            0 : }
    7738              : 
    7739            0 : int mg_http_create_digest_auth_header(char *buf, size_t buf_len,
    7740              :                                       const char *method, const char *uri,
    7741              :                                       const char *auth_domain, const char *user,
    7742              :                                       const char *passwd, const char *nonce) {
    7743              :   static const char colon[] = ":", qop[] = "auth";
    7744              :   static const size_t one = 1;
    7745              :   char ha1[33], resp[33], cnonce[40];
    7746              : 
    7747            0 :   snprintf(cnonce, sizeof(cnonce), "%lx", (unsigned long) mg_time());
    7748            0 :   cs_md5(ha1, user, (size_t) strlen(user), colon, one, auth_domain,
    7749              :          (size_t) strlen(auth_domain), colon, one, passwd,
    7750              :          (size_t) strlen(passwd), NULL);
    7751            0 :   mg_mkmd5resp(method, strlen(method), uri, strlen(uri), ha1, sizeof(ha1) - 1,
    7752              :                nonce, strlen(nonce), "1", one, cnonce, strlen(cnonce), qop,
    7753              :                sizeof(qop) - 1, resp);
    7754            0 :   return snprintf(buf, buf_len,
    7755              :                   "Authorization: Digest username=\"%s\","
    7756              :                   "realm=\"%s\",uri=\"%s\",qop=%s,nc=1,cnonce=%s,"
    7757              :                   "nonce=%s,response=%s\r\n",
    7758            0 :                   user, auth_domain, uri, qop, cnonce, nonce, resp);
    7759              : }
    7760              : 
    7761              : /*
    7762              :  * Check for authentication timeout.
    7763              :  * Clients send time stamp encoded in nonce. Make sure it is not too old,
    7764              :  * to prevent replay attacks.
    7765              :  * Assumption: nonce is a hexadecimal number of seconds since 1970.
    7766              :  */
    7767            0 : static int mg_check_nonce(const char *nonce) {
    7768            0 :   unsigned long now = (unsigned long) mg_time();
    7769            0 :   unsigned long val = (unsigned long) strtoul(nonce, NULL, 16);
    7770            0 :   return (now >= val) && (now - val < 60 * 60);
    7771              : }
    7772              : 
    7773            0 : int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain,
    7774              :                               FILE *fp) {
    7775            0 :   int ret = 0;
    7776              :   struct mg_str *hdr;
    7777              :   char username_buf[50], cnonce_buf[64], response_buf[40], uri_buf[200],
    7778              :       qop_buf[20], nc_buf[20], nonce_buf[16];
    7779              : 
    7780            0 :   char *username = username_buf, *cnonce = cnonce_buf, *response = response_buf,
    7781            0 :        *uri = uri_buf, *qop = qop_buf, *nc = nc_buf, *nonce = nonce_buf;
    7782              : 
    7783              :   /* Parse "Authorization:" header, fail fast on parse error */
    7784            0 :   if (hm == NULL || fp == NULL ||
    7785            0 :       (hdr = mg_get_http_header(hm, "Authorization")) == NULL ||
    7786            0 :       mg_http_parse_header2(hdr, "username", &username, sizeof(username_buf)) ==
    7787            0 :           0 ||
    7788            0 :       mg_http_parse_header2(hdr, "cnonce", &cnonce, sizeof(cnonce_buf)) == 0 ||
    7789            0 :       mg_http_parse_header2(hdr, "response", &response, sizeof(response_buf)) ==
    7790            0 :           0 ||
    7791            0 :       mg_http_parse_header2(hdr, "uri", &uri, sizeof(uri_buf)) == 0 ||
    7792            0 :       mg_http_parse_header2(hdr, "qop", &qop, sizeof(qop_buf)) == 0 ||
    7793            0 :       mg_http_parse_header2(hdr, "nc", &nc, sizeof(nc_buf)) == 0 ||
    7794            0 :       mg_http_parse_header2(hdr, "nonce", &nonce, sizeof(nonce_buf)) == 0 ||
    7795            0 :       mg_check_nonce(nonce) == 0) {
    7796            0 :     ret = 0;
    7797            0 :     goto clean;
    7798              :   }
    7799              : 
    7800              :   /* NOTE(lsm): due to a bug in MSIE, we do not compare URIs */
    7801              : 
    7802            0 :   ret = mg_check_digest_auth(
    7803              :       hm->method,
    7804              :       mg_mk_str_n(
    7805              :           hm->uri.p,
    7806            0 :           hm->uri.len + (hm->query_string.len ? hm->query_string.len + 1 : 0)),
    7807              :       mg_mk_str(username), mg_mk_str(cnonce), mg_mk_str(response),
    7808              :       mg_mk_str(qop), mg_mk_str(nc), mg_mk_str(nonce), mg_mk_str(auth_domain),
    7809              :       fp);
    7810              : 
    7811            0 : clean:
    7812            0 :   if (username != username_buf) MG_FREE(username);
    7813            0 :   if (cnonce != cnonce_buf) MG_FREE(cnonce);
    7814            0 :   if (response != response_buf) MG_FREE(response);
    7815            0 :   if (uri != uri_buf) MG_FREE(uri);
    7816            0 :   if (qop != qop_buf) MG_FREE(qop);
    7817            0 :   if (nc != nc_buf) MG_FREE(nc);
    7818            0 :   if (nonce != nonce_buf) MG_FREE(nonce);
    7819              : 
    7820            0 :   return ret;
    7821              : }
    7822              : 
    7823            0 : int mg_check_digest_auth(struct mg_str method, struct mg_str uri,
    7824              :                          struct mg_str username, struct mg_str cnonce,
    7825              :                          struct mg_str response, struct mg_str qop,
    7826              :                          struct mg_str nc, struct mg_str nonce,
    7827              :                          struct mg_str auth_domain, FILE *fp) {
    7828              :   char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)];
    7829              :   char exp_resp[33];
    7830              : 
    7831              :   /*
    7832              :    * Read passwords file line by line. If should have htdigest format,
    7833              :    * i.e. each line should be a colon-separated sequence:
    7834              :    * USER_NAME:DOMAIN_NAME:HA1_HASH_OF_USER_DOMAIN_AND_PASSWORD
    7835              :    */
    7836            0 :   while (fgets(buf, sizeof(buf), fp) != NULL) {
    7837            0 :     if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3 &&
    7838            0 :         mg_vcmp(&username, f_user) == 0 &&
    7839            0 :         mg_vcmp(&auth_domain, f_domain) == 0) {
    7840              :       /* Username and domain matched, check the password */
    7841            0 :       mg_mkmd5resp(method.p, method.len, uri.p, uri.len, f_ha1, strlen(f_ha1),
    7842              :                    nonce.p, nonce.len, nc.p, nc.len, cnonce.p, cnonce.len,
    7843              :                    qop.p, qop.len, exp_resp);
    7844            0 :       LOG(LL_DEBUG, ("%.*s %s %.*s %s", (int) username.len, username.p,
    7845              :                      f_domain, (int) response.len, response.p, exp_resp));
    7846            0 :       return mg_ncasecmp(response.p, exp_resp, strlen(exp_resp)) == 0;
    7847              :     }
    7848              :   }
    7849              : 
    7850              :   /* None of the entries in the passwords file matched - return failure */
    7851            0 :   return 0;
    7852              : }
    7853              : 
    7854            0 : int mg_http_is_authorized(struct http_message *hm, struct mg_str path,
    7855              :                           const char *domain, const char *passwords_file,
    7856              :                           int flags) {
    7857              :   char buf[MG_MAX_PATH];
    7858              :   const char *p;
    7859              :   FILE *fp;
    7860            0 :   int authorized = 1;
    7861              : 
    7862            0 :   if (domain != NULL && passwords_file != NULL) {
    7863            0 :     if (flags & MG_AUTH_FLAG_IS_GLOBAL_PASS_FILE) {
    7864            0 :       fp = mg_fopen(passwords_file, "r");
    7865            0 :     } else if (flags & MG_AUTH_FLAG_IS_DIRECTORY) {
    7866            0 :       snprintf(buf, sizeof(buf), "%.*s%c%s", (int) path.len, path.p, DIRSEP,
    7867              :                passwords_file);
    7868            0 :       fp = mg_fopen(buf, "r");
    7869              :     } else {
    7870            0 :       p = strrchr(path.p, DIRSEP);
    7871            0 :       if (p == NULL) p = path.p;
    7872            0 :       snprintf(buf, sizeof(buf), "%.*s%c%s", (int) (p - path.p), path.p, DIRSEP,
    7873              :                passwords_file);
    7874            0 :       fp = mg_fopen(buf, "r");
    7875              :     }
    7876              : 
    7877            0 :     if (fp != NULL) {
    7878            0 :       authorized = mg_http_check_digest_auth(hm, domain, fp);
    7879            0 :       fclose(fp);
    7880            0 :     } else if (!(flags & MG_AUTH_FLAG_ALLOW_MISSING_FILE)) {
    7881            0 :       authorized = 0;
    7882              :     }
    7883              :   }
    7884              : 
    7885            0 :   LOG(LL_DEBUG, ("%.*s %s %x %d", (int) path.len, path.p,
    7886              :                  passwords_file ? passwords_file : "", flags, authorized));
    7887            0 :   return authorized;
    7888              : }
    7889              : #else
    7890              : int mg_http_is_authorized(struct http_message *hm, const struct mg_str path,
    7891              :                           const char *domain, const char *passwords_file,
    7892              :                           int flags) {
    7893              :   (void) hm;
    7894              :   (void) path;
    7895              :   (void) domain;
    7896              :   (void) passwords_file;
    7897              :   (void) flags;
    7898              :   return 1;
    7899              : }
    7900              : #endif
    7901              : 
    7902              : #if MG_ENABLE_DIRECTORY_LISTING
    7903            0 : static void mg_escape(const char *src, char *dst, size_t dst_len) {
    7904            0 :   size_t n = 0;
    7905            0 :   while (*src != '\0' && n + 5 < dst_len) {
    7906            0 :     unsigned char ch = *(unsigned char *) src++;
    7907            0 :     if (ch == '<') {
    7908            0 :       n += snprintf(dst + n, dst_len - n, "%s", "&lt;");
    7909              :     } else {
    7910            0 :       dst[n++] = ch;
    7911              :     }
    7912              :   }
    7913            0 :   dst[n] = '\0';
    7914            0 : }
    7915              : 
    7916            0 : static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name,
    7917              :                                cs_stat_t *stp) {
    7918              :   char size[64], mod[64], path[MG_MAX_PATH];
    7919            0 :   int64_t fsize = stp->st_size;
    7920            0 :   int is_dir = S_ISDIR(stp->st_mode);
    7921            0 :   const char *slash = is_dir ? "/" : "";
    7922              :   struct mg_str href;
    7923              : 
    7924            0 :   if (is_dir) {
    7925            0 :     snprintf(size, sizeof(size), "%s", "[DIRECTORY]");
    7926              :   } else {
    7927              :     /*
    7928              :      * We use (double) cast below because MSVC 6 compiler cannot
    7929              :      * convert unsigned __int64 to double.
    7930              :      */
    7931            0 :     if (fsize < 1024) {
    7932            0 :       snprintf(size, sizeof(size), "%d", (int) fsize);
    7933            0 :     } else if (fsize < 0x100000) {
    7934            0 :       snprintf(size, sizeof(size), "%.1fk", (double) fsize / 1024.0);
    7935            0 :     } else if (fsize < 0x40000000) {
    7936            0 :       snprintf(size, sizeof(size), "%.1fM", (double) fsize / 1048576);
    7937              :     } else {
    7938            0 :       snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824);
    7939              :     }
    7940              :   }
    7941            0 :   strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&stp->st_mtime));
    7942            0 :   mg_escape(file_name, path, sizeof(path));
    7943            0 :   href = mg_url_encode(mg_mk_str(file_name));
    7944            0 :   mg_printf_http_chunk(nc,
    7945              :                        "<tr><td><a href=\"%s%s\">%s%s</a></td>"
    7946              :                        "<td>%s</td><td name=%" INT64_FMT ">%s</td></tr>\n",
    7947              :                        href.p, slash, path, slash, mod, is_dir ? -1 : fsize,
    7948              :                        size);
    7949            0 :   free((void *) href.p);
    7950            0 : }
    7951              : 
    7952            0 : static void mg_scan_directory(struct mg_connection *nc, const char *dir,
    7953              :                               const struct mg_serve_http_opts *opts,
    7954              :                               void (*func)(struct mg_connection *, const char *,
    7955              :                                            cs_stat_t *)) {
    7956              :   char path[MG_MAX_PATH + 1];
    7957              :   cs_stat_t st;
    7958              :   struct dirent *dp;
    7959              :   DIR *dirp;
    7960              : 
    7961            0 :   LOG(LL_DEBUG, ("%p [%s]", nc, dir));
    7962            0 :   if ((dirp = (opendir(dir))) != NULL) {
    7963            0 :     while ((dp = readdir(dirp)) != NULL) {
    7964              :       /* Do not show current dir and hidden files */
    7965            0 :       if (mg_is_file_hidden((const char *) dp->d_name, opts, 1)) {
    7966            0 :         continue;
    7967              :       }
    7968            0 :       snprintf(path, sizeof(path), "%s/%s", dir, dp->d_name);
    7969            0 :       if (mg_stat(path, &st) == 0) {
    7970            0 :         func(nc, (const char *) dp->d_name, &st);
    7971              :       }
    7972              :     }
    7973            0 :     closedir(dirp);
    7974              :   } else {
    7975            0 :     LOG(LL_DEBUG, ("%p opendir(%s) -> %d", nc, dir, mg_get_errno()));
    7976              :   }
    7977            0 : }
    7978              : 
    7979            0 : static void mg_send_directory_listing(struct mg_connection *nc, const char *dir,
    7980              :                                       struct http_message *hm,
    7981              :                                       struct mg_serve_http_opts *opts) {
    7982              :   static const char *sort_js_code =
    7983              :       "<script>function srt(tb, sc, so, d) {"
    7984              :       "var tr = Array.prototype.slice.call(tb.rows, 0),"
    7985              :       "tr = tr.sort(function (a, b) { var c1 = a.cells[sc], c2 = b.cells[sc],"
    7986              :       "n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), "
    7987              :       "t1 = a.cells[2].getAttribute('name'), "
    7988              :       "t2 = b.cells[2].getAttribute('name'); "
    7989              :       "return so * (t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : "
    7990              :       "n1 ? parseInt(n2) - parseInt(n1) : "
    7991              :       "c1.textContent.trim().localeCompare(c2.textContent.trim())); });";
    7992              :   static const char *sort_js_code2 =
    7993              :       "for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]); "
    7994              :       "if (!d) window.location.hash = ('sc=' + sc + '&so=' + so); "
    7995              :       "};"
    7996              :       "window.onload = function() {"
    7997              :       "var tb = document.getElementById('tb');"
    7998              :       "var m = /sc=([012]).so=(1|-1)/.exec(window.location.hash) || [0, 2, 1];"
    7999              :       "var sc = m[1], so = m[2]; document.onclick = function(ev) { "
    8000              :       "var c = ev.target.rel; if (c) {if (c == sc) so *= -1; srt(tb, c, so); "
    8001              :       "sc = c; ev.preventDefault();}};"
    8002              :       "srt(tb, sc, so, true);"
    8003              :       "}"
    8004              :       "</script>";
    8005              : 
    8006            0 :   mg_send_response_line(nc, 200, opts->extra_headers);
    8007            0 :   mg_printf(nc, "%s: %s\r\n%s: %s\r\n\r\n", "Transfer-Encoding", "chunked",
    8008              :             "Content-Type", "text/html; charset=utf-8");
    8009              : 
    8010            0 :   mg_printf_http_chunk(
    8011              :       nc,
    8012              :       "<html><head><title>Index of %.*s</title>%s%s"
    8013              :       "<style>th,td {text-align: left; padding-right: 1em; "
    8014              :       "font-family: monospace; }</style></head>\n"
    8015              :       "<body><h1>Index of %.*s</h1>\n<table cellpadding=0><thead>"
    8016              :       "<tr><th><a href=# rel=0>Name</a></th><th>"
    8017              :       "<a href=# rel=1>Modified</a</th>"
    8018              :       "<th><a href=# rel=2>Size</a></th></tr>"
    8019              :       "<tr><td colspan=3><hr></td></tr>\n"
    8020              :       "</thead>\n"
    8021              :       "<tbody id=tb>",
    8022            0 :       (int) hm->uri.len, hm->uri.p, sort_js_code, sort_js_code2,
    8023            0 :       (int) hm->uri.len, hm->uri.p);
    8024            0 :   mg_scan_directory(nc, dir, opts, mg_print_dir_entry);
    8025            0 :   mg_printf_http_chunk(nc,
    8026              :                        "</tbody><tr><td colspan=3><hr></td></tr>\n"
    8027              :                        "</table>\n"
    8028              :                        "<address>%s</address>\n"
    8029              :                        "</body></html>",
    8030              :                        mg_version_header);
    8031            0 :   mg_send_http_chunk(nc, "", 0);
    8032              :   /* TODO(rojer): Remove when cesanta/dev/issues/197 is fixed. */
    8033            0 :   nc->flags |= MG_F_SEND_AND_CLOSE;
    8034            0 : }
    8035              : #endif /* MG_ENABLE_DIRECTORY_LISTING */
    8036              : 
    8037              : /*
    8038              :  * Given a directory path, find one of the files specified in the
    8039              :  * comma-separated list of index files `list`.
    8040              :  * First found index file wins. If an index file is found, then gets
    8041              :  * appended to the `path`, stat-ed, and result of `stat()` passed to `stp`.
    8042              :  * If index file is not found, then `path` and `stp` remain unchanged.
    8043              :  */
    8044            0 : MG_INTERNAL void mg_find_index_file(const char *path, const char *list,
    8045              :                                     char **index_file, cs_stat_t *stp) {
    8046              :   struct mg_str vec;
    8047            0 :   size_t path_len = strlen(path);
    8048            0 :   int found = 0;
    8049            0 :   *index_file = NULL;
    8050              : 
    8051              :   /* Traverse index files list. For each entry, append it to the given */
    8052              :   /* path and see if the file exists. If it exists, break the loop */
    8053            0 :   while ((list = mg_next_comma_list_entry(list, &vec, NULL)) != NULL) {
    8054              :     cs_stat_t st;
    8055            0 :     size_t len = path_len + 1 + vec.len + 1;
    8056            0 :     *index_file = (char *) MG_REALLOC(*index_file, len);
    8057            0 :     if (*index_file == NULL) break;
    8058            0 :     snprintf(*index_file, len, "%s%c%.*s", path, DIRSEP, (int) vec.len, vec.p);
    8059              : 
    8060              :     /* Does it exist? Is it a file? */
    8061            0 :     if (mg_stat(*index_file, &st) == 0 && S_ISREG(st.st_mode)) {
    8062              :       /* Yes it does, break the loop */
    8063            0 :       *stp = st;
    8064            0 :       found = 1;
    8065            0 :       break;
    8066              :     }
    8067              :   }
    8068            0 :   if (!found) {
    8069            0 :     MG_FREE(*index_file);
    8070            0 :     *index_file = NULL;
    8071              :   }
    8072            0 :   LOG(LL_DEBUG, ("[%s] [%s]", path, (*index_file ? *index_file : "")));
    8073            0 : }
    8074              : 
    8075              : #if MG_ENABLE_HTTP_URL_REWRITES
    8076            0 : static int mg_http_send_port_based_redirect(
    8077              :     struct mg_connection *c, struct http_message *hm,
    8078              :     const struct mg_serve_http_opts *opts) {
    8079            0 :   const char *rewrites = opts->url_rewrites;
    8080              :   struct mg_str a, b;
    8081            0 :   char local_port[20] = {'%'};
    8082              : 
    8083            0 :   mg_conn_addr_to_str(c, local_port + 1, sizeof(local_port) - 1,
    8084              :                       MG_SOCK_STRINGIFY_PORT);
    8085              : 
    8086            0 :   while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
    8087            0 :     if (mg_vcmp(&a, local_port) == 0) {
    8088            0 :       mg_send_response_line(c, 301, NULL);
    8089            0 :       mg_printf(c, "Content-Length: 0\r\nLocation: %.*s%.*s\r\n\r\n",
    8090            0 :                 (int) b.len, b.p, (int) (hm->proto.p - hm->uri.p - 1),
    8091              :                 hm->uri.p);
    8092            0 :       return 1;
    8093              :     }
    8094              :   }
    8095              : 
    8096            0 :   return 0;
    8097              : }
    8098              : 
    8099            0 : static uint64_t ContentLength(const std::string& msg)
    8100              : {
    8101            0 :   const char* CRLFCRLF = "\r\n\r\n";
    8102            0 :   size_t pos = msg.find(CRLFCRLF);
    8103            0 :   if (pos == std::string::npos) {
    8104            0 :     return 0;
    8105              :   }
    8106              :   //printf("msg.length %d, pos %d\n", (int)msg.length(), (int)pos);
    8107            0 :   return msg.length() - pos - 4;
    8108              : }
    8109              : 
    8110            0 : static void SetContentLength(std::string& msg, uint64_t len)
    8111              : { 
    8112            0 :   const char* CRLF = "\r\n";
    8113            0 :   const char* CL = "Content-Length: ";
    8114            0 :   size_t pos = msg.find(CL);
    8115            0 :   if (pos == std::string::npos) {
    8116            0 :     return;
    8117              :   }
    8118            0 :   pos += strlen(CL);
    8119            0 :   size_t pos2 = msg.find(CRLF, pos);
    8120            0 :   if (pos2 == std::string::npos) {
    8121            0 :     return;
    8122              :   }
    8123              :   char buf[256];
    8124            0 :   sprintf(buf, "%llu", (long long unsigned)len);
    8125            0 :   msg.replace(pos, pos2-pos, buf);
    8126              :   //printf("content-length %d, pos %d, pos2 %d\n", (int)len, (int)pos, (int)pos2);
    8127              : }
    8128              : 
    8129            0 : bool Rewrite(std::string& message, const char* re, const char* rs)
    8130              : {
    8131            0 :   bool changed = false;
    8132            0 :   size_t pos = 0;
    8133            0 :   size_t len = strlen(re);
    8134              :   while (1) {
    8135            0 :     pos = message.find(re, pos);
    8136            0 :     if (pos == std::string::npos) {
    8137            0 :       break;
    8138              :     }
    8139            0 :     message.replace(pos, len, rs);
    8140            0 :     changed = true;
    8141              :   }
    8142            0 :   return changed;
    8143              : }
    8144              : 
    8145            0 : static void mg_reverse_proxy_handler(struct mg_connection *nc, int ev,
    8146              :                                      void *ev_data MG_UD_ARG(void *user_data)) {
    8147            0 :   struct http_message *hm = (struct http_message *) ev_data;
    8148            0 :   struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
    8149              : 
    8150            0 :   if (pd == NULL || pd->reverse_proxy_data.linked_conn == NULL) {
    8151            0 :     DBG(("%p: upstream closed", nc));
    8152            0 :     return;
    8153              :   }
    8154              : 
    8155              :   //if (ev != 0) {
    8156              :   //   printf("proxy event %d\n", ev);
    8157              :   //}
    8158              : 
    8159            0 :   switch (ev) {
    8160            0 :     case MG_EV_CONNECT:
    8161            0 :       if (*(int *) ev_data != 0) {
    8162            0 :         mg_http_send_error(pd->reverse_proxy_data.linked_conn, 502, NULL);
    8163              :       }
    8164            0 :       break;
    8165              :     /* TODO(mkm): handle streaming */
    8166            0 :   case MG_EV_RECV: {
    8167              :      //struct mbuf *io = &nc->recv_mbuf;
    8168              :      //printf("proxy read: %d bytes [%s]\n", (int)io->len, io->buf);
    8169            0 :      break;
    8170              :   }
    8171            0 :   case MG_EV_HTTP_REPLY: {
    8172              :      // HTTP header "Transfer-Encoding: chunked" has to be removed:
    8173              :      // proxy data is chunked, after mongoose reads it, chunking is removed,
    8174              :      // it is sent to requestor all in one go (not chunked), but
    8175              :      // Transfer-Encoding header is still there and confuses the web browser.
    8176              :      // We hack the message to hide this header and everything works. K.O.
    8177              :      mg_str xstr;
    8178            0 :      xstr.p = "Transfer-Encoding: chunked";
    8179            0 :      xstr.len = strlen(xstr.p);
    8180            0 :      const char* s = mg_strstr(hm->message, xstr);
    8181            0 :      if (s) {
    8182            0 :         *(char*)s = 'X';
    8183              :      }
    8184              :      //printf("proxy reply: [%s]\n", hm->message.p);
    8185              :      if (0) {
    8186              :        std::string message_in(hm->message.p, hm->message.len);
    8187              :        // <link rel="icon" type="image/png" href="/static/favicons/favicon-16px-a64986.png" sizes="16x16">
    8188              :        // <script type="text/javascript" src="/static/scripts/bundle-9e842c.js"></script></body>
    8189              :        //std::regex re("href=\"/");
    8190              :        //std::string rs("href=\"");
    8191              :        //std::regex re("h");
    8192              :        //std::string rs("XXX");
    8193              :        //std::regex re ("\\b(sub)([^ ]*)");
    8194              :        //std::string message = std::regex_replace(message_in.c_str(), re, "sub-$2");
    8195              :        bool changed = false;
    8196              :        std::string message = message_in;
    8197              :        changed |= Rewrite(message, "href=\"/", "href=\"");
    8198              :        changed |= Rewrite(message, "src=\"/", "src=\"");
    8199              :        // ...post("/api/...
    8200              :        changed |= Rewrite(message, "post(\"/api/", "post(\"api/");
    8201              :        if (changed) {
    8202              :          // need to doctor ContentLength!
    8203              :          SetContentLength(message, ContentLength(message));
    8204              :          //printf("proxy rewrite:\n[%s] content-length %d\n[%s] content-length %d\n", message_in.c_str(), (int)ContentLength(message_in), message.c_str(), (int)ContentLength(message));
    8205              :          mg_send(pd->reverse_proxy_data.linked_conn, message.c_str(), message.length());
    8206              :        } else {
    8207              :          mg_send(pd->reverse_proxy_data.linked_conn, hm->message.p, hm->message.len);
    8208              :        }
    8209              :      } else {
    8210            0 :        mg_send(pd->reverse_proxy_data.linked_conn, hm->message.p, hm->message.len);
    8211              :      }
    8212            0 :      pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE;
    8213            0 :      nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    8214            0 :      break;
    8215              :   }
    8216            0 :   case MG_EV_CLOSE: {
    8217            0 :      struct mbuf *io = &nc->recv_mbuf;
    8218              :      //printf("proxy close: mbuf %p, bytes %d\n", io, (int)io->len); //, io->buf);
    8219            0 :      if (io->len > 0) {
    8220            0 :         mg_send(pd->reverse_proxy_data.linked_conn, io->buf, io->len);
    8221              :      }
    8222            0 :      pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE;
    8223            0 :      break;
    8224              :   }
    8225              :   }
    8226              : 
    8227              : #if MG_ENABLE_CALLBACK_USERDATA
    8228              :   (void) user_data;
    8229              : #endif
    8230              : }
    8231              : 
    8232            0 : void mg_http_reverse_proxy(struct mg_connection *nc,
    8233              :                            const struct http_message *hm, struct mg_str mount,
    8234              :                            struct mg_str upstream) {
    8235              :   struct mg_connection *be;
    8236            0 :   char burl[256], *purl = burl;
    8237              :   int i;
    8238              :   const char *error;
    8239              :   struct mg_connect_opts opts;
    8240            0 :   struct mg_str path = MG_NULL_STR, user_info = MG_NULL_STR, host = MG_NULL_STR;
    8241            0 :   memset(&opts, 0, sizeof(opts));
    8242            0 :   opts.error_string = &error;
    8243              : 
    8244            0 :   mg_asprintf(&purl, sizeof(burl), "%.*s%.*s%s%.*s", (int) upstream.len, upstream.p,
    8245            0 :     (int) (hm->uri.len - mount.len), hm->uri.p + mount.len, (hm->query_string.len > 0 ? "?" : ""), (int) hm->query_string.len, hm->query_string.p);
    8246              : 
    8247              :   //printf("proxy url: [%s]\n", purl);
    8248              : 
    8249            0 :   be = mg_connect_http_base(nc->mgr, MG_CB(mg_reverse_proxy_handler, NULL),
    8250              :                             opts, "http", NULL, "https", NULL, purl, &path,
    8251              :                             &user_info, &host);
    8252            0 :   LOG(LL_DEBUG, ("Proxying %.*s to %s (rule: %.*s)", (int) hm->uri.len,
    8253              :                  hm->uri.p, purl, (int) mount.len, mount.p));
    8254              : 
    8255            0 :   if (be == NULL) {
    8256            0 :     LOG(LL_ERROR, ("Error connecting to %s: %s", purl, error));
    8257            0 :     mg_http_send_error(nc, 502, NULL);
    8258            0 :     goto cleanup;
    8259              :   }
    8260              : 
    8261            0 :   mg_http_create_proto_data(be);
    8262              : 
    8263              :   /* link connections to each other, they must live and die together */
    8264            0 :   mg_http_get_proto_data(be)->reverse_proxy_data.linked_conn = nc;
    8265            0 :   mg_http_get_proto_data(nc)->reverse_proxy_data.linked_conn = be;
    8266              : 
    8267              :   /* send request upstream */
    8268            0 :   mg_printf(be, "%.*s %.*s HTTP/1.1\r\n", (int) hm->method.len, hm->method.p,
    8269            0 :             (int) path.len, path.p);
    8270              : 
    8271            0 :   mg_printf(be, "Host: %.*s\r\n", (int) host.len, host.p);
    8272            0 :   for (i = 0; i < MG_MAX_HTTP_HEADERS && hm->header_names[i].len > 0; i++) {
    8273            0 :     struct mg_str hn = hm->header_names[i];
    8274            0 :     struct mg_str hv = hm->header_values[i];
    8275              : 
    8276              :     /* we rewrite the host header */
    8277            0 :     if (mg_vcasecmp(&hn, "Host") == 0) continue;
    8278              :     /*
    8279              :      * Don't pass chunked transfer encoding to the client because hm->body is
    8280              :      * already dechunked when we arrive here.
    8281              :      */
    8282            0 :     if (mg_vcasecmp(&hn, "Transfer-encoding") == 0 &&
    8283            0 :         mg_vcasecmp(&hv, "chunked") == 0) {
    8284            0 :       mg_printf(be, "Content-Length: %" SIZE_T_FMT "\r\n", hm->body.len);
    8285            0 :       continue;
    8286              :     }
    8287              :     /* We don't support proxying Expect: 100-continue. */
    8288            0 :     if (mg_vcasecmp(&hn, "Expect") == 0 &&
    8289            0 :         mg_vcasecmp(&hv, "100-continue") == 0) {
    8290            0 :       continue;
    8291              :     }
    8292              : 
    8293            0 :     mg_printf(be, "%.*s: %.*s\r\n", (int) hn.len, hn.p, (int) hv.len, hv.p);
    8294              :   }
    8295              : 
    8296            0 :   mg_send(be, "\r\n", 2);
    8297            0 :   mg_send(be, hm->body.p, hm->body.len);
    8298              : 
    8299            0 : cleanup:
    8300            0 :   if (purl != burl) MG_FREE(purl);
    8301            0 : }
    8302              : 
    8303            0 : static int mg_http_handle_forwarding(struct mg_connection *nc,
    8304              :                                      struct http_message *hm,
    8305              :                                      const struct mg_serve_http_opts *opts) {
    8306            0 :   const char *rewrites = opts->url_rewrites;
    8307              :   struct mg_str a, b;
    8308            0 :   struct mg_str p1 = MG_MK_STR("http://"), p2 = MG_MK_STR("https://");
    8309              : 
    8310            0 :   while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
    8311            0 :     if (mg_strncmp(a, hm->uri, a.len) == 0) {
    8312            0 :       if (mg_strncmp(b, p1, p1.len) == 0 || mg_strncmp(b, p2, p2.len) == 0) {
    8313            0 :         mg_http_reverse_proxy(nc, hm, a, b);
    8314            0 :         return 1;
    8315              :       }
    8316              :     }
    8317              :   }
    8318              : 
    8319            0 :   return 0;
    8320              : }
    8321              : #endif /* MG_ENABLE_FILESYSTEM */
    8322              : 
    8323              : #if 0
    8324              : MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
    8325              :                                      const struct mg_serve_http_opts *opts,
    8326              :                                      char **local_path,
    8327              :                                      struct mg_str *remainder) {
    8328              :   int ok = 1;
    8329              :   const char *cp = hm->uri.p, *cp_end = hm->uri.p + hm->uri.len;
    8330              :   struct mg_str root = {NULL, 0};
    8331              :   const char *file_uri_start = cp;
    8332              :   *local_path = NULL;
    8333              :   remainder->p = NULL;
    8334              :   remainder->len = 0;
    8335              : 
    8336              :   { /* 1. Determine which root to use. */
    8337              : 
    8338              : #if MG_ENABLE_HTTP_URL_REWRITES
    8339              :     const char *rewrites = opts->url_rewrites;
    8340              : #else
    8341              :     const char *rewrites = "";
    8342              : #endif
    8343              :     struct mg_str *hh = mg_get_http_header(hm, "Host");
    8344              :     struct mg_str a, b;
    8345              :     /* Check rewrites first. */
    8346              :     while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
    8347              :       if (a.len > 1 && a.p[0] == '@') {
    8348              :         /* Host rewrite. */
    8349              :         if (hh != NULL && hh->len == a.len - 1 &&
    8350              :             mg_ncasecmp(a.p + 1, hh->p, a.len - 1) == 0) {
    8351              :           root = b;
    8352              :           break;
    8353              :         }
    8354              :       } else {
    8355              :         /* Regular rewrite, URI=directory */
    8356              :         size_t match_len = mg_match_prefix_n(a, hm->uri);
    8357              :         if (match_len > 0) {
    8358              :           file_uri_start = hm->uri.p + match_len;
    8359              :           if (*file_uri_start == '/' || file_uri_start == cp_end) {
    8360              :             /* Match ended at component boundary, ok. */
    8361              :           } else if (*(file_uri_start - 1) == '/') {
    8362              :             /* Pattern ends with '/', backtrack. */
    8363              :             file_uri_start--;
    8364              :           } else {
    8365              :             /* No match: must fall on the component boundary. */
    8366              :             continue;
    8367              :           }
    8368              :           root = b;
    8369              :           break;
    8370              :         }
    8371              :       }
    8372              :     }
    8373              :     /* If no rewrite rules matched, use DAV or regular document root. */
    8374              :     if (root.p == NULL) {
    8375              : #if MG_ENABLE_HTTP_WEBDAV
    8376              :       if (opts->dav_document_root != NULL && mg_is_dav_request(&hm->method)) {
    8377              :         root.p = opts->dav_document_root;
    8378              :         root.len = strlen(opts->dav_document_root);
    8379              :       } else
    8380              : #endif
    8381              :       {
    8382              :         root.p = opts->document_root;
    8383              :         root.len = strlen(opts->document_root);
    8384              :       }
    8385              :     }
    8386              :     assert(root.p != NULL && root.len > 0);
    8387              :   }
    8388              : 
    8389              :   { /* 2. Find where in the canonical URI path the local path ends. */
    8390              :     const char *u = file_uri_start + 1;
    8391              :     char *lp = (char *) MG_MALLOC(root.len + hm->uri.len + 1);
    8392              :     char *lp_end = lp + root.len + hm->uri.len + 1;
    8393              :     char *p = lp, *ps;
    8394              :     int exists = 1;
    8395              :     if (lp == NULL) {
    8396              :       ok = 0;
    8397              :       goto out;
    8398              :     }
    8399              :     memcpy(p, root.p, root.len);
    8400              :     p += root.len;
    8401              :     if (*(p - 1) == DIRSEP) p--;
    8402              :     *p = '\0';
    8403              :     ps = p;
    8404              : 
    8405              :     /* Chop off URI path components one by one and build local path. */
    8406              :     while (u <= cp_end) {
    8407              :       const char *next = u;
    8408              :       struct mg_str component;
    8409              :       if (exists) {
    8410              :         cs_stat_t st;
    8411              :         exists = (mg_stat(lp, &st) == 0);
    8412              :         if (exists && S_ISREG(st.st_mode)) {
    8413              :           /* We found the terminal, the rest of the URI (if any) is path_info.
    8414              :            */
    8415              :           if (*(u - 1) == '/') u--;
    8416              :           break;
    8417              :         }
    8418              :       }
    8419              :       if (u >= cp_end) break;
    8420              :       parse_uri_component((const char **) &next, cp_end, "/", &component);
    8421              :       if (component.len > 0) {
    8422              :         int len;
    8423              :         memmove(p + 1, component.p, component.len);
    8424              :         len = mg_url_decode(p + 1, component.len, p + 1, lp_end - p - 1, 0);
    8425              :         if (len <= 0) {
    8426              :           ok = 0;
    8427              :           break;
    8428              :         }
    8429              :         component.p = p + 1;
    8430              :         component.len = len;
    8431              :         if (mg_vcmp(&component, ".") == 0) {
    8432              :           /* Yum. */
    8433              :         } else if (mg_vcmp(&component, "..") == 0) {
    8434              :           while (p > ps && *p != DIRSEP) p--;
    8435              :           *p = '\0';
    8436              :         } else {
    8437              :           size_t i;
    8438              : #ifdef _WIN32
    8439              :           /* On Windows, make sure it's valid Unicode (no funny stuff). */
    8440              :           wchar_t buf[MG_MAX_PATH * 2];
    8441              :           if (to_wchar(component.p, buf, MG_MAX_PATH) == 0) {
    8442              :             DBG(("[%.*s] smells funny", (int) component.len, component.p));
    8443              :             ok = 0;
    8444              :             break;
    8445              :           }
    8446              : #endif
    8447              :           *p++ = DIRSEP;
    8448              :           /* No NULs and DIRSEPs in the component (percent-encoded). */
    8449              :           for (i = 0; i < component.len; i++, p++) {
    8450              :             if (*p == '\0' || *p == DIRSEP
    8451              : #ifdef _WIN32
    8452              :                 /* On Windows, "/" is also accepted, so check for that too. */
    8453              :                 ||
    8454              :                 *p == '/'
    8455              : #endif
    8456              :                 ) {
    8457              :               ok = 0;
    8458              :               break;
    8459              :             }
    8460              :           }
    8461              :         }
    8462              :       }
    8463              :       u = next;
    8464              :     }
    8465              :     if (ok) {
    8466              :       *local_path = lp;
    8467              :       if (u > cp_end) u = cp_end;
    8468              :       remainder->p = u;
    8469              :       remainder->len = cp_end - u;
    8470              :     } else {
    8471              :       MG_FREE(lp);
    8472              :     }
    8473              :   }
    8474              : 
    8475              : out:
    8476              :   LOG(LL_DEBUG,
    8477              :       ("'%.*s' -> '%s' + '%.*s'", (int) hm->uri.len, hm->uri.p,
    8478              :        *local_path ? *local_path : "", (int) remainder->len, remainder->p));
    8479              :   return ok;
    8480              : }
    8481              : #endif
    8482              : 
    8483            0 : static int mg_get_month_index(const char *s) {
    8484              :   static const char *month_names[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
    8485              :                                       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    8486              :   size_t i;
    8487              : 
    8488            0 :   for (i = 0; i < ARRAY_SIZE(month_names); i++)
    8489            0 :     if (!strcmp(s, month_names[i])) return (int) i;
    8490              : 
    8491            0 :   return -1;
    8492              : }
    8493              : 
    8494            0 : static int mg_num_leap_years(int year) {
    8495            0 :   return year / 4 - year / 100 + year / 400;
    8496              : }
    8497              : 
    8498              : /* Parse UTC date-time string, and return the corresponding time_t value. */
    8499            0 : MG_INTERNAL time_t mg_parse_date_string(const char *datetime) {
    8500              :   static const unsigned short days_before_month[] = {
    8501              :       0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
    8502              :   char month_str[32];
    8503              :   int second, minute, hour, day, month, year, leap_days, days;
    8504            0 :   time_t result = (time_t) 0;
    8505              : 
    8506            0 :   if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d", &day, month_str, &year, &hour,
    8507            0 :                &minute, &second) == 6) ||
    8508            0 :        (sscanf(datetime, "%d %3s %d %d:%d:%d", &day, month_str, &year, &hour,
    8509            0 :                &minute, &second) == 6) ||
    8510            0 :        (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d", &day, month_str, &year,
    8511            0 :                &hour, &minute, &second) == 6) ||
    8512            0 :        (sscanf(datetime, "%d-%3s-%d %d:%d:%d", &day, month_str, &year, &hour,
    8513            0 :                &minute, &second) == 6)) &&
    8514            0 :       year > 1970 && (month = mg_get_month_index(month_str)) != -1) {
    8515            0 :     leap_days = mg_num_leap_years(year) - mg_num_leap_years(1970);
    8516            0 :     year -= 1970;
    8517            0 :     days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
    8518            0 :     result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
    8519              :   }
    8520              : 
    8521            0 :   return result;
    8522              : }
    8523              : 
    8524            0 : MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st) {
    8525              :   struct mg_str *hdr;
    8526            0 :   if ((hdr = mg_get_http_header(hm, "If-None-Match")) != NULL) {
    8527              :     char etag[64];
    8528            0 :     mg_http_construct_etag(etag, sizeof(etag), st);
    8529            0 :     return mg_vcasecmp(hdr, etag) == 0;
    8530            0 :   } else if ((hdr = mg_get_http_header(hm, "If-Modified-Since")) != NULL) {
    8531            0 :     return st->st_mtime <= mg_parse_date_string(hdr->p);
    8532              :   } else {
    8533            0 :     return 0;
    8534              :   }
    8535              : }
    8536              : 
    8537            0 : void mg_http_send_digest_auth_request(struct mg_connection *c,
    8538              :                                       const char *domain) {
    8539            0 :   mg_printf(c,
    8540              :             "HTTP/1.1 401 Unauthorized\r\n"
    8541              :             "WWW-Authenticate: Digest qop=\"auth\", "
    8542              :             "realm=\"%s\", nonce=\"%lx\"\r\n"
    8543              :             "Content-Length: 0\r\n\r\n",
    8544            0 :             domain, (unsigned long) mg_time());
    8545            0 : }
    8546              : 
    8547            0 : static void mg_http_send_options(struct mg_connection *nc,
    8548              :                                  struct mg_serve_http_opts *opts) {
    8549            0 :   mg_send_response_line(nc, 200, opts->extra_headers);
    8550            0 :   mg_printf(nc, "%s",
    8551              :             "Allow: GET, POST, HEAD, CONNECT, OPTIONS"
    8552              : #if MG_ENABLE_HTTP_WEBDAV
    8553              :             ", MKCOL, PUT, DELETE, PROPFIND, MOVE\r\nDAV: 1,2"
    8554              : #endif
    8555              :             "\r\n\r\n");
    8556            0 :   nc->flags |= MG_F_SEND_AND_CLOSE;
    8557            0 : }
    8558              : 
    8559            0 : static int mg_is_creation_request(const struct http_message *hm) {
    8560            0 :   return mg_vcmp(&hm->method, "MKCOL") == 0 || mg_vcmp(&hm->method, "PUT") == 0;
    8561              : }
    8562              : 
    8563            0 : MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
    8564              :                                    const struct mg_str *path_info,
    8565              :                                    struct http_message *hm,
    8566              :                                    struct mg_serve_http_opts *opts) {
    8567              :   int exists, is_directory, is_cgi;
    8568              : #if MG_ENABLE_HTTP_WEBDAV
    8569              :   int is_dav = mg_is_dav_request(&hm->method);
    8570              : #else
    8571            0 :   int is_dav = 0;
    8572              : #endif
    8573            0 :   char *index_file = NULL;
    8574              :   cs_stat_t st;
    8575              : 
    8576            0 :   exists = (mg_stat(path, &st) == 0);
    8577            0 :   is_directory = exists && S_ISDIR(st.st_mode);
    8578              : 
    8579            0 :   if (is_directory)
    8580            0 :     mg_find_index_file(path, opts->index_files, &index_file, &st);
    8581              : 
    8582            0 :   is_cgi =
    8583            0 :       (mg_match_prefix(opts->cgi_file_pattern, strlen(opts->cgi_file_pattern),
    8584            0 :                        index_file ? index_file : path) > 0);
    8585              : 
    8586            0 :   LOG(LL_DEBUG,
    8587              :       ("%p %.*s [%s] exists=%d is_dir=%d is_dav=%d is_cgi=%d index=%s", nc,
    8588              :        (int) hm->method.len, hm->method.p, path, exists, is_directory, is_dav,
    8589              :        is_cgi, index_file ? index_file : ""));
    8590              : 
    8591            0 :   if (is_directory && hm->uri.p[hm->uri.len - 1] != '/' && !is_dav) {
    8592            0 :     mg_printf(nc,
    8593              :               "HTTP/1.1 301 Moved\r\nLocation: %.*s/\r\n"
    8594              :               "Content-Length: 0\r\n\r\n",
    8595            0 :               (int) hm->uri.len, hm->uri.p);
    8596            0 :     MG_FREE(index_file);
    8597            0 :     return;
    8598              :   }
    8599              : 
    8600              :   /* If we have path_info, the only way to handle it is CGI. */
    8601            0 :   if (path_info->len > 0 && !is_cgi) {
    8602            0 :     mg_http_send_error(nc, 501, NULL);
    8603            0 :     MG_FREE(index_file);
    8604            0 :     return;
    8605              :   }
    8606              : 
    8607            0 :   if (is_dav && opts->dav_document_root == NULL) {
    8608            0 :     mg_http_send_error(nc, 501, NULL);
    8609            0 :   } else if (!mg_http_is_authorized(
    8610              :                  hm, mg_mk_str(path), opts->auth_domain, opts->global_auth_file,
    8611              :                  ((is_directory ? MG_AUTH_FLAG_IS_DIRECTORY : 0) |
    8612              :                   MG_AUTH_FLAG_IS_GLOBAL_PASS_FILE |
    8613            0 :                   MG_AUTH_FLAG_ALLOW_MISSING_FILE)) ||
    8614            0 :              !mg_http_is_authorized(
    8615              :                  hm, mg_mk_str(path), opts->auth_domain,
    8616              :                  opts->per_directory_auth_file,
    8617              :                  ((is_directory ? MG_AUTH_FLAG_IS_DIRECTORY : 0) |
    8618              :                   MG_AUTH_FLAG_ALLOW_MISSING_FILE))) {
    8619            0 :     mg_http_send_digest_auth_request(nc, opts->auth_domain);
    8620            0 :   } else if (is_cgi) {
    8621              : #if MG_ENABLE_HTTP_CGI
    8622            0 :     mg_handle_cgi(nc, index_file ? index_file : path, path_info, hm, opts);
    8623              : #else
    8624              :     mg_http_send_error(nc, 501, NULL);
    8625              : #endif /* MG_ENABLE_HTTP_CGI */
    8626            0 :   } else if ((!exists ||
    8627            0 :               mg_is_file_hidden(path, opts, 0 /* specials are ok */)) &&
    8628            0 :              !mg_is_creation_request(hm)) {
    8629            0 :     mg_http_send_error(nc, 404, NULL);
    8630              : #if MG_ENABLE_HTTP_WEBDAV
    8631              :   } else if (!mg_vcmp(&hm->method, "PROPFIND")) {
    8632              :     mg_handle_propfind(nc, path, &st, hm, opts);
    8633              : #if !MG_DISABLE_DAV_AUTH
    8634              :   } else if (is_dav &&
    8635              :              (opts->dav_auth_file == NULL ||
    8636              :               (strcmp(opts->dav_auth_file, "-") != 0 &&
    8637              :                !mg_http_is_authorized(
    8638              :                    hm, mg_mk_str(path), opts->auth_domain, opts->dav_auth_file,
    8639              :                    ((is_directory ? MG_AUTH_FLAG_IS_DIRECTORY : 0) |
    8640              :                     MG_AUTH_FLAG_IS_GLOBAL_PASS_FILE |
    8641              :                     MG_AUTH_FLAG_ALLOW_MISSING_FILE))))) {
    8642              :     mg_http_send_digest_auth_request(nc, opts->auth_domain);
    8643              : #endif
    8644              :   } else if (!mg_vcmp(&hm->method, "MKCOL")) {
    8645              :     mg_handle_mkcol(nc, path, hm);
    8646              :   } else if (!mg_vcmp(&hm->method, "DELETE")) {
    8647              :     mg_handle_delete(nc, opts, path);
    8648              :   } else if (!mg_vcmp(&hm->method, "PUT")) {
    8649              :     mg_handle_put(nc, path, hm);
    8650              :   } else if (!mg_vcmp(&hm->method, "MOVE")) {
    8651              :     mg_handle_move(nc, opts, path, hm);
    8652              : #if MG_ENABLE_FAKE_DAVLOCK
    8653              :   } else if (!mg_vcmp(&hm->method, "LOCK")) {
    8654              :     mg_handle_lock(nc, path);
    8655              : #endif
    8656              : #endif /* MG_ENABLE_HTTP_WEBDAV */
    8657            0 :   } else if (!mg_vcmp(&hm->method, "OPTIONS")) {
    8658            0 :     mg_http_send_options(nc, opts);
    8659            0 :   } else if (is_directory && index_file == NULL) {
    8660              : #if MG_ENABLE_DIRECTORY_LISTING
    8661            0 :     if (strcmp(opts->enable_directory_listing, "yes") == 0) {
    8662            0 :       mg_send_directory_listing(nc, path, hm, opts);
    8663              :     } else {
    8664            0 :       mg_http_send_error(nc, 403, NULL);
    8665              :     }
    8666              : #else
    8667              :     mg_http_send_error(nc, 501, NULL);
    8668              : #endif
    8669            0 :   } else if (mg_is_not_modified(hm, &st)) {
    8670            0 :     mg_http_send_error(nc, 304, "Not Modified");
    8671              :   } else {
    8672            0 :     mg_http_serve_file2(nc, index_file ? index_file : path, hm, opts);
    8673              :   }
    8674            0 :   MG_FREE(index_file);
    8675              : }
    8676              : 
    8677              : #if 0
    8678              : void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
    8679              :                    struct mg_serve_http_opts opts) {
    8680              :   char *path = NULL;
    8681              :   struct mg_str *hdr, path_info;
    8682              :   uint32_t remote_ip = ntohl(*(uint32_t *) &nc->sa.sin.sin_addr);
    8683              : 
    8684              :   if (mg_check_ip_acl(opts.ip_acl, remote_ip) != 1) {
    8685              :     /* Not allowed to connect */
    8686              :     mg_http_send_error(nc, 403, NULL);
    8687              :     nc->flags |= MG_F_SEND_AND_CLOSE;
    8688              :     return;
    8689              :   }
    8690              : 
    8691              : #if MG_ENABLE_HTTP_URL_REWRITES
    8692              :   if (mg_http_handle_forwarding(nc, hm, &opts)) {
    8693              :     return;
    8694              :   }
    8695              : 
    8696              :   if (mg_http_send_port_based_redirect(nc, hm, &opts)) {
    8697              :     return;
    8698              :   }
    8699              : #endif
    8700              : 
    8701              :   if (opts.document_root == NULL) {
    8702              :     opts.document_root = ".";
    8703              :   }
    8704              :   if (opts.per_directory_auth_file == NULL) {
    8705              :     opts.per_directory_auth_file = ".htpasswd";
    8706              :   }
    8707              :   if (opts.enable_directory_listing == NULL) {
    8708              :     opts.enable_directory_listing = "yes";
    8709              :   }
    8710              :   if (opts.cgi_file_pattern == NULL) {
    8711              :     opts.cgi_file_pattern = "**.cgi$|**.php$";
    8712              :   }
    8713              :   if (opts.ssi_pattern == NULL) {
    8714              :     opts.ssi_pattern = "**.shtml$|**.shtm$";
    8715              :   }
    8716              :   if (opts.index_files == NULL) {
    8717              :     opts.index_files = "index.html,index.htm,index.shtml,index.cgi,index.php";
    8718              :   }
    8719              :   /* Normalize path - resolve "." and ".." (in-place). */
    8720              :   if (!mg_normalize_uri_path(&hm->uri, &hm->uri)) {
    8721              :     mg_http_send_error(nc, 400, NULL);
    8722              :     return;
    8723              :   }
    8724              :   if (mg_uri_to_local_path(hm, &opts, &path, &path_info) == 0) {
    8725              :     mg_http_send_error(nc, 404, NULL);
    8726              :     return;
    8727              :   }
    8728              :   mg_send_http_file(nc, path, &path_info, hm, &opts);
    8729              : 
    8730              :   MG_FREE(path);
    8731              :   path = NULL;
    8732              : 
    8733              :   /* Close connection for non-keep-alive requests */
    8734              :   if (mg_vcmp(&hm->proto, "HTTP/1.1") != 0 ||
    8735              :       ((hdr = mg_get_http_header(hm, "Connection")) != NULL &&
    8736              :        mg_vcmp(hdr, "keep-alive") != 0)) {
    8737              : #if 0
    8738              :     nc->flags |= MG_F_SEND_AND_CLOSE;
    8739              : #endif
    8740              :   }
    8741              : }
    8742              : #endif
    8743              : 
    8744              : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
    8745              : void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
    8746              :                             mg_fu_fname_fn local_name_fn
    8747              :                                 MG_UD_ARG(void *user_data)) {
    8748              :   switch (ev) {
    8749              :     case MG_EV_HTTP_PART_BEGIN: {
    8750              :       struct mg_http_multipart_part *mp =
    8751              :           (struct mg_http_multipart_part *) ev_data;
    8752              :       struct file_upload_state *fus;
    8753              :       struct mg_str lfn = local_name_fn(nc, mg_mk_str(mp->file_name));
    8754              :       mp->user_data = NULL;
    8755              :       if (lfn.p == NULL || lfn.len == 0) {
    8756              :         LOG(LL_ERROR, ("%p Not allowed to upload %s", nc, mp->file_name));
    8757              :         mg_printf(nc,
    8758              :                   "HTTP/1.1 403 Not Allowed\r\n"
    8759              :                   "Content-Type: text/plain\r\n"
    8760              :                   "Connection: close\r\n\r\n"
    8761              :                   "Not allowed to upload %s\r\n",
    8762              :                   mp->file_name);
    8763              :         nc->flags |= MG_F_SEND_AND_CLOSE;
    8764              :         return;
    8765              :       }
    8766              :       fus = (struct file_upload_state *) MG_CALLOC(1, sizeof(*fus));
    8767              :       if (fus == NULL) {
    8768              :         nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    8769              :         return;
    8770              :       }
    8771              :       fus->lfn = (char *) MG_MALLOC(lfn.len + 1);
    8772              :       memcpy(fus->lfn, lfn.p, lfn.len);
    8773              :       fus->lfn[lfn.len] = '\0';
    8774              :       if (lfn.p != mp->file_name) MG_FREE((char *) lfn.p);
    8775              :       LOG(LL_DEBUG,
    8776              :           ("%p Receiving file %s -> %s", nc, mp->file_name, fus->lfn));
    8777              :       fus->fp = mg_fopen(fus->lfn, "wb");
    8778              :       if (fus->fp == NULL) {
    8779              :         mg_printf(nc,
    8780              :                   "HTTP/1.1 500 Internal Server Error\r\n"
    8781              :                   "Content-Type: text/plain\r\n"
    8782              :                   "Connection: close\r\n\r\n");
    8783              :         LOG(LL_ERROR, ("Failed to open %s: %d\n", fus->lfn, mg_get_errno()));
    8784              :         mg_printf(nc, "Failed to open %s: %d\n", fus->lfn, mg_get_errno());
    8785              :         /* Do not close the connection just yet, discard remainder of the data.
    8786              :          * This is because at the time of writing some browsers (Chrome) fail to
    8787              :          * render response before all the data is sent. */
    8788              :       }
    8789              :       mp->user_data = (void *) fus;
    8790              :       break;
    8791              :     }
    8792              :     case MG_EV_HTTP_PART_DATA: {
    8793              :       struct mg_http_multipart_part *mp =
    8794              :           (struct mg_http_multipart_part *) ev_data;
    8795              :       struct file_upload_state *fus =
    8796              :           (struct file_upload_state *) mp->user_data;
    8797              :       if (fus == NULL || fus->fp == NULL) break;
    8798              :       if (mg_fwrite(mp->data.p, 1, mp->data.len, fus->fp) != mp->data.len) {
    8799              :         LOG(LL_ERROR, ("Failed to write to %s: %d, wrote %d", fus->lfn,
    8800              :                        mg_get_errno(), (int) fus->num_recd));
    8801              :         if (mg_get_errno() == ENOSPC
    8802              : #ifdef SPIFFS_ERR_FULL
    8803              :             || mg_get_errno() == SPIFFS_ERR_FULL
    8804              : #endif
    8805              :             ) {
    8806              :           mg_printf(nc,
    8807              :                     "HTTP/1.1 413 Payload Too Large\r\n"
    8808              :                     "Content-Type: text/plain\r\n"
    8809              :                     "Connection: close\r\n\r\n");
    8810              :           mg_printf(nc, "Failed to write to %s: no space left; wrote %d\r\n",
    8811              :                     fus->lfn, (int) fus->num_recd);
    8812              :         } else {
    8813              :           mg_printf(nc,
    8814              :                     "HTTP/1.1 500 Internal Server Error\r\n"
    8815              :                     "Content-Type: text/plain\r\n"
    8816              :                     "Connection: close\r\n\r\n");
    8817              :           mg_printf(nc, "Failed to write to %s: %d, wrote %d", mp->file_name,
    8818              :                     mg_get_errno(), (int) fus->num_recd);
    8819              :         }
    8820              :         fclose(fus->fp);
    8821              :         remove(fus->lfn);
    8822              :         fus->fp = NULL;
    8823              :         /* Do not close the connection just yet, discard remainder of the data.
    8824              :          * This is because at the time of writing some browsers (Chrome) fail to
    8825              :          * render response before all the data is sent. */
    8826              :         return;
    8827              :       }
    8828              :       fus->num_recd += mp->data.len;
    8829              :       LOG(LL_DEBUG, ("%p rec'd %d bytes, %d total", nc, (int) mp->data.len,
    8830              :                      (int) fus->num_recd));
    8831              :       break;
    8832              :     }
    8833              :     case MG_EV_HTTP_PART_END: {
    8834              :       struct mg_http_multipart_part *mp =
    8835              :           (struct mg_http_multipart_part *) ev_data;
    8836              :       struct file_upload_state *fus =
    8837              :           (struct file_upload_state *) mp->user_data;
    8838              :       if (fus == NULL) break;
    8839              :       if (mp->status >= 0 && fus->fp != NULL) {
    8840              :         LOG(LL_DEBUG, ("%p Uploaded %s (%s), %d bytes", nc, mp->file_name,
    8841              :                        fus->lfn, (int) fus->num_recd));
    8842              :       } else {
    8843              :         LOG(LL_ERROR, ("Failed to store %s (%s)", mp->file_name, fus->lfn));
    8844              :         /*
    8845              :          * mp->status < 0 means connection was terminated, so no reason to send
    8846              :          * HTTP reply
    8847              :          */
    8848              :       }
    8849              :       if (fus->fp != NULL) fclose(fus->fp);
    8850              :       MG_FREE(fus->lfn);
    8851              :       MG_FREE(fus);
    8852              :       mp->user_data = NULL;
    8853              :       /* Don't close the connection yet, there may be more files to come. */
    8854              :       break;
    8855              :     }
    8856              :     case MG_EV_HTTP_MULTIPART_REQUEST_END: {
    8857              :       mg_printf(nc,
    8858              :                 "HTTP/1.1 200 OK\r\n"
    8859              :                 "Content-Type: text/plain\r\n"
    8860              :                 "Connection: close\r\n\r\n"
    8861              :                 "Ok.\r\n");
    8862              :       nc->flags |= MG_F_SEND_AND_CLOSE;
    8863              :       break;
    8864              :     }
    8865              :   }
    8866              : 
    8867              : #if MG_ENABLE_CALLBACK_USERDATA
    8868              :   (void) user_data;
    8869              : #endif
    8870              : }
    8871              : 
    8872              : #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
    8873              : #endif /* MG_ENABLE_FILESYSTEM */
    8874              : 
    8875            0 : struct mg_connection *mg_connect_http_base(
    8876              :     struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
    8877              :     struct mg_connect_opts opts, const char *scheme1, const char *scheme2,
    8878              :     const char *scheme_ssl1, const char *scheme_ssl2, const char *url,
    8879              :     struct mg_str *path, struct mg_str *user_info, struct mg_str *host) {
    8880            0 :   struct mg_connection *nc = NULL;
    8881            0 :   unsigned int port_i = 0;
    8882            0 :   int use_ssl = 0;
    8883              :   struct mg_str scheme, query, fragment;
    8884              :   char conn_addr_buf[2];
    8885            0 :   char *conn_addr = conn_addr_buf;
    8886              : 
    8887            0 :   if (mg_parse_uri(mg_mk_str(url), &scheme, user_info, host, &port_i, path,
    8888            0 :                    &query, &fragment) != 0) {
    8889            0 :     MG_SET_PTRPTR(opts.error_string, "cannot parse url");
    8890            0 :     goto out;
    8891              :   }
    8892              : 
    8893              :   /* If query is present, do not strip it. Pass to the caller. */
    8894            0 :   if (query.len > 0) path->len += query.len + 1;
    8895              : 
    8896            0 :   if (scheme.len == 0 || mg_vcmp(&scheme, scheme1) == 0 ||
    8897            0 :       (scheme2 != NULL && mg_vcmp(&scheme, scheme2) == 0)) {
    8898            0 :     use_ssl = 0;
    8899            0 :     if (port_i == 0) port_i = 80;
    8900            0 :   } else if (mg_vcmp(&scheme, scheme_ssl1) == 0 ||
    8901            0 :              (scheme2 != NULL && mg_vcmp(&scheme, scheme_ssl2) == 0)) {
    8902            0 :     use_ssl = 1;
    8903            0 :     if (port_i == 0) port_i = 443;
    8904              :   } else {
    8905            0 :     goto out;
    8906              :   }
    8907              : 
    8908            0 :   mg_asprintf(&conn_addr, sizeof(conn_addr_buf), "tcp://%.*s:%u",
    8909            0 :               (int) host->len, host->p, port_i);
    8910            0 :   if (conn_addr == NULL) goto out;
    8911              : 
    8912            0 :   LOG(LL_DEBUG, ("%s use_ssl? %d %s", url, use_ssl, conn_addr));
    8913            0 :   if (use_ssl) {
    8914              : #if MG_ENABLE_SSL
    8915              :     /*
    8916              :      * Schema requires SSL, but no SSL parameters were provided in opts.
    8917              :      * In order to maintain backward compatibility, use a faux-SSL with no
    8918              :      * verification.
    8919              :      */
    8920              :     if (opts.ssl_ca_cert == NULL) {
    8921              :       opts.ssl_ca_cert = "*";
    8922              :     }
    8923              : #else
    8924            0 :     MG_SET_PTRPTR(opts.error_string, "ssl is disabled");
    8925            0 :     goto out;
    8926              : #endif
    8927              :   }
    8928              : 
    8929            0 :   if ((nc = mg_connect_opt(mgr, conn_addr, MG_CB(ev_handler, user_data),
    8930            0 :                            opts)) != NULL) {
    8931            0 :     mg_set_protocol_http_websocket(nc);
    8932              :   }
    8933              : 
    8934            0 : out:
    8935            0 :   if (conn_addr != NULL && conn_addr != conn_addr_buf) MG_FREE(conn_addr);
    8936            0 :   return nc;
    8937              : }
    8938              : 
    8939            0 : struct mg_connection *mg_connect_http_opt(
    8940              :     struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
    8941              :     struct mg_connect_opts opts, const char *url, const char *extra_headers,
    8942              :     const char *post_data) {
    8943            0 :   struct mg_str user = MG_NULL_STR, null_str = MG_NULL_STR;
    8944            0 :   struct mg_str host = MG_NULL_STR, path = MG_NULL_STR;
    8945              :   struct mbuf auth;
    8946              :   struct mg_connection *nc =
    8947            0 :       mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "http",
    8948              :                            NULL, "https", NULL, url, &path, &user, &host);
    8949              : 
    8950            0 :   if (nc == NULL) {
    8951            0 :     return NULL;
    8952              :   }
    8953              : 
    8954            0 :   mbuf_init(&auth, 0);
    8955            0 :   if (user.len > 0) {
    8956            0 :     mg_basic_auth_header(user, null_str, &auth);
    8957              :   }
    8958              : 
    8959            0 :   if (post_data == NULL) post_data = "";
    8960            0 :   if (extra_headers == NULL) extra_headers = "";
    8961            0 :   if (path.len == 0) path = mg_mk_str("/");
    8962            0 :   if (host.len == 0) host = mg_mk_str("");
    8963              : 
    8964            0 :   mg_printf(nc, "%s %.*s HTTP/1.1\r\nHost: %.*s\r\nContent-Length: %" SIZE_T_FMT
    8965              :                 "\r\n%.*s%s\r\n%s",
    8966            0 :             (post_data[0] == '\0' ? "GET" : "POST"), (int) path.len, path.p,
    8967            0 :             (int) (path.p - host.p), host.p, strlen(post_data), (int) auth.len,
    8968            0 :             (auth.buf == NULL ? "" : auth.buf), extra_headers, post_data);
    8969              : 
    8970            0 :   mbuf_free(&auth);
    8971            0 :   return nc;
    8972              : }
    8973              : 
    8974            0 : struct mg_connection *mg_connect_http(
    8975              :     struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
    8976              :     const char *url, const char *extra_headers, const char *post_data) {
    8977              :   struct mg_connect_opts opts;
    8978            0 :   memset(&opts, 0, sizeof(opts));
    8979            0 :   return mg_connect_http_opt(mgr, MG_CB(ev_handler, user_data), opts, url,
    8980            0 :                              extra_headers, post_data);
    8981              : }
    8982              : 
    8983            0 : size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name,
    8984              :                           size_t var_name_len, char *file_name,
    8985              :                           size_t file_name_len, const char **data,
    8986              :                           size_t *data_len) {
    8987              :   static const char cd[] = "Content-Disposition: ";
    8988            0 :   size_t hl, bl, n, ll, pos, cdl = sizeof(cd) - 1;
    8989              :   int shl;
    8990              : 
    8991            0 :   if (buf == NULL || buf_len <= 0) return 0;
    8992            0 :   if ((shl = mg_http_get_request_len(buf, buf_len)) <= 0) return 0;
    8993            0 :   hl = shl;
    8994            0 :   if (buf[0] != '-' || buf[1] != '-' || buf[2] == '\n') return 0;
    8995              : 
    8996              :   /* Get boundary length */
    8997            0 :   bl = mg_get_line_len(buf, buf_len);
    8998              : 
    8999              :   /* Loop through headers, fetch variable name and file name */
    9000            0 :   var_name[0] = file_name[0] = '\0';
    9001            0 :   for (n = bl; (ll = mg_get_line_len(buf + n, hl - n)) > 0; n += ll) {
    9002            0 :     if (mg_ncasecmp(cd, buf + n, cdl) == 0) {
    9003              :       struct mg_str header;
    9004            0 :       header.p = buf + n + cdl;
    9005            0 :       header.len = ll - (cdl + 2);
    9006              :       {
    9007            0 :         char *var_name2 = var_name;
    9008            0 :         mg_http_parse_header2(&header, "name", &var_name2, var_name_len);
    9009              :         /* TODO: handle reallocated buffer correctly */
    9010            0 :         if (var_name2 != var_name) {
    9011            0 :           MG_FREE(var_name2);
    9012            0 :           var_name[0] = '\0';
    9013              :         }
    9014              :       }
    9015              :       {
    9016            0 :         char *file_name2 = file_name;
    9017            0 :         mg_http_parse_header2(&header, "filename", &file_name2, file_name_len);
    9018              :         /* TODO: handle reallocated buffer correctly */
    9019            0 :         if (file_name2 != file_name) {
    9020            0 :           MG_FREE(file_name2);
    9021            0 :           file_name[0] = '\0';
    9022              :         }
    9023              :       }
    9024              :     }
    9025              :   }
    9026              : 
    9027              :   /* Scan through the body, search for terminating boundary */
    9028            0 :   for (pos = hl; pos + (bl - 2) < buf_len; pos++) {
    9029            0 :     if (buf[pos] == '-' && !strncmp(buf, &buf[pos], bl - 2)) {
    9030            0 :       if (data_len != NULL) *data_len = (pos - 2) - hl;
    9031            0 :       if (data != NULL) *data = buf + hl;
    9032            0 :       return pos;
    9033              :     }
    9034              :   }
    9035              : 
    9036            0 :   return 0;
    9037              : }
    9038              : 
    9039            0 : void mg_register_http_endpoint_opt(struct mg_connection *nc,
    9040              :                                    const char *uri_path,
    9041              :                                    mg_event_handler_t handler,
    9042              :                                    struct mg_http_endpoint_opts opts) {
    9043            0 :   struct mg_http_proto_data *pd = NULL;
    9044            0 :   struct mg_http_endpoint *new_ep = NULL;
    9045              : 
    9046            0 :   if (nc == NULL) return;
    9047            0 :   new_ep = (struct mg_http_endpoint *) MG_CALLOC(1, sizeof(*new_ep));
    9048            0 :   if (new_ep == NULL) return;
    9049              : 
    9050            0 :   pd = mg_http_get_proto_data(nc);
    9051            0 :   if (pd == NULL) pd = mg_http_create_proto_data(nc);
    9052            0 :   new_ep->uri_pattern = mg_strdup(mg_mk_str(uri_path));
    9053            0 :   if (opts.auth_domain != NULL && opts.auth_file != NULL) {
    9054            0 :     new_ep->auth_domain = strdup(opts.auth_domain);
    9055            0 :     new_ep->auth_file = strdup(opts.auth_file);
    9056              :   }
    9057            0 :   new_ep->handler = handler;
    9058              : #if MG_ENABLE_CALLBACK_USERDATA
    9059              :   new_ep->user_data = opts.user_data;
    9060              : #endif
    9061            0 :   new_ep->next = pd->endpoints;
    9062            0 :   pd->endpoints = new_ep;
    9063              : }
    9064              : 
    9065            0 : static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
    9066              :                                           struct http_message *hm) {
    9067            0 :   struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
    9068            0 :   void *user_data = nc->user_data;
    9069              : 
    9070            0 :   if (ev == MG_EV_HTTP_REQUEST
    9071              : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
    9072              :       || ev == MG_EV_HTTP_MULTIPART_REQUEST
    9073              : #endif
    9074              :       ) {
    9075              :     struct mg_http_endpoint *ep =
    9076            0 :         mg_http_get_endpoint_handler(nc->listener, &hm->uri);
    9077            0 :     if (ep != NULL) {
    9078              : #if MG_ENABLE_FILESYSTEM && !MG_DISABLE_HTTP_DIGEST_AUTH
    9079            0 :       if (!mg_http_is_authorized(hm, hm->uri, ep->auth_domain, ep->auth_file,
    9080              :                                  MG_AUTH_FLAG_IS_GLOBAL_PASS_FILE)) {
    9081            0 :         mg_http_send_digest_auth_request(nc, ep->auth_domain);
    9082            0 :         return;
    9083              :       }
    9084              : #endif
    9085            0 :       pd->endpoint_handler = ep->handler;
    9086              : #if MG_ENABLE_CALLBACK_USERDATA
    9087              :       user_data = ep->user_data;
    9088              : #endif
    9089              :     }
    9090              :   }
    9091            0 :   mg_call(nc, pd->endpoint_handler ? pd->endpoint_handler : nc->handler,
    9092              :           user_data, ev, hm);
    9093              : }
    9094              : 
    9095            0 : void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
    9096              :                                MG_CB(mg_event_handler_t handler,
    9097              :                                      void *user_data)) {
    9098              :   struct mg_http_endpoint_opts opts;
    9099            0 :   memset(&opts, 0, sizeof(opts));
    9100              : #if MG_ENABLE_CALLBACK_USERDATA
    9101              :   opts.user_data = user_data;
    9102              : #endif
    9103            0 :   mg_register_http_endpoint_opt(nc, uri_path, handler, opts);
    9104            0 : }
    9105              : 
    9106              : #endif /* MG_ENABLE_HTTP */
    9107              : #ifdef MG_MODULE_LINES
    9108              : #line 1 "mongoose/src/mg_http_cgi.c"
    9109              : #endif
    9110              : /*
    9111              :  * Copyright (c) 2014-2016 Cesanta Software Limited
    9112              :  * All rights reserved
    9113              :  */
    9114              : 
    9115              : #ifndef _WIN32
    9116              : #include <signal.h>
    9117              : #endif
    9118              : 
    9119              : #if MG_ENABLE_HTTP && MG_ENABLE_HTTP_CGI
    9120              : 
    9121              : #ifndef MG_MAX_CGI_ENVIR_VARS
    9122              : #define MG_MAX_CGI_ENVIR_VARS 64
    9123              : #endif
    9124              : 
    9125              : #ifndef MG_ENV_EXPORT_TO_CGI
    9126              : #define MG_ENV_EXPORT_TO_CGI "MONGOOSE_CGI"
    9127              : #endif
    9128              : 
    9129              : #define MG_F_HTTP_CGI_PARSE_HEADERS MG_F_USER_1
    9130              : 
    9131              : /*
    9132              :  * This structure helps to create an environment for the spawned CGI program.
    9133              :  * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
    9134              :  * last element must be NULL.
    9135              :  * However, on Windows there is a requirement that all these VARIABLE=VALUE\0
    9136              :  * strings must reside in a contiguous buffer. The end of the buffer is
    9137              :  * marked by two '\0' characters.
    9138              :  * We satisfy both worlds: we create an envp array (which is vars), all
    9139              :  * entries are actually pointers inside buf.
    9140              :  */
    9141              : struct mg_cgi_env_block {
    9142              :   struct mg_connection *nc;
    9143              :   char buf[MG_CGI_ENVIRONMENT_SIZE];       /* Environment buffer */
    9144              :   const char *vars[MG_MAX_CGI_ENVIR_VARS]; /* char *envp[] */
    9145              :   int len;                                 /* Space taken */
    9146              :   int nvars;                               /* Number of variables in envp[] */
    9147              : };
    9148              : 
    9149              : #ifdef _WIN32
    9150              : struct mg_threadparam {
    9151              :   sock_t s;
    9152              :   HANDLE hPipe;
    9153              : };
    9154              : 
    9155              : static int mg_wait_until_ready(sock_t sock, int for_read) {
    9156              :   fd_set set;
    9157              :   FD_ZERO(&set);
    9158              :   FD_SET(sock, &set);
    9159              :   return select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0) == 1;
    9160              : }
    9161              : 
    9162              : static void *mg_push_to_stdin(void *arg) {
    9163              :   struct mg_threadparam *tp = (struct mg_threadparam *) arg;
    9164              :   int n, sent, stop = 0;
    9165              :   DWORD k;
    9166              :   char buf[BUFSIZ];
    9167              : 
    9168              :   while (!stop && mg_wait_until_ready(tp->s, 1) &&
    9169              :          (n = recv(tp->s, buf, sizeof(buf), 0)) > 0) {
    9170              :     if (n == -1 && GetLastError() == WSAEWOULDBLOCK) continue;
    9171              :     for (sent = 0; !stop && sent < n; sent += k) {
    9172              :       if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1;
    9173              :     }
    9174              :   }
    9175              :   DBG(("%s", "FORWARED EVERYTHING TO CGI"));
    9176              :   CloseHandle(tp->hPipe);
    9177              :   MG_FREE(tp);
    9178              :   return NULL;
    9179              : }
    9180              : 
    9181              : static void *mg_pull_from_stdout(void *arg) {
    9182              :   struct mg_threadparam *tp = (struct mg_threadparam *) arg;
    9183              :   int k = 0, stop = 0;
    9184              :   DWORD n, sent;
    9185              :   char buf[BUFSIZ];
    9186              : 
    9187              :   while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
    9188              :     for (sent = 0; !stop && sent < n; sent += k) {
    9189              :       if (mg_wait_until_ready(tp->s, 0) &&
    9190              :           (k = send(tp->s, buf + sent, n - sent, 0)) <= 0)
    9191              :         stop = 1;
    9192              :     }
    9193              :   }
    9194              :   DBG(("%s", "EOF FROM CGI"));
    9195              :   CloseHandle(tp->hPipe);
    9196              :   shutdown(tp->s, 2);  // Without this, IO thread may get truncated data
    9197              :   closesocket(tp->s);
    9198              :   MG_FREE(tp);
    9199              :   return NULL;
    9200              : }
    9201              : 
    9202              : static void mg_spawn_stdio_thread(sock_t sock, HANDLE hPipe,
    9203              :                                   void *(*func)(void *)) {
    9204              :   struct mg_threadparam *tp = (struct mg_threadparam *) MG_MALLOC(sizeof(*tp));
    9205              :   if (tp != NULL) {
    9206              :     tp->s = sock;
    9207              :     tp->hPipe = hPipe;
    9208              :     mg_start_thread(func, tp);
    9209              :   }
    9210              : }
    9211              : 
    9212              : static void mg_abs_path(const char *utf8_path, char *abs_path, size_t len) {
    9213              :   wchar_t buf[MG_MAX_PATH], buf2[MG_MAX_PATH];
    9214              :   to_wchar(utf8_path, buf, ARRAY_SIZE(buf));
    9215              :   GetFullPathNameW(buf, ARRAY_SIZE(buf2), buf2, NULL);
    9216              :   WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0);
    9217              : }
    9218              : 
    9219              : static int mg_start_process(const char *interp, const char *cmd,
    9220              :                             const char *env, const char *envp[],
    9221              :                             const char *dir, sock_t sock) {
    9222              :   STARTUPINFOW si;
    9223              :   PROCESS_INFORMATION pi;
    9224              :   HANDLE a[2], b[2], me = GetCurrentProcess();
    9225              :   wchar_t wcmd[MG_MAX_PATH], full_dir[MG_MAX_PATH];
    9226              :   char buf[MG_MAX_PATH], buf2[MG_MAX_PATH], buf5[MG_MAX_PATH],
    9227              :       buf4[MG_MAX_PATH], cmdline[MG_MAX_PATH];
    9228              :   DWORD flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
    9229              :   FILE *fp;
    9230              : 
    9231              :   memset(&si, 0, sizeof(si));
    9232              :   memset(&pi, 0, sizeof(pi));
    9233              : 
    9234              :   si.cb = sizeof(si);
    9235              :   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    9236              :   si.wShowWindow = SW_HIDE;
    9237              :   si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
    9238              : 
    9239              :   CreatePipe(&a[0], &a[1], NULL, 0);
    9240              :   CreatePipe(&b[0], &b[1], NULL, 0);
    9241              :   DuplicateHandle(me, a[0], me, &si.hStdInput, 0, TRUE, flags);
    9242              :   DuplicateHandle(me, b[1], me, &si.hStdOutput, 0, TRUE, flags);
    9243              : 
    9244              :   if (interp == NULL && (fp = mg_fopen(cmd, "r")) != NULL) {
    9245              :     buf[0] = buf[1] = '\0';
    9246              :     fgets(buf, sizeof(buf), fp);
    9247              :     buf[sizeof(buf) - 1] = '\0';
    9248              :     if (buf[0] == '#' && buf[1] == '!') {
    9249              :       interp = buf + 2;
    9250              :       /* Trim leading spaces: https://github.com/cesanta/mongoose/issues/489 */
    9251              :       while (*interp != '\0' && isspace(*(unsigned char *) interp)) {
    9252              :         interp++;
    9253              :       }
    9254              :     }
    9255              :     fclose(fp);
    9256              :   }
    9257              : 
    9258              :   snprintf(buf, sizeof(buf), "%s/%s", dir, cmd);
    9259              :   mg_abs_path(buf, buf2, ARRAY_SIZE(buf2));
    9260              : 
    9261              :   mg_abs_path(dir, buf5, ARRAY_SIZE(buf5));
    9262              :   to_wchar(dir, full_dir, ARRAY_SIZE(full_dir));
    9263              : 
    9264              :   if (interp != NULL) {
    9265              :     mg_abs_path(interp, buf4, ARRAY_SIZE(buf4));
    9266              :     snprintf(cmdline, sizeof(cmdline), "%s \"%s\"", buf4, buf2);
    9267              :   } else {
    9268              :     snprintf(cmdline, sizeof(cmdline), "\"%s\"", buf2);
    9269              :   }
    9270              :   to_wchar(cmdline, wcmd, ARRAY_SIZE(wcmd));
    9271              : 
    9272              :   if (CreateProcessW(NULL, wcmd, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP,
    9273              :                      (void *) env, full_dir, &si, &pi) != 0) {
    9274              :     mg_spawn_stdio_thread(sock, a[1], mg_push_to_stdin);
    9275              :     mg_spawn_stdio_thread(sock, b[0], mg_pull_from_stdout);
    9276              : 
    9277              :     CloseHandle(si.hStdOutput);
    9278              :     CloseHandle(si.hStdInput);
    9279              : 
    9280              :     CloseHandle(pi.hThread);
    9281              :     CloseHandle(pi.hProcess);
    9282              :   } else {
    9283              :     CloseHandle(a[1]);
    9284              :     CloseHandle(b[0]);
    9285              :     closesocket(sock);
    9286              :   }
    9287              :   DBG(("CGI command: [%ls] -> %p", wcmd, pi.hProcess));
    9288              : 
    9289              :   /* Not closing a[0] and b[1] because we've used DUPLICATE_CLOSE_SOURCE */
    9290              :   (void) envp;
    9291              :   return (pi.hProcess != NULL);
    9292              : }
    9293              : #else
    9294            0 : static int mg_start_process(const char *interp, const char *cmd,
    9295              :                             const char *env, const char *envp[],
    9296              :                             const char *dir, sock_t sock) {
    9297              :   char buf[500];
    9298            0 :   pid_t pid = fork();
    9299              :   (void) env;
    9300              : 
    9301            0 :   if (pid == 0) {
    9302              :     /*
    9303              :      * In Linux `chdir` declared with `warn_unused_result` attribute
    9304              :      * To shutup compiler we have yo use result in some way
    9305              :      */
    9306            0 :     int tmp = chdir(dir);
    9307              :     (void) tmp;
    9308            0 :     (void) dup2(sock, 0);
    9309            0 :     (void) dup2(sock, 1);
    9310            0 :     closesocket(sock);
    9311              : 
    9312              :     /*
    9313              :      * After exec, all signal handlers are restored to their default values,
    9314              :      * with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
    9315              :      * implementation, SIGCHLD's handler will leave unchanged after exec
    9316              :      * if it was set to be ignored. Restore it to default action.
    9317              :      */
    9318            0 :     signal(SIGCHLD, SIG_DFL);
    9319              : 
    9320            0 :     if (interp == NULL) {
    9321            0 :       execle(cmd, cmd, (char *) 0, envp); /* (char *) 0 to squash warning */
    9322              :     } else {
    9323            0 :       execle(interp, interp, cmd, (char *) 0, envp);
    9324              :     }
    9325            0 :     snprintf(buf, sizeof(buf),
    9326              :              "Status: 500\r\n\r\n"
    9327              :              "500 Server Error: %s%s%s: %s",
    9328              :              interp == NULL ? "" : interp, interp == NULL ? "" : " ", cmd,
    9329            0 :              strerror(errno));
    9330            0 :     send(1, buf, strlen(buf), 0);
    9331            0 :     _exit(EXIT_FAILURE); /* exec call failed */
    9332              :   }
    9333              : 
    9334            0 :   return (pid != 0);
    9335              : }
    9336              : #endif /* _WIN32 */
    9337              : 
    9338              : /*
    9339              :  * Append VARIABLE=VALUE\0 string to the buffer, and add a respective
    9340              :  * pointer into the vars array.
    9341              :  */
    9342            0 : static char *mg_addenv(struct mg_cgi_env_block *block, const char *fmt, ...) {
    9343              :   int n, space;
    9344            0 :   char *added = block->buf + block->len;
    9345              :   va_list ap;
    9346              : 
    9347              :   /* Calculate how much space is left in the buffer */
    9348            0 :   space = sizeof(block->buf) - (block->len + 2);
    9349            0 :   if (space > 0) {
    9350              :     /* Copy VARIABLE=VALUE\0 string into the free space */
    9351            0 :     va_start(ap, fmt);
    9352            0 :     n = vsnprintf(added, (size_t) space, fmt, ap);
    9353            0 :     va_end(ap);
    9354              : 
    9355              :     /* Make sure we do not overflow buffer and the envp array */
    9356            0 :     if (n > 0 && n + 1 < space &&
    9357            0 :         block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
    9358              :       /* Append a pointer to the added string into the envp array */
    9359            0 :       block->vars[block->nvars++] = added;
    9360              :       /* Bump up used length counter. Include \0 terminator */
    9361            0 :       block->len += n + 1;
    9362              :     }
    9363              :   }
    9364              : 
    9365            0 :   return added;
    9366              : }
    9367              : 
    9368            0 : static void mg_addenv2(struct mg_cgi_env_block *blk, const char *name) {
    9369              :   const char *s;
    9370            0 :   if ((s = getenv(name)) != NULL) mg_addenv(blk, "%s=%s", name, s);
    9371            0 : }
    9372              : 
    9373            0 : static void mg_prepare_cgi_environment(struct mg_connection *nc,
    9374              :                                        const char *prog,
    9375              :                                        const struct mg_str *path_info,
    9376              :                                        const struct http_message *hm,
    9377              :                                        const struct mg_serve_http_opts *opts,
    9378              :                                        struct mg_cgi_env_block *blk) {
    9379              :   const char *s;
    9380              :   struct mg_str *h;
    9381              :   char *p;
    9382              :   size_t i;
    9383              :   char buf[100];
    9384            0 :   size_t path_info_len = path_info != NULL ? path_info->len : 0;
    9385              : 
    9386            0 :   blk->len = blk->nvars = 0;
    9387            0 :   blk->nc = nc;
    9388              : 
    9389            0 :   if ((s = getenv("SERVER_NAME")) != NULL) {
    9390            0 :     mg_addenv(blk, "SERVER_NAME=%s", s);
    9391              :   } else {
    9392            0 :     mg_sock_to_str(nc->sock, buf, sizeof(buf), 3);
    9393            0 :     mg_addenv(blk, "SERVER_NAME=%s", buf);
    9394              :   }
    9395            0 :   mg_addenv(blk, "SERVER_ROOT=%s", opts->document_root);
    9396            0 :   mg_addenv(blk, "DOCUMENT_ROOT=%s", opts->document_root);
    9397            0 :   mg_addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", MG_VERSION);
    9398              : 
    9399              :   /* Prepare the environment block */
    9400            0 :   mg_addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
    9401            0 :   mg_addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
    9402            0 :   mg_addenv(blk, "%s", "REDIRECT_STATUS=200"); /* For PHP */
    9403              : 
    9404            0 :   mg_addenv(blk, "REQUEST_METHOD=%.*s", (int) hm->method.len, hm->method.p);
    9405              : 
    9406            0 :   mg_addenv(blk, "REQUEST_URI=%.*s%s%.*s", (int) hm->uri.len, hm->uri.p,
    9407            0 :             hm->query_string.len == 0 ? "" : "?", (int) hm->query_string.len,
    9408            0 :             hm->query_string.p);
    9409              : 
    9410            0 :   mg_conn_addr_to_str(nc, buf, sizeof(buf),
    9411              :                       MG_SOCK_STRINGIFY_REMOTE | MG_SOCK_STRINGIFY_IP);
    9412            0 :   mg_addenv(blk, "REMOTE_ADDR=%s", buf);
    9413            0 :   mg_conn_addr_to_str(nc, buf, sizeof(buf), MG_SOCK_STRINGIFY_PORT);
    9414            0 :   mg_addenv(blk, "SERVER_PORT=%s", buf);
    9415              : 
    9416            0 :   s = hm->uri.p + hm->uri.len - path_info_len - 1;
    9417            0 :   if (*s == '/') {
    9418            0 :     const char *base_name = strrchr(prog, DIRSEP);
    9419            0 :     mg_addenv(blk, "SCRIPT_NAME=%.*s/%s", (int) (s - hm->uri.p), hm->uri.p,
    9420              :               (base_name != NULL ? base_name + 1 : prog));
    9421              :   } else {
    9422            0 :     mg_addenv(blk, "SCRIPT_NAME=%.*s", (int) (s - hm->uri.p + 1), hm->uri.p);
    9423              :   }
    9424            0 :   mg_addenv(blk, "SCRIPT_FILENAME=%s", prog);
    9425              : 
    9426            0 :   if (path_info != NULL && path_info->len > 0) {
    9427            0 :     mg_addenv(blk, "PATH_INFO=%.*s", (int) path_info->len, path_info->p);
    9428              :     /* Not really translated... */
    9429            0 :     mg_addenv(blk, "PATH_TRANSLATED=%.*s", (int) path_info->len, path_info->p);
    9430              :   }
    9431              : 
    9432              : #if MG_ENABLE_SSL
    9433              :   mg_addenv(blk, "HTTPS=%s", (nc->flags & MG_F_SSL ? "on" : "off"));
    9434              : #else
    9435            0 :   mg_addenv(blk, "HTTPS=off");
    9436              : #endif
    9437              : 
    9438            0 :   if ((h = mg_get_http_header((struct http_message *) hm, "Content-Type")) !=
    9439              :       NULL) {
    9440            0 :     mg_addenv(blk, "CONTENT_TYPE=%.*s", (int) h->len, h->p);
    9441              :   }
    9442              : 
    9443            0 :   if (hm->query_string.len > 0) {
    9444            0 :     mg_addenv(blk, "QUERY_STRING=%.*s", (int) hm->query_string.len,
    9445            0 :               hm->query_string.p);
    9446              :   }
    9447              : 
    9448            0 :   if ((h = mg_get_http_header((struct http_message *) hm, "Content-Length")) !=
    9449              :       NULL) {
    9450            0 :     mg_addenv(blk, "CONTENT_LENGTH=%.*s", (int) h->len, h->p);
    9451              :   }
    9452              : 
    9453            0 :   mg_addenv2(blk, "PATH");
    9454            0 :   mg_addenv2(blk, "TMP");
    9455            0 :   mg_addenv2(blk, "TEMP");
    9456            0 :   mg_addenv2(blk, "TMPDIR");
    9457            0 :   mg_addenv2(blk, "PERLLIB");
    9458            0 :   mg_addenv2(blk, MG_ENV_EXPORT_TO_CGI);
    9459              : 
    9460              : #ifdef _WIN32
    9461              :   mg_addenv2(blk, "COMSPEC");
    9462              :   mg_addenv2(blk, "SYSTEMROOT");
    9463              :   mg_addenv2(blk, "SystemDrive");
    9464              :   mg_addenv2(blk, "ProgramFiles");
    9465              :   mg_addenv2(blk, "ProgramFiles(x86)");
    9466              :   mg_addenv2(blk, "CommonProgramFiles(x86)");
    9467              : #else
    9468            0 :   mg_addenv2(blk, "LD_LIBRARY_PATH");
    9469              : #endif /* _WIN32 */
    9470              : 
    9471              :   /* Add all headers as HTTP_* variables */
    9472            0 :   for (i = 0; hm->header_names[i].len > 0; i++) {
    9473            0 :     p = mg_addenv(blk, "HTTP_%.*s=%.*s", (int) hm->header_names[i].len,
    9474            0 :                   hm->header_names[i].p, (int) hm->header_values[i].len,
    9475            0 :                   hm->header_values[i].p);
    9476              : 
    9477              :     /* Convert variable name into uppercase, and change - to _ */
    9478            0 :     for (; *p != '=' && *p != '\0'; p++) {
    9479            0 :       if (*p == '-') *p = '_';
    9480            0 :       *p = (char) toupper(*(unsigned char *) p);
    9481              :     }
    9482              :   }
    9483              : 
    9484            0 :   blk->vars[blk->nvars++] = NULL;
    9485            0 :   blk->buf[blk->len++] = '\0';
    9486            0 : }
    9487              : 
    9488            0 : static void mg_cgi_ev_handler(struct mg_connection *cgi_nc, int ev,
    9489              :                               void *ev_data MG_UD_ARG(void *user_data)) {
    9490              : #if !MG_ENABLE_CALLBACK_USERDATA
    9491            0 :   void *user_data = cgi_nc->user_data;
    9492              : #endif
    9493            0 :   struct mg_connection *nc = (struct mg_connection *) user_data;
    9494              :   (void) ev_data;
    9495              : 
    9496            0 :   if (nc == NULL) {
    9497              :     /* The corresponding network connection was closed. */
    9498            0 :     cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    9499            0 :     return;
    9500              :   }
    9501              : 
    9502            0 :   switch (ev) {
    9503            0 :     case MG_EV_RECV:
    9504              :       /*
    9505              :        * CGI script does not output reply line, like "HTTP/1.1 CODE XXXXX\n"
    9506              :        * It outputs headers, then body. Headers might include "Status"
    9507              :        * header, which changes CODE, and it might include "Location" header
    9508              :        * which changes CODE to 302.
    9509              :        *
    9510              :        * Therefore we do not send the output from the CGI script to the user
    9511              :        * until all CGI headers are received.
    9512              :        *
    9513              :        * Here we parse the output from the CGI script, and if all headers has
    9514              :        * been received, send appropriate reply line, and forward all
    9515              :        * received headers to the client.
    9516              :        */
    9517            0 :       if (nc->flags & MG_F_HTTP_CGI_PARSE_HEADERS) {
    9518            0 :         struct mbuf *io = &cgi_nc->recv_mbuf;
    9519            0 :         int len = mg_http_get_request_len(io->buf, io->len);
    9520              : 
    9521            0 :         if (len == 0) break;
    9522            0 :         if (len < 0 || io->len > MG_MAX_HTTP_REQUEST_SIZE) {
    9523            0 :           cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    9524            0 :           mg_http_send_error(nc, 500, "Bad headers");
    9525              :         } else {
    9526              :           struct http_message hm;
    9527              :           struct mg_str *h;
    9528            0 :           mg_http_parse_headers(io->buf, io->buf + io->len, io->len, &hm);
    9529            0 :           if (mg_get_http_header(&hm, "Location") != NULL) {
    9530            0 :             mg_printf(nc, "%s", "HTTP/1.1 302 Moved\r\n");
    9531            0 :           } else if ((h = mg_get_http_header(&hm, "Status")) != NULL) {
    9532            0 :             mg_printf(nc, "HTTP/1.1 %.*s\r\n", (int) h->len, h->p);
    9533              :           } else {
    9534            0 :             mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\n");
    9535              :           }
    9536              :         }
    9537            0 :         nc->flags &= ~MG_F_HTTP_CGI_PARSE_HEADERS;
    9538              :       }
    9539            0 :       if (!(nc->flags & MG_F_HTTP_CGI_PARSE_HEADERS)) {
    9540            0 :         mg_forward(cgi_nc, nc);
    9541              :       }
    9542            0 :       break;
    9543            0 :     case MG_EV_CLOSE:
    9544            0 :       DBG(("%p CLOSE", cgi_nc));
    9545            0 :       mg_http_free_proto_data_cgi(&mg_http_get_proto_data(nc)->cgi);
    9546            0 :       nc->flags |= MG_F_SEND_AND_CLOSE;
    9547            0 :       break;
    9548              :   }
    9549              : }
    9550              : 
    9551            0 : MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
    9552              :                                const struct mg_str *path_info,
    9553              :                                const struct http_message *hm,
    9554              :                                const struct mg_serve_http_opts *opts) {
    9555              :   struct mg_cgi_env_block blk;
    9556              :   char dir[MG_MAX_PATH];
    9557              :   const char *p;
    9558              :   sock_t fds[2];
    9559              : 
    9560            0 :   DBG(("%p [%s]", nc, prog));
    9561            0 :   mg_prepare_cgi_environment(nc, prog, path_info, hm, opts, &blk);
    9562              :   /*
    9563              :    * CGI must be executed in its own directory. 'dir' must point to the
    9564              :    * directory containing executable program, 'p' must point to the
    9565              :    * executable program name relative to 'dir'.
    9566              :    */
    9567            0 :   if ((p = strrchr(prog, DIRSEP)) == NULL) {
    9568            0 :     snprintf(dir, sizeof(dir), "%s", ".");
    9569              :   } else {
    9570            0 :     snprintf(dir, sizeof(dir), "%.*s", (int) (p - prog), prog);
    9571            0 :     prog = p + 1;
    9572              :   }
    9573              : 
    9574            0 :   if (!mg_socketpair(fds, SOCK_STREAM)) {
    9575            0 :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    9576            0 :     return;
    9577              :   }
    9578              : 
    9579              : #ifndef _WIN32
    9580              :   struct sigaction sa;
    9581              : 
    9582            0 :   sigemptyset(&sa.sa_mask);
    9583            0 :   sa.sa_handler = SIG_IGN;
    9584            0 :   sa.sa_flags = 0;
    9585            0 :   sigaction(SIGCHLD, &sa, NULL);
    9586              : #endif
    9587              : 
    9588            0 :   if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir,
    9589            0 :                        fds[1]) != 0) {
    9590              :     struct mg_connection *cgi_nc =
    9591            0 :         mg_add_sock(nc->mgr, fds[0], mg_cgi_ev_handler MG_UD_ARG(nc));
    9592            0 :     struct mg_http_proto_data *cgi_pd = mg_http_get_proto_data(nc);
    9593            0 :     cgi_pd->cgi.cgi_nc = cgi_nc;
    9594              : #if !MG_ENABLE_CALLBACK_USERDATA
    9595            0 :     cgi_pd->cgi.cgi_nc->user_data = nc;
    9596              : #endif
    9597            0 :     nc->flags |= MG_F_HTTP_CGI_PARSE_HEADERS;
    9598              :     /* Push POST data to the CGI */
    9599            0 :     if (hm->body.len > 0) {
    9600            0 :       mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, hm->body.len);
    9601              :     }
    9602            0 :     mbuf_remove(&nc->recv_mbuf, nc->recv_mbuf.len);
    9603              :   } else {
    9604            0 :     closesocket(fds[0]);
    9605            0 :     mg_http_send_error(nc, 500, "CGI failure");
    9606              :   }
    9607              : 
    9608              : #ifndef _WIN32
    9609            0 :   closesocket(fds[1]); /* On Windows, CGI stdio thread closes that socket */
    9610              : #endif
    9611              : }
    9612              : 
    9613            0 : MG_INTERNAL void mg_http_free_proto_data_cgi(struct mg_http_proto_data_cgi *d) {
    9614            0 :   if (d == NULL) return;
    9615            0 :   if (d->cgi_nc != NULL) {
    9616            0 :     d->cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
    9617            0 :     d->cgi_nc->user_data = NULL;
    9618              :   }
    9619            0 :   memset(d, 0, sizeof(*d));
    9620              : }
    9621              : 
    9622              : #endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_CGI */
    9623              : #ifdef MG_MODULE_LINES
    9624              : #line 1 "mongoose/src/mg_http_ssi.c"
    9625              : #endif
    9626              : /*
    9627              :  * Copyright (c) 2014-2016 Cesanta Software Limited
    9628              :  * All rights reserved
    9629              :  */
    9630              : 
    9631              : #if MG_ENABLE_HTTP && MG_ENABLE_HTTP_SSI && MG_ENABLE_FILESYSTEM
    9632              : 
    9633              : static void mg_send_ssi_file(struct mg_connection *nc, struct http_message *hm,
    9634              :                              const char *path, FILE *fp, int include_level,
    9635              :                              const struct mg_serve_http_opts *opts);
    9636              : 
    9637              : static void mg_send_file_data(struct mg_connection *nc, FILE *fp) {
    9638              :   char buf[BUFSIZ];
    9639              :   size_t n;
    9640              :   while ((n = mg_fread(buf, 1, sizeof(buf), fp)) > 0) {
    9641              :     mg_send(nc, buf, n);
    9642              :   }
    9643              : }
    9644              : 
    9645              : #if 0
    9646              : static void mg_do_ssi_include(struct mg_connection *nc, struct http_message *hm,
    9647              :                               const char *ssi, char *tag, int include_level,
    9648              :                               const struct mg_serve_http_opts *opts) {
    9649              :   char file_name[MG_MAX_PATH], path[MG_MAX_PATH], *p;
    9650              :   FILE *fp;
    9651              : 
    9652              :   /*
    9653              :    * sscanf() is safe here, since send_ssi_file() also uses buffer
    9654              :    * of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
    9655              :    */
    9656              :   if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
    9657              :     /* File name is relative to the webserver root */
    9658              :     snprintf(path, sizeof(path), "%s/%s", opts->document_root, file_name);
    9659              :   } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
    9660              :     /*
    9661              :      * File name is relative to the webserver working directory
    9662              :      * or it is absolute system path
    9663              :      */
    9664              :     snprintf(path, sizeof(path), "%s", file_name);
    9665              :   } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
    9666              :              sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
    9667              :     /* File name is relative to the currect document */
    9668              :     snprintf(path, sizeof(path), "%s", ssi);
    9669              :     if ((p = strrchr(path, DIRSEP)) != NULL) {
    9670              :       p[1] = '\0';
    9671              :     }
    9672              :     snprintf(path + strlen(path), sizeof(path) - strlen(path), "%s", file_name);
    9673              :   } else {
    9674              :     mg_printf(nc, "Bad SSI #include: [%s]", tag);
    9675              :     return;
    9676              :   }
    9677              : 
    9678              :   if ((fp = mg_fopen(path, "rb")) == NULL) {
    9679              :     mg_printf(nc, "SSI include error: mg_fopen(%s): %s", path,
    9680              :               strerror(mg_get_errno()));
    9681              :   } else {
    9682              :     mg_set_close_on_exec((sock_t) fileno(fp));
    9683              :     if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern), path) >
    9684              :         0) {
    9685              :       mg_send_ssi_file(nc, hm, path, fp, include_level + 1, opts);
    9686              :     } else {
    9687              :       mg_send_file_data(nc, fp);
    9688              :     }
    9689              :     fclose(fp);
    9690              :   }
    9691              : }
    9692              : #endif
    9693              : 
    9694              : #if MG_ENABLE_HTTP_SSI_EXEC
    9695              : static void do_ssi_exec(struct mg_connection *nc, char *tag) {
    9696              :   char cmd[BUFSIZ];
    9697              :   FILE *fp;
    9698              : 
    9699              :   if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
    9700              :     mg_printf(nc, "Bad SSI #exec: [%s]", tag);
    9701              :   } else if ((fp = popen(cmd, "r")) == NULL) {
    9702              :     mg_printf(nc, "Cannot SSI #exec: [%s]: %s", cmd, strerror(mg_get_errno()));
    9703              :   } else {
    9704              :     mg_send_file_data(nc, fp);
    9705              :     pclose(fp);
    9706              :   }
    9707              : }
    9708              : #endif /* MG_ENABLE_HTTP_SSI_EXEC */
    9709              : 
    9710              : /*
    9711              :  * SSI directive has the following format:
    9712              :  * <!--#directive parameter=value parameter=value -->
    9713              :  */
    9714              : #if 0
    9715              : static void mg_send_ssi_file(struct mg_connection *nc, struct http_message *hm,
    9716              :                              const char *path, FILE *fp, int include_level,
    9717              :                              const struct mg_serve_http_opts *opts) {
    9718              :   static const struct mg_str btag = MG_MK_STR("<!--#");
    9719              :   static const struct mg_str d_include = MG_MK_STR("include");
    9720              :   static const struct mg_str d_call = MG_MK_STR("call");
    9721              : #if MG_ENABLE_HTTP_SSI_EXEC
    9722              :   static const struct mg_str d_exec = MG_MK_STR("exec");
    9723              : #endif
    9724              :   char buf[BUFSIZ], *p = buf + btag.len; /* p points to SSI directive */
    9725              :   int ch, len, in_ssi_tag;
    9726              : 
    9727              :   if (include_level > 10) {
    9728              :     mg_printf(nc, "SSI #include level is too deep (%s)", path);
    9729              :     return;
    9730              :   }
    9731              : 
    9732              :   in_ssi_tag = len = 0;
    9733              :   while ((ch = fgetc(fp)) != EOF) {
    9734              :     if (in_ssi_tag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') {
    9735              :       size_t i = len - 2;
    9736              :       in_ssi_tag = 0;
    9737              : 
    9738              :       /* Trim closing --> */
    9739              :       buf[i--] = '\0';
    9740              :       while (i > 0 && buf[i] == ' ') {
    9741              :         buf[i--] = '\0';
    9742              :       }
    9743              : 
    9744              :       /* Handle known SSI directives */
    9745              :       if (strncmp(p, d_include.p, d_include.len) == 0) {
    9746              :         mg_do_ssi_include(nc, hm, path, p + d_include.len + 1, include_level,
    9747              :                           opts);
    9748              :       } else if (strncmp(p, d_call.p, d_call.len) == 0) {
    9749              :         struct mg_ssi_call_ctx cctx;
    9750              :         memset(&cctx, 0, sizeof(cctx));
    9751              :         cctx.req = hm;
    9752              :         cctx.file = mg_mk_str(path);
    9753              :         cctx.arg = mg_mk_str(p + d_call.len + 1);
    9754              :         mg_call(nc, NULL, nc->user_data, MG_EV_SSI_CALL,
    9755              :                 (void *) cctx.arg.p); /* NUL added above */
    9756              :         mg_call(nc, NULL, nc->user_data, MG_EV_SSI_CALL_CTX, &cctx);
    9757              : #if MG_ENABLE_HTTP_SSI_EXEC
    9758              :       } else if (strncmp(p, d_exec.p, d_exec.len) == 0) {
    9759              :         do_ssi_exec(nc, p + d_exec.len + 1);
    9760              : #endif
    9761              :       } else {
    9762              :         /* Silently ignore unknown SSI directive. */
    9763              :       }
    9764              :       len = 0;
    9765              :     } else if (ch == '<') {
    9766              :       in_ssi_tag = 1;
    9767              :       if (len > 0) {
    9768              :         mg_send(nc, buf, (size_t) len);
    9769              :       }
    9770              :       len = 0;
    9771              :       buf[len++] = ch & 0xff;
    9772              :     } else if (in_ssi_tag) {
    9773              :       if (len == (int) btag.len && strncmp(buf, btag.p, btag.len) != 0) {
    9774              :         /* Not an SSI tag */
    9775              :         in_ssi_tag = 0;
    9776              :       } else if (len == (int) sizeof(buf) - 2) {
    9777              :         mg_printf(nc, "%s: SSI tag is too large", path);
    9778              :         len = 0;
    9779              :       }
    9780              :       buf[len++] = ch & 0xff;
    9781              :     } else {
    9782              :       buf[len++] = ch & 0xff;
    9783              :       if (len == (int) sizeof(buf)) {
    9784              :         mg_send(nc, buf, (size_t) len);
    9785              :         len = 0;
    9786              :       }
    9787              :     }
    9788              :   }
    9789              : 
    9790              :   /* Send the rest of buffered data */
    9791              :   if (len > 0) {
    9792              :     mg_send(nc, buf, (size_t) len);
    9793              :   }
    9794              : }
    9795              : 
    9796              : MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc,
    9797              :                                        struct http_message *hm,
    9798              :                                        const char *path,
    9799              :                                        const struct mg_serve_http_opts *opts) {
    9800              :   FILE *fp;
    9801              :   struct mg_str mime_type;
    9802              :   DBG(("%p %s", nc, path));
    9803              : 
    9804              :   if ((fp = mg_fopen(path, "rb")) == NULL) {
    9805              :     mg_http_send_error(nc, 404, NULL);
    9806              :   } else {
    9807              :     mg_set_close_on_exec((sock_t) fileno(fp));
    9808              : 
    9809              :     mime_type = mg_get_mime_type(path, "text/plain", opts);
    9810              :     mg_send_response_line(nc, 200, opts->extra_headers);
    9811              :     mg_printf(nc,
    9812              :               "Content-Type: %.*s\r\n"
    9813              :               "Connection: close\r\n\r\n",
    9814              :               (int) mime_type.len, mime_type.p);
    9815              :     mg_send_ssi_file(nc, hm, path, fp, 0, opts);
    9816              :     fclose(fp);
    9817              :     nc->flags |= MG_F_SEND_AND_CLOSE;
    9818              :   }
    9819              : }
    9820              : #endif
    9821              : 
    9822              : #endif /* MG_ENABLE_HTTP_SSI && MG_ENABLE_HTTP && MG_ENABLE_FILESYSTEM */
    9823              : #ifdef MG_MODULE_LINES
    9824              : #line 1 "mongoose/src/mg_http_webdav.c"
    9825              : #endif
    9826              : /*
    9827              :  * Copyright (c) 2014-2016 Cesanta Software Limited
    9828              :  * All rights reserved
    9829              :  */
    9830              : 
    9831              : #if MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBDAV
    9832              : 
    9833              : MG_INTERNAL int mg_is_dav_request(const struct mg_str *s) {
    9834              :   static const char *methods[] = {
    9835              :     "PUT",
    9836              :     "DELETE",
    9837              :     "MKCOL",
    9838              :     "PROPFIND",
    9839              :     "MOVE"
    9840              : #if MG_ENABLE_FAKE_DAVLOCK
    9841              :     ,
    9842              :     "LOCK",
    9843              :     "UNLOCK"
    9844              : #endif
    9845              :   };
    9846              :   size_t i;
    9847              : 
    9848              :   for (i = 0; i < ARRAY_SIZE(methods); i++) {
    9849              :     if (mg_vcmp(s, methods[i]) == 0) {
    9850              :       return 1;
    9851              :     }
    9852              :   }
    9853              : 
    9854              :   return 0;
    9855              : }
    9856              : 
    9857              : static int mg_mkdir(const char *path, uint32_t mode) {
    9858              : #ifndef _WIN32
    9859              :   return mkdir(path, mode);
    9860              : #else
    9861              :   (void) mode;
    9862              :   return _mkdir(path);
    9863              : #endif
    9864              : }
    9865              : 
    9866              : static void mg_print_props(struct mg_connection *nc, const char *name,
    9867              :                            cs_stat_t *stp) {
    9868              :   char mtime[64];
    9869              :   time_t t = stp->st_mtime; /* store in local variable for NDK compile */
    9870              :   struct mg_str name_esc = mg_url_encode(mg_mk_str(name));
    9871              :   mg_gmt_time_string(mtime, sizeof(mtime), &t);
    9872              :   mg_printf(nc,
    9873              :             "<d:response>"
    9874              :             "<d:href>%s</d:href>"
    9875              :             "<d:propstat>"
    9876              :             "<d:prop>"
    9877              :             "<d:resourcetype>%s</d:resourcetype>"
    9878              :             "<d:getcontentlength>%" INT64_FMT
    9879              :             "</d:getcontentlength>"
    9880              :             "<d:getlastmodified>%s</d:getlastmodified>"
    9881              :             "</d:prop>"
    9882              :             "<d:status>HTTP/1.1 200 OK</d:status>"
    9883              :             "</d:propstat>"
    9884              :             "</d:response>\n",
    9885              :             name_esc.p, S_ISDIR(stp->st_mode) ? "<d:collection/>" : "",
    9886              :             (int64_t) stp->st_size, mtime);
    9887              :   free((void *) name_esc.p);
    9888              : }
    9889              : 
    9890              : MG_INTERNAL void mg_handle_propfind(struct mg_connection *nc, const char *path,
    9891              :                                     cs_stat_t *stp, struct http_message *hm,
    9892              :                                     struct mg_serve_http_opts *opts) {
    9893              :   static const char header[] =
    9894              :       "HTTP/1.1 207 Multi-Status\r\n"
    9895              :       "Connection: close\r\n"
    9896              :       "Content-Type: text/xml; charset=utf-8\r\n\r\n"
    9897              :       "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
    9898              :       "<d:multistatus xmlns:d='DAV:'>\n";
    9899              :   static const char footer[] = "</d:multistatus>\n";
    9900              :   const struct mg_str *depth = mg_get_http_header(hm, "Depth");
    9901              : 
    9902              :   /* Print properties for the requested resource itself */
    9903              :   if (S_ISDIR(stp->st_mode) &&
    9904              :       strcmp(opts->enable_directory_listing, "yes") != 0) {
    9905              :     mg_printf(nc, "%s", "HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
    9906              :   } else {
    9907              :     char uri[MG_MAX_PATH];
    9908              :     mg_send(nc, header, sizeof(header) - 1);
    9909              :     snprintf(uri, sizeof(uri), "%.*s", (int) hm->uri.len, hm->uri.p);
    9910              :     mg_print_props(nc, uri, stp);
    9911              :     if (S_ISDIR(stp->st_mode) && (depth == NULL || mg_vcmp(depth, "0") != 0)) {
    9912              :       mg_scan_directory(nc, path, opts, mg_print_props);
    9913              :     }
    9914              :     mg_send(nc, footer, sizeof(footer) - 1);
    9915              :     nc->flags |= MG_F_SEND_AND_CLOSE;
    9916              :   }
    9917              : }
    9918              : 
    9919              : #if MG_ENABLE_FAKE_DAVLOCK
    9920              : /*
    9921              :  * Windows explorer (probably there are another WebDav clients like it)
    9922              :  * requires LOCK support in webdav. W/out this, it still works, but fails
    9923              :  * to save file: shows error message and offers "Save As".
    9924              :  * "Save as" works, but this message is very annoying.
    9925              :  * This is fake lock, which doesn't lock something, just returns LOCK token,
    9926              :  * UNLOCK always answers "OK".
    9927              :  * With this fake LOCK Windows Explorer looks happy and saves file.
    9928              :  * NOTE: that is not DAV LOCK imlementation, it is just a way to shut up
    9929              :  * Windows native DAV client. This is why FAKE LOCK is not enabed by default
    9930              :  */
    9931              : MG_INTERNAL void mg_handle_lock(struct mg_connection *nc, const char *path) {
    9932              :   static const char *reply =
    9933              :       "HTTP/1.1 207 Multi-Status\r\n"
    9934              :       "Connection: close\r\n"
    9935              :       "Content-Type: text/xml; charset=utf-8\r\n\r\n"
    9936              :       "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
    9937              :       "<d:multistatus xmlns:d='DAV:'>\n"
    9938              :       "<D:lockdiscovery>\n"
    9939              :       "<D:activelock>\n"
    9940              :       "<D:locktoken>\n"
    9941              :       "<D:href>\n"
    9942              :       "opaquelocktoken:%s%u"
    9943              :       "</D:href>"
    9944              :       "</D:locktoken>"
    9945              :       "</D:activelock>\n"
    9946              :       "</D:lockdiscovery>"
    9947              :       "</d:multistatus>\n";
    9948              :   mg_printf(nc, reply, path, (unsigned int) mg_time());
    9949              :   nc->flags |= MG_F_SEND_AND_CLOSE;
    9950              : }
    9951              : #endif
    9952              : 
    9953              : MG_INTERNAL void mg_handle_mkcol(struct mg_connection *nc, const char *path,
    9954              :                                  struct http_message *hm) {
    9955              :   int status_code = 500;
    9956              :   if (hm->body.len != (size_t) ~0 && hm->body.len > 0) {
    9957              :     status_code = 415;
    9958              :   } else if (!mg_mkdir(path, 0755)) {
    9959              :     status_code = 201;
    9960              :   } else if (errno == EEXIST) {
    9961              :     status_code = 405;
    9962              :   } else if (errno == EACCES) {
    9963              :     status_code = 403;
    9964              :   } else if (errno == ENOENT) {
    9965              :     status_code = 409;
    9966              :   } else {
    9967              :     status_code = 500;
    9968              :   }
    9969              :   mg_http_send_error(nc, status_code, NULL);
    9970              : }
    9971              : 
    9972              : static int mg_remove_directory(const struct mg_serve_http_opts *opts,
    9973              :                                const char *dir) {
    9974              :   char path[MG_MAX_PATH];
    9975              :   struct dirent *dp;
    9976              :   cs_stat_t st;
    9977              :   DIR *dirp;
    9978              : 
    9979              :   if ((dirp = opendir(dir)) == NULL) return 0;
    9980              : 
    9981              :   while ((dp = readdir(dirp)) != NULL) {
    9982              :     if (mg_is_file_hidden((const char *) dp->d_name, opts, 1)) {
    9983              :       continue;
    9984              :     }
    9985              :     snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
    9986              :     mg_stat(path, &st);
    9987              :     if (S_ISDIR(st.st_mode)) {
    9988              :       mg_remove_directory(opts, path);
    9989              :     } else {
    9990              :       remove(path);
    9991              :     }
    9992              :   }
    9993              :   closedir(dirp);
    9994              :   rmdir(dir);
    9995              : 
    9996              :   return 1;
    9997              : }
    9998              : 
    9999              : MG_INTERNAL void mg_handle_move(struct mg_connection *c,
   10000              :                                 const struct mg_serve_http_opts *opts,
   10001              :                                 const char *path, struct http_message *hm) {
   10002              :   const struct mg_str *dest = mg_get_http_header(hm, "Destination");
   10003              :   if (dest == NULL) {
   10004              :     mg_http_send_error(c, 411, NULL);
   10005              :   } else {
   10006              :     const char *p = (char *) memchr(dest->p, '/', dest->len);
   10007              :     if (p != NULL && p[1] == '/' &&
   10008              :         (p = (char *) memchr(p + 2, '/', dest->p + dest->len - p)) != NULL) {
   10009              :       char buf[MG_MAX_PATH];
   10010              :       snprintf(buf, sizeof(buf), "%s%.*s", opts->dav_document_root,
   10011              :                (int) (dest->p + dest->len - p), p);
   10012              :       if (rename(path, buf) == 0) {
   10013              :         mg_http_send_error(c, 200, NULL);
   10014              :       } else {
   10015              :         mg_http_send_error(c, 418, NULL);
   10016              :       }
   10017              :     } else {
   10018              :       mg_http_send_error(c, 500, NULL);
   10019              :     }
   10020              :   }
   10021              : }
   10022              : 
   10023              : MG_INTERNAL void mg_handle_delete(struct mg_connection *nc,
   10024              :                                   const struct mg_serve_http_opts *opts,
   10025              :                                   const char *path) {
   10026              :   cs_stat_t st;
   10027              :   if (mg_stat(path, &st) != 0) {
   10028              :     mg_http_send_error(nc, 404, NULL);
   10029              :   } else if (S_ISDIR(st.st_mode)) {
   10030              :     mg_remove_directory(opts, path);
   10031              :     mg_http_send_error(nc, 204, NULL);
   10032              :   } else if (remove(path) == 0) {
   10033              :     mg_http_send_error(nc, 204, NULL);
   10034              :   } else {
   10035              :     mg_http_send_error(nc, 423, NULL);
   10036              :   }
   10037              : }
   10038              : 
   10039              : /* Return -1 on error, 1 on success. */
   10040              : static int mg_create_itermediate_directories(const char *path) {
   10041              :   const char *s;
   10042              : 
   10043              :   /* Create intermediate directories if they do not exist */
   10044              :   for (s = path + 1; *s != '\0'; s++) {
   10045              :     if (*s == '/') {
   10046              :       char buf[MG_MAX_PATH];
   10047              :       cs_stat_t st;
   10048              :       snprintf(buf, sizeof(buf), "%.*s", (int) (s - path), path);
   10049              :       buf[sizeof(buf) - 1] = '\0';
   10050              :       if (mg_stat(buf, &st) != 0 && mg_mkdir(buf, 0755) != 0) {
   10051              :         return -1;
   10052              :       }
   10053              :     }
   10054              :   }
   10055              : 
   10056              :   return 1;
   10057              : }
   10058              : 
   10059              : MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path,
   10060              :                                struct http_message *hm) {
   10061              :   struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
   10062              :   cs_stat_t st;
   10063              :   const struct mg_str *cl_hdr = mg_get_http_header(hm, "Content-Length");
   10064              :   int rc, status_code = mg_stat(path, &st) == 0 ? 200 : 201;
   10065              : 
   10066              :   mg_http_free_proto_data_file(&pd->file);
   10067              :   if ((rc = mg_create_itermediate_directories(path)) == 0) {
   10068              :     mg_printf(nc, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
   10069              :   } else if (rc == -1) {
   10070              :     mg_http_send_error(nc, 500, NULL);
   10071              :   } else if (cl_hdr == NULL) {
   10072              :     mg_http_send_error(nc, 411, NULL);
   10073              :   } else if ((pd->file.fp = mg_fopen(path, "w+b")) == NULL) {
   10074              :     mg_http_send_error(nc, 500, NULL);
   10075              :   } else {
   10076              :     const struct mg_str *range_hdr = mg_get_http_header(hm, "Content-Range");
   10077              :     int64_t r1 = 0, r2 = 0;
   10078              :     pd->file.type = DATA_PUT;
   10079              :     mg_set_close_on_exec((sock_t) fileno(pd->file.fp));
   10080              :     pd->file.cl = to64(cl_hdr->p);
   10081              :     if (range_hdr != NULL &&
   10082              :         mg_http_parse_range_header(range_hdr, &r1, &r2) > 0) {
   10083              :       status_code = 206;
   10084              :       fseeko(pd->file.fp, r1, SEEK_SET);
   10085              :       pd->file.cl = r2 > r1 ? r2 - r1 + 1 : pd->file.cl - r1;
   10086              :     }
   10087              :     mg_printf(nc, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
   10088              :     /* Remove HTTP request from the mbuf, leave only payload */
   10089              :     mbuf_remove(&nc->recv_mbuf, hm->message.len - hm->body.len);
   10090              :     mg_http_transfer_file_data(nc);
   10091              :   }
   10092              : }
   10093              : 
   10094              : #endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBDAV */
   10095              : #ifdef MG_MODULE_LINES
   10096              : #line 1 "mongoose/src/mg_http_websocket.c"
   10097              : #endif
   10098              : /*
   10099              :  * Copyright (c) 2014 Cesanta Software Limited
   10100              :  * All rights reserved
   10101              :  */
   10102              : 
   10103              : #if MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBSOCKET
   10104              : 
   10105              : /* Amalgamated: #include "common/cs_sha1.h" */
   10106              : 
   10107              : #ifndef MG_WEBSOCKET_PING_INTERVAL_SECONDS
   10108              : #define MG_WEBSOCKET_PING_INTERVAL_SECONDS 5
   10109              : #endif
   10110              : 
   10111              : #define FLAGS_MASK_FIN (1 << 7)
   10112              : #define FLAGS_MASK_OP 0x0f
   10113              : 
   10114            0 : static int mg_is_ws_fragment(unsigned char flags) {
   10115            0 :   return (flags & FLAGS_MASK_FIN) == 0 ||
   10116            0 :          (flags & FLAGS_MASK_OP) == WEBSOCKET_OP_CONTINUE;
   10117              : }
   10118              : 
   10119            0 : static int mg_is_ws_first_fragment(unsigned char flags) {
   10120            0 :   return (flags & FLAGS_MASK_FIN) == 0 &&
   10121            0 :          (flags & FLAGS_MASK_OP) != WEBSOCKET_OP_CONTINUE;
   10122              : }
   10123              : 
   10124            0 : static int mg_is_ws_control_frame(unsigned char flags) {
   10125            0 :   unsigned char op = (flags & FLAGS_MASK_OP);
   10126            0 :   return op == WEBSOCKET_OP_CLOSE || op == WEBSOCKET_OP_PING ||
   10127            0 :          op == WEBSOCKET_OP_PONG;
   10128              : }
   10129              : 
   10130            0 : static void mg_handle_incoming_websocket_frame(struct mg_connection *nc,
   10131              :                                                struct websocket_message *wsm) {
   10132            0 :   if (wsm->flags & 0x8) {
   10133            0 :     mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_CONTROL_FRAME, wsm);
   10134              :   } else {
   10135            0 :     mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_FRAME, wsm);
   10136              :   }
   10137            0 : }
   10138              : 
   10139            0 : static struct mg_ws_proto_data *mg_ws_get_proto_data(struct mg_connection *nc) {
   10140            0 :   struct mg_http_proto_data *htd = mg_http_get_proto_data(nc);
   10141            0 :   return (htd != NULL ? &htd->ws_data : NULL);
   10142              : }
   10143              : 
   10144              : /*
   10145              :  * Sends a Close websocket frame with the given data, and closes the underlying
   10146              :  * connection. If `len` is ~0, strlen(data) is used.
   10147              :  */
   10148            0 : static void mg_ws_close(struct mg_connection *nc, const void *data,
   10149              :                         size_t len) {
   10150            0 :   if ((int) len == ~0) {
   10151            0 :     len = strlen((const char *) data);
   10152              :   }
   10153            0 :   mg_send_websocket_frame(nc, WEBSOCKET_OP_CLOSE, data, len);
   10154            0 :   nc->flags |= MG_F_SEND_AND_CLOSE;
   10155            0 : }
   10156              : 
   10157            0 : static int mg_deliver_websocket_data(struct mg_connection *nc) {
   10158              :   /* Using unsigned char *, cause of integer arithmetic below */
   10159            0 :   uint64_t i, data_len = 0, frame_len = 0, new_data_len = nc->recv_mbuf.len,
   10160            0 :               len, mask_len = 0, header_len = 0;
   10161            0 :   struct mg_ws_proto_data *wsd = mg_ws_get_proto_data(nc);
   10162            0 :   unsigned char *new_data = (unsigned char *) nc->recv_mbuf.buf,
   10163            0 :                 *e = (unsigned char *) nc->recv_mbuf.buf + nc->recv_mbuf.len;
   10164              :   uint8_t flags;
   10165              :   int ok, reass;
   10166              : 
   10167            0 :   if (wsd->reass_len > 0) {
   10168              :     /*
   10169              :      * We already have some previously received data which we need to
   10170              :      * reassemble and deliver to the client code when we get the final
   10171              :      * fragment.
   10172              :      *
   10173              :      * NOTE: it doesn't mean that the current message must be a continuation:
   10174              :      * it might be a control frame (Close, Ping or Pong), which should be
   10175              :      * handled without breaking the fragmented message.
   10176              :      */
   10177              : 
   10178            0 :     size_t existing_len = wsd->reass_len;
   10179            0 :     assert(new_data_len >= existing_len);
   10180              : 
   10181            0 :     new_data += existing_len;
   10182            0 :     new_data_len -= existing_len;
   10183              :   }
   10184              : 
   10185            0 :   flags = new_data[0];
   10186              : 
   10187            0 :   reass = new_data_len > 0 && mg_is_ws_fragment(flags) &&
   10188            0 :           !(nc->flags & MG_F_WEBSOCKET_NO_DEFRAG);
   10189              : 
   10190            0 :   if (reass && mg_is_ws_control_frame(flags)) {
   10191              :     /*
   10192              :      * Control frames can't be fragmented, so if we encounter fragmented
   10193              :      * control frame, close connection immediately.
   10194              :      */
   10195            0 :     mg_ws_close(nc, "fragmented control frames are illegal", ~0);
   10196            0 :     return 0;
   10197            0 :   } else if (new_data_len > 0 && !reass && !mg_is_ws_control_frame(flags) &&
   10198            0 :              wsd->reass_len > 0) {
   10199              :     /*
   10200              :      * When in the middle of a fragmented message, only the continuations
   10201              :      * and control frames are allowed.
   10202              :      */
   10203            0 :     mg_ws_close(nc, "non-continuation in the middle of a fragmented message",
   10204              :                 ~0);
   10205            0 :     return 0;
   10206              :   }
   10207              : 
   10208            0 :   if (new_data_len >= 2) {
   10209            0 :     len = new_data[1] & 0x7f;
   10210            0 :     mask_len = new_data[1] & FLAGS_MASK_FIN ? 4 : 0;
   10211            0 :     if (len < 126 && new_data_len >= mask_len) {
   10212            0 :       data_len = len;
   10213            0 :       header_len = 2 + mask_len;
   10214            0 :     } else if (len == 126 && new_data_len >= 4 + mask_len) {
   10215            0 :       header_len = 4 + mask_len;
   10216            0 :       data_len = ntohs(*(uint16_t *) &new_data[2]);
   10217            0 :     } else if (new_data_len >= 10 + mask_len) {
   10218            0 :       header_len = 10 + mask_len;
   10219            0 :       data_len = (((uint64_t) ntohl(*(uint32_t *) &new_data[2])) << 32) +
   10220            0 :                  ntohl(*(uint32_t *) &new_data[6]);
   10221              :     }
   10222              :   }
   10223              : 
   10224            0 :   frame_len = header_len + data_len;
   10225            0 :   ok = (frame_len > 0 && frame_len <= new_data_len);
   10226              : 
   10227              :   /* Check for overflow */
   10228            0 :   if (frame_len < header_len || frame_len < data_len) {
   10229            0 :     ok = 0;
   10230            0 :     mg_ws_close(nc, "overflowed message", ~0);
   10231              :   }
   10232              : 
   10233            0 :   if (ok) {
   10234            0 :     size_t cleanup_len = 0;
   10235              :     struct websocket_message wsm;
   10236              : 
   10237            0 :     wsm.size = (size_t) data_len;
   10238            0 :     wsm.data = new_data + header_len;
   10239            0 :     wsm.flags = flags;
   10240              : 
   10241              :     /* Apply mask if necessary */
   10242            0 :     if (mask_len > 0) {
   10243            0 :       for (i = 0; i < data_len; i++) {
   10244            0 :         new_data[i + header_len] ^= (new_data + header_len - mask_len)[i % 4];
   10245              :       }
   10246              :     }
   10247              : 
   10248            0 :     if (reass) {
   10249              :       /* This is a message fragment */
   10250              : 
   10251            0 :       if (mg_is_ws_first_fragment(flags)) {
   10252              :         /*
   10253              :          * On the first fragmented frame, skip the first byte (op) and also
   10254              :          * reset size to 1 (op), it'll be incremented with the data len below.
   10255              :          */
   10256            0 :         new_data += 1;
   10257            0 :         wsd->reass_len = 1 /* op */;
   10258              :       }
   10259              : 
   10260              :       /* Append this frame to the reassembled buffer */
   10261            0 :       memmove(new_data, wsm.data, e - wsm.data);
   10262            0 :       wsd->reass_len += wsm.size;
   10263            0 :       nc->recv_mbuf.len -= wsm.data - new_data;
   10264              : 
   10265            0 :       if (flags & FLAGS_MASK_FIN) {
   10266              :         /* On last fragmented frame - call user handler and remove data */
   10267            0 :         wsm.flags = FLAGS_MASK_FIN | nc->recv_mbuf.buf[0];
   10268            0 :         wsm.data = (unsigned char *) nc->recv_mbuf.buf + 1 /* op */;
   10269            0 :         wsm.size = wsd->reass_len - 1 /* op */;
   10270            0 :         cleanup_len = wsd->reass_len;
   10271            0 :         wsd->reass_len = 0;
   10272              : 
   10273              :         /* Pass reassembled message to the client code. */
   10274            0 :         mg_handle_incoming_websocket_frame(nc, &wsm);
   10275            0 :         mbuf_remove(&nc->recv_mbuf, cleanup_len); /* Cleanup frame */
   10276              :       }
   10277              :     } else {
   10278              :       /*
   10279              :        * This is a complete message, not a fragment. It might happen in between
   10280              :        * of a fragmented message (in this case, WebSocket protocol requires
   10281              :        * current message to be a control frame).
   10282              :        */
   10283            0 :       cleanup_len = (size_t) frame_len;
   10284              : 
   10285              :       /* First of all, check if we need to react on a control frame. */
   10286            0 :       switch (flags & FLAGS_MASK_OP) {
   10287            0 :         case WEBSOCKET_OP_PING:
   10288            0 :           mg_send_websocket_frame(nc, WEBSOCKET_OP_PONG, wsm.data, wsm.size);
   10289            0 :           break;
   10290              : 
   10291            0 :         case WEBSOCKET_OP_CLOSE:
   10292            0 :           mg_ws_close(nc, wsm.data, wsm.size);
   10293            0 :           break;
   10294              :       }
   10295              : 
   10296              :       /* Pass received message to the client code. */
   10297            0 :       mg_handle_incoming_websocket_frame(nc, &wsm);
   10298              : 
   10299              :       /* Cleanup frame */
   10300            0 :       memmove(nc->recv_mbuf.buf + wsd->reass_len,
   10301            0 :               nc->recv_mbuf.buf + wsd->reass_len + cleanup_len,
   10302            0 :               nc->recv_mbuf.len - wsd->reass_len - cleanup_len);
   10303            0 :       nc->recv_mbuf.len -= cleanup_len;
   10304              :     }
   10305              :   }
   10306              : 
   10307            0 :   return ok;
   10308              : }
   10309              : 
   10310              : struct ws_mask_ctx {
   10311              :   size_t pos; /* zero means unmasked */
   10312              :   uint32_t mask;
   10313              : };
   10314              : 
   10315            0 : static uint32_t mg_ws_random_mask(void) {
   10316              :   uint32_t mask;
   10317              : /*
   10318              :  * The spec requires WS client to generate hard to
   10319              :  * guess mask keys. From RFC6455, Section 5.3:
   10320              :  *
   10321              :  * The unpredictability of the masking key is essential to prevent
   10322              :  * authors of malicious applications from selecting the bytes that appear on
   10323              :  * the wire.
   10324              :  *
   10325              :  * Hence this feature is essential when the actual end user of this API
   10326              :  * is untrusted code that wouldn't have access to a lower level net API
   10327              :  * anyway (e.g. web browsers). Hence this feature is low prio for most
   10328              :  * mongoose use cases and thus can be disabled, e.g. when porting to a platform
   10329              :  * that lacks rand().
   10330              :  */
   10331              : #if MG_DISABLE_WS_RANDOM_MASK
   10332              :   mask = 0xefbeadde; /* generated with a random number generator, I swear */
   10333              : #else
   10334              :   if (sizeof(long) >= 4) {
   10335            0 :     mask = (uint32_t) rand();
   10336              :   } else if (sizeof(long) == 2) {
   10337              :     mask = (uint32_t) rand() << 16 | (uint32_t) rand();
   10338              :   }
   10339              : #endif
   10340            0 :   return mask;
   10341              : }
   10342              : 
   10343            0 : static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len,
   10344              :                               struct ws_mask_ctx *ctx) {
   10345              :   int header_len;
   10346              :   unsigned char header[10];
   10347              : 
   10348            0 :   header[0] =
   10349            0 :       (op & WEBSOCKET_DONT_FIN ? 0x0 : FLAGS_MASK_FIN) | (op & FLAGS_MASK_OP);
   10350            0 :   if (len < 126) {
   10351            0 :     header[1] = (unsigned char) len;
   10352            0 :     header_len = 2;
   10353            0 :   } else if (len < 65535) {
   10354            0 :     uint16_t tmp = htons((uint16_t) len);
   10355            0 :     header[1] = 126;
   10356            0 :     memcpy(&header[2], &tmp, sizeof(tmp));
   10357            0 :     header_len = 4;
   10358              :   } else {
   10359              :     uint32_t tmp;
   10360            0 :     header[1] = 127;
   10361            0 :     tmp = htonl((uint32_t)((uint64_t) len >> 32));
   10362            0 :     memcpy(&header[2], &tmp, sizeof(tmp));
   10363            0 :     tmp = htonl((uint32_t)(len & 0xffffffff));
   10364            0 :     memcpy(&header[6], &tmp, sizeof(tmp));
   10365            0 :     header_len = 10;
   10366              :   }
   10367              : 
   10368              :   /* client connections enable masking */
   10369            0 :   if (nc->listener == NULL) {
   10370            0 :     header[1] |= 1 << 7; /* set masking flag */
   10371            0 :     mg_send(nc, header, header_len);
   10372            0 :     ctx->mask = mg_ws_random_mask();
   10373            0 :     mg_send(nc, &ctx->mask, sizeof(ctx->mask));
   10374            0 :     ctx->pos = nc->send_mbuf.len;
   10375              :   } else {
   10376            0 :     mg_send(nc, header, header_len);
   10377            0 :     ctx->pos = 0;
   10378              :   }
   10379            0 : }
   10380              : 
   10381            0 : static void mg_ws_mask_frame(struct mbuf *mbuf, struct ws_mask_ctx *ctx) {
   10382              :   size_t i;
   10383            0 :   if (ctx->pos == 0) return;
   10384            0 :   for (i = 0; i < (mbuf->len - ctx->pos); i++) {
   10385            0 :     mbuf->buf[ctx->pos + i] ^= ((char *) &ctx->mask)[i % 4];
   10386              :   }
   10387              : }
   10388              : 
   10389            0 : void mg_send_websocket_frame(struct mg_connection *nc, int op, const void *data,
   10390              :                              size_t len) {
   10391              :   struct ws_mask_ctx ctx;
   10392            0 :   DBG(("%p %d %d", nc, op, (int) len));
   10393            0 :   mg_send_ws_header(nc, op, len, &ctx);
   10394            0 :   mg_send(nc, data, len);
   10395              : 
   10396            0 :   mg_ws_mask_frame(&nc->send_mbuf, &ctx);
   10397              : 
   10398            0 :   if (op == WEBSOCKET_OP_CLOSE) {
   10399            0 :     nc->flags |= MG_F_SEND_AND_CLOSE;
   10400              :   }
   10401            0 : }
   10402              : 
   10403            0 : void mg_send_websocket_framev(struct mg_connection *nc, int op,
   10404              :                               const struct mg_str *strv, int strvcnt) {
   10405              :   struct ws_mask_ctx ctx;
   10406              :   int i;
   10407            0 :   int len = 0;
   10408            0 :   for (i = 0; i < strvcnt; i++) {
   10409            0 :     len += strv[i].len;
   10410              :   }
   10411              : 
   10412            0 :   mg_send_ws_header(nc, op, len, &ctx);
   10413              : 
   10414            0 :   for (i = 0; i < strvcnt; i++) {
   10415            0 :     mg_send(nc, strv[i].p, strv[i].len);
   10416              :   }
   10417              : 
   10418            0 :   mg_ws_mask_frame(&nc->send_mbuf, &ctx);
   10419              : 
   10420            0 :   if (op == WEBSOCKET_OP_CLOSE) {
   10421            0 :     nc->flags |= MG_F_SEND_AND_CLOSE;
   10422              :   }
   10423            0 : }
   10424              : 
   10425            0 : void mg_printf_websocket_frame(struct mg_connection *nc, int op,
   10426              :                                const char *fmt, ...) {
   10427            0 :   char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
   10428              :   va_list ap;
   10429              :   int len;
   10430              : 
   10431            0 :   va_start(ap, fmt);
   10432            0 :   if ((len = mg_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
   10433            0 :     mg_send_websocket_frame(nc, op, buf, len);
   10434              :   }
   10435            0 :   va_end(ap);
   10436              : 
   10437            0 :   if (buf != mem && buf != NULL) {
   10438            0 :     MG_FREE(buf);
   10439              :   }
   10440            0 : }
   10441              : 
   10442            0 : MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev,
   10443              :                                void *ev_data MG_UD_ARG(void *user_data)) {
   10444            0 :   mg_call(nc, nc->handler, nc->user_data, ev, ev_data);
   10445              : 
   10446            0 :   switch (ev) {
   10447            0 :     case MG_EV_RECV:
   10448              :       do {
   10449            0 :       } while (mg_deliver_websocket_data(nc));
   10450            0 :       break;
   10451            0 :     case MG_EV_POLL:
   10452              :       /* Ping idle websocket connections */
   10453              :       {
   10454            0 :         time_t now = *(time_t *) ev_data;
   10455            0 :         if (nc->flags & MG_F_IS_WEBSOCKET &&
   10456            0 :             now > nc->last_io_time + MG_WEBSOCKET_PING_INTERVAL_SECONDS) {
   10457            0 :           mg_send_websocket_frame(nc, WEBSOCKET_OP_PING, "", 0);
   10458              :         }
   10459              :       }
   10460            0 :       break;
   10461            0 :     default:
   10462            0 :       break;
   10463              :   }
   10464              : #if MG_ENABLE_CALLBACK_USERDATA
   10465              :   (void) user_data;
   10466              : #endif
   10467            0 : }
   10468              : 
   10469              : #ifndef MG_EXT_SHA1
   10470            0 : void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
   10471              :                     const size_t *msg_lens, uint8_t *digest) {
   10472              :   size_t i;
   10473              :   cs_sha1_ctx sha_ctx;
   10474            0 :   cs_sha1_init(&sha_ctx);
   10475            0 :   for (i = 0; i < num_msgs; i++) {
   10476            0 :     cs_sha1_update(&sha_ctx, msgs[i], msg_lens[i]);
   10477              :   }
   10478            0 :   cs_sha1_final(digest, &sha_ctx);
   10479            0 : }
   10480              : #else
   10481              : extern void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
   10482              :                            const size_t *msg_lens, uint8_t *digest);
   10483              : #endif
   10484              : 
   10485            0 : MG_INTERNAL void mg_ws_handshake(struct mg_connection *nc,
   10486              :                                  const struct mg_str *key,
   10487              :                                  struct http_message *hm) {
   10488              :   static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
   10489            0 :   const uint8_t *msgs[2] = {(const uint8_t *) key->p, (const uint8_t *) magic};
   10490            0 :   const size_t msg_lens[2] = {key->len, 36};
   10491              :   unsigned char sha[20];
   10492              :   char b64_sha[30];
   10493              :   struct mg_str *s;
   10494              : 
   10495            0 :   mg_hash_sha1_v(2, msgs, msg_lens, sha);
   10496            0 :   mg_base64_encode(sha, sizeof(sha), b64_sha);
   10497            0 :   mg_printf(nc, "%s",
   10498              :             "HTTP/1.1 101 Switching Protocols\r\n"
   10499              :             "Upgrade: websocket\r\n"
   10500              :             "Connection: Upgrade\r\n");
   10501              : 
   10502            0 :   s = mg_get_http_header(hm, "Sec-WebSocket-Protocol");
   10503            0 :   if (s != NULL) {
   10504            0 :     mg_printf(nc, "Sec-WebSocket-Protocol: %.*s\r\n", (int) s->len, s->p);
   10505              :   }
   10506            0 :   mg_printf(nc, "Sec-WebSocket-Accept: %s%s", b64_sha, "\r\n\r\n");
   10507              : 
   10508            0 :   DBG(("%p %.*s %s", nc, (int) key->len, key->p, b64_sha));
   10509            0 : }
   10510              : 
   10511            0 : void mg_send_websocket_handshake2(struct mg_connection *nc, const char *path,
   10512              :                                   const char *host, const char *protocol,
   10513              :                                   const char *extra_headers) {
   10514            0 :   mg_send_websocket_handshake3(nc, path, host, protocol, extra_headers, NULL,
   10515              :                                NULL);
   10516            0 : }
   10517              : 
   10518            0 : void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path,
   10519              :                                   const char *host, const char *protocol,
   10520              :                                   const char *extra_headers, const char *user,
   10521              :                                   const char *pass) {
   10522            0 :   mg_send_websocket_handshake3v(nc, mg_mk_str(path), mg_mk_str(host),
   10523              :                                 mg_mk_str(protocol), mg_mk_str(extra_headers),
   10524              :                                 mg_mk_str(user), mg_mk_str(pass));
   10525            0 : }
   10526              : 
   10527            0 : void mg_send_websocket_handshake3v(struct mg_connection *nc,
   10528              :                                    const struct mg_str path,
   10529              :                                    const struct mg_str host,
   10530              :                                    const struct mg_str protocol,
   10531              :                                    const struct mg_str extra_headers,
   10532              :                                    const struct mg_str user,
   10533              :                                    const struct mg_str pass) {
   10534              :   struct mbuf auth;
   10535              :   char key[25];
   10536              :   uint32_t nonce[4];
   10537            0 :   nonce[0] = mg_ws_random_mask();
   10538            0 :   nonce[1] = mg_ws_random_mask();
   10539            0 :   nonce[2] = mg_ws_random_mask();
   10540            0 :   nonce[3] = mg_ws_random_mask();
   10541            0 :   mg_base64_encode((unsigned char *) &nonce, sizeof(nonce), key);
   10542              : 
   10543            0 :   mbuf_init(&auth, 0);
   10544            0 :   if (user.len > 0) {
   10545            0 :     mg_basic_auth_header(user, pass, &auth);
   10546              :   }
   10547              : 
   10548              :   /*
   10549              :    * NOTE: the  (auth.buf == NULL ? "" : auth.buf) is because cc3200 libc is
   10550              :    * broken: it doesn't like zero length to be passed to %.*s
   10551              :    * i.e. sprintf("f%.*so", (int)0, NULL), yields `f\0o`.
   10552              :    * because it handles NULL specially (and incorrectly).
   10553              :    */
   10554            0 :   mg_printf(nc,
   10555              :             "GET %.*s HTTP/1.1\r\n"
   10556              :             "Upgrade: websocket\r\n"
   10557              :             "Connection: Upgrade\r\n"
   10558              :             "%.*s"
   10559              :             "Sec-WebSocket-Version: 13\r\n"
   10560              :             "Sec-WebSocket-Key: %s\r\n",
   10561            0 :             (int) path.len, path.p, (int) auth.len,
   10562            0 :             (auth.buf == NULL ? "" : auth.buf), key);
   10563              : 
   10564              :   /* TODO(mkm): take default hostname from http proto data if host == NULL */
   10565            0 :   if (host.len > 0) {
   10566            0 :     int host_len = (int) (path.p - host.p); /* Account for possible :PORT */
   10567            0 :     mg_printf(nc, "Host: %.*s\r\n", host_len, host.p);
   10568              :   }
   10569            0 :   if (protocol.len > 0) {
   10570            0 :     mg_printf(nc, "Sec-WebSocket-Protocol: %.*s\r\n", (int) protocol.len,
   10571            0 :               protocol.p);
   10572              :   }
   10573            0 :   if (extra_headers.len > 0) {
   10574            0 :     mg_printf(nc, "%.*s", (int) extra_headers.len, extra_headers.p);
   10575              :   }
   10576            0 :   mg_printf(nc, "\r\n");
   10577              : 
   10578            0 :   nc->flags |= MG_F_IS_WEBSOCKET;
   10579              : 
   10580            0 :   mbuf_free(&auth);
   10581            0 : }
   10582              : 
   10583            0 : void mg_send_websocket_handshake(struct mg_connection *nc, const char *path,
   10584              :                                  const char *extra_headers) {
   10585            0 :   struct mg_str null_str = MG_NULL_STR;
   10586            0 :   mg_send_websocket_handshake3v(
   10587              :       nc, mg_mk_str(path), null_str /* host */, null_str /* protocol */,
   10588              :       mg_mk_str(extra_headers), null_str /* user */, null_str /* pass */);
   10589            0 : }
   10590              : 
   10591            0 : struct mg_connection *mg_connect_ws_opt(
   10592              :     struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
   10593              :     struct mg_connect_opts opts, const char *url, const char *protocol,
   10594              :     const char *extra_headers) {
   10595            0 :   struct mg_str null_str = MG_NULL_STR;
   10596            0 :   struct mg_str host = MG_NULL_STR, path = MG_NULL_STR, user_info = MG_NULL_STR;
   10597              :   struct mg_connection *nc =
   10598            0 :       mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "http",
   10599              :                            "ws", "https", "wss", url, &path, &user_info, &host);
   10600            0 :   if (nc != NULL) {
   10601            0 :     mg_send_websocket_handshake3v(nc, path, host, mg_mk_str(protocol),
   10602              :                                   mg_mk_str(extra_headers), user_info,
   10603              :                                   null_str);
   10604              :   }
   10605            0 :   return nc;
   10606              : }
   10607              : 
   10608            0 : struct mg_connection *mg_connect_ws(
   10609              :     struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
   10610              :     const char *url, const char *protocol, const char *extra_headers) {
   10611              :   struct mg_connect_opts opts;
   10612            0 :   memset(&opts, 0, sizeof(opts));
   10613            0 :   return mg_connect_ws_opt(mgr, MG_CB(ev_handler, user_data), opts, url,
   10614            0 :                            protocol, extra_headers);
   10615              : }
   10616              : #endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBSOCKET */
   10617              : #ifdef MG_MODULE_LINES
   10618              : #line 1 "mongoose/src/mg_util.c"
   10619              : #endif
   10620              : /*
   10621              :  * Copyright (c) 2014 Cesanta Software Limited
   10622              :  * All rights reserved
   10623              :  */
   10624              : 
   10625              : /* Amalgamated: #include "common/cs_base64.h" */
   10626              : /* Amalgamated: #include "mg_internal.h" */
   10627              : /* Amalgamated: #include "mg_util.h" */
   10628              : 
   10629              : /* For platforms with limited libc */
   10630              : #ifndef MAX
   10631              : #define MAX(a, b) ((a) > (b) ? (a) : (b))
   10632              : #endif
   10633              : 
   10634            0 : const char *mg_skip(const char *s, const char *end, const char *delims,
   10635              :                     struct mg_str *v) {
   10636            0 :   v->p = s;
   10637            0 :   while (s < end && strchr(delims, *(unsigned char *) s) == NULL) s++;
   10638            0 :   v->len = s - v->p;
   10639            0 :   while (s < end && strchr(delims, *(unsigned char *) s) != NULL) s++;
   10640            0 :   return s;
   10641              : }
   10642              : 
   10643              : #if MG_ENABLE_FILESYSTEM && !defined(MG_USER_FILE_FUNCTIONS)
   10644            0 : int mg_stat(const char *path, cs_stat_t *st) {
   10645              : #ifdef _WIN32
   10646              :   wchar_t wpath[MG_MAX_PATH];
   10647              :   to_wchar(path, wpath, ARRAY_SIZE(wpath));
   10648              :   DBG(("[%ls] -> %d", wpath, _wstati64(wpath, st)));
   10649              :   return _wstati64(wpath, st);
   10650              : #else
   10651            0 :   return stat(path, st);
   10652              : #endif
   10653              : }
   10654              : 
   10655            0 : FILE *mg_fopen(const char *path, const char *mode) {
   10656              : #ifdef _WIN32
   10657              :   wchar_t wpath[MG_MAX_PATH], wmode[10];
   10658              :   to_wchar(path, wpath, ARRAY_SIZE(wpath));
   10659              :   to_wchar(mode, wmode, ARRAY_SIZE(wmode));
   10660              :   return _wfopen(wpath, wmode);
   10661              : #else
   10662            0 :   return fopen(path, mode);
   10663              : #endif
   10664              : }
   10665              : 
   10666              : int mg_open(const char *path, int flag, int mode) { /* LCOV_EXCL_LINE */
   10667              : #if defined(_WIN32) && !defined(WINCE)
   10668              :   wchar_t wpath[MG_MAX_PATH];
   10669              :   to_wchar(path, wpath, ARRAY_SIZE(wpath));
   10670              :   return _wopen(wpath, flag, mode);
   10671              : #else
   10672              :   return open(path, flag, mode); /* LCOV_EXCL_LINE */
   10673              : #endif
   10674              : }
   10675              : 
   10676            0 : size_t mg_fread(void *ptr, size_t size, size_t count, FILE *f) {
   10677            0 :   return fread(ptr, size, count, f);
   10678              : }
   10679              : 
   10680            0 : size_t mg_fwrite(const void *ptr, size_t size, size_t count, FILE *f) {
   10681            0 :   return fwrite(ptr, size, count, f);
   10682              : }
   10683              : #endif
   10684              : 
   10685            0 : void mg_base64_encode(const unsigned char *src, int src_len, char *dst) {
   10686            0 :   cs_base64_encode(src, src_len, dst);
   10687            0 : }
   10688              : 
   10689            0 : int mg_base64_decode(const unsigned char *s, int len, char *dst) {
   10690            0 :   return cs_base64_decode(s, len, dst, NULL);
   10691              : }
   10692              : 
   10693              : #if MG_ENABLE_THREADS
   10694            0 : void *mg_start_thread(void *(*f)(void *), void *p) {
   10695              : #ifdef WINCE
   10696              :   return (void *) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) f, p, 0, NULL);
   10697              : #elif defined(_WIN32)
   10698              :   return (void *) _beginthread((void(__cdecl *) (void *) ) f, 0, p);
   10699              : #else
   10700            0 :   pthread_t thread_id = (pthread_t) 0;
   10701              :   pthread_attr_t attr;
   10702              : 
   10703            0 :   (void) pthread_attr_init(&attr);
   10704            0 :   (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
   10705              : 
   10706              : #if defined(MG_STACK_SIZE) && MG_STACK_SIZE > 1
   10707              :   (void) pthread_attr_setstacksize(&attr, MG_STACK_SIZE);
   10708              : #endif
   10709              : 
   10710            0 :   pthread_create(&thread_id, &attr, f, p);
   10711            0 :   pthread_attr_destroy(&attr);
   10712              : 
   10713            0 :   return (void *) thread_id;
   10714              : #endif
   10715              : }
   10716              : #endif /* MG_ENABLE_THREADS */
   10717              : 
   10718              : /* Set close-on-exec bit for a given socket. */
   10719            0 : void mg_set_close_on_exec(sock_t sock) {
   10720              : #if defined(_WIN32) && !defined(WINCE)
   10721              :   (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
   10722              : #elif defined(__unix__)
   10723            0 :   fcntl(sock, F_SETFD, FD_CLOEXEC);
   10724              : #else
   10725              :   (void) sock;
   10726              : #endif
   10727            0 : }
   10728              : 
   10729            0 : int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len,
   10730              :                         int flags) {
   10731              :   int is_v6;
   10732            0 :   if (buf == NULL || len <= 0) return 0;
   10733            0 :   memset(buf, 0, len);
   10734              : #if MG_ENABLE_IPV6
   10735            0 :   is_v6 = sa->sa.sa_family == AF_INET6;
   10736              : #else
   10737              :   is_v6 = 0;
   10738              : #endif
   10739            0 :   if (flags & MG_SOCK_STRINGIFY_IP) {
   10740              : #if MG_ENABLE_IPV6
   10741            0 :     const void *addr = NULL;
   10742            0 :     char *start = buf;
   10743            0 :     socklen_t capacity = len;
   10744            0 :     if (!is_v6) {
   10745            0 :       addr = &sa->sin.sin_addr;
   10746              :     } else {
   10747            0 :       addr = (void *) &sa->sin6.sin6_addr;
   10748            0 :       if (flags & MG_SOCK_STRINGIFY_PORT) {
   10749            0 :         *buf = '[';
   10750            0 :         start++;
   10751            0 :         capacity--;
   10752              :       }
   10753              :     }
   10754            0 :     if (inet_ntop(sa->sa.sa_family, addr, start, capacity) == NULL) {
   10755            0 :       goto cleanup;
   10756              :     }
   10757              : #elif defined(_WIN32) || MG_LWIP || (MG_NET_IF == MG_NET_IF_PIC32)
   10758              :     /* Only Windoze Vista (and newer) have inet_ntop() */
   10759              :     char *addr_str = inet_ntoa(sa->sin.sin_addr);
   10760              :     if (addr_str != NULL) {
   10761              :       strncpy(buf, inet_ntoa(sa->sin.sin_addr), len - 1);
   10762              :     } else {
   10763              :       goto cleanup;
   10764              :     }
   10765              : #else
   10766              :     if (inet_ntop(AF_INET, (void *) &sa->sin.sin_addr, buf, len) == NULL) {
   10767              :       goto cleanup;
   10768              :     }
   10769              : #endif
   10770              :   }
   10771            0 :   if (flags & MG_SOCK_STRINGIFY_PORT) {
   10772            0 :     int port = ntohs(sa->sin.sin_port);
   10773            0 :     if (flags & MG_SOCK_STRINGIFY_IP) {
   10774            0 :       int buf_len = strlen(buf);
   10775            0 :       snprintf(buf + buf_len, len - (buf_len + 1), "%s:%d", (is_v6 ? "]" : ""),
   10776              :                port);
   10777              :     } else {
   10778            0 :       snprintf(buf, len, "%d", port);
   10779              :     }
   10780              :   }
   10781              : 
   10782            0 :   return strlen(buf);
   10783              : 
   10784            0 : cleanup:
   10785            0 :   *buf = '\0';
   10786            0 :   return 0;
   10787              : }
   10788              : 
   10789            0 : int mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len,
   10790              :                         int flags) {
   10791              :   union socket_address sa;
   10792            0 :   memset(&sa, 0, sizeof(sa));
   10793            0 :   mg_if_get_conn_addr(nc, flags & MG_SOCK_STRINGIFY_REMOTE, &sa);
   10794            0 :   return mg_sock_addr_to_str(&sa, buf, len, flags);
   10795              : }
   10796              : 
   10797              : #if MG_ENABLE_HEXDUMP
   10798            0 : static int mg_hexdump_n(const void *buf, int len, char *dst, int dst_len,
   10799              :                         int offset) {
   10800            0 :   const unsigned char *p = (const unsigned char *) buf;
   10801            0 :   char ascii[17] = "";
   10802            0 :   int i, idx, n = 0;
   10803              : 
   10804            0 :   for (i = 0; i < len; i++) {
   10805            0 :     idx = i % 16;
   10806            0 :     if (idx == 0) {
   10807            0 :       if (i > 0) n += snprintf(dst + n, MAX(dst_len - n, 0), "  %s\n", ascii);
   10808            0 :       n += snprintf(dst + n, MAX(dst_len - n, 0), "%04x ", i + offset);
   10809              :     }
   10810            0 :     if (dst_len - n < 0) {
   10811            0 :       return n;
   10812              :     }
   10813            0 :     n += snprintf(dst + n, MAX(dst_len - n, 0), " %02x", p[i]);
   10814            0 :     ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i];
   10815            0 :     ascii[idx + 1] = '\0';
   10816              :   }
   10817              : 
   10818            0 :   while (i++ % 16) n += snprintf(dst + n, MAX(dst_len - n, 0), "%s", "   ");
   10819            0 :   n += snprintf(dst + n, MAX(dst_len - n, 0), "  %s\n", ascii);
   10820              : 
   10821            0 :   return n;
   10822              : }
   10823              : 
   10824            0 : int mg_hexdump(const void *buf, int len, char *dst, int dst_len) {
   10825            0 :   return mg_hexdump_n(buf, len, dst, dst_len, 0);
   10826              : }
   10827              : 
   10828            0 : void mg_hexdumpf(FILE *fp, const void *buf, int len) {
   10829              :   char tmp[80];
   10830            0 :   int offset = 0, n;
   10831            0 :   while (len > 0) {
   10832            0 :     n = (len < 16 ? len : 16);
   10833            0 :     mg_hexdump_n(((const char *) buf) + offset, n, tmp, sizeof(tmp), offset);
   10834            0 :     fputs(tmp, fp);
   10835            0 :     offset += n;
   10836            0 :     len -= n;
   10837              :   }
   10838            0 : }
   10839              : 
   10840            0 : void mg_hexdump_connection(struct mg_connection *nc, const char *path,
   10841              :                            const void *buf, int num_bytes, int ev) {
   10842            0 :   FILE *fp = NULL;
   10843              :   char src[60], dst[60];
   10844            0 :   const char *tag = NULL;
   10845            0 :   switch (ev) {
   10846            0 :     case MG_EV_RECV:
   10847            0 :       tag = "<-";
   10848            0 :       break;
   10849            0 :     case MG_EV_SEND:
   10850            0 :       tag = "->";
   10851            0 :       break;
   10852            0 :     case MG_EV_ACCEPT:
   10853            0 :       tag = "<A";
   10854            0 :       break;
   10855            0 :     case MG_EV_CONNECT:
   10856            0 :       tag = "C>";
   10857            0 :       break;
   10858            0 :     case MG_EV_CLOSE:
   10859            0 :       tag = "XX";
   10860            0 :       break;
   10861              :   }
   10862            0 :   if (tag == NULL) return; /* Don't log MG_EV_TIMER, etc */
   10863              : 
   10864            0 :   if (strcmp(path, "-") == 0) {
   10865            0 :     fp = stdout;
   10866            0 :   } else if (strcmp(path, "--") == 0) {
   10867            0 :     fp = stderr;
   10868              : #if MG_ENABLE_FILESYSTEM
   10869              :   } else {
   10870            0 :     fp = mg_fopen(path, "a");
   10871              : #endif
   10872              :   }
   10873            0 :   if (fp == NULL) return;
   10874              : 
   10875            0 :   mg_conn_addr_to_str(nc, src, sizeof(src),
   10876              :                       MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
   10877            0 :   mg_conn_addr_to_str(nc, dst, sizeof(dst), MG_SOCK_STRINGIFY_IP |
   10878              :                                                 MG_SOCK_STRINGIFY_PORT |
   10879              :                                                 MG_SOCK_STRINGIFY_REMOTE);
   10880            0 :   fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) mg_time(), (void *) nc,
   10881              :           src, tag, dst, (int) num_bytes);
   10882            0 :   if (num_bytes > 0) {
   10883            0 :     mg_hexdumpf(fp, buf, num_bytes);
   10884              :   }
   10885            0 :   if (fp != stdout && fp != stderr) fclose(fp);
   10886              : }
   10887              : #endif
   10888              : 
   10889            0 : int mg_is_big_endian(void) {
   10890              :   static const int n = 1;
   10891              :   /* TODO(mkm) use compiletime check with 4-byte char literal */
   10892            0 :   return ((char *) &n)[0] == 0;
   10893              : }
   10894              : 
   10895            0 : DO_NOT_WARN_UNUSED MG_INTERNAL int mg_get_errno(void) {
   10896              : #ifndef WINCE
   10897            0 :   return errno;
   10898              : #else
   10899              :   /* TODO(alashkin): translate error codes? */
   10900              :   return GetLastError();
   10901              : #endif
   10902              : }
   10903              : 
   10904            0 : void mg_mbuf_append_base64_putc(char ch, void *user_data) {
   10905            0 :   struct mbuf *mbuf = (struct mbuf *) user_data;
   10906            0 :   mbuf_append(mbuf, &ch, sizeof(ch));
   10907            0 : }
   10908              : 
   10909            0 : void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len) {
   10910              :   struct cs_base64_ctx ctx;
   10911            0 :   cs_base64_init(&ctx, mg_mbuf_append_base64_putc, mbuf);
   10912            0 :   cs_base64_update(&ctx, (const char *) data, len);
   10913            0 :   cs_base64_finish(&ctx);
   10914            0 : }
   10915              : 
   10916            0 : void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
   10917              :                           struct mbuf *buf) {
   10918            0 :   const char *header_prefix = "Authorization: Basic ";
   10919            0 :   const char *header_suffix = "\r\n";
   10920              : 
   10921              :   struct cs_base64_ctx ctx;
   10922            0 :   cs_base64_init(&ctx, mg_mbuf_append_base64_putc, buf);
   10923              : 
   10924            0 :   mbuf_append(buf, header_prefix, strlen(header_prefix));
   10925              : 
   10926            0 :   cs_base64_update(&ctx, user.p, user.len);
   10927            0 :   if (pass.len > 0) {
   10928            0 :     cs_base64_update(&ctx, ":", 1);
   10929            0 :     cs_base64_update(&ctx, pass.p, pass.len);
   10930              :   }
   10931            0 :   cs_base64_finish(&ctx);
   10932            0 :   mbuf_append(buf, header_suffix, strlen(header_suffix));
   10933            0 : }
   10934              : 
   10935            0 : struct mg_str mg_url_encode_opt(const struct mg_str src,
   10936              :                                 const struct mg_str safe, unsigned int flags) {
   10937            0 :   const char *hex =
   10938            0 :       (flags & MG_URL_ENCODE_F_UPPERCASE_HEX ? "0123456789ABCDEF"
   10939              :                                              : "0123456789abcdef");
   10940            0 :   size_t i = 0;
   10941              :   struct mbuf mb;
   10942            0 :   mbuf_init(&mb, src.len);
   10943              : 
   10944            0 :   for (i = 0; i < src.len; i++) {
   10945            0 :     const unsigned char c = *((const unsigned char *) src.p + i);
   10946            0 :     if (isalnum(c) || mg_strchr(safe, c) != NULL) {
   10947            0 :       mbuf_append(&mb, &c, 1);
   10948            0 :     } else if (c == ' ' && (flags & MG_URL_ENCODE_F_SPACE_AS_PLUS)) {
   10949            0 :       mbuf_append(&mb, "+", 1);
   10950              :     } else {
   10951            0 :       mbuf_append(&mb, "%", 1);
   10952            0 :       mbuf_append(&mb, &hex[c >> 4], 1);
   10953            0 :       mbuf_append(&mb, &hex[c & 15], 1);
   10954              :     }
   10955              :   }
   10956            0 :   mbuf_append(&mb, "", 1);
   10957            0 :   mbuf_trim(&mb);
   10958            0 :   return mg_mk_str_n(mb.buf, mb.len - 1);
   10959              : }
   10960              : 
   10961            0 : struct mg_str mg_url_encode(const struct mg_str src) {
   10962            0 :   return mg_url_encode_opt(src, mg_mk_str("._-$,;~()/"), 0);
   10963              : }
   10964              : #ifdef MG_MODULE_LINES
   10965              : #line 1 "mongoose/src/mg_mqtt.c"
   10966              : #endif
   10967              : /*
   10968              :  * Copyright (c) 2014 Cesanta Software Limited
   10969              :  * All rights reserved
   10970              :  */
   10971              : 
   10972              : #if MG_ENABLE_MQTT
   10973              : 
   10974              : #include <string.h>
   10975              : 
   10976              : /* Amalgamated: #include "mg_internal.h" */
   10977              : /* Amalgamated: #include "mg_mqtt.h" */
   10978              : 
   10979            0 : static uint16_t getu16(const char *p) {
   10980            0 :   const uint8_t *up = (const uint8_t *) p;
   10981            0 :   return (up[0] << 8) + up[1];
   10982              : }
   10983              : 
   10984            0 : static const char *scanto(const char *p, struct mg_str *s) {
   10985            0 :   s->len = getu16(p);
   10986            0 :   s->p = p + 2;
   10987            0 :   return s->p + s->len;
   10988              : }
   10989              : 
   10990            0 : MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) {
   10991              :   uint8_t header;
   10992            0 :   size_t len = 0, len_len = 0;
   10993            0 :   const char *p, *end, *eop = &io->buf[io->len];
   10994            0 :   unsigned char lc = 0;
   10995              :   int cmd;
   10996              : 
   10997            0 :   if (io->len < 2) return MG_MQTT_ERROR_INCOMPLETE_MSG;
   10998            0 :   header = io->buf[0];
   10999            0 :   cmd = header >> 4;
   11000              : 
   11001              :   /* decode mqtt variable length */
   11002            0 :   len = len_len = 0;
   11003            0 :   p = io->buf + 1;
   11004            0 :   while (p < eop) {
   11005            0 :     lc = *((const unsigned char *) p++);
   11006            0 :     len += (lc & 0x7f) << 7 * len_len;
   11007            0 :     len_len++;
   11008            0 :     if (!(lc & 0x80)) break;
   11009            0 :     if (len_len > 4) return MG_MQTT_ERROR_MALFORMED_MSG;
   11010              :   }
   11011              : 
   11012            0 :   end = p + len;
   11013            0 :   if (lc & 0x80 || end > eop) return MG_MQTT_ERROR_INCOMPLETE_MSG;
   11014              : 
   11015            0 :   mm->cmd = cmd;
   11016            0 :   mm->qos = MG_MQTT_GET_QOS(header);
   11017              : 
   11018            0 :   switch (cmd) {
   11019            0 :     case MG_MQTT_CMD_CONNECT: {
   11020            0 :       p = scanto(p, &mm->protocol_name);
   11021            0 :       if (p > end - 4) return MG_MQTT_ERROR_MALFORMED_MSG;
   11022            0 :       mm->protocol_version = *(uint8_t *) p++;
   11023            0 :       mm->connect_flags = *(uint8_t *) p++;
   11024            0 :       mm->keep_alive_timer = getu16(p);
   11025            0 :       p += 2;
   11026            0 :       if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
   11027            0 :       p = scanto(p, &mm->client_id);
   11028            0 :       if (p > end) return MG_MQTT_ERROR_MALFORMED_MSG;
   11029            0 :       if (mm->connect_flags & MG_MQTT_HAS_WILL) {
   11030            0 :         if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
   11031            0 :         p = scanto(p, &mm->will_topic);
   11032              :       }
   11033            0 :       if (mm->connect_flags & MG_MQTT_HAS_WILL) {
   11034            0 :         if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
   11035            0 :         p = scanto(p, &mm->will_message);
   11036              :       }
   11037            0 :       if (mm->connect_flags & MG_MQTT_HAS_USER_NAME) {
   11038            0 :         if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
   11039            0 :         p = scanto(p, &mm->user_name);
   11040              :       }
   11041            0 :       if (mm->connect_flags & MG_MQTT_HAS_PASSWORD) {
   11042            0 :         if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
   11043            0 :         p = scanto(p, &mm->password);
   11044              :       }
   11045            0 :       if (p != end) return MG_MQTT_ERROR_MALFORMED_MSG;
   11046              : 
   11047            0 :       LOG(LL_DEBUG,
   11048              :           ("%d %2x %d proto [%.*s] client_id [%.*s] will_topic [%.*s] "
   11049              :            "will_msg [%.*s] user_name [%.*s] password [%.*s]",
   11050              :            (int) len, (int) mm->connect_flags, (int) mm->keep_alive_timer,
   11051              :            (int) mm->protocol_name.len, mm->protocol_name.p,
   11052              :            (int) mm->client_id.len, mm->client_id.p, (int) mm->will_topic.len,
   11053              :            mm->will_topic.p, (int) mm->will_message.len, mm->will_message.p,
   11054              :            (int) mm->user_name.len, mm->user_name.p, (int) mm->password.len,
   11055              :            mm->password.p));
   11056            0 :       break;
   11057              :     }
   11058            0 :     case MG_MQTT_CMD_CONNACK:
   11059            0 :       if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
   11060            0 :       mm->connack_ret_code = p[1];
   11061            0 :       break;
   11062            0 :     case MG_MQTT_CMD_PUBACK:
   11063              :     case MG_MQTT_CMD_PUBREC:
   11064              :     case MG_MQTT_CMD_PUBREL:
   11065              :     case MG_MQTT_CMD_PUBCOMP:
   11066              :     case MG_MQTT_CMD_SUBACK:
   11067            0 :       if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
   11068            0 :       mm->message_id = getu16(p);
   11069            0 :       p += 2;
   11070            0 :       break;
   11071            0 :     case MG_MQTT_CMD_PUBLISH: {
   11072            0 :       p = scanto(p, &mm->topic);
   11073            0 :       if (p > end) return MG_MQTT_ERROR_MALFORMED_MSG;
   11074            0 :       if (mm->qos > 0) {
   11075            0 :         if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
   11076            0 :         mm->message_id = getu16(p);
   11077            0 :         p += 2;
   11078              :       }
   11079            0 :       mm->payload.p = p;
   11080            0 :       mm->payload.len = end - p;
   11081            0 :       break;
   11082              :     }
   11083            0 :     case MG_MQTT_CMD_SUBSCRIBE:
   11084            0 :       if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
   11085            0 :       mm->message_id = getu16(p);
   11086            0 :       p += 2;
   11087              :       /*
   11088              :        * topic expressions are left in the payload and can be parsed with
   11089              :        * `mg_mqtt_next_subscribe_topic`
   11090              :        */
   11091            0 :       mm->payload.p = p;
   11092            0 :       mm->payload.len = end - p;
   11093            0 :       break;
   11094            0 :     default:
   11095              :       /* Unhandled command */
   11096            0 :       break;
   11097              :   }
   11098              : 
   11099            0 :   mm->len = end - io->buf;
   11100            0 :   return mm->len;
   11101              : }
   11102              : 
   11103            0 : static void mqtt_handler(struct mg_connection *nc, int ev,
   11104              :                          void *ev_data MG_UD_ARG(void *user_data)) {
   11105            0 :   struct mbuf *io = &nc->recv_mbuf;
   11106              :   struct mg_mqtt_message mm;
   11107            0 :   memset(&mm, 0, sizeof(mm));
   11108              : 
   11109            0 :   nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
   11110              : 
   11111            0 :   switch (ev) {
   11112            0 :     case MG_EV_ACCEPT:
   11113            0 :       if (nc->proto_data == NULL) mg_set_protocol_mqtt(nc);
   11114            0 :       break;
   11115            0 :     case MG_EV_RECV: {
   11116              :       /* There can be multiple messages in the buffer, process them all. */
   11117              :       while (1) {
   11118            0 :         int len = parse_mqtt(io, &mm);
   11119            0 :         if (len < 0) {
   11120            0 :           if (len == MG_MQTT_ERROR_MALFORMED_MSG) {
   11121              :             /* Protocol error. */
   11122            0 :             nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   11123            0 :           } else if (len == MG_MQTT_ERROR_INCOMPLETE_MSG) {
   11124              :             /* Not fully buffered, let's check if we have a chance to get more
   11125              :              * data later */
   11126            0 :             if (nc->recv_mbuf_limit > 0 &&
   11127            0 :                 nc->recv_mbuf.len >= nc->recv_mbuf_limit) {
   11128            0 :               LOG(LL_ERROR, ("%p recv buffer (%lu bytes) exceeds the limit "
   11129              :                              "%lu bytes, and not drained, closing",
   11130              :                              nc, (unsigned long) nc->recv_mbuf.len,
   11131              :                              (unsigned long) nc->recv_mbuf_limit));
   11132            0 :               nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   11133              :             }
   11134              :           } else {
   11135              :             /* Should never be here */
   11136            0 :             LOG(LL_ERROR, ("%p invalid len: %d, closing", nc, len));
   11137            0 :             nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   11138              :           }
   11139            0 :           break;
   11140              :         }
   11141              : 
   11142            0 :         nc->handler(nc, MG_MQTT_EVENT_BASE + mm.cmd, &mm MG_UD_ARG(user_data));
   11143            0 :         mbuf_remove(io, len);
   11144            0 :       }
   11145            0 :       break;
   11146              :     }
   11147            0 :     case MG_EV_POLL: {
   11148            0 :       struct mg_mqtt_proto_data *pd =
   11149              :           (struct mg_mqtt_proto_data *) nc->proto_data;
   11150            0 :       double now = mg_time();
   11151            0 :       if (pd->keep_alive > 0 && pd->last_control_time > 0 &&
   11152            0 :           (now - pd->last_control_time) > pd->keep_alive) {
   11153            0 :         LOG(LL_DEBUG, ("Send PINGREQ"));
   11154            0 :         mg_mqtt_ping(nc);
   11155              :       }
   11156            0 :       break;
   11157              :     }
   11158              :   }
   11159            0 : }
   11160              : 
   11161            0 : static void mg_mqtt_proto_data_destructor(void *proto_data) {
   11162            0 :   MG_FREE(proto_data);
   11163            0 : }
   11164              : 
   11165            0 : static struct mg_str mg_mqtt_next_topic_component(struct mg_str *topic) {
   11166            0 :   struct mg_str res = *topic;
   11167            0 :   const char *c = mg_strchr(*topic, '/');
   11168            0 :   if (c != NULL) {
   11169            0 :     res.len = (c - topic->p);
   11170            0 :     topic->len -= (res.len + 1);
   11171            0 :     topic->p += (res.len + 1);
   11172              :   } else {
   11173            0 :     topic->len = 0;
   11174              :   }
   11175            0 :   return res;
   11176              : }
   11177              : 
   11178              : /* Refernce: https://mosquitto.org/man/mqtt-7.html */
   11179            0 : int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic) {
   11180              :   struct mg_str ec, tc;
   11181            0 :   if (exp.len == 0) return 0;
   11182              :   while (1) {
   11183            0 :     ec = mg_mqtt_next_topic_component(&exp);
   11184            0 :     tc = mg_mqtt_next_topic_component(&topic);
   11185            0 :     if (ec.len == 0) {
   11186            0 :       if (tc.len != 0) return 0;
   11187            0 :       if (exp.len == 0) break;
   11188            0 :       continue;
   11189              :     }
   11190            0 :     if (mg_vcmp(&ec, "+") == 0) {
   11191            0 :       if (tc.len == 0 && topic.len == 0) return 0;
   11192            0 :       continue;
   11193              :     }
   11194            0 :     if (mg_vcmp(&ec, "#") == 0) {
   11195              :       /* Must be the last component in the expression or it's invalid. */
   11196            0 :       return (exp.len == 0);
   11197              :     }
   11198            0 :     if (mg_strcmp(ec, tc) != 0) {
   11199            0 :       return 0;
   11200              :     }
   11201              :   }
   11202            0 :   return (tc.len == 0 && topic.len == 0);
   11203              : }
   11204              : 
   11205            0 : int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic) {
   11206            0 :   return mg_mqtt_match_topic_expression(mg_mk_str(exp), topic);
   11207              : }
   11208              : 
   11209            0 : void mg_set_protocol_mqtt(struct mg_connection *nc) {
   11210            0 :   nc->proto_handler = mqtt_handler;
   11211            0 :   nc->proto_data = MG_CALLOC(1, sizeof(struct mg_mqtt_proto_data));
   11212            0 :   nc->proto_data_destructor = mg_mqtt_proto_data_destructor;
   11213            0 : }
   11214              : 
   11215            0 : static void mg_send_mqtt_header(struct mg_connection *nc, uint8_t cmd,
   11216              :                                 uint8_t flags, size_t len) {
   11217            0 :   struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data;
   11218              :   uint8_t buf[1 + sizeof(size_t)];
   11219            0 :   uint8_t *vlen = &buf[1];
   11220              : 
   11221            0 :   buf[0] = (cmd << 4) | flags;
   11222              : 
   11223              :   /* mqtt variable length encoding */
   11224              :   do {
   11225            0 :     *vlen = len % 0x80;
   11226            0 :     len /= 0x80;
   11227            0 :     if (len > 0) *vlen |= 0x80;
   11228            0 :     vlen++;
   11229            0 :   } while (len > 0);
   11230              : 
   11231            0 :   mg_send(nc, buf, vlen - buf);
   11232            0 :   pd->last_control_time = mg_time();
   11233            0 : }
   11234              : 
   11235            0 : void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id) {
   11236              :   static struct mg_send_mqtt_handshake_opts opts;
   11237            0 :   mg_send_mqtt_handshake_opt(nc, client_id, opts);
   11238            0 : }
   11239              : 
   11240            0 : void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id,
   11241              :                                 struct mg_send_mqtt_handshake_opts opts) {
   11242            0 :   struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data;
   11243            0 :   uint16_t id_len = 0, wt_len = 0, wm_len = 0, user_len = 0, pw_len = 0;
   11244              :   uint16_t netbytes;
   11245              :   size_t total_len;
   11246              : 
   11247            0 :   if (client_id != NULL) {
   11248            0 :     id_len = strlen(client_id);
   11249              :   }
   11250              : 
   11251            0 :   total_len = 7 + 1 + 2 + 2 + id_len;
   11252              : 
   11253            0 :   if (opts.user_name != NULL) {
   11254            0 :     opts.flags |= MG_MQTT_HAS_USER_NAME;
   11255              :   }
   11256            0 :   if (opts.password != NULL) {
   11257            0 :     opts.flags |= MG_MQTT_HAS_PASSWORD;
   11258              :   }
   11259            0 :   if (opts.will_topic != NULL && opts.will_message != NULL) {
   11260            0 :     wt_len = strlen(opts.will_topic);
   11261            0 :     wm_len = strlen(opts.will_message);
   11262            0 :     opts.flags |= MG_MQTT_HAS_WILL;
   11263              :   }
   11264            0 :   if (opts.keep_alive == 0) {
   11265            0 :     opts.keep_alive = 60;
   11266              :   }
   11267              : 
   11268            0 :   if (opts.flags & MG_MQTT_HAS_WILL) {
   11269            0 :     total_len += 2 + wt_len + 2 + wm_len;
   11270              :   }
   11271            0 :   if (opts.flags & MG_MQTT_HAS_USER_NAME) {
   11272            0 :     user_len = strlen(opts.user_name);
   11273            0 :     total_len += 2 + user_len;
   11274              :   }
   11275            0 :   if (opts.flags & MG_MQTT_HAS_PASSWORD) {
   11276            0 :     pw_len = strlen(opts.password);
   11277            0 :     total_len += 2 + pw_len;
   11278              :   }
   11279              : 
   11280            0 :   mg_send_mqtt_header(nc, MG_MQTT_CMD_CONNECT, 0, total_len);
   11281            0 :   mg_send(nc, "\00\04MQTT\04", 7);
   11282            0 :   mg_send(nc, &opts.flags, 1);
   11283              : 
   11284            0 :   netbytes = htons(opts.keep_alive);
   11285            0 :   mg_send(nc, &netbytes, 2);
   11286              : 
   11287            0 :   netbytes = htons(id_len);
   11288            0 :   mg_send(nc, &netbytes, 2);
   11289            0 :   mg_send(nc, client_id, id_len);
   11290              : 
   11291            0 :   if (opts.flags & MG_MQTT_HAS_WILL) {
   11292            0 :     netbytes = htons(wt_len);
   11293            0 :     mg_send(nc, &netbytes, 2);
   11294            0 :     mg_send(nc, opts.will_topic, wt_len);
   11295              : 
   11296            0 :     netbytes = htons(wm_len);
   11297            0 :     mg_send(nc, &netbytes, 2);
   11298            0 :     mg_send(nc, opts.will_message, wm_len);
   11299              :   }
   11300              : 
   11301            0 :   if (opts.flags & MG_MQTT_HAS_USER_NAME) {
   11302            0 :     netbytes = htons(user_len);
   11303            0 :     mg_send(nc, &netbytes, 2);
   11304            0 :     mg_send(nc, opts.user_name, user_len);
   11305              :   }
   11306            0 :   if (opts.flags & MG_MQTT_HAS_PASSWORD) {
   11307            0 :     netbytes = htons(pw_len);
   11308            0 :     mg_send(nc, &netbytes, 2);
   11309            0 :     mg_send(nc, opts.password, pw_len);
   11310              :   }
   11311              : 
   11312            0 :   if (pd != NULL) {
   11313            0 :     pd->keep_alive = opts.keep_alive;
   11314              :   }
   11315            0 : }
   11316              : 
   11317            0 : void mg_mqtt_publish(struct mg_connection *nc, const char *topic,
   11318              :                      uint16_t message_id, int flags, const void *data,
   11319              :                      size_t len) {
   11320              :   uint16_t netbytes;
   11321            0 :   uint16_t topic_len = strlen(topic);
   11322              : 
   11323            0 :   size_t total_len = 2 + topic_len + len;
   11324            0 :   if (MG_MQTT_GET_QOS(flags) > 0) {
   11325            0 :     total_len += 2;
   11326              :   }
   11327              : 
   11328            0 :   mg_send_mqtt_header(nc, MG_MQTT_CMD_PUBLISH, flags, total_len);
   11329              : 
   11330            0 :   netbytes = htons(topic_len);
   11331            0 :   mg_send(nc, &netbytes, 2);
   11332            0 :   mg_send(nc, topic, topic_len);
   11333              : 
   11334            0 :   if (MG_MQTT_GET_QOS(flags) > 0) {
   11335            0 :     netbytes = htons(message_id);
   11336            0 :     mg_send(nc, &netbytes, 2);
   11337              :   }
   11338              : 
   11339            0 :   mg_send(nc, data, len);
   11340            0 : }
   11341              : 
   11342            0 : void mg_mqtt_subscribe(struct mg_connection *nc,
   11343              :                        const struct mg_mqtt_topic_expression *topics,
   11344              :                        size_t topics_len, uint16_t message_id) {
   11345              :   uint16_t netbytes;
   11346              :   size_t i;
   11347              :   uint16_t topic_len;
   11348            0 :   size_t total_len = 2;
   11349              : 
   11350            0 :   for (i = 0; i < topics_len; i++) {
   11351            0 :     total_len += 2 + strlen(topics[i].topic) + 1;
   11352              :   }
   11353              : 
   11354            0 :   mg_send_mqtt_header(nc, MG_MQTT_CMD_SUBSCRIBE, MG_MQTT_QOS(1), total_len);
   11355              : 
   11356            0 :   netbytes = htons(message_id);
   11357            0 :   mg_send(nc, (char *) &netbytes, 2);
   11358              : 
   11359            0 :   for (i = 0; i < topics_len; i++) {
   11360            0 :     topic_len = strlen(topics[i].topic);
   11361            0 :     netbytes = htons(topic_len);
   11362            0 :     mg_send(nc, &netbytes, 2);
   11363            0 :     mg_send(nc, topics[i].topic, topic_len);
   11364            0 :     mg_send(nc, &topics[i].qos, 1);
   11365              :   }
   11366            0 : }
   11367              : 
   11368            0 : int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg,
   11369              :                                  struct mg_str *topic, uint8_t *qos, int pos) {
   11370            0 :   unsigned char *buf = (unsigned char *) msg->payload.p + pos;
   11371              :   int new_pos;
   11372              : 
   11373            0 :   if ((size_t) pos >= msg->payload.len) return -1;
   11374              : 
   11375            0 :   topic->len = buf[0] << 8 | buf[1];
   11376            0 :   topic->p = (char *) buf + 2;
   11377            0 :   new_pos = pos + 2 + topic->len + 1;
   11378            0 :   if ((size_t) new_pos > msg->payload.len) return -1;
   11379            0 :   *qos = buf[2 + topic->len];
   11380            0 :   return new_pos;
   11381              : }
   11382              : 
   11383            0 : void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics,
   11384              :                          size_t topics_len, uint16_t message_id) {
   11385              :   uint16_t netbytes;
   11386              :   size_t i;
   11387              :   uint16_t topic_len;
   11388            0 :   size_t total_len = 2;
   11389              : 
   11390            0 :   for (i = 0; i < topics_len; i++) {
   11391            0 :     total_len += 2 + strlen(topics[i]);
   11392              :   }
   11393              : 
   11394            0 :   mg_send_mqtt_header(nc, MG_MQTT_CMD_UNSUBSCRIBE, MG_MQTT_QOS(1), total_len);
   11395              : 
   11396            0 :   netbytes = htons(message_id);
   11397            0 :   mg_send(nc, (char *) &netbytes, 2);
   11398              : 
   11399            0 :   for (i = 0; i < topics_len; i++) {
   11400            0 :     topic_len = strlen(topics[i]);
   11401            0 :     netbytes = htons(topic_len);
   11402            0 :     mg_send(nc, &netbytes, 2);
   11403            0 :     mg_send(nc, topics[i], topic_len);
   11404              :   }
   11405            0 : }
   11406              : 
   11407            0 : void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code) {
   11408            0 :   uint8_t unused = 0;
   11409            0 :   mg_send_mqtt_header(nc, MG_MQTT_CMD_CONNACK, 0, 2);
   11410            0 :   mg_send(nc, &unused, 1);
   11411            0 :   mg_send(nc, &return_code, 1);
   11412            0 : }
   11413              : 
   11414              : /*
   11415              :  * Sends a command which contains only a `message_id` and a QoS level of 1.
   11416              :  *
   11417              :  * Helper function.
   11418              :  */
   11419            0 : static void mg_send_mqtt_short_command(struct mg_connection *nc, uint8_t cmd,
   11420              :                                        uint16_t message_id) {
   11421              :   uint16_t netbytes;
   11422            0 :   uint8_t flags = (cmd == MG_MQTT_CMD_PUBREL ? 2 : 0);
   11423              : 
   11424            0 :   mg_send_mqtt_header(nc, cmd, flags, 2 /* len */);
   11425              : 
   11426            0 :   netbytes = htons(message_id);
   11427            0 :   mg_send(nc, &netbytes, 2);
   11428            0 : }
   11429              : 
   11430            0 : void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id) {
   11431            0 :   mg_send_mqtt_short_command(nc, MG_MQTT_CMD_PUBACK, message_id);
   11432            0 : }
   11433              : 
   11434            0 : void mg_mqtt_pubrec(struct mg_connection *nc, uint16_t message_id) {
   11435            0 :   mg_send_mqtt_short_command(nc, MG_MQTT_CMD_PUBREC, message_id);
   11436            0 : }
   11437              : 
   11438            0 : void mg_mqtt_pubrel(struct mg_connection *nc, uint16_t message_id) {
   11439            0 :   mg_send_mqtt_short_command(nc, MG_MQTT_CMD_PUBREL, message_id);
   11440            0 : }
   11441              : 
   11442            0 : void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id) {
   11443            0 :   mg_send_mqtt_short_command(nc, MG_MQTT_CMD_PUBCOMP, message_id);
   11444            0 : }
   11445              : 
   11446            0 : void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len,
   11447              :                     uint16_t message_id) {
   11448              :   size_t i;
   11449              :   uint16_t netbytes;
   11450              : 
   11451            0 :   mg_send_mqtt_header(nc, MG_MQTT_CMD_SUBACK, MG_MQTT_QOS(1), 2 + qoss_len);
   11452              : 
   11453            0 :   netbytes = htons(message_id);
   11454            0 :   mg_send(nc, &netbytes, 2);
   11455              : 
   11456            0 :   for (i = 0; i < qoss_len; i++) {
   11457            0 :     mg_send(nc, &qoss[i], 1);
   11458              :   }
   11459            0 : }
   11460              : 
   11461            0 : void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) {
   11462            0 :   mg_send_mqtt_short_command(nc, MG_MQTT_CMD_UNSUBACK, message_id);
   11463            0 : }
   11464              : 
   11465            0 : void mg_mqtt_ping(struct mg_connection *nc) {
   11466            0 :   mg_send_mqtt_header(nc, MG_MQTT_CMD_PINGREQ, 0, 0);
   11467            0 : }
   11468              : 
   11469            0 : void mg_mqtt_pong(struct mg_connection *nc) {
   11470            0 :   mg_send_mqtt_header(nc, MG_MQTT_CMD_PINGRESP, 0, 0);
   11471            0 : }
   11472              : 
   11473            0 : void mg_mqtt_disconnect(struct mg_connection *nc) {
   11474            0 :   mg_send_mqtt_header(nc, MG_MQTT_CMD_DISCONNECT, 0, 0);
   11475            0 : }
   11476              : 
   11477              : #endif /* MG_ENABLE_MQTT */
   11478              : #ifdef MG_MODULE_LINES
   11479              : #line 1 "mongoose/src/mg_mqtt_server.c"
   11480              : #endif
   11481              : /*
   11482              :  * Copyright (c) 2014 Cesanta Software Limited
   11483              :  * All rights reserved
   11484              :  */
   11485              : 
   11486              : /* Amalgamated: #include "mg_internal.h" */
   11487              : /* Amalgamated: #include "mg_mqtt_server.h" */
   11488              : 
   11489              : #if MG_ENABLE_MQTT_BROKER
   11490              : 
   11491              : static void mg_mqtt_session_init(struct mg_mqtt_broker *brk,
   11492              :                                  struct mg_mqtt_session *s,
   11493              :                                  struct mg_connection *nc) {
   11494              :   s->brk = brk;
   11495              :   s->subscriptions = NULL;
   11496              :   s->num_subscriptions = 0;
   11497              :   s->nc = nc;
   11498              : }
   11499              : 
   11500              : static void mg_mqtt_add_session(struct mg_mqtt_session *s) {
   11501              :   LIST_INSERT_HEAD(&s->brk->sessions, s, link);
   11502              : }
   11503              : 
   11504              : static void mg_mqtt_remove_session(struct mg_mqtt_session *s) {
   11505              :   LIST_REMOVE(s, link);
   11506              : }
   11507              : 
   11508              : static void mg_mqtt_destroy_session(struct mg_mqtt_session *s) {
   11509              :   size_t i;
   11510              :   for (i = 0; i < s->num_subscriptions; i++) {
   11511              :     MG_FREE((void *) s->subscriptions[i].topic);
   11512              :   }
   11513              :   MG_FREE(s->subscriptions);
   11514              :   MG_FREE(s);
   11515              : }
   11516              : 
   11517              : static void mg_mqtt_close_session(struct mg_mqtt_session *s) {
   11518              :   mg_mqtt_remove_session(s);
   11519              :   mg_mqtt_destroy_session(s);
   11520              : }
   11521              : 
   11522              : void mg_mqtt_broker_init(struct mg_mqtt_broker *brk, void *user_data) {
   11523              :   LIST_INIT(&brk->sessions);
   11524              :   brk->user_data = user_data;
   11525              : }
   11526              : 
   11527              : static void mg_mqtt_broker_handle_connect(struct mg_mqtt_broker *brk,
   11528              :                                           struct mg_connection *nc) {
   11529              :   struct mg_mqtt_session *s =
   11530              :       (struct mg_mqtt_session *) MG_CALLOC(1, sizeof *s);
   11531              :   if (s == NULL) {
   11532              :     /* LCOV_EXCL_START */
   11533              :     mg_mqtt_connack(nc, MG_EV_MQTT_CONNACK_SERVER_UNAVAILABLE);
   11534              :     return;
   11535              :     /* LCOV_EXCL_STOP */
   11536              :   }
   11537              : 
   11538              :   /* TODO(mkm): check header (magic and version) */
   11539              : 
   11540              :   mg_mqtt_session_init(brk, s, nc);
   11541              :   nc->priv_2 = s;
   11542              :   mg_mqtt_add_session(s);
   11543              : 
   11544              :   mg_mqtt_connack(nc, MG_EV_MQTT_CONNACK_ACCEPTED);
   11545              : }
   11546              : 
   11547              : static void mg_mqtt_broker_handle_subscribe(struct mg_connection *nc,
   11548              :                                             struct mg_mqtt_message *msg) {
   11549              :   struct mg_mqtt_session *ss = (struct mg_mqtt_session *) nc->priv_2;
   11550              :   uint8_t qoss[MG_MQTT_MAX_SESSION_SUBSCRIPTIONS];
   11551              :   size_t num_subs = 0;
   11552              :   struct mg_str topic;
   11553              :   uint8_t qos;
   11554              :   int pos;
   11555              :   struct mg_mqtt_topic_expression *te;
   11556              : 
   11557              :   for (pos = 0;
   11558              :        (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1;) {
   11559              :     if (num_subs >= sizeof(MG_MQTT_MAX_SESSION_SUBSCRIPTIONS) ||
   11560              :         (ss->num_subscriptions + num_subs >=
   11561              :          MG_MQTT_MAX_SESSION_SUBSCRIPTIONS)) {
   11562              :       nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   11563              :       return;
   11564              :     }
   11565              :     qoss[num_subs++] = qos;
   11566              :   }
   11567              : 
   11568              :   if (num_subs > 0) {
   11569              :     te = (struct mg_mqtt_topic_expression *) MG_REALLOC(
   11570              :         ss->subscriptions,
   11571              :         sizeof(*ss->subscriptions) * (ss->num_subscriptions + num_subs));
   11572              :     if (te == NULL) {
   11573              :       nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   11574              :       return;
   11575              :     }
   11576              :     ss->subscriptions = te;
   11577              :     for (pos = 0;
   11578              :          pos < (int) msg->payload.len &&
   11579              :              (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1;
   11580              :          ss->num_subscriptions++) {
   11581              :       te = &ss->subscriptions[ss->num_subscriptions];
   11582              :       te->topic = (char *) MG_MALLOC(topic.len + 1);
   11583              :       te->qos = qos;
   11584              :       memcpy((char *) te->topic, topic.p, topic.len);
   11585              :       ((char *) te->topic)[topic.len] = '\0';
   11586              :     }
   11587              :   }
   11588              : 
   11589              :   if (pos == (int) msg->payload.len) {
   11590              :     mg_mqtt_suback(nc, qoss, num_subs, msg->message_id);
   11591              :   } else {
   11592              :     /* We did not fully parse the payload, something must be wrong. */
   11593              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   11594              :   }
   11595              : }
   11596              : 
   11597              : static void mg_mqtt_broker_handle_publish(struct mg_mqtt_broker *brk,
   11598              :                                           struct mg_mqtt_message *msg) {
   11599              :   struct mg_mqtt_session *s;
   11600              :   size_t i;
   11601              : 
   11602              :   for (s = mg_mqtt_next(brk, NULL); s != NULL; s = mg_mqtt_next(brk, s)) {
   11603              :     for (i = 0; i < s->num_subscriptions; i++) {
   11604              :       if (mg_mqtt_vmatch_topic_expression(s->subscriptions[i].topic,
   11605              :                                           msg->topic)) {
   11606              :         char buf[100], *p = buf;
   11607              :         mg_asprintf(&p, sizeof(buf), "%.*s", (int) msg->topic.len,
   11608              :                     msg->topic.p);
   11609              :         if (p == NULL) {
   11610              :           return;
   11611              :         }
   11612              :         mg_mqtt_publish(s->nc, p, 0, 0, msg->payload.p, msg->payload.len);
   11613              :         if (p != buf) {
   11614              :           MG_FREE(p);
   11615              :         }
   11616              :         break;
   11617              :       }
   11618              :     }
   11619              :   }
   11620              : }
   11621              : 
   11622              : void mg_mqtt_broker(struct mg_connection *nc, int ev, void *data) {
   11623              :   struct mg_mqtt_message *msg = (struct mg_mqtt_message *) data;
   11624              :   struct mg_mqtt_broker *brk;
   11625              : 
   11626              :   if (nc->listener) {
   11627              :     brk = (struct mg_mqtt_broker *) nc->listener->priv_2;
   11628              :   } else {
   11629              :     brk = (struct mg_mqtt_broker *) nc->priv_2;
   11630              :   }
   11631              : 
   11632              :   switch (ev) {
   11633              :     case MG_EV_ACCEPT:
   11634              :       if (nc->proto_data == NULL) mg_set_protocol_mqtt(nc);
   11635              :       nc->priv_2 = NULL; /* Clear up the inherited pointer to broker */
   11636              :       break;
   11637              :     case MG_EV_MQTT_CONNECT:
   11638              :       if (nc->priv_2 == NULL) {
   11639              :         mg_mqtt_broker_handle_connect(brk, nc);
   11640              :       } else {
   11641              :         /* Repeated CONNECT */
   11642              :         nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   11643              :       }
   11644              :       break;
   11645              :     case MG_EV_MQTT_SUBSCRIBE:
   11646              :       if (nc->priv_2 != NULL) {
   11647              :         mg_mqtt_broker_handle_subscribe(nc, msg);
   11648              :       } else {
   11649              :         /* Subscribe before CONNECT */
   11650              :         nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   11651              :       }
   11652              :       break;
   11653              :     case MG_EV_MQTT_PUBLISH:
   11654              :       if (nc->priv_2 != NULL) {
   11655              :         mg_mqtt_broker_handle_publish(brk, msg);
   11656              :       } else {
   11657              :         /* Publish before CONNECT */
   11658              :         nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   11659              :       }
   11660              :       break;
   11661              :     case MG_EV_CLOSE:
   11662              :       if (nc->listener && nc->priv_2 != NULL) {
   11663              :         mg_mqtt_close_session((struct mg_mqtt_session *) nc->priv_2);
   11664              :       }
   11665              :       break;
   11666              :   }
   11667              : }
   11668              : 
   11669              : struct mg_mqtt_session *mg_mqtt_next(struct mg_mqtt_broker *brk,
   11670              :                                      struct mg_mqtt_session *s) {
   11671              :   return s == NULL ? LIST_FIRST(&brk->sessions) : LIST_NEXT(s, link);
   11672              : }
   11673              : 
   11674              : #endif /* MG_ENABLE_MQTT_BROKER */
   11675              : #ifdef MG_MODULE_LINES
   11676              : #line 1 "mongoose/src/mg_dns.c"
   11677              : #endif
   11678              : /*
   11679              :  * Copyright (c) 2014 Cesanta Software Limited
   11680              :  * All rights reserved
   11681              :  */
   11682              : 
   11683              : #if MG_ENABLE_DNS
   11684              : 
   11685              : /* Amalgamated: #include "mg_internal.h" */
   11686              : /* Amalgamated: #include "mg_dns.h" */
   11687              : 
   11688              : static int mg_dns_tid = 0xa0;
   11689              : 
   11690              : struct mg_dns_header {
   11691              :   uint16_t transaction_id;
   11692              :   uint16_t flags;
   11693              :   uint16_t num_questions;
   11694              :   uint16_t num_answers;
   11695              :   uint16_t num_authority_prs;
   11696              :   uint16_t num_other_prs;
   11697              : };
   11698              : 
   11699            0 : struct mg_dns_resource_record *mg_dns_next_record(
   11700              :     struct mg_dns_message *msg, int query,
   11701              :     struct mg_dns_resource_record *prev) {
   11702              :   struct mg_dns_resource_record *rr;
   11703              : 
   11704            0 :   for (rr = (prev == NULL ? msg->answers : prev + 1);
   11705            0 :        rr - msg->answers < msg->num_answers; rr++) {
   11706            0 :     if (rr->rtype == query) {
   11707            0 :       return rr;
   11708              :     }
   11709              :   }
   11710            0 :   return NULL;
   11711              : }
   11712              : 
   11713            0 : int mg_dns_parse_record_data(struct mg_dns_message *msg,
   11714              :                              struct mg_dns_resource_record *rr, void *data,
   11715              :                              size_t data_len) {
   11716            0 :   switch (rr->rtype) {
   11717            0 :     case MG_DNS_A_RECORD:
   11718            0 :       if (data_len < sizeof(struct in_addr)) {
   11719            0 :         return -1;
   11720              :       }
   11721            0 :       if (rr->rdata.p + data_len > msg->pkt.p + msg->pkt.len) {
   11722            0 :         return -1;
   11723              :       }
   11724            0 :       memcpy(data, rr->rdata.p, data_len);
   11725            0 :       return 0;
   11726              : #if MG_ENABLE_IPV6
   11727            0 :     case MG_DNS_AAAA_RECORD:
   11728            0 :       if (data_len < sizeof(struct in6_addr)) {
   11729              :         return -1; /* LCOV_EXCL_LINE */
   11730              :       }
   11731            0 :       memcpy(data, rr->rdata.p, data_len);
   11732            0 :       return 0;
   11733              : #endif
   11734            0 :     case MG_DNS_CNAME_RECORD:
   11735            0 :       mg_dns_uncompress_name(msg, &rr->rdata, (char *) data, data_len);
   11736            0 :       return 0;
   11737              :   }
   11738              : 
   11739            0 :   return -1;
   11740              : }
   11741              : 
   11742            0 : int mg_dns_insert_header(struct mbuf *io, size_t pos,
   11743              :                          struct mg_dns_message *msg) {
   11744              :   struct mg_dns_header header;
   11745              : 
   11746            0 :   memset(&header, 0, sizeof(header));
   11747            0 :   header.transaction_id = msg->transaction_id;
   11748            0 :   header.flags = htons(msg->flags);
   11749            0 :   header.num_questions = htons(msg->num_questions);
   11750            0 :   header.num_answers = htons(msg->num_answers);
   11751              : 
   11752            0 :   return mbuf_insert(io, pos, &header, sizeof(header));
   11753              : }
   11754              : 
   11755            0 : int mg_dns_copy_questions(struct mbuf *io, struct mg_dns_message *msg) {
   11756              :   unsigned char *begin, *end;
   11757              :   struct mg_dns_resource_record *last_q;
   11758            0 :   if (msg->num_questions <= 0) return 0;
   11759            0 :   begin = (unsigned char *) msg->pkt.p + sizeof(struct mg_dns_header);
   11760            0 :   last_q = &msg->questions[msg->num_questions - 1];
   11761            0 :   end = (unsigned char *) last_q->name.p + last_q->name.len + 4;
   11762            0 :   return mbuf_append(io, begin, end - begin);
   11763              : }
   11764              : 
   11765            0 : int mg_dns_encode_name(struct mbuf *io, const char *name, size_t len) {
   11766              :   const char *s;
   11767              :   unsigned char n;
   11768            0 :   size_t pos = io->len;
   11769              : 
   11770              :   do {
   11771            0 :     if ((s = strchr(name, '.')) == NULL) {
   11772            0 :       s = name + len;
   11773              :     }
   11774              : 
   11775            0 :     if (s - name > 127) {
   11776            0 :       return -1; /* TODO(mkm) cover */
   11777              :     }
   11778            0 :     n = s - name;           /* chunk length */
   11779            0 :     mbuf_append(io, &n, 1); /* send length */
   11780            0 :     mbuf_append(io, name, n);
   11781              : 
   11782            0 :     if (*s == '.') {
   11783            0 :       n++;
   11784              :     }
   11785              : 
   11786            0 :     name += n;
   11787            0 :     len -= n;
   11788            0 :   } while (*s != '\0');
   11789            0 :   mbuf_append(io, "\0", 1); /* Mark end of host name */
   11790              : 
   11791            0 :   return io->len - pos;
   11792              : }
   11793              : 
   11794            0 : int mg_dns_encode_record(struct mbuf *io, struct mg_dns_resource_record *rr,
   11795              :                          const char *name, size_t nlen, const void *rdata,
   11796              :                          size_t rlen) {
   11797            0 :   size_t pos = io->len;
   11798              :   uint16_t u16;
   11799              :   uint32_t u32;
   11800              : 
   11801            0 :   if (rr->kind == MG_DNS_INVALID_RECORD) {
   11802              :     return -1; /* LCOV_EXCL_LINE */
   11803              :   }
   11804              : 
   11805            0 :   if (mg_dns_encode_name(io, name, nlen) == -1) {
   11806            0 :     return -1;
   11807              :   }
   11808              : 
   11809            0 :   u16 = htons(rr->rtype);
   11810            0 :   mbuf_append(io, &u16, 2);
   11811            0 :   u16 = htons(rr->rclass);
   11812            0 :   mbuf_append(io, &u16, 2);
   11813              : 
   11814            0 :   if (rr->kind == MG_DNS_ANSWER) {
   11815            0 :     u32 = htonl(rr->ttl);
   11816            0 :     mbuf_append(io, &u32, 4);
   11817              : 
   11818            0 :     if (rr->rtype == MG_DNS_CNAME_RECORD) {
   11819              :       int clen;
   11820              :       /* fill size after encoding */
   11821            0 :       size_t off = io->len;
   11822            0 :       mbuf_append(io, &u16, 2);
   11823            0 :       if ((clen = mg_dns_encode_name(io, (const char *) rdata, rlen)) == -1) {
   11824            0 :         return -1;
   11825              :       }
   11826            0 :       u16 = clen;
   11827            0 :       io->buf[off] = u16 >> 8;
   11828            0 :       io->buf[off + 1] = u16 & 0xff;
   11829              :     } else {
   11830            0 :       u16 = htons((uint16_t) rlen);
   11831            0 :       mbuf_append(io, &u16, 2);
   11832            0 :       mbuf_append(io, rdata, rlen);
   11833              :     }
   11834              :   }
   11835              : 
   11836            0 :   return io->len - pos;
   11837              : }
   11838              : 
   11839            0 : void mg_send_dns_query(struct mg_connection *nc, const char *name,
   11840              :                        int query_type) {
   11841              :   struct mg_dns_message *msg =
   11842            0 :       (struct mg_dns_message *) MG_CALLOC(1, sizeof(*msg));
   11843              :   struct mbuf pkt;
   11844            0 :   struct mg_dns_resource_record *rr = &msg->questions[0];
   11845              : 
   11846            0 :   DBG(("%s %d", name, query_type));
   11847              : 
   11848            0 :   mbuf_init(&pkt, 64 /* Start small, it'll grow as needed. */);
   11849              : 
   11850            0 :   msg->transaction_id = ++mg_dns_tid;
   11851            0 :   msg->flags = 0x100;
   11852            0 :   msg->num_questions = 1;
   11853              : 
   11854            0 :   mg_dns_insert_header(&pkt, 0, msg);
   11855              : 
   11856            0 :   rr->rtype = query_type;
   11857            0 :   rr->rclass = 1; /* Class: inet */
   11858            0 :   rr->kind = MG_DNS_QUESTION;
   11859              : 
   11860            0 :   if (mg_dns_encode_record(&pkt, rr, name, strlen(name), NULL, 0) == -1) {
   11861              :     /* TODO(mkm): return an error code */
   11862              :     goto cleanup; /* LCOV_EXCL_LINE */
   11863              :   }
   11864              : 
   11865              :   /* TCP DNS requires messages to be prefixed with len */
   11866            0 :   if (!(nc->flags & MG_F_UDP)) {
   11867            0 :     uint16_t len = htons((uint16_t) pkt.len);
   11868            0 :     mbuf_insert(&pkt, 0, &len, 2);
   11869              :   }
   11870              : 
   11871            0 :   mg_send(nc, pkt.buf, pkt.len);
   11872            0 :   mbuf_free(&pkt);
   11873              : 
   11874            0 : cleanup:
   11875            0 :   MG_FREE(msg);
   11876            0 : }
   11877              : 
   11878            0 : static unsigned char *mg_parse_dns_resource_record(
   11879              :     unsigned char *data, unsigned char *end, struct mg_dns_resource_record *rr,
   11880              :     int reply) {
   11881            0 :   unsigned char *name = data;
   11882              :   int chunk_len, data_len;
   11883              : 
   11884            0 :   while (data < end && (chunk_len = *data)) {
   11885            0 :     if (((unsigned char *) data)[0] & 0xc0) {
   11886            0 :       data += 1;
   11887            0 :       break;
   11888              :     }
   11889            0 :     data += chunk_len + 1;
   11890              :   }
   11891              : 
   11892            0 :   if (data > end - 5) {
   11893            0 :     return NULL;
   11894              :   }
   11895              : 
   11896            0 :   rr->name.p = (char *) name;
   11897            0 :   rr->name.len = data - name + 1;
   11898            0 :   data++;
   11899              : 
   11900            0 :   rr->rtype = data[0] << 8 | data[1];
   11901            0 :   data += 2;
   11902              : 
   11903            0 :   rr->rclass = data[0] << 8 | data[1];
   11904            0 :   data += 2;
   11905              : 
   11906            0 :   rr->kind = reply ? MG_DNS_ANSWER : MG_DNS_QUESTION;
   11907            0 :   if (reply) {
   11908            0 :     if (data >= end - 6) {
   11909            0 :       return NULL;
   11910              :     }
   11911              : 
   11912            0 :     rr->ttl = (uint32_t) data[0] << 24 | (uint32_t) data[1] << 16 |
   11913            0 :               data[2] << 8 | data[3];
   11914            0 :     data += 4;
   11915              : 
   11916            0 :     data_len = *data << 8 | *(data + 1);
   11917            0 :     data += 2;
   11918              : 
   11919            0 :     rr->rdata.p = (char *) data;
   11920            0 :     rr->rdata.len = data_len;
   11921            0 :     data += data_len;
   11922              :   }
   11923            0 :   return data;
   11924              : }
   11925              : 
   11926            0 : int mg_parse_dns(const char *buf, int len, struct mg_dns_message *msg) {
   11927            0 :   struct mg_dns_header *header = (struct mg_dns_header *) buf;
   11928            0 :   unsigned char *data = (unsigned char *) buf + sizeof(*header);
   11929            0 :   unsigned char *end = (unsigned char *) buf + len;
   11930              :   int i;
   11931              : 
   11932            0 :   memset(msg, 0, sizeof(*msg));
   11933            0 :   msg->pkt.p = buf;
   11934            0 :   msg->pkt.len = len;
   11935              : 
   11936            0 :   if (len < (int) sizeof(*header)) return -1;
   11937              : 
   11938            0 :   msg->transaction_id = header->transaction_id;
   11939            0 :   msg->flags = ntohs(header->flags);
   11940            0 :   msg->num_questions = ntohs(header->num_questions);
   11941            0 :   if (msg->num_questions > (int) ARRAY_SIZE(msg->questions)) {
   11942            0 :     msg->num_questions = (int) ARRAY_SIZE(msg->questions);
   11943              :   }
   11944            0 :   msg->num_answers = ntohs(header->num_answers);
   11945            0 :   if (msg->num_answers > (int) ARRAY_SIZE(msg->answers)) {
   11946            0 :     msg->num_answers = (int) ARRAY_SIZE(msg->answers);
   11947              :   }
   11948              : 
   11949            0 :   for (i = 0; i < msg->num_questions; i++) {
   11950            0 :     data = mg_parse_dns_resource_record(data, end, &msg->questions[i], 0);
   11951            0 :     if (data == NULL) return -1;
   11952              :   }
   11953              : 
   11954            0 :   for (i = 0; i < msg->num_answers; i++) {
   11955            0 :     data = mg_parse_dns_resource_record(data, end, &msg->answers[i], 1);
   11956            0 :     if (data == NULL) return -1;
   11957              :   }
   11958              : 
   11959            0 :   return 0;
   11960              : }
   11961              : 
   11962            0 : size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name,
   11963              :                               char *dst, int dst_len) {
   11964            0 :   int chunk_len, num_ptrs = 0;
   11965            0 :   char *old_dst = dst;
   11966            0 :   const unsigned char *data = (unsigned char *) name->p;
   11967            0 :   const unsigned char *end = (unsigned char *) msg->pkt.p + msg->pkt.len;
   11968              : 
   11969            0 :   if (data >= end) {
   11970            0 :     return 0;
   11971              :   }
   11972              : 
   11973            0 :   while ((chunk_len = *data++)) {
   11974            0 :     int leeway = dst_len - (dst - old_dst);
   11975            0 :     if (data >= end) {
   11976            0 :       return 0;
   11977              :     }
   11978              : 
   11979            0 :     if ((chunk_len & 0xc0) == 0xc0) {
   11980            0 :       uint16_t off = (data[-1] & (~0xc0)) << 8 | data[0];
   11981            0 :       if (off >= msg->pkt.len) {
   11982            0 :         return 0;
   11983              :       }
   11984              :       /* Basic circular loop avoidance: allow up to 16 pointer hops. */
   11985            0 :       if (++num_ptrs > 15) {
   11986            0 :         return 0;
   11987              :       }
   11988            0 :       data = (unsigned char *) msg->pkt.p + off;
   11989            0 :       continue;
   11990            0 :     }
   11991            0 :     if (chunk_len > 63) {
   11992            0 :       return 0;
   11993              :     }
   11994            0 :     if (chunk_len > leeway) {
   11995            0 :       chunk_len = leeway;
   11996              :     }
   11997              : 
   11998            0 :     if (data + chunk_len >= end) {
   11999            0 :       return 0;
   12000              :     }
   12001              : 
   12002            0 :     memcpy(dst, data, chunk_len);
   12003            0 :     data += chunk_len;
   12004            0 :     dst += chunk_len;
   12005            0 :     leeway -= chunk_len;
   12006            0 :     if (leeway == 0) {
   12007            0 :       return dst - old_dst;
   12008              :     }
   12009            0 :     *dst++ = '.';
   12010              :   }
   12011              : 
   12012            0 :   if (dst != old_dst) {
   12013            0 :     *--dst = 0;
   12014              :   }
   12015            0 :   return dst - old_dst;
   12016              : }
   12017              : 
   12018            0 : static void dns_handler(struct mg_connection *nc, int ev,
   12019              :                         void *ev_data MG_UD_ARG(void *user_data)) {
   12020            0 :   struct mbuf *io = &nc->recv_mbuf;
   12021              :   struct mg_dns_message msg;
   12022              : 
   12023              :   /* Pass low-level events to the user handler */
   12024            0 :   nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
   12025              : 
   12026            0 :   switch (ev) {
   12027            0 :     case MG_EV_RECV:
   12028            0 :       if (!(nc->flags & MG_F_UDP)) {
   12029            0 :         mbuf_remove(&nc->recv_mbuf, 2);
   12030              :       }
   12031            0 :       if (mg_parse_dns(nc->recv_mbuf.buf, nc->recv_mbuf.len, &msg) == -1) {
   12032              :         /* reply + recursion allowed + format error */
   12033            0 :         memset(&msg, 0, sizeof(msg));
   12034            0 :         msg.flags = 0x8081;
   12035            0 :         mg_dns_insert_header(io, 0, &msg);
   12036            0 :         if (!(nc->flags & MG_F_UDP)) {
   12037            0 :           uint16_t len = htons((uint16_t) io->len);
   12038            0 :           mbuf_insert(io, 0, &len, 2);
   12039              :         }
   12040            0 :         mg_send(nc, io->buf, io->len);
   12041              :       } else {
   12042              :         /* Call user handler with parsed message */
   12043            0 :         nc->handler(nc, MG_DNS_MESSAGE, &msg MG_UD_ARG(user_data));
   12044              :       }
   12045            0 :       mbuf_remove(io, io->len);
   12046            0 :       break;
   12047              :   }
   12048            0 : }
   12049              : 
   12050            0 : void mg_set_protocol_dns(struct mg_connection *nc) {
   12051            0 :   nc->proto_handler = dns_handler;
   12052            0 : }
   12053              : 
   12054              : #endif /* MG_ENABLE_DNS */
   12055              : #ifdef MG_MODULE_LINES
   12056              : #line 1 "mongoose/src/mg_dns_server.c"
   12057              : #endif
   12058              : /*
   12059              :  * Copyright (c) 2014 Cesanta Software Limited
   12060              :  * All rights reserved
   12061              :  */
   12062              : 
   12063              : #if MG_ENABLE_DNS_SERVER
   12064              : 
   12065              : /* Amalgamated: #include "mg_internal.h" */
   12066              : /* Amalgamated: #include "dns-server.h" */
   12067              : 
   12068              : struct mg_dns_reply mg_dns_create_reply(struct mbuf *io,
   12069              :                                         struct mg_dns_message *msg) {
   12070              :   struct mg_dns_reply rep;
   12071              :   rep.msg = msg;
   12072              :   rep.io = io;
   12073              :   rep.start = io->len;
   12074              : 
   12075              :   /* reply + recursion allowed */
   12076              :   msg->flags |= 0x8080;
   12077              :   mg_dns_copy_questions(io, msg);
   12078              : 
   12079              :   msg->num_answers = 0;
   12080              :   return rep;
   12081              : }
   12082              : 
   12083              : void mg_dns_send_reply(struct mg_connection *nc, struct mg_dns_reply *r) {
   12084              :   size_t sent = r->io->len - r->start;
   12085              :   mg_dns_insert_header(r->io, r->start, r->msg);
   12086              :   if (!(nc->flags & MG_F_UDP)) {
   12087              :     uint16_t len = htons((uint16_t) sent);
   12088              :     mbuf_insert(r->io, r->start, &len, 2);
   12089              :   }
   12090              : 
   12091              :   if (&nc->send_mbuf != r->io) {
   12092              :     mg_send(nc, r->io->buf + r->start, r->io->len - r->start);
   12093              :     r->io->len = r->start;
   12094              :   }
   12095              : }
   12096              : 
   12097              : int mg_dns_reply_record(struct mg_dns_reply *reply,
   12098              :                         struct mg_dns_resource_record *question,
   12099              :                         const char *name, int rtype, int ttl, const void *rdata,
   12100              :                         size_t rdata_len) {
   12101              :   struct mg_dns_message *msg = (struct mg_dns_message *) reply->msg;
   12102              :   char rname[512];
   12103              :   struct mg_dns_resource_record *ans = &msg->answers[msg->num_answers];
   12104              :   if (msg->num_answers >= MG_MAX_DNS_ANSWERS) {
   12105              :     return -1; /* LCOV_EXCL_LINE */
   12106              :   }
   12107              : 
   12108              :   if (name == NULL) {
   12109              :     name = rname;
   12110              :     rname[511] = 0;
   12111              :     mg_dns_uncompress_name(msg, &question->name, rname, sizeof(rname) - 1);
   12112              :   }
   12113              : 
   12114              :   *ans = *question;
   12115              :   ans->kind = MG_DNS_ANSWER;
   12116              :   ans->rtype = rtype;
   12117              :   ans->ttl = ttl;
   12118              : 
   12119              :   if (mg_dns_encode_record(reply->io, ans, name, strlen(name), rdata,
   12120              :                            rdata_len) == -1) {
   12121              :     return -1; /* LCOV_EXCL_LINE */
   12122              :   };
   12123              : 
   12124              :   msg->num_answers++;
   12125              :   return 0;
   12126              : }
   12127              : 
   12128              : #endif /* MG_ENABLE_DNS_SERVER */
   12129              : #ifdef MG_MODULE_LINES
   12130              : #line 1 "mongoose/src/mg_resolv.c"
   12131              : #endif
   12132              : /*
   12133              :  * Copyright (c) 2014 Cesanta Software Limited
   12134              :  * All rights reserved
   12135              :  */
   12136              : 
   12137              : #if MG_ENABLE_ASYNC_RESOLVER
   12138              : 
   12139              : /* Amalgamated: #include "mg_internal.h" */
   12140              : /* Amalgamated: #include "mg_resolv.h" */
   12141              : 
   12142              : #ifndef MG_DEFAULT_NAMESERVER
   12143              : #define MG_DEFAULT_NAMESERVER "8.8.8.8"
   12144              : #endif
   12145              : 
   12146              : struct mg_resolve_async_request {
   12147              :   char name[1024];
   12148              :   int query;
   12149              :   mg_resolve_callback_t callback;
   12150              :   void *data;
   12151              :   time_t timeout;
   12152              :   int max_retries;
   12153              :   enum mg_resolve_err err;
   12154              : 
   12155              :   /* state */
   12156              :   time_t last_time;
   12157              :   int retries;
   12158              : };
   12159              : 
   12160              : /*
   12161              :  * Find what nameserver to use.
   12162              :  *
   12163              :  * Return 0 if OK, -1 if error
   12164              :  */
   12165            0 : static int mg_get_ip_address_of_nameserver(char *name, size_t name_len) {
   12166            0 :   int ret = -1;
   12167              : 
   12168              : #ifdef _WIN32
   12169              :   int i;
   12170              :   LONG err;
   12171              :   HKEY hKey, hSub;
   12172              :   wchar_t subkey[512], value[128],
   12173              :       *key = L"SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces";
   12174              : 
   12175              :   if ((err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey)) !=
   12176              :       ERROR_SUCCESS) {
   12177              :     fprintf(stderr, "cannot open reg key %S: %ld\n", key, err);
   12178              :     ret = -1;
   12179              :   } else {
   12180              :     for (ret = -1, i = 0; 1; i++) {
   12181              :       DWORD subkey_size = sizeof(subkey), type, len = sizeof(value);
   12182              :       if (RegEnumKeyExW(hKey, i, subkey, &subkey_size, NULL, NULL, NULL,
   12183              :                         NULL) != ERROR_SUCCESS) {
   12184              :         break;
   12185              :       }
   12186              :       if (RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hSub) == ERROR_SUCCESS &&
   12187              :           ((RegQueryValueExW(hSub, L"NameServer", 0, &type, (void *) value,
   12188              :                              &len) == ERROR_SUCCESS &&
   12189              :             value[0] != '\0') ||
   12190              :            (RegQueryValueExW(hSub, L"DhcpNameServer", 0, &type, (void *) value,
   12191              :                              &len) == ERROR_SUCCESS &&
   12192              :             value[0] != '\0'))) {
   12193              :         /*
   12194              :          * See https://github.com/cesanta/mongoose/issues/176
   12195              :          * The value taken from the registry can be empty, a single
   12196              :          * IP address, or multiple IP addresses separated by comma.
   12197              :          * If it's empty, check the next interface.
   12198              :          * If it's multiple IP addresses, take the first one.
   12199              :          */
   12200              :         wchar_t *comma = wcschr(value, ',');
   12201              :         if (comma != NULL) {
   12202              :           *comma = '\0';
   12203              :         }
   12204              :         /* %S will convert wchar_t -> char */
   12205              :         snprintf(name, name_len, "%S", value);
   12206              :         ret = 0;
   12207              :         RegCloseKey(hSub);
   12208              :         break;
   12209              :       }
   12210              :     }
   12211              :     RegCloseKey(hKey);
   12212              :   }
   12213              : #elif MG_ENABLE_FILESYSTEM && defined(MG_RESOLV_CONF_FILE_NAME)
   12214              :   FILE *fp;
   12215              :   char line[512];
   12216              : 
   12217            0 :   if ((fp = mg_fopen(MG_RESOLV_CONF_FILE_NAME, "r")) == NULL) {
   12218            0 :     ret = -1;
   12219              :   } else {
   12220              :     /* Try to figure out what nameserver to use */
   12221            0 :     for (ret = -1; fgets(line, sizeof(line), fp) != NULL;) {
   12222              :       unsigned int a, b, c, d;
   12223            0 :       if (sscanf(line, "nameserver %u.%u.%u.%u", &a, &b, &c, &d) == 4) {
   12224            0 :         snprintf(name, name_len, "%u.%u.%u.%u", a, b, c, d);
   12225            0 :         ret = 0;
   12226            0 :         break;
   12227              :       }
   12228              :     }
   12229            0 :     (void) fclose(fp);
   12230              :   }
   12231              : #else
   12232              :   snprintf(name, name_len, "%s", MG_DEFAULT_NAMESERVER);
   12233              : #endif /* _WIN32 */
   12234              : 
   12235            0 :   return ret;
   12236              : }
   12237              : 
   12238            0 : int mg_resolve_from_hosts_file(const char *name, union socket_address *usa) {
   12239              : #if MG_ENABLE_FILESYSTEM && defined(MG_HOSTS_FILE_NAME)
   12240              :   /* TODO(mkm) cache /etc/hosts */
   12241              :   FILE *fp;
   12242              :   char line[1024];
   12243              :   char *p;
   12244              :   char alias[256];
   12245              :   unsigned int a, b, c, d;
   12246            0 :   int len = 0;
   12247              : 
   12248            0 :   if ((fp = mg_fopen(MG_HOSTS_FILE_NAME, "r")) == NULL) {
   12249            0 :     return -1;
   12250              :   }
   12251              : 
   12252            0 :   for (; fgets(line, sizeof(line), fp) != NULL;) {
   12253            0 :     if (line[0] == '#') continue;
   12254              : 
   12255            0 :     if (sscanf(line, "%u.%u.%u.%u%n", &a, &b, &c, &d, &len) == 0) {
   12256              :       /* TODO(mkm): handle ipv6 */
   12257            0 :       continue;
   12258              :     }
   12259            0 :     for (p = line + len; sscanf(p, "%s%n", alias, &len) == 1; p += len) {
   12260            0 :       if (strcmp(alias, name) == 0) {
   12261            0 :         usa->sin.sin_addr.s_addr = htonl(a << 24 | b << 16 | c << 8 | d);
   12262            0 :         fclose(fp);
   12263            0 :         return 0;
   12264              :       }
   12265              :     }
   12266              :   }
   12267              : 
   12268            0 :   fclose(fp);
   12269              : #else
   12270              :   (void) name;
   12271              :   (void) usa;
   12272              : #endif
   12273              : 
   12274            0 :   return -1;
   12275              : }
   12276              : 
   12277            0 : static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
   12278              :                                 void *data MG_UD_ARG(void *user_data)) {
   12279            0 :   time_t now = (time_t) mg_time();
   12280              :   struct mg_resolve_async_request *req;
   12281              :   struct mg_dns_message *msg;
   12282              : #if !MG_ENABLE_CALLBACK_USERDATA
   12283            0 :   void *user_data = nc->user_data;
   12284              : #endif
   12285              : 
   12286            0 :   if (ev != MG_EV_POLL) {
   12287            0 :     DBG(("ev=%d user_data=%p", ev, user_data));
   12288              :   }
   12289              : 
   12290            0 :   req = (struct mg_resolve_async_request *) user_data;
   12291              : 
   12292            0 :   if (req == NULL) {
   12293            0 :     return;
   12294              :   }
   12295              : 
   12296            0 :   switch (ev) {
   12297            0 :     case MG_EV_POLL:
   12298            0 :       if (req->retries > req->max_retries) {
   12299            0 :         req->err = MG_RESOLVE_EXCEEDED_RETRY_COUNT;
   12300            0 :         nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   12301            0 :         break;
   12302              :       }
   12303            0 :       if (nc->flags & MG_F_CONNECTING) break;
   12304              :     /* fallthrough */
   12305              :     case MG_EV_CONNECT:
   12306            0 :       if (req->retries == 0 || now - req->last_time >= req->timeout) {
   12307            0 :         mg_send_dns_query(nc, req->name, req->query);
   12308            0 :         req->last_time = now;
   12309            0 :         req->retries++;
   12310              :       }
   12311            0 :       break;
   12312            0 :     case MG_EV_RECV:
   12313            0 :       msg = (struct mg_dns_message *) MG_MALLOC(sizeof(*msg));
   12314            0 :       if (mg_parse_dns(nc->recv_mbuf.buf, *(int *) data, msg) == 0 &&
   12315            0 :           msg->num_answers > 0) {
   12316            0 :         req->callback(msg, req->data, MG_RESOLVE_OK);
   12317            0 :         nc->user_data = NULL;
   12318            0 :         MG_FREE(req);
   12319              :       } else {
   12320            0 :         req->err = MG_RESOLVE_NO_ANSWERS;
   12321              :       }
   12322            0 :       MG_FREE(msg);
   12323            0 :       nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   12324            0 :       break;
   12325            0 :     case MG_EV_SEND:
   12326              :       /*
   12327              :        * If a send error occurs, prevent closing of the connection by the core.
   12328              :        * We will retry after timeout.
   12329              :        */
   12330            0 :       nc->flags &= ~MG_F_CLOSE_IMMEDIATELY;
   12331            0 :       mbuf_remove(&nc->send_mbuf, nc->send_mbuf.len);
   12332            0 :       break;
   12333            0 :     case MG_EV_TIMER:
   12334            0 :       req->err = MG_RESOLVE_TIMEOUT;
   12335            0 :       nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   12336            0 :       break;
   12337            0 :     case MG_EV_CLOSE:
   12338              :       /* If we got here with request still not done, fire an error callback. */
   12339            0 :       if (req != NULL) {
   12340              :         char addr[32];
   12341            0 :         mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), MG_SOCK_STRINGIFY_IP);
   12342              : #ifdef MG_LOG_DNS_FAILURES
   12343              :         LOG(LL_ERROR, ("Failed to resolve '%s', server %s", req->name, addr));
   12344              : #endif
   12345            0 :         req->callback(NULL, req->data, req->err);
   12346            0 :         nc->user_data = NULL;
   12347            0 :         MG_FREE(req);
   12348              :       }
   12349            0 :       break;
   12350              :   }
   12351              : }
   12352              : 
   12353            0 : int mg_resolve_async(struct mg_mgr *mgr, const char *name, int query,
   12354              :                      mg_resolve_callback_t cb, void *data) {
   12355              :   struct mg_resolve_async_opts opts;
   12356            0 :   memset(&opts, 0, sizeof(opts));
   12357            0 :   return mg_resolve_async_opt(mgr, name, query, cb, data, opts);
   12358              : }
   12359              : 
   12360            0 : int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query,
   12361              :                          mg_resolve_callback_t cb, void *data,
   12362              :                          struct mg_resolve_async_opts opts) {
   12363              :   struct mg_resolve_async_request *req;
   12364              :   struct mg_connection *dns_nc;
   12365            0 :   const char *nameserver = opts.nameserver;
   12366              :   char dns_server_buff[17], nameserver_url[26];
   12367              : 
   12368            0 :   if (nameserver == NULL) {
   12369            0 :     nameserver = mgr->nameserver;
   12370              :   }
   12371              : 
   12372            0 :   DBG(("%s %d %p", name, query, opts.dns_conn));
   12373              : 
   12374              :   /* resolve with DNS */
   12375            0 :   req = (struct mg_resolve_async_request *) MG_CALLOC(1, sizeof(*req));
   12376            0 :   if (req == NULL) {
   12377            0 :     return -1;
   12378              :   }
   12379              : 
   12380            0 :   strncpy(req->name, name, sizeof(req->name));
   12381            0 :   req->name[sizeof(req->name) - 1] = '\0';
   12382              : 
   12383            0 :   req->query = query;
   12384            0 :   req->callback = cb;
   12385            0 :   req->data = data;
   12386              :   /* TODO(mkm): parse defaults out of resolve.conf */
   12387            0 :   req->max_retries = opts.max_retries ? opts.max_retries : 2;
   12388            0 :   req->timeout = opts.timeout ? opts.timeout : 5;
   12389              : 
   12390              :   /* Lazily initialize dns server */
   12391            0 :   if (nameserver == NULL) {
   12392            0 :     if (mg_get_ip_address_of_nameserver(dns_server_buff,
   12393            0 :                                         sizeof(dns_server_buff)) != -1) {
   12394            0 :       nameserver = dns_server_buff;
   12395              :     } else {
   12396            0 :       nameserver = MG_DEFAULT_NAMESERVER;
   12397              :     }
   12398              :   }
   12399              : 
   12400            0 :   snprintf(nameserver_url, sizeof(nameserver_url), "udp://%s:53", nameserver);
   12401              : 
   12402            0 :   dns_nc = mg_connect(mgr, nameserver_url, MG_CB(mg_resolve_async_eh, NULL));
   12403            0 :   if (dns_nc == NULL) {
   12404            0 :     MG_FREE(req);
   12405            0 :     return -1;
   12406              :   }
   12407            0 :   dns_nc->user_data = req;
   12408            0 :   if (opts.dns_conn != NULL) {
   12409            0 :     *opts.dns_conn = dns_nc;
   12410              :   }
   12411              : 
   12412            0 :   return 0;
   12413              : }
   12414              : 
   12415            0 : void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver) {
   12416            0 :   MG_FREE((char *) mgr->nameserver);
   12417            0 :   mgr->nameserver = NULL;
   12418            0 :   if (nameserver != NULL) {
   12419            0 :     mgr->nameserver = strdup(nameserver);
   12420              :   }
   12421            0 : }
   12422              : 
   12423              : #endif /* MG_ENABLE_ASYNC_RESOLVER */
   12424              : #ifdef MG_MODULE_LINES
   12425              : #line 1 "mongoose/src/mg_coap.c"
   12426              : #endif
   12427              : /*
   12428              :  * Copyright (c) 2015 Cesanta Software Limited
   12429              :  * All rights reserved
   12430              :  * This software is dual-licensed: you can redistribute it and/or modify
   12431              :  * it under the terms of the GNU General Public License version 2 as
   12432              :  * published by the Free Software Foundation. For the terms of this
   12433              :  * license, see <http://www.gnu.org/licenses/>.
   12434              :  *
   12435              :  * You are free to use this software under the terms of the GNU General
   12436              :  * Public License, but WITHOUT ANY WARRANTY; without even the implied
   12437              :  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   12438              :  * See the GNU General Public License for more details.
   12439              :  *
   12440              :  * Alternatively, you can license this software under a commercial
   12441              :  * license, as set out in <https://www.cesanta.com/license>.
   12442              :  */
   12443              : 
   12444              : /* Amalgamated: #include "mg_internal.h" */
   12445              : /* Amalgamated: #include "mg_coap.h" */
   12446              : 
   12447              : #if MG_ENABLE_COAP
   12448              : 
   12449              : void mg_coap_free_options(struct mg_coap_message *cm) {
   12450              :   while (cm->options != NULL) {
   12451              :     struct mg_coap_option *next = cm->options->next;
   12452              :     MG_FREE(cm->options);
   12453              :     cm->options = next;
   12454              :   }
   12455              : }
   12456              : 
   12457              : struct mg_coap_option *mg_coap_add_option(struct mg_coap_message *cm,
   12458              :                                           uint32_t number, char *value,
   12459              :                                           size_t len) {
   12460              :   struct mg_coap_option *new_option =
   12461              :       (struct mg_coap_option *) MG_CALLOC(1, sizeof(*new_option));
   12462              : 
   12463              :   new_option->number = number;
   12464              :   new_option->value.p = value;
   12465              :   new_option->value.len = len;
   12466              : 
   12467              :   if (cm->options == NULL) {
   12468              :     cm->options = cm->optiomg_tail = new_option;
   12469              :   } else {
   12470              :     /*
   12471              :      * A very simple attention to help clients to compose options:
   12472              :      * CoAP wants to see options ASC ordered.
   12473              :      * Could be change by using sort in coap_compose
   12474              :      */
   12475              :     if (cm->optiomg_tail->number <= new_option->number) {
   12476              :       /* if option is already ordered just add it */
   12477              :       cm->optiomg_tail = cm->optiomg_tail->next = new_option;
   12478              :     } else {
   12479              :       /* looking for appropriate position */
   12480              :       struct mg_coap_option *current_opt = cm->options;
   12481              :       struct mg_coap_option *prev_opt = 0;
   12482              : 
   12483              :       while (current_opt != NULL) {
   12484              :         if (current_opt->number > new_option->number) {
   12485              :           break;
   12486              :         }
   12487              :         prev_opt = current_opt;
   12488              :         current_opt = current_opt->next;
   12489              :       }
   12490              : 
   12491              :       if (prev_opt != NULL) {
   12492              :         prev_opt->next = new_option;
   12493              :         new_option->next = current_opt;
   12494              :       } else {
   12495              :         /* insert new_option to the beginning */
   12496              :         new_option->next = cm->options;
   12497              :         cm->options = new_option;
   12498              :       }
   12499              :     }
   12500              :   }
   12501              : 
   12502              :   return new_option;
   12503              : }
   12504              : 
   12505              : /*
   12506              :  * Fills CoAP header in mg_coap_message.
   12507              :  *
   12508              :  * Helper function.
   12509              :  */
   12510              : static char *coap_parse_header(char *ptr, struct mbuf *io,
   12511              :                                struct mg_coap_message *cm) {
   12512              :   if (io->len < sizeof(uint32_t)) {
   12513              :     cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
   12514              :     return NULL;
   12515              :   }
   12516              : 
   12517              :   /*
   12518              :    * Version (Ver):  2-bit unsigned integer.  Indicates the CoAP version
   12519              :    * number.  Implementations of this specification MUST set this field
   12520              :    * to 1 (01 binary).  Other values are reserved for future versions.
   12521              :    * Messages with unknown version numbers MUST be silently ignored.
   12522              :    */
   12523              :   if (((uint8_t) *ptr >> 6) != 1) {
   12524              :     cm->flags |= MG_COAP_IGNORE;
   12525              :     return NULL;
   12526              :   }
   12527              : 
   12528              :   /*
   12529              :    * Type (T):  2-bit unsigned integer.  Indicates if this message is of
   12530              :    * type Confirmable (0), Non-confirmable (1), Acknowledgement (2), or
   12531              :    * Reset (3).
   12532              :    */
   12533              :   cm->msg_type = ((uint8_t) *ptr & 0x30) >> 4;
   12534              :   cm->flags |= MG_COAP_MSG_TYPE_FIELD;
   12535              : 
   12536              :   /*
   12537              :    * Token Length (TKL):  4-bit unsigned integer.  Indicates the length of
   12538              :    * the variable-length Token field (0-8 bytes).  Lengths 9-15 are
   12539              :    * reserved, MUST NOT be sent, and MUST be processed as a message
   12540              :    * format error.
   12541              :    */
   12542              :   cm->token.len = *ptr & 0x0F;
   12543              :   if (cm->token.len > 8) {
   12544              :     cm->flags |= MG_COAP_FORMAT_ERROR;
   12545              :     return NULL;
   12546              :   }
   12547              : 
   12548              :   ptr++;
   12549              : 
   12550              :   /*
   12551              :    * Code:  8-bit unsigned integer, split into a 3-bit class (most
   12552              :    * significant bits) and a 5-bit detail (least significant bits)
   12553              :    */
   12554              :   cm->code_class = (uint8_t) *ptr >> 5;
   12555              :   cm->code_detail = *ptr & 0x1F;
   12556              :   cm->flags |= (MG_COAP_CODE_CLASS_FIELD | MG_COAP_CODE_DETAIL_FIELD);
   12557              : 
   12558              :   ptr++;
   12559              : 
   12560              :   /* Message ID:  16-bit unsigned integer in network byte order. */
   12561              :   cm->msg_id = (uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1);
   12562              :   cm->flags |= MG_COAP_MSG_ID_FIELD;
   12563              : 
   12564              :   ptr += 2;
   12565              : 
   12566              :   return ptr;
   12567              : }
   12568              : 
   12569              : /*
   12570              :  * Fills token information in mg_coap_message.
   12571              :  *
   12572              :  * Helper function.
   12573              :  */
   12574              : static char *coap_get_token(char *ptr, struct mbuf *io,
   12575              :                             struct mg_coap_message *cm) {
   12576              :   if (cm->token.len != 0) {
   12577              :     if (ptr + cm->token.len > io->buf + io->len) {
   12578              :       cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
   12579              :       return NULL;
   12580              :     } else {
   12581              :       cm->token.p = ptr;
   12582              :       ptr += cm->token.len;
   12583              :       cm->flags |= MG_COAP_TOKEN_FIELD;
   12584              :     }
   12585              :   }
   12586              : 
   12587              :   return ptr;
   12588              : }
   12589              : 
   12590              : /*
   12591              :  * Returns Option Delta or Length.
   12592              :  *
   12593              :  * Helper function.
   12594              :  */
   12595              : static int coap_get_ext_opt(char *ptr, struct mbuf *io, uint16_t *opt_info) {
   12596              :   int ret = 0;
   12597              : 
   12598              :   if (*opt_info == 13) {
   12599              :     /*
   12600              :      * 13:  An 8-bit unsigned integer follows the initial byte and
   12601              :      * indicates the Option Delta/Length minus 13.
   12602              :      */
   12603              :     if (ptr < io->buf + io->len) {
   12604              :       *opt_info = (uint8_t) *ptr + 13;
   12605              :       ret = sizeof(uint8_t);
   12606              :     } else {
   12607              :       ret = -1; /* LCOV_EXCL_LINE */
   12608              :     }
   12609              :   } else if (*opt_info == 14) {
   12610              :     /*
   12611              :      * 14:  A 16-bit unsigned integer in network byte order follows the
   12612              :      * initial byte and indicates the Option Delta/Length minus 269.
   12613              :      */
   12614              :     if (ptr + sizeof(uint8_t) < io->buf + io->len) {
   12615              :       *opt_info = ((uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1)) + 269;
   12616              :       ret = sizeof(uint16_t);
   12617              :     } else {
   12618              :       ret = -1; /* LCOV_EXCL_LINE */
   12619              :     }
   12620              :   }
   12621              : 
   12622              :   return ret;
   12623              : }
   12624              : 
   12625              : /*
   12626              :  * Fills options in mg_coap_message.
   12627              :  *
   12628              :  * Helper function.
   12629              :  *
   12630              :  * General options format:
   12631              :  * +---------------+---------------+
   12632              :  * | Option Delta  | Option Length |  1 byte
   12633              :  * +---------------+---------------+
   12634              :  * \    Option Delta (extended)    \  0-2 bytes
   12635              :  * +-------------------------------+
   12636              :  * / Option Length  (extended)     \  0-2 bytes
   12637              :  * +-------------------------------+
   12638              :  * \         Option Value          \  0 or more bytes
   12639              :  * +-------------------------------+
   12640              :  */
   12641              : static char *coap_get_options(char *ptr, struct mbuf *io,
   12642              :                               struct mg_coap_message *cm) {
   12643              :   uint16_t prev_opt = 0;
   12644              : 
   12645              :   if (ptr == io->buf + io->len) {
   12646              :     /* end of packet, ok */
   12647              :     return NULL;
   12648              :   }
   12649              : 
   12650              :   /* 0xFF is payload marker */
   12651              :   while (ptr < io->buf + io->len && (uint8_t) *ptr != 0xFF) {
   12652              :     uint16_t option_delta, option_lenght;
   12653              :     int optinfo_len;
   12654              : 
   12655              :     /* Option Delta:  4-bit unsigned integer */
   12656              :     option_delta = ((uint8_t) *ptr & 0xF0) >> 4;
   12657              :     /* Option Length:  4-bit unsigned integer */
   12658              :     option_lenght = *ptr & 0x0F;
   12659              : 
   12660              :     if (option_delta == 15 || option_lenght == 15) {
   12661              :       /*
   12662              :        * 15:  Reserved for future use.  If the field is set to this value,
   12663              :        * it MUST be processed as a message format error
   12664              :        */
   12665              :       cm->flags |= MG_COAP_FORMAT_ERROR;
   12666              :       break;
   12667              :     }
   12668              : 
   12669              :     ptr++;
   12670              : 
   12671              :     /* check for extended option delta */
   12672              :     optinfo_len = coap_get_ext_opt(ptr, io, &option_delta);
   12673              :     if (optinfo_len == -1) {
   12674              :       cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
   12675              :       break;                                /* LCOV_EXCL_LINE */
   12676              :     }
   12677              : 
   12678              :     ptr += optinfo_len;
   12679              : 
   12680              :     /* check or extended option lenght */
   12681              :     optinfo_len = coap_get_ext_opt(ptr, io, &option_lenght);
   12682              :     if (optinfo_len == -1) {
   12683              :       cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
   12684              :       break;                                /* LCOV_EXCL_LINE */
   12685              :     }
   12686              : 
   12687              :     ptr += optinfo_len;
   12688              : 
   12689              :     /*
   12690              :      * Instead of specifying the Option Number directly, the instances MUST
   12691              :      * appear in order of their Option Numbers and a delta encoding is used
   12692              :      * between them.
   12693              :      */
   12694              :     option_delta += prev_opt;
   12695              : 
   12696              :     mg_coap_add_option(cm, option_delta, ptr, option_lenght);
   12697              : 
   12698              :     prev_opt = option_delta;
   12699              : 
   12700              :     if (ptr + option_lenght > io->buf + io->len) {
   12701              :       cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
   12702              :       break;                                /* LCOV_EXCL_LINE */
   12703              :     }
   12704              : 
   12705              :     ptr += option_lenght;
   12706              :   }
   12707              : 
   12708              :   if ((cm->flags & MG_COAP_ERROR) != 0) {
   12709              :     mg_coap_free_options(cm);
   12710              :     return NULL;
   12711              :   }
   12712              : 
   12713              :   cm->flags |= MG_COAP_OPTIOMG_FIELD;
   12714              : 
   12715              :   if (ptr == io->buf + io->len) {
   12716              :     /* end of packet, ok */
   12717              :     return NULL;
   12718              :   }
   12719              : 
   12720              :   ptr++;
   12721              : 
   12722              :   return ptr;
   12723              : }
   12724              : 
   12725              : uint32_t mg_coap_parse(struct mbuf *io, struct mg_coap_message *cm) {
   12726              :   char *ptr;
   12727              : 
   12728              :   memset(cm, 0, sizeof(*cm));
   12729              : 
   12730              :   if ((ptr = coap_parse_header(io->buf, io, cm)) == NULL) {
   12731              :     return cm->flags;
   12732              :   }
   12733              : 
   12734              :   if ((ptr = coap_get_token(ptr, io, cm)) == NULL) {
   12735              :     return cm->flags;
   12736              :   }
   12737              : 
   12738              :   if ((ptr = coap_get_options(ptr, io, cm)) == NULL) {
   12739              :     return cm->flags;
   12740              :   }
   12741              : 
   12742              :   /* the rest is payload */
   12743              :   cm->payload.len = io->len - (ptr - io->buf);
   12744              :   if (cm->payload.len != 0) {
   12745              :     cm->payload.p = ptr;
   12746              :     cm->flags |= MG_COAP_PAYLOAD_FIELD;
   12747              :   }
   12748              : 
   12749              :   return cm->flags;
   12750              : }
   12751              : 
   12752              : /*
   12753              :  * Calculates extended size of given Opt Number/Length in coap message.
   12754              :  *
   12755              :  * Helper function.
   12756              :  */
   12757              : static size_t coap_get_ext_opt_size(uint32_t value) {
   12758              :   int ret = 0;
   12759              : 
   12760              :   if (value >= 13 && value <= 0xFF + 13) {
   12761              :     ret = sizeof(uint8_t);
   12762              :   } else if (value > 0xFF + 13 && value <= 0xFFFF + 269) {
   12763              :     ret = sizeof(uint16_t);
   12764              :   }
   12765              : 
   12766              :   return ret;
   12767              : }
   12768              : 
   12769              : /*
   12770              :  * Splits given Opt Number/Length into base and ext values.
   12771              :  *
   12772              :  * Helper function.
   12773              :  */
   12774              : static int coap_split_opt(uint32_t value, uint8_t *base, uint16_t *ext) {
   12775              :   int ret = 0;
   12776              : 
   12777              :   if (value < 13) {
   12778              :     *base = value;
   12779              :   } else if (value >= 13 && value <= 0xFF + 13) {
   12780              :     *base = 13;
   12781              :     *ext = value - 13;
   12782              :     ret = sizeof(uint8_t);
   12783              :   } else if (value > 0xFF + 13 && value <= 0xFFFF + 269) {
   12784              :     *base = 14;
   12785              :     *ext = value - 269;
   12786              :     ret = sizeof(uint16_t);
   12787              :   }
   12788              : 
   12789              :   return ret;
   12790              : }
   12791              : 
   12792              : /*
   12793              :  * Puts uint16_t (in network order) into given char stream.
   12794              :  *
   12795              :  * Helper function.
   12796              :  */
   12797              : static char *coap_add_uint16(char *ptr, uint16_t val) {
   12798              :   *ptr = val >> 8;
   12799              :   ptr++;
   12800              :   *ptr = val & 0x00FF;
   12801              :   ptr++;
   12802              :   return ptr;
   12803              : }
   12804              : 
   12805              : /*
   12806              :  * Puts extended value of Opt Number/Length into given char stream.
   12807              :  *
   12808              :  * Helper function.
   12809              :  */
   12810              : static char *coap_add_opt_info(char *ptr, uint16_t val, size_t len) {
   12811              :   if (len == sizeof(uint8_t)) {
   12812              :     *ptr = (char) val;
   12813              :     ptr++;
   12814              :   } else if (len == sizeof(uint16_t)) {
   12815              :     ptr = coap_add_uint16(ptr, val);
   12816              :   }
   12817              : 
   12818              :   return ptr;
   12819              : }
   12820              : 
   12821              : /*
   12822              :  * Verifies given mg_coap_message and calculates message size for it.
   12823              :  *
   12824              :  * Helper function.
   12825              :  */
   12826              : static uint32_t coap_calculate_packet_size(struct mg_coap_message *cm,
   12827              :                                            size_t *len) {
   12828              :   struct mg_coap_option *opt;
   12829              :   uint32_t prev_opt_number;
   12830              : 
   12831              :   *len = 4; /* header */
   12832              :   if (cm->msg_type > MG_COAP_MSG_MAX) {
   12833              :     return MG_COAP_ERROR | MG_COAP_MSG_TYPE_FIELD;
   12834              :   }
   12835              :   if (cm->token.len > 8) {
   12836              :     return MG_COAP_ERROR | MG_COAP_TOKEN_FIELD;
   12837              :   }
   12838              :   if (cm->code_class > 7) {
   12839              :     return MG_COAP_ERROR | MG_COAP_CODE_CLASS_FIELD;
   12840              :   }
   12841              :   if (cm->code_detail > 31) {
   12842              :     return MG_COAP_ERROR | MG_COAP_CODE_DETAIL_FIELD;
   12843              :   }
   12844              : 
   12845              :   *len += cm->token.len;
   12846              :   if (cm->payload.len != 0) {
   12847              :     *len += cm->payload.len + 1; /* ... + 1; add payload marker */
   12848              :   }
   12849              : 
   12850              :   opt = cm->options;
   12851              :   prev_opt_number = 0;
   12852              :   while (opt != NULL) {
   12853              :     *len += 1; /* basic delta/length */
   12854              :     *len += coap_get_ext_opt_size(opt->number - prev_opt_number);
   12855              :     *len += coap_get_ext_opt_size((uint32_t) opt->value.len);
   12856              :     /*
   12857              :      * Current implementation performs check if
   12858              :      * option_number > previous option_number and produces an error
   12859              :      * TODO(alashkin): write design doc with limitations
   12860              :      * May be resorting is more suitable solution.
   12861              :      */
   12862              :     if ((opt->next != NULL && opt->number > opt->next->number) ||
   12863              :         opt->value.len > 0xFFFF + 269 ||
   12864              :         opt->number - prev_opt_number > 0xFFFF + 269) {
   12865              :       return MG_COAP_ERROR | MG_COAP_OPTIOMG_FIELD;
   12866              :     }
   12867              :     *len += opt->value.len;
   12868              :     prev_opt_number = opt->number;
   12869              :     opt = opt->next;
   12870              :   }
   12871              : 
   12872              :   return 0;
   12873              : }
   12874              : 
   12875              : uint32_t mg_coap_compose(struct mg_coap_message *cm, struct mbuf *io) {
   12876              :   struct mg_coap_option *opt;
   12877              :   uint32_t res, prev_opt_number;
   12878              :   size_t prev_io_len, packet_size;
   12879              :   char *ptr;
   12880              : 
   12881              :   res = coap_calculate_packet_size(cm, &packet_size);
   12882              :   if (res != 0) {
   12883              :     return res;
   12884              :   }
   12885              : 
   12886              :   /* saving previous lenght to handle non-empty mbuf */
   12887              :   prev_io_len = io->len;
   12888              :   if (mbuf_append(io, NULL, packet_size) == 0) return MG_COAP_ERROR;
   12889              :   ptr = io->buf + prev_io_len;
   12890              : 
   12891              :   /*
   12892              :    * since cm is verified, it is possible to use bits shift operator
   12893              :    * without additional zeroing of unused bits
   12894              :    */
   12895              : 
   12896              :   /* ver: 2 bits, msg_type: 2 bits, toklen: 4 bits */
   12897              :   *ptr = (1 << 6) | (cm->msg_type << 4) | (uint8_t)(cm->token.len);
   12898              :   ptr++;
   12899              : 
   12900              :   /* code class: 3 bits, code detail: 5 bits */
   12901              :   *ptr = (cm->code_class << 5) | (cm->code_detail);
   12902              :   ptr++;
   12903              : 
   12904              :   ptr = coap_add_uint16(ptr, cm->msg_id);
   12905              : 
   12906              :   if (cm->token.len != 0) {
   12907              :     memcpy(ptr, cm->token.p, cm->token.len);
   12908              :     ptr += cm->token.len;
   12909              :   }
   12910              : 
   12911              :   opt = cm->options;
   12912              :   prev_opt_number = 0;
   12913              :   while (opt != NULL) {
   12914              :     uint8_t delta_base = 0, length_base = 0;
   12915              :     uint16_t delta_ext = 0, length_ext = 0;
   12916              : 
   12917              :     size_t opt_delta_len =
   12918              :         coap_split_opt(opt->number - prev_opt_number, &delta_base, &delta_ext);
   12919              :     size_t opt_lenght_len =
   12920              :         coap_split_opt((uint32_t) opt->value.len, &length_base, &length_ext);
   12921              : 
   12922              :     *ptr = (delta_base << 4) | length_base;
   12923              :     ptr++;
   12924              : 
   12925              :     ptr = coap_add_opt_info(ptr, delta_ext, opt_delta_len);
   12926              :     ptr = coap_add_opt_info(ptr, length_ext, opt_lenght_len);
   12927              : 
   12928              :     if (opt->value.len != 0) {
   12929              :       memcpy(ptr, opt->value.p, opt->value.len);
   12930              :       ptr += opt->value.len;
   12931              :     }
   12932              : 
   12933              :     prev_opt_number = opt->number;
   12934              :     opt = opt->next;
   12935              :   }
   12936              : 
   12937              :   if (cm->payload.len != 0) {
   12938              :     *ptr = (char) -1;
   12939              :     ptr++;
   12940              :     memcpy(ptr, cm->payload.p, cm->payload.len);
   12941              :   }
   12942              : 
   12943              :   return 0;
   12944              : }
   12945              : 
   12946              : uint32_t mg_coap_send_message(struct mg_connection *nc,
   12947              :                               struct mg_coap_message *cm) {
   12948              :   struct mbuf packet_out;
   12949              :   uint32_t compose_res;
   12950              : 
   12951              :   mbuf_init(&packet_out, 0);
   12952              :   compose_res = mg_coap_compose(cm, &packet_out);
   12953              :   if (compose_res != 0) {
   12954              :     return compose_res; /* LCOV_EXCL_LINE */
   12955              :   }
   12956              : 
   12957              :   mg_send(nc, packet_out.buf, (int) packet_out.len);
   12958              :   mbuf_free(&packet_out);
   12959              : 
   12960              :   return 0;
   12961              : }
   12962              : 
   12963              : uint32_t mg_coap_send_ack(struct mg_connection *nc, uint16_t msg_id) {
   12964              :   struct mg_coap_message cm;
   12965              :   memset(&cm, 0, sizeof(cm));
   12966              :   cm.msg_type = MG_COAP_MSG_ACK;
   12967              :   cm.msg_id = msg_id;
   12968              : 
   12969              :   return mg_coap_send_message(nc, &cm);
   12970              : }
   12971              : 
   12972              : static void coap_handler(struct mg_connection *nc, int ev,
   12973              :                          void *ev_data MG_UD_ARG(void *user_data)) {
   12974              :   struct mbuf *io = &nc->recv_mbuf;
   12975              :   struct mg_coap_message cm;
   12976              :   uint32_t parse_res;
   12977              : 
   12978              :   memset(&cm, 0, sizeof(cm));
   12979              : 
   12980              :   nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
   12981              : 
   12982              :   switch (ev) {
   12983              :     case MG_EV_RECV:
   12984              :       parse_res = mg_coap_parse(io, &cm);
   12985              :       if ((parse_res & MG_COAP_IGNORE) == 0) {
   12986              :         if ((cm.flags & MG_COAP_NOT_ENOUGH_DATA) != 0) {
   12987              :           /*
   12988              :            * Since we support UDP only
   12989              :            * MG_COAP_NOT_ENOUGH_DATA == MG_COAP_FORMAT_ERROR
   12990              :            */
   12991              :           cm.flags |= MG_COAP_FORMAT_ERROR; /* LCOV_EXCL_LINE */
   12992              :         }                                   /* LCOV_EXCL_LINE */
   12993              :         nc->handler(nc, MG_COAP_EVENT_BASE + cm.msg_type,
   12994              :                     &cm MG_UD_ARG(user_data));
   12995              :       }
   12996              : 
   12997              :       mg_coap_free_options(&cm);
   12998              :       mbuf_remove(io, io->len);
   12999              :       break;
   13000              :   }
   13001              : }
   13002              : /*
   13003              :  * Attach built-in CoAP event handler to the given connection.
   13004              :  *
   13005              :  * The user-defined event handler will receive following extra events:
   13006              :  *
   13007              :  * - MG_EV_COAP_CON
   13008              :  * - MG_EV_COAP_NOC
   13009              :  * - MG_EV_COAP_ACK
   13010              :  * - MG_EV_COAP_RST
   13011              :  */
   13012              : int mg_set_protocol_coap(struct mg_connection *nc) {
   13013              :   /* supports UDP only */
   13014              :   if ((nc->flags & MG_F_UDP) == 0) {
   13015              :     return -1;
   13016              :   }
   13017              : 
   13018              :   nc->proto_handler = coap_handler;
   13019              : 
   13020              :   return 0;
   13021              : }
   13022              : 
   13023              : #endif /* MG_ENABLE_COAP */
   13024              : #ifdef MG_MODULE_LINES
   13025              : #line 1 "mongoose/src/mg_sntp.c"
   13026              : #endif
   13027              : /*
   13028              :  * Copyright (c) 2016 Cesanta Software Limited
   13029              :  * All rights reserved
   13030              :  */
   13031              : 
   13032              : /* Amalgamated: #include "mg_internal.h" */
   13033              : /* Amalgamated: #include "mg_sntp.h" */
   13034              : /* Amalgamated: #include "mg_util.h" */
   13035              : 
   13036              : #if MG_ENABLE_SNTP
   13037              : 
   13038              : #define SNTP_TIME_OFFSET 2208988800
   13039              : 
   13040              : #ifndef SNTP_TIMEOUT
   13041              : #define SNTP_TIMEOUT 10
   13042              : #endif
   13043              : 
   13044              : #ifndef SNTP_ATTEMPTS
   13045              : #define SNTP_ATTEMPTS 3
   13046              : #endif
   13047              : 
   13048              : static uint64_t mg_get_sec(uint64_t val) {
   13049              :   return (val & 0xFFFFFFFF00000000) >> 32;
   13050              : }
   13051              : 
   13052              : static uint64_t mg_get_usec(uint64_t val) {
   13053              :   uint64_t tmp = (val & 0x00000000FFFFFFFF);
   13054              :   tmp *= 1000000;
   13055              :   tmp >>= 32;
   13056              :   return tmp;
   13057              : }
   13058              : 
   13059              : static void mg_ntp_to_tv(uint64_t val, struct timeval *tv) {
   13060              :   uint64_t tmp;
   13061              :   tmp = mg_get_sec(val);
   13062              :   tmp -= SNTP_TIME_OFFSET;
   13063              :   tv->tv_sec = tmp;
   13064              :   tv->tv_usec = mg_get_usec(val);
   13065              : }
   13066              : 
   13067              : static void mg_get_ntp_ts(const char *ntp, uint64_t *val) {
   13068              :   uint32_t tmp;
   13069              :   memcpy(&tmp, ntp, sizeof(tmp));
   13070              :   tmp = ntohl(tmp);
   13071              :   *val = (uint64_t) tmp << 32;
   13072              :   memcpy(&tmp, ntp + 4, sizeof(tmp));
   13073              :   tmp = ntohl(tmp);
   13074              :   *val |= tmp;
   13075              : }
   13076              : 
   13077              : void mg_sntp_send_request(struct mg_connection *c) {
   13078              :   uint8_t buf[48] = {0};
   13079              :   /*
   13080              :    * header - 8 bit:
   13081              :    * LI (2 bit) - 3 (not in sync), VN (3 bit) - 4 (version),
   13082              :    * mode (3 bit) - 3 (client)
   13083              :    */
   13084              :   buf[0] = (3 << 6) | (4 << 3) | 3;
   13085              : 
   13086              : /*
   13087              :  * Next fields should be empty in client request
   13088              :  * stratum, 8 bit
   13089              :  * poll interval, 8 bit
   13090              :  * rrecision, 8 bit
   13091              :  * root delay, 32 bit
   13092              :  * root dispersion, 32 bit
   13093              :  * ref id, 32 bit
   13094              :  * ref timestamp, 64 bit
   13095              :  * originate Timestamp, 64 bit
   13096              :  * receive Timestamp, 64 bit
   13097              : */
   13098              : 
   13099              : /*
   13100              :  * convert time to sntp format (sntp starts from 00:00:00 01.01.1900)
   13101              :  * according to rfc868 it is 2208988800L sec
   13102              :  * this information is used to correct roundtrip delay
   13103              :  * but if local clock is absolutely broken (and doesn't work even
   13104              :  * as simple timer), it is better to disable it
   13105              : */
   13106              : #ifndef MG_SNTP_NO_DELAY_CORRECTION
   13107              :   uint32_t sec;
   13108              :   sec = htonl((uint32_t)(mg_time() + SNTP_TIME_OFFSET));
   13109              :   memcpy(&buf[40], &sec, sizeof(sec));
   13110              : #endif
   13111              : 
   13112              :   mg_send(c, buf, sizeof(buf));
   13113              : }
   13114              : 
   13115              : #ifndef MG_SNTP_NO_DELAY_CORRECTION
   13116              : static uint64_t mg_calculate_delay(uint64_t t1, uint64_t t2, uint64_t t3) {
   13117              :   /* roundloop delay = (T4 - T1) - (T3 - T2) */
   13118              :   uint64_t d1 = ((mg_time() + SNTP_TIME_OFFSET) * 1000000) -
   13119              :                 (mg_get_sec(t1) * 1000000 + mg_get_usec(t1));
   13120              :   uint64_t d2 = (mg_get_sec(t3) * 1000000 + mg_get_usec(t3)) -
   13121              :                 (mg_get_sec(t2) * 1000000 + mg_get_usec(t2));
   13122              : 
   13123              :   return (d1 > d2) ? d1 - d2 : 0;
   13124              : }
   13125              : #endif
   13126              : 
   13127              : MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len,
   13128              :                                     struct mg_sntp_message *msg) {
   13129              :   uint8_t hdr;
   13130              :   uint64_t trsm_ts_T3, delay = 0;
   13131              :   int mode;
   13132              :   struct timeval tv;
   13133              : 
   13134              :   if (len < 48) {
   13135              :     return -1;
   13136              :   }
   13137              : 
   13138              :   hdr = buf[0];
   13139              : 
   13140              :   if ((hdr & 0x38) >> 3 != 4) {
   13141              :     /* Wrong version */
   13142              :     return -1;
   13143              :   }
   13144              : 
   13145              :   mode = hdr & 0x7;
   13146              :   if (mode != 4 && mode != 5) {
   13147              :     /* Not a server reply */
   13148              :     return -1;
   13149              :   }
   13150              : 
   13151              :   memset(msg, 0, sizeof(*msg));
   13152              : 
   13153              :   msg->kiss_of_death = (buf[1] == 0); /* Server asks to not send requests */
   13154              : 
   13155              :   mg_get_ntp_ts(&buf[40], &trsm_ts_T3);
   13156              : 
   13157              : #ifndef MG_SNTP_NO_DELAY_CORRECTION
   13158              :   {
   13159              :     uint64_t orig_ts_T1, recv_ts_T2;
   13160              :     mg_get_ntp_ts(&buf[24], &orig_ts_T1);
   13161              :     mg_get_ntp_ts(&buf[32], &recv_ts_T2);
   13162              :     delay = mg_calculate_delay(orig_ts_T1, recv_ts_T2, trsm_ts_T3);
   13163              :   }
   13164              : #endif
   13165              : 
   13166              :   mg_ntp_to_tv(trsm_ts_T3, &tv);
   13167              : 
   13168              :   msg->time = (double) tv.tv_sec + (((double) tv.tv_usec + delay) / 1000000.0);
   13169              : 
   13170              :   return 0;
   13171              : }
   13172              : 
   13173              : static void mg_sntp_handler(struct mg_connection *c, int ev,
   13174              :                             void *ev_data MG_UD_ARG(void *user_data)) {
   13175              :   struct mbuf *io = &c->recv_mbuf;
   13176              :   struct mg_sntp_message msg;
   13177              : 
   13178              :   c->handler(c, ev, ev_data MG_UD_ARG(user_data));
   13179              : 
   13180              :   switch (ev) {
   13181              :     case MG_EV_RECV: {
   13182              :       if (mg_sntp_parse_reply(io->buf, io->len, &msg) < 0) {
   13183              :         DBG(("Invalid SNTP packet received (%d)", (int) io->len));
   13184              :         c->handler(c, MG_SNTP_MALFORMED_REPLY, NULL MG_UD_ARG(user_data));
   13185              :       } else {
   13186              :         c->handler(c, MG_SNTP_REPLY, (void *) &msg MG_UD_ARG(user_data));
   13187              :       }
   13188              : 
   13189              :       mbuf_remove(io, io->len);
   13190              :       break;
   13191              :     }
   13192              :   }
   13193              : }
   13194              : 
   13195              : int mg_set_protocol_sntp(struct mg_connection *c) {
   13196              :   if ((c->flags & MG_F_UDP) == 0) {
   13197              :     return -1;
   13198              :   }
   13199              : 
   13200              :   c->proto_handler = mg_sntp_handler;
   13201              : 
   13202              :   return 0;
   13203              : }
   13204              : 
   13205              : struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr,
   13206              :                                       MG_CB(mg_event_handler_t event_handler,
   13207              :                                             void *user_data),
   13208              :                                       const char *sntp_server_name) {
   13209              :   struct mg_connection *c = NULL;
   13210              :   char url[100], *p_url = url;
   13211              :   const char *proto = "", *port = "", *tmp;
   13212              : 
   13213              :   /* If port is not specified, use default (123) */
   13214              :   tmp = strchr(sntp_server_name, ':');
   13215              :   if (tmp != NULL && *(tmp + 1) == '/') {
   13216              :     tmp = strchr(tmp + 1, ':');
   13217              :   }
   13218              : 
   13219              :   if (tmp == NULL) {
   13220              :     port = ":123";
   13221              :   }
   13222              : 
   13223              :   /* Add udp:// if needed */
   13224              :   if (strncmp(sntp_server_name, "udp://", 6) != 0) {
   13225              :     proto = "udp://";
   13226              :   }
   13227              : 
   13228              :   mg_asprintf(&p_url, sizeof(url), "%s%s%s", proto, sntp_server_name, port);
   13229              : 
   13230              :   c = mg_connect(mgr, p_url, event_handler MG_UD_ARG(user_data));
   13231              : 
   13232              :   if (c == NULL) {
   13233              :     goto cleanup;
   13234              :   }
   13235              : 
   13236              :   mg_set_protocol_sntp(c);
   13237              : 
   13238              : cleanup:
   13239              :   if (p_url != url) {
   13240              :     MG_FREE(p_url);
   13241              :   }
   13242              : 
   13243              :   return c;
   13244              : }
   13245              : 
   13246              : struct sntp_data {
   13247              :   mg_event_handler_t hander;
   13248              :   int count;
   13249              : };
   13250              : 
   13251              : static void mg_sntp_util_ev_handler(struct mg_connection *c, int ev,
   13252              :                                     void *ev_data MG_UD_ARG(void *user_data)) {
   13253              : #if !MG_ENABLE_CALLBACK_USERDATA
   13254              :   void *user_data = c->user_data;
   13255              : #endif
   13256              :   struct sntp_data *sd = (struct sntp_data *) user_data;
   13257              : 
   13258              :   switch (ev) {
   13259              :     case MG_EV_CONNECT:
   13260              :       if (*(int *) ev_data != 0) {
   13261              :         mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
   13262              :         break;
   13263              :       }
   13264              :     /* fallthrough */
   13265              :     case MG_EV_TIMER:
   13266              :       if (sd->count <= SNTP_ATTEMPTS) {
   13267              :         mg_sntp_send_request(c);
   13268              :         mg_set_timer(c, mg_time() + 10);
   13269              :         sd->count++;
   13270              :       } else {
   13271              :         mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
   13272              :         c->flags |= MG_F_CLOSE_IMMEDIATELY;
   13273              :       }
   13274              :       break;
   13275              :     case MG_SNTP_MALFORMED_REPLY:
   13276              :       mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
   13277              :       c->flags |= MG_F_CLOSE_IMMEDIATELY;
   13278              :       break;
   13279              :     case MG_SNTP_REPLY:
   13280              :       mg_call(c, sd->hander, c->user_data, MG_SNTP_REPLY, ev_data);
   13281              :       c->flags |= MG_F_CLOSE_IMMEDIATELY;
   13282              :       break;
   13283              :     case MG_EV_CLOSE:
   13284              :       MG_FREE(user_data);
   13285              :       c->user_data = NULL;
   13286              :       break;
   13287              :   }
   13288              : }
   13289              : 
   13290              : struct mg_connection *mg_sntp_get_time(struct mg_mgr *mgr,
   13291              :                                        mg_event_handler_t event_handler,
   13292              :                                        const char *sntp_server_name) {
   13293              :   struct mg_connection *c;
   13294              :   struct sntp_data *sd = (struct sntp_data *) MG_CALLOC(1, sizeof(*sd));
   13295              :   if (sd == NULL) {
   13296              :     return NULL;
   13297              :   }
   13298              : 
   13299              :   c = mg_sntp_connect(mgr, MG_CB(mg_sntp_util_ev_handler, sd),
   13300              :                       sntp_server_name);
   13301              :   if (c == NULL) {
   13302              :     MG_FREE(sd);
   13303              :     return NULL;
   13304              :   }
   13305              : 
   13306              :   sd->hander = event_handler;
   13307              : #if !MG_ENABLE_CALLBACK_USERDATA
   13308              :   c->user_data = sd;
   13309              : #endif
   13310              : 
   13311              :   return c;
   13312              : }
   13313              : 
   13314              : #endif /* MG_ENABLE_SNTP */
   13315              : #ifdef MG_MODULE_LINES
   13316              : #line 1 "mongoose/src/mg_socks.c"
   13317              : #endif
   13318              : /*
   13319              :  * Copyright (c) 2017 Cesanta Software Limited
   13320              :  * All rights reserved
   13321              :  */
   13322              : 
   13323              : #if MG_ENABLE_SOCKS
   13324              : 
   13325              : /* Amalgamated: #include "mg_socks.h" */
   13326              : /* Amalgamated: #include "mg_internal.h" */
   13327              : 
   13328              : /*
   13329              :  *  https://www.ietf.org/rfc/rfc1928.txt paragraph 3, handle client handshake
   13330              :  *
   13331              :  *  +----+----------+----------+
   13332              :  *  |VER | NMETHODS | METHODS  |
   13333              :  *  +----+----------+----------+
   13334              :  *  | 1  |    1     | 1 to 255 |
   13335              :  *  +----+----------+----------+
   13336              :  */
   13337              : static void mg_socks5_handshake(struct mg_connection *c) {
   13338              :   struct mbuf *r = &c->recv_mbuf;
   13339              :   if (r->buf[0] != MG_SOCKS_VERSION) {
   13340              :     c->flags |= MG_F_CLOSE_IMMEDIATELY;
   13341              :   } else if (r->len > 2 && (size_t) r->buf[1] + 2 <= r->len) {
   13342              :     /* https://www.ietf.org/rfc/rfc1928.txt paragraph 3 */
   13343              :     unsigned char reply[2] = {MG_SOCKS_VERSION, MG_SOCKS_HANDSHAKE_FAILURE};
   13344              :     int i;
   13345              :     for (i = 2; i < r->buf[1] + 2; i++) {
   13346              :       /* TODO(lsm): support other auth methods */
   13347              :       if (r->buf[i] == MG_SOCKS_HANDSHAKE_NOAUTH) reply[1] = r->buf[i];
   13348              :     }
   13349              :     mbuf_remove(r, 2 + r->buf[1]);
   13350              :     mg_send(c, reply, sizeof(reply));
   13351              :     c->flags |= MG_SOCKS_HANDSHAKE_DONE; /* Mark handshake done */
   13352              :   }
   13353              : }
   13354              : 
   13355              : static void disband(struct mg_connection *c) {
   13356              :   struct mg_connection *c2 = (struct mg_connection *) c->user_data;
   13357              :   if (c2 != NULL) {
   13358              :     c2->flags |= MG_F_SEND_AND_CLOSE;
   13359              :     c2->user_data = NULL;
   13360              :   }
   13361              :   c->flags |= MG_F_SEND_AND_CLOSE;
   13362              :   c->user_data = NULL;
   13363              : }
   13364              : 
   13365              : static void relay_data(struct mg_connection *c) {
   13366              :   struct mg_connection *c2 = (struct mg_connection *) c->user_data;
   13367              :   if (c2 != NULL) {
   13368              :     mg_send(c2, c->recv_mbuf.buf, c->recv_mbuf.len);
   13369              :     mbuf_remove(&c->recv_mbuf, c->recv_mbuf.len);
   13370              :   } else {
   13371              :     c->flags |= MG_F_SEND_AND_CLOSE;
   13372              :   }
   13373              : }
   13374              : 
   13375              : static void serv_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
   13376              :   if (ev == MG_EV_CLOSE) {
   13377              :     disband(c);
   13378              :   } else if (ev == MG_EV_RECV) {
   13379              :     relay_data(c);
   13380              :   } else if (ev == MG_EV_CONNECT) {
   13381              :     int res = *(int *) ev_data;
   13382              :     if (res != 0) LOG(LL_ERROR, ("connect error: %d", res));
   13383              :   }
   13384              : }
   13385              : 
   13386              : static void mg_socks5_connect(struct mg_connection *c, const char *addr) {
   13387              :   struct mg_connection *serv = mg_connect(c->mgr, addr, serv_ev_handler);
   13388              :   serv->user_data = c;
   13389              :   c->user_data = serv;
   13390              : }
   13391              : 
   13392              : /*
   13393              :  *  Request, https://www.ietf.org/rfc/rfc1928.txt paragraph 4
   13394              :  *
   13395              :  *  +----+-----+-------+------+----------+----------+
   13396              :  *  |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
   13397              :  *  +----+-----+-------+------+----------+----------+
   13398              :  *  | 1  |  1  | X'00' |  1   | Variable |    2     |
   13399              :  *  +----+-----+-------+------+----------+----------+
   13400              :  */
   13401              : static void mg_socks5_handle_request(struct mg_connection *c) {
   13402              :   struct mbuf *r = &c->recv_mbuf;
   13403              :   unsigned char *p = (unsigned char *) r->buf;
   13404              :   unsigned char addr_len = 4, reply = MG_SOCKS_SUCCESS;
   13405              :   int ver, cmd, atyp;
   13406              :   char addr[300];
   13407              : 
   13408              :   if (r->len < 8) return; /* return if not fully buffered. min DST.ADDR is 2 */
   13409              :   ver = p[0];
   13410              :   cmd = p[1];
   13411              :   atyp = p[3];
   13412              : 
   13413              :   /* TODO(lsm): support other commands */
   13414              :   if (ver != MG_SOCKS_VERSION || cmd != MG_SOCKS_CMD_CONNECT) {
   13415              :     reply = MG_SOCKS_CMD_NOT_SUPPORTED;
   13416              :   } else if (atyp == MG_SOCKS_ADDR_IPV4) {
   13417              :     addr_len = 4;
   13418              :     if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
   13419              :     snprintf(addr, sizeof(addr), "%d.%d.%d.%d:%d", p[4], p[5], p[6], p[7],
   13420              :              p[8] << 8 | p[9]);
   13421              :     mg_socks5_connect(c, addr);
   13422              :   } else if (atyp == MG_SOCKS_ADDR_IPV6) {
   13423              :     addr_len = 16;
   13424              :     if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
   13425              :     snprintf(addr, sizeof(addr), "[%x:%x:%x:%x:%x:%x:%x:%x]:%d",
   13426              :              p[4] << 8 | p[5], p[6] << 8 | p[7], p[8] << 8 | p[9],
   13427              :              p[10] << 8 | p[11], p[12] << 8 | p[13], p[14] << 8 | p[15],
   13428              :              p[16] << 8 | p[17], p[18] << 8 | p[19], p[20] << 8 | p[21]);
   13429              :     mg_socks5_connect(c, addr);
   13430              :   } else if (atyp == MG_SOCKS_ADDR_DOMAIN) {
   13431              :     addr_len = p[4] + 1;
   13432              :     if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
   13433              :     snprintf(addr, sizeof(addr), "%.*s:%d", p[4], p + 5,
   13434              :              p[4 + addr_len] << 8 | p[4 + addr_len + 1]);
   13435              :     mg_socks5_connect(c, addr);
   13436              :   } else {
   13437              :     reply = MG_SOCKS_ADDR_NOT_SUPPORTED;
   13438              :   }
   13439              : 
   13440              :   /*
   13441              :    *  Reply, https://www.ietf.org/rfc/rfc1928.txt paragraph 5
   13442              :    *
   13443              :    *  +----+-----+-------+------+----------+----------+
   13444              :    *  |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
   13445              :    *  +----+-----+-------+------+----------+----------+
   13446              :    *  | 1  |  1  | X'00' |  1   | Variable |    2     |
   13447              :    *  +----+-----+-------+------+----------+----------+
   13448              :    */
   13449              :   {
   13450              :     unsigned char buf[] = {MG_SOCKS_VERSION, reply, 0};
   13451              :     mg_send(c, buf, sizeof(buf));
   13452              :   }
   13453              :   mg_send(c, r->buf + 3, addr_len + 1 + 2);
   13454              : 
   13455              :   mbuf_remove(r, 6 + addr_len);      /* Remove request from the input stream */
   13456              :   c->flags |= MG_SOCKS_CONNECT_DONE; /* Mark ourselves as connected */
   13457              : }
   13458              : 
   13459              : static void socks_handler(struct mg_connection *c, int ev, void *ev_data) {
   13460              :   if (ev == MG_EV_RECV) {
   13461              :     if (!(c->flags & MG_SOCKS_HANDSHAKE_DONE)) mg_socks5_handshake(c);
   13462              :     if (c->flags & MG_SOCKS_HANDSHAKE_DONE &&
   13463              :         !(c->flags & MG_SOCKS_CONNECT_DONE)) {
   13464              :       mg_socks5_handle_request(c);
   13465              :     }
   13466              :     if (c->flags & MG_SOCKS_CONNECT_DONE) relay_data(c);
   13467              :   } else if (ev == MG_EV_CLOSE) {
   13468              :     disband(c);
   13469              :   }
   13470              :   (void) ev_data;
   13471              : }
   13472              : 
   13473              : void mg_set_protocol_socks(struct mg_connection *c) {
   13474              :   c->proto_handler = socks_handler;
   13475              : }
   13476              : #endif
   13477              : #ifdef MG_MODULE_LINES
   13478              : #line 1 "common/platforms/cc3200/cc3200_libc.c"
   13479              : #endif
   13480              : /*
   13481              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   13482              :  * All rights reserved
   13483              :  *
   13484              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   13485              :  * you may not use this file except in compliance with the License.
   13486              :  * You may obtain a copy of the License at
   13487              :  *
   13488              :  *     http://www.apache.org/licenses/LICENSE-2.0
   13489              :  *
   13490              :  * Unless required by applicable law or agreed to in writing, software
   13491              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   13492              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13493              :  * See the License for the specific language governing permissions and
   13494              :  * limitations under the License.
   13495              :  */
   13496              : 
   13497              : #if CS_PLATFORM == CS_P_CC3200
   13498              : 
   13499              : /* Amalgamated: #include "common/mg_mem.h" */
   13500              : #include <stdio.h>
   13501              : #include <string.h>
   13502              : 
   13503              : #ifndef __TI_COMPILER_VERSION__
   13504              : #include <reent.h>
   13505              : #include <sys/stat.h>
   13506              : #include <sys/time.h>
   13507              : #include <unistd.h>
   13508              : #endif
   13509              : 
   13510              : #include <inc/hw_types.h>
   13511              : #include <inc/hw_memmap.h>
   13512              : #include <driverlib/prcm.h>
   13513              : #include <driverlib/rom.h>
   13514              : #include <driverlib/rom_map.h>
   13515              : #include <driverlib/uart.h>
   13516              : #include <driverlib/utils.h>
   13517              : 
   13518              : #define CONSOLE_UART UARTA0_BASE
   13519              : 
   13520              : #ifdef __TI_COMPILER_VERSION__
   13521              : int asprintf(char **strp, const char *fmt, ...) {
   13522              :   va_list ap;
   13523              :   int len;
   13524              : 
   13525              :   *strp = MG_MALLOC(BUFSIZ);
   13526              :   if (*strp == NULL) return -1;
   13527              : 
   13528              :   va_start(ap, fmt);
   13529              :   len = vsnprintf(*strp, BUFSIZ, fmt, ap);
   13530              :   va_end(ap);
   13531              : 
   13532              :   if (len > 0) {
   13533              :     *strp = MG_REALLOC(*strp, len + 1);
   13534              :     if (*strp == NULL) return -1;
   13535              :   }
   13536              : 
   13537              :   if (len >= BUFSIZ) {
   13538              :     va_start(ap, fmt);
   13539              :     len = vsnprintf(*strp, len + 1, fmt, ap);
   13540              :     va_end(ap);
   13541              :   }
   13542              : 
   13543              :   return len;
   13544              : }
   13545              : 
   13546              : #if MG_TI_NO_HOST_INTERFACE
   13547              : time_t HOSTtime() {
   13548              :   struct timeval tp;
   13549              :   gettimeofday(&tp, NULL);
   13550              :   return tp.tv_sec;
   13551              : }
   13552              : #endif
   13553              : 
   13554              : #endif /* __TI_COMPILER_VERSION__ */
   13555              : 
   13556              : void fprint_str(FILE *fp, const char *str) {
   13557              :   while (*str != '\0') {
   13558              :     if (*str == '\n') MAP_UARTCharPut(CONSOLE_UART, '\r');
   13559              :     MAP_UARTCharPut(CONSOLE_UART, *str++);
   13560              :   }
   13561              : }
   13562              : 
   13563              : void _exit(int status) {
   13564              :   fprint_str(stderr, "_exit\n");
   13565              :   /* cause an unaligned access exception, that will drop you into gdb */
   13566              :   *(int *) 1 = status;
   13567              :   while (1)
   13568              :     ; /* avoid gcc warning because stdlib abort() has noreturn attribute */
   13569              : }
   13570              : 
   13571              : void _not_implemented(const char *what) {
   13572              :   fprint_str(stderr, what);
   13573              :   fprint_str(stderr, " is not implemented\n");
   13574              :   _exit(42);
   13575              : }
   13576              : 
   13577              : int _kill(int pid, int sig) {
   13578              :   (void) pid;
   13579              :   (void) sig;
   13580              :   _not_implemented("_kill");
   13581              :   return -1;
   13582              : }
   13583              : 
   13584              : int _getpid() {
   13585              :   fprint_str(stderr, "_getpid is not implemented\n");
   13586              :   return 42;
   13587              : }
   13588              : 
   13589              : int _isatty(int fd) {
   13590              :   /* 0, 1 and 2 are TTYs. */
   13591              :   return fd < 2;
   13592              : }
   13593              : 
   13594              : #endif /* CS_PLATFORM == CS_P_CC3200 */
   13595              : #ifdef MG_MODULE_LINES
   13596              : #line 1 "common/platforms/msp432/msp432_libc.c"
   13597              : #endif
   13598              : /*
   13599              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   13600              :  * All rights reserved
   13601              :  *
   13602              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   13603              :  * you may not use this file except in compliance with the License.
   13604              :  * You may obtain a copy of the License at
   13605              :  *
   13606              :  *     http://www.apache.org/licenses/LICENSE-2.0
   13607              :  *
   13608              :  * Unless required by applicable law or agreed to in writing, software
   13609              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   13610              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13611              :  * See the License for the specific language governing permissions and
   13612              :  * limitations under the License.
   13613              :  */
   13614              : 
   13615              : #if CS_PLATFORM == CS_P_MSP432
   13616              : 
   13617              : #include <ti/sysbios/BIOS.h>
   13618              : #include <ti/sysbios/knl/Clock.h>
   13619              : 
   13620              : int gettimeofday(struct timeval *tp, void *tzp) {
   13621              :   uint32_t ticks = Clock_getTicks();
   13622              :   tp->tv_sec = ticks / 1000;
   13623              :   tp->tv_usec = (ticks % 1000) * 1000;
   13624              :   return 0;
   13625              : }
   13626              : 
   13627              : #endif /* CS_PLATFORM == CS_P_MSP432 */
   13628              : #ifdef MG_MODULE_LINES
   13629              : #line 1 "common/platforms/nrf5/nrf5_libc.c"
   13630              : #endif
   13631              : /*
   13632              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   13633              :  * All rights reserved
   13634              :  *
   13635              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   13636              :  * you may not use this file except in compliance with the License.
   13637              :  * You may obtain a copy of the License at
   13638              :  *
   13639              :  *     http://www.apache.org/licenses/LICENSE-2.0
   13640              :  *
   13641              :  * Unless required by applicable law or agreed to in writing, software
   13642              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   13643              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13644              :  * See the License for the specific language governing permissions and
   13645              :  * limitations under the License.
   13646              :  */
   13647              : 
   13648              : #if (CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52) && \
   13649              :     defined(__ARMCC_VERSION)
   13650              : int gettimeofday(struct timeval *tp, void *tzp) {
   13651              :   /* TODO */
   13652              :   tp->tv_sec = 0;
   13653              :   tp->tv_usec = 0;
   13654              :   return 0;
   13655              : }
   13656              : #endif
   13657              : #ifdef MG_MODULE_LINES
   13658              : #line 1 "common/platforms/simplelink/sl_fs_slfs.h"
   13659              : #endif
   13660              : /*
   13661              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   13662              :  * All rights reserved
   13663              :  *
   13664              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   13665              :  * you may not use this file except in compliance with the License.
   13666              :  * You may obtain a copy of the License at
   13667              :  *
   13668              :  *     http://www.apache.org/licenses/LICENSE-2.0
   13669              :  *
   13670              :  * Unless required by applicable law or agreed to in writing, software
   13671              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   13672              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13673              :  * See the License for the specific language governing permissions and
   13674              :  * limitations under the License.
   13675              :  */
   13676              : 
   13677              : #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
   13678              : #define CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
   13679              : 
   13680              : #if defined(MG_FS_SLFS)
   13681              : 
   13682              : #include <stdio.h>
   13683              : #ifndef __TI_COMPILER_VERSION__
   13684              : #include <unistd.h>
   13685              : #include <sys/stat.h>
   13686              : #endif
   13687              : 
   13688              : #define MAX_OPEN_SLFS_FILES 8
   13689              : 
   13690              : /* Indirect libc interface - same functions, different names. */
   13691              : int fs_slfs_open(const char *pathname, int flags, mode_t mode);
   13692              : int fs_slfs_close(int fd);
   13693              : ssize_t fs_slfs_read(int fd, void *buf, size_t count);
   13694              : ssize_t fs_slfs_write(int fd, const void *buf, size_t count);
   13695              : int fs_slfs_stat(const char *pathname, struct stat *s);
   13696              : int fs_slfs_fstat(int fd, struct stat *s);
   13697              : off_t fs_slfs_lseek(int fd, off_t offset, int whence);
   13698              : int fs_slfs_unlink(const char *filename);
   13699              : int fs_slfs_rename(const char *from, const char *to);
   13700              : 
   13701              : void fs_slfs_set_file_size(const char *name, size_t size);
   13702              : void fs_slfs_set_file_flags(const char *name, uint32_t flags, uint32_t *token);
   13703              : void fs_slfs_unset_file_flags(const char *name);
   13704              : 
   13705              : #endif /* defined(MG_FS_SLFS) */
   13706              : 
   13707              : #endif /* CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_ */
   13708              : #ifdef MG_MODULE_LINES
   13709              : #line 1 "common/platforms/simplelink/sl_fs_slfs.c"
   13710              : #endif
   13711              : /*
   13712              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   13713              :  * All rights reserved
   13714              :  *
   13715              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   13716              :  * you may not use this file except in compliance with the License.
   13717              :  * You may obtain a copy of the License at
   13718              :  *
   13719              :  *     http://www.apache.org/licenses/LICENSE-2.0
   13720              :  *
   13721              :  * Unless required by applicable law or agreed to in writing, software
   13722              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   13723              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13724              :  * See the License for the specific language governing permissions and
   13725              :  * limitations under the License.
   13726              :  */
   13727              : 
   13728              : /* Standard libc interface to TI SimpleLink FS. */
   13729              : 
   13730              : #if defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS)
   13731              : 
   13732              : /* Amalgamated: #include "common/platforms/simplelink/sl_fs_slfs.h" */
   13733              : 
   13734              : #include <errno.h>
   13735              : 
   13736              : #if CS_PLATFORM == CS_P_CC3200
   13737              : #include <inc/hw_types.h>
   13738              : #endif
   13739              : 
   13740              : /* Amalgamated: #include "common/cs_dbg.h" */
   13741              : /* Amalgamated: #include "common/mg_mem.h" */
   13742              : 
   13743              : #if SL_MAJOR_VERSION_NUM < 2
   13744              : int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token) {
   13745              :   _i32 fh;
   13746              :   _i32 r = sl_FsOpen(fname, flags, (unsigned long *) token, &fh);
   13747              :   return (r < 0 ? r : fh);
   13748              : }
   13749              : #else /* SL_MAJOR_VERSION_NUM >= 2 */
   13750              : int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token) {
   13751              :   return sl_FsOpen(fname, flags, (unsigned long *) token);
   13752              : }
   13753              : #endif
   13754              : 
   13755              : /* From sl_fs.c */
   13756              : int set_errno(int e);
   13757              : const char *drop_dir(const char *fname, bool *is_slfs);
   13758              : 
   13759              : /*
   13760              :  * With SLFS, you have to pre-declare max file size. Yes. Really.
   13761              :  * 64K should be enough for everyone. Right?
   13762              :  */
   13763              : #ifndef FS_SLFS_MAX_FILE_SIZE
   13764              : #define FS_SLFS_MAX_FILE_SIZE (64 * 1024)
   13765              : #endif
   13766              : 
   13767              : struct sl_file_open_info {
   13768              :   char *name;
   13769              :   size_t size;
   13770              :   uint32_t flags;
   13771              :   uint32_t *token;
   13772              : };
   13773              : 
   13774              : struct sl_fd_info {
   13775              :   _i32 fh;
   13776              :   _off_t pos;
   13777              :   size_t size;
   13778              : };
   13779              : 
   13780              : static struct sl_fd_info s_sl_fds[MAX_OPEN_SLFS_FILES];
   13781              : static struct sl_file_open_info s_sl_file_open_infos[MAX_OPEN_SLFS_FILES];
   13782              : 
   13783              : static struct sl_file_open_info *fs_slfs_find_foi(const char *name,
   13784              :                                                   bool create);
   13785              : 
   13786              : static int sl_fs_to_errno(_i32 r) {
   13787              :   DBG(("SL error: %d", (int) r));
   13788              :   switch (r) {
   13789              :     case SL_FS_OK:
   13790              :       return 0;
   13791              :     case SL_ERROR_FS_FILE_NAME_EXIST:
   13792              :       return EEXIST;
   13793              :     case SL_ERROR_FS_WRONG_FILE_NAME:
   13794              :       return EINVAL;
   13795              :     case SL_ERROR_FS_NO_AVAILABLE_NV_INDEX:
   13796              :     case SL_ERROR_FS_NOT_ENOUGH_STORAGE_SPACE:
   13797              :       return ENOSPC;
   13798              :     case SL_ERROR_FS_FAILED_TO_ALLOCATE_MEM:
   13799              :       return ENOMEM;
   13800              :     case SL_ERROR_FS_FILE_NOT_EXISTS:
   13801              :       return ENOENT;
   13802              :     case SL_ERROR_FS_NOT_SUPPORTED:
   13803              :       return ENOTSUP;
   13804              :   }
   13805              :   return ENXIO;
   13806              : }
   13807              : 
   13808              : int fs_slfs_open(const char *pathname, int flags, mode_t mode) {
   13809              :   int fd;
   13810              :   for (fd = 0; fd < MAX_OPEN_SLFS_FILES; fd++) {
   13811              :     if (s_sl_fds[fd].fh <= 0) break;
   13812              :   }
   13813              :   if (fd >= MAX_OPEN_SLFS_FILES) return set_errno(ENOMEM);
   13814              :   struct sl_fd_info *fi = &s_sl_fds[fd];
   13815              : 
   13816              :   /*
   13817              :    * Apply path manipulations again, in case we got here directly
   13818              :    * (via TI libc's "add_device").
   13819              :    */
   13820              :   pathname = drop_dir(pathname, NULL);
   13821              : 
   13822              :   _u32 am = 0;
   13823              :   fi->size = (size_t) -1;
   13824              :   int rw = (flags & 3);
   13825              :   size_t new_size = 0;
   13826              :   struct sl_file_open_info *foi =
   13827              :       fs_slfs_find_foi(pathname, false /* create */);
   13828              :   if (foi != NULL) {
   13829              :     LOG(LL_DEBUG, ("FOI for %s: %d 0x%x %p", pathname, (int) foi->size,
   13830              :                    (unsigned int) foi->flags, foi->token));
   13831              :   }
   13832              :   if (rw == O_RDONLY) {
   13833              :     SlFsFileInfo_t sl_fi;
   13834              :     _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
   13835              :     if (r == SL_FS_OK) {
   13836              :       fi->size = SL_FI_FILE_SIZE(sl_fi);
   13837              :     }
   13838              :     am = SL_FS_READ;
   13839              :   } else {
   13840              :     if (!(flags & O_TRUNC) || (flags & O_APPEND)) {
   13841              :       // FailFS files cannot be opened for append and will be truncated
   13842              :       // when opened for write.
   13843              :       return set_errno(ENOTSUP);
   13844              :     }
   13845              :     if (flags & O_CREAT) {
   13846              :       if (foi->size > 0) {
   13847              :         new_size = foi->size;
   13848              :       } else {
   13849              :         new_size = FS_SLFS_MAX_FILE_SIZE;
   13850              :       }
   13851              :       am = FS_MODE_OPEN_CREATE(new_size, 0);
   13852              :     } else {
   13853              :       am = SL_FS_WRITE;
   13854              :     }
   13855              : #if SL_MAJOR_VERSION_NUM >= 2
   13856              :     am |= SL_FS_OVERWRITE;
   13857              : #endif
   13858              :   }
   13859              :   uint32_t *token = NULL;
   13860              :   if (foi != NULL) {
   13861              :     am |= foi->flags;
   13862              :     token = foi->token;
   13863              :   }
   13864              :   fi->fh = slfs_open((_u8 *) pathname, am, token);
   13865              :   LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x, %p) sz %u = %d", pathname, (int) am,
   13866              :                  token, (unsigned int) new_size, (int) fi->fh));
   13867              :   int r;
   13868              :   if (fi->fh >= 0) {
   13869              :     fi->pos = 0;
   13870              :     r = fd;
   13871              :   } else {
   13872              :     r = set_errno(sl_fs_to_errno(fi->fh));
   13873              :   }
   13874              :   return r;
   13875              : }
   13876              : 
   13877              : int fs_slfs_close(int fd) {
   13878              :   struct sl_fd_info *fi = &s_sl_fds[fd];
   13879              :   if (fi->fh <= 0) return set_errno(EBADF);
   13880              :   _i32 r = sl_FsClose(fi->fh, NULL, NULL, 0);
   13881              :   LOG(LL_DEBUG, ("sl_FsClose(%d) = %d", (int) fi->fh, (int) r));
   13882              :   s_sl_fds[fd].fh = -1;
   13883              :   return set_errno(sl_fs_to_errno(r));
   13884              : }
   13885              : 
   13886              : ssize_t fs_slfs_read(int fd, void *buf, size_t count) {
   13887              :   struct sl_fd_info *fi = &s_sl_fds[fd];
   13888              :   if (fi->fh <= 0) return set_errno(EBADF);
   13889              :   /* Simulate EOF. sl_FsRead @ file_size return SL_FS_ERR_OFFSET_OUT_OF_RANGE.
   13890              :    */
   13891              :   if (fi->pos == fi->size) return 0;
   13892              :   _i32 r = sl_FsRead(fi->fh, fi->pos, buf, count);
   13893              :   DBG(("sl_FsRead(%d, %d, %d) = %d", (int) fi->fh, (int) fi->pos, (int) count,
   13894              :        (int) r));
   13895              :   if (r >= 0) {
   13896              :     fi->pos += r;
   13897              :     return r;
   13898              :   }
   13899              :   return set_errno(sl_fs_to_errno(r));
   13900              : }
   13901              : 
   13902              : ssize_t fs_slfs_write(int fd, const void *buf, size_t count) {
   13903              :   struct sl_fd_info *fi = &s_sl_fds[fd];
   13904              :   if (fi->fh <= 0) return set_errno(EBADF);
   13905              :   _i32 r = sl_FsWrite(fi->fh, fi->pos, (_u8 *) buf, count);
   13906              :   DBG(("sl_FsWrite(%d, %d, %d) = %d", (int) fi->fh, (int) fi->pos, (int) count,
   13907              :        (int) r));
   13908              :   if (r >= 0) {
   13909              :     fi->pos += r;
   13910              :     return r;
   13911              :   }
   13912              :   return set_errno(sl_fs_to_errno(r));
   13913              : }
   13914              : 
   13915              : int fs_slfs_stat(const char *pathname, struct stat *s) {
   13916              :   SlFsFileInfo_t sl_fi;
   13917              :   /*
   13918              :    * Apply path manipulations again, in case we got here directly
   13919              :    * (via TI libc's "add_device").
   13920              :    */
   13921              :   pathname = drop_dir(pathname, NULL);
   13922              :   _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
   13923              :   if (r == SL_FS_OK) {
   13924              :     s->st_mode = S_IFREG | 0666;
   13925              :     s->st_nlink = 1;
   13926              :     s->st_size = SL_FI_FILE_SIZE(sl_fi);
   13927              :     return 0;
   13928              :   }
   13929              :   return set_errno(sl_fs_to_errno(r));
   13930              : }
   13931              : 
   13932              : int fs_slfs_fstat(int fd, struct stat *s) {
   13933              :   struct sl_fd_info *fi = &s_sl_fds[fd];
   13934              :   if (fi->fh <= 0) return set_errno(EBADF);
   13935              :   s->st_mode = 0666;
   13936              :   s->st_mode = S_IFREG | 0666;
   13937              :   s->st_nlink = 1;
   13938              :   s->st_size = fi->size;
   13939              :   return 0;
   13940              : }
   13941              : 
   13942              : off_t fs_slfs_lseek(int fd, off_t offset, int whence) {
   13943              :   if (s_sl_fds[fd].fh <= 0) return set_errno(EBADF);
   13944              :   switch (whence) {
   13945              :     case SEEK_SET:
   13946              :       s_sl_fds[fd].pos = offset;
   13947              :       break;
   13948              :     case SEEK_CUR:
   13949              :       s_sl_fds[fd].pos += offset;
   13950              :       break;
   13951              :     case SEEK_END:
   13952              :       return set_errno(ENOTSUP);
   13953              :   }
   13954              :   return 0;
   13955              : }
   13956              : 
   13957              : int fs_slfs_unlink(const char *pathname) {
   13958              :   /*
   13959              :    * Apply path manipulations again, in case we got here directly
   13960              :    * (via TI libc's "add_device").
   13961              :    */
   13962              :   pathname = drop_dir(pathname, NULL);
   13963              :   return set_errno(sl_fs_to_errno(sl_FsDel((const _u8 *) pathname, 0)));
   13964              : }
   13965              : 
   13966              : int fs_slfs_rename(const char *from, const char *to) {
   13967              :   return set_errno(ENOTSUP);
   13968              : }
   13969              : 
   13970              : static struct sl_file_open_info *fs_slfs_find_foi(const char *name,
   13971              :                                                   bool create) {
   13972              :   int i = 0;
   13973              :   for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
   13974              :     if (s_sl_file_open_infos[i].name != NULL &&
   13975              :         strcmp(drop_dir(s_sl_file_open_infos[i].name, NULL), name) == 0) {
   13976              :       break;
   13977              :     }
   13978              :   }
   13979              :   if (i != MAX_OPEN_SLFS_FILES) return &s_sl_file_open_infos[i];
   13980              :   if (!create) return NULL;
   13981              :   for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
   13982              :     if (s_sl_file_open_infos[i].name == NULL) break;
   13983              :   }
   13984              :   if (i == MAX_OPEN_SLFS_FILES) {
   13985              :     i = 0; /* Evict a random slot. */
   13986              :   }
   13987              :   if (s_sl_file_open_infos[i].name != NULL) {
   13988              :     free(s_sl_file_open_infos[i].name);
   13989              :   }
   13990              :   s_sl_file_open_infos[i].name = strdup(name);
   13991              :   return &s_sl_file_open_infos[i];
   13992              : }
   13993              : 
   13994              : void fs_slfs_set_file_size(const char *name, size_t size) {
   13995              :   struct sl_file_open_info *foi = fs_slfs_find_foi(name, true /* create */);
   13996              :   foi->size = size;
   13997              : }
   13998              : 
   13999              : void fs_slfs_set_file_flags(const char *name, uint32_t flags, uint32_t *token) {
   14000              :   struct sl_file_open_info *foi = fs_slfs_find_foi(name, true /* create */);
   14001              :   foi->flags = flags;
   14002              :   foi->token = token;
   14003              : }
   14004              : 
   14005              : void fs_slfs_unset_file_flags(const char *name) {
   14006              :   struct sl_file_open_info *foi = fs_slfs_find_foi(name, false /* create */);
   14007              :   if (foi == NULL) return;
   14008              :   free(foi->name);
   14009              :   memset(foi, 0, sizeof(*foi));
   14010              : }
   14011              : 
   14012              : #endif /* defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS) */
   14013              : #ifdef MG_MODULE_LINES
   14014              : #line 1 "common/platforms/simplelink/sl_fs.c"
   14015              : #endif
   14016              : /*
   14017              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   14018              :  * All rights reserved
   14019              :  *
   14020              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   14021              :  * you may not use this file except in compliance with the License.
   14022              :  * You may obtain a copy of the License at
   14023              :  *
   14024              :  *     http://www.apache.org/licenses/LICENSE-2.0
   14025              :  *
   14026              :  * Unless required by applicable law or agreed to in writing, software
   14027              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   14028              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14029              :  * See the License for the specific language governing permissions and
   14030              :  * limitations under the License.
   14031              :  */
   14032              : 
   14033              : #if MG_NET_IF == MG_NET_IF_SIMPLELINK && \
   14034              :     (defined(MG_FS_SLFS) || defined(MG_FS_SPIFFS))
   14035              : 
   14036              : int set_errno(int e) {
   14037              :   errno = e;
   14038              :   return (e == 0 ? 0 : -1);
   14039              : }
   14040              : 
   14041              : const char *drop_dir(const char *fname, bool *is_slfs) {
   14042              :   if (is_slfs != NULL) {
   14043              :     *is_slfs = (strncmp(fname, "SL:", 3) == 0);
   14044              :     if (*is_slfs) fname += 3;
   14045              :   }
   14046              :   /* Drop "./", if any */
   14047              :   if (fname[0] == '.' && fname[1] == '/') {
   14048              :     fname += 2;
   14049              :   }
   14050              :   /*
   14051              :    * Drop / if it is the only one in the path.
   14052              :    * This allows use of /pretend/directories but serves /file.txt as normal.
   14053              :    */
   14054              :   if (fname[0] == '/' && strchr(fname + 1, '/') == NULL) {
   14055              :     fname++;
   14056              :   }
   14057              :   return fname;
   14058              : }
   14059              : 
   14060              : #if !defined(MG_FS_NO_VFS)
   14061              : 
   14062              : #include <errno.h>
   14063              : #include <stdbool.h>
   14064              : #include <stdio.h>
   14065              : #include <stdlib.h>
   14066              : #include <string.h>
   14067              : #ifdef __TI_COMPILER_VERSION__
   14068              : #include <file.h>
   14069              : #endif
   14070              : 
   14071              : /* Amalgamated: #include "common/cs_dbg.h" */
   14072              : /* Amalgamated: #include "common/platform.h" */
   14073              : 
   14074              : #ifdef CC3200_FS_SPIFFS
   14075              : /* Amalgamated: #include "cc3200_fs_spiffs.h" */
   14076              : #endif
   14077              : 
   14078              : #ifdef MG_FS_SLFS
   14079              : /* Amalgamated: #include "sl_fs_slfs.h" */
   14080              : #endif
   14081              : 
   14082              : #define NUM_SYS_FDS 3
   14083              : #define SPIFFS_FD_BASE 10
   14084              : #define SLFS_FD_BASE 100
   14085              : 
   14086              : #if !defined(MG_UART_CHAR_PUT) && !defined(MG_UART_WRITE)
   14087              : #if CS_PLATFORM == CS_P_CC3200
   14088              : #include <inc/hw_types.h>
   14089              : #include <inc/hw_memmap.h>
   14090              : #include <driverlib/rom.h>
   14091              : #include <driverlib/rom_map.h>
   14092              : #include <driverlib/uart.h>
   14093              : #define MG_UART_CHAR_PUT(fd, c) MAP_UARTCharPut(UARTA0_BASE, c);
   14094              : #else
   14095              : #define MG_UART_WRITE(fd, buf, len)
   14096              : #endif /* CS_PLATFORM == CS_P_CC3200 */
   14097              : #endif /* !MG_UART_CHAR_PUT */
   14098              : 
   14099              : enum fd_type {
   14100              :   FD_INVALID,
   14101              :   FD_SYS,
   14102              : #ifdef CC3200_FS_SPIFFS
   14103              :   FD_SPIFFS,
   14104              : #endif
   14105              : #ifdef MG_FS_SLFS
   14106              :   FD_SLFS
   14107              : #endif
   14108              : };
   14109              : static int fd_type(int fd) {
   14110              :   if (fd >= 0 && fd < NUM_SYS_FDS) return FD_SYS;
   14111              : #ifdef CC3200_FS_SPIFFS
   14112              :   if (fd >= SPIFFS_FD_BASE && fd < SPIFFS_FD_BASE + MAX_OPEN_SPIFFS_FILES) {
   14113              :     return FD_SPIFFS;
   14114              :   }
   14115              : #endif
   14116              : #ifdef MG_FS_SLFS
   14117              :   if (fd >= SLFS_FD_BASE && fd < SLFS_FD_BASE + MAX_OPEN_SLFS_FILES) {
   14118              :     return FD_SLFS;
   14119              :   }
   14120              : #endif
   14121              :   return FD_INVALID;
   14122              : }
   14123              : 
   14124              : #if MG_TI_NO_HOST_INTERFACE
   14125              : int open(const char *pathname, unsigned flags, int mode) {
   14126              : #else
   14127              : int _open(const char *pathname, int flags, mode_t mode) {
   14128              : #endif
   14129              :   int fd = -1;
   14130              :   bool is_sl;
   14131              :   const char *fname = drop_dir(pathname, &is_sl);
   14132              :   if (is_sl) {
   14133              : #ifdef MG_FS_SLFS
   14134              :     fd = fs_slfs_open(fname, flags, mode);
   14135              :     if (fd >= 0) fd += SLFS_FD_BASE;
   14136              : #endif
   14137              :   } else {
   14138              : #ifdef CC3200_FS_SPIFFS
   14139              :     fd = fs_spiffs_open(fname, flags, mode);
   14140              :     if (fd >= 0) fd += SPIFFS_FD_BASE;
   14141              : #endif
   14142              :   }
   14143              :   LOG(LL_DEBUG,
   14144              :       ("open(%s, 0x%x) = %d, fname = %s", pathname, flags, fd, fname));
   14145              :   return fd;
   14146              : }
   14147              : 
   14148              : int _stat(const char *pathname, struct stat *st) {
   14149              :   int res = -1;
   14150              :   bool is_sl;
   14151              :   const char *fname = drop_dir(pathname, &is_sl);
   14152              :   memset(st, 0, sizeof(*st));
   14153              :   /* Simulate statting the root directory. */
   14154              :   if (fname[0] == '\0' || strcmp(fname, ".") == 0) {
   14155              :     st->st_ino = 0;
   14156              :     st->st_mode = S_IFDIR | 0777;
   14157              :     st->st_nlink = 1;
   14158              :     st->st_size = 0;
   14159              :     return 0;
   14160              :   }
   14161              :   if (is_sl) {
   14162              : #ifdef MG_FS_SLFS
   14163              :     res = fs_slfs_stat(fname, st);
   14164              : #endif
   14165              :   } else {
   14166              : #ifdef CC3200_FS_SPIFFS
   14167              :     res = fs_spiffs_stat(fname, st);
   14168              : #endif
   14169              :   }
   14170              :   LOG(LL_DEBUG, ("stat(%s) = %d; fname = %s", pathname, res, fname));
   14171              :   return res;
   14172              : }
   14173              : 
   14174              : #if MG_TI_NO_HOST_INTERFACE
   14175              : int close(int fd) {
   14176              : #else
   14177              : int _close(int fd) {
   14178              : #endif
   14179              :   int r = -1;
   14180              :   switch (fd_type(fd)) {
   14181              :     case FD_INVALID:
   14182              :       r = set_errno(EBADF);
   14183              :       break;
   14184              :     case FD_SYS:
   14185              :       r = set_errno(EACCES);
   14186              :       break;
   14187              : #ifdef CC3200_FS_SPIFFS
   14188              :     case FD_SPIFFS:
   14189              :       r = fs_spiffs_close(fd - SPIFFS_FD_BASE);
   14190              :       break;
   14191              : #endif
   14192              : #ifdef MG_FS_SLFS
   14193              :     case FD_SLFS:
   14194              :       r = fs_slfs_close(fd - SLFS_FD_BASE);
   14195              :       break;
   14196              : #endif
   14197              :   }
   14198              :   DBG(("close(%d) = %d", fd, r));
   14199              :   return r;
   14200              : }
   14201              : 
   14202              : #if MG_TI_NO_HOST_INTERFACE
   14203              : off_t lseek(int fd, off_t offset, int whence) {
   14204              : #else
   14205              : off_t _lseek(int fd, off_t offset, int whence) {
   14206              : #endif
   14207              :   int r = -1;
   14208              :   switch (fd_type(fd)) {
   14209              :     case FD_INVALID:
   14210              :       r = set_errno(EBADF);
   14211              :       break;
   14212              :     case FD_SYS:
   14213              :       r = set_errno(ESPIPE);
   14214              :       break;
   14215              : #ifdef CC3200_FS_SPIFFS
   14216              :     case FD_SPIFFS:
   14217              :       r = fs_spiffs_lseek(fd - SPIFFS_FD_BASE, offset, whence);
   14218              :       break;
   14219              : #endif
   14220              : #ifdef MG_FS_SLFS
   14221              :     case FD_SLFS:
   14222              :       r = fs_slfs_lseek(fd - SLFS_FD_BASE, offset, whence);
   14223              :       break;
   14224              : #endif
   14225              :   }
   14226              :   DBG(("lseek(%d, %d, %d) = %d", fd, (int) offset, whence, r));
   14227              :   return r;
   14228              : }
   14229              : 
   14230              : int _fstat(int fd, struct stat *s) {
   14231              :   int r = -1;
   14232              :   memset(s, 0, sizeof(*s));
   14233              :   switch (fd_type(fd)) {
   14234              :     case FD_INVALID:
   14235              :       r = set_errno(EBADF);
   14236              :       break;
   14237              :     case FD_SYS: {
   14238              :       /* Create barely passable stats for STD{IN,OUT,ERR}. */
   14239              :       memset(s, 0, sizeof(*s));
   14240              :       s->st_ino = fd;
   14241              :       s->st_mode = S_IFCHR | 0666;
   14242              :       r = 0;
   14243              :       break;
   14244              :     }
   14245              : #ifdef CC3200_FS_SPIFFS
   14246              :     case FD_SPIFFS:
   14247              :       r = fs_spiffs_fstat(fd - SPIFFS_FD_BASE, s);
   14248              :       break;
   14249              : #endif
   14250              : #ifdef MG_FS_SLFS
   14251              :     case FD_SLFS:
   14252              :       r = fs_slfs_fstat(fd - SLFS_FD_BASE, s);
   14253              :       break;
   14254              : #endif
   14255              :   }
   14256              :   DBG(("fstat(%d) = %d", fd, r));
   14257              :   return r;
   14258              : }
   14259              : 
   14260              : #if MG_TI_NO_HOST_INTERFACE
   14261              : int read(int fd, char *buf, unsigned count) {
   14262              : #else
   14263              : ssize_t _read(int fd, void *buf, size_t count) {
   14264              : #endif
   14265              :   int r = -1;
   14266              :   switch (fd_type(fd)) {
   14267              :     case FD_INVALID:
   14268              :       r = set_errno(EBADF);
   14269              :       break;
   14270              :     case FD_SYS: {
   14271              :       if (fd != 0) {
   14272              :         r = set_errno(EACCES);
   14273              :         break;
   14274              :       }
   14275              :       /* Should we allow reading from stdin = uart? */
   14276              :       r = set_errno(ENOTSUP);
   14277              :       break;
   14278              :     }
   14279              : #ifdef CC3200_FS_SPIFFS
   14280              :     case FD_SPIFFS:
   14281              :       r = fs_spiffs_read(fd - SPIFFS_FD_BASE, buf, count);
   14282              :       break;
   14283              : #endif
   14284              : #ifdef MG_FS_SLFS
   14285              :     case FD_SLFS:
   14286              :       r = fs_slfs_read(fd - SLFS_FD_BASE, buf, count);
   14287              :       break;
   14288              : #endif
   14289              :   }
   14290              :   DBG(("read(%d, %u) = %d", fd, count, r));
   14291              :   return r;
   14292              : }
   14293              : 
   14294              : #if MG_TI_NO_HOST_INTERFACE
   14295              : int write(int fd, const char *buf, unsigned count) {
   14296              : #else
   14297              : ssize_t _write(int fd, const void *buf, size_t count) {
   14298              : #endif
   14299              :   int r = -1;
   14300              :   switch (fd_type(fd)) {
   14301              :     case FD_INVALID:
   14302              :       r = set_errno(EBADF);
   14303              :       break;
   14304              :     case FD_SYS: {
   14305              :       if (fd == 0) {
   14306              :         r = set_errno(EACCES);
   14307              :         break;
   14308              :       }
   14309              : #ifdef MG_UART_WRITE
   14310              :       MG_UART_WRITE(fd, buf, count);
   14311              : #elif defined(MG_UART_CHAR_PUT)
   14312              :       {
   14313              :         size_t i;
   14314              :         for (i = 0; i < count; i++) {
   14315              :           const char c = ((const char *) buf)[i];
   14316              :           if (c == '\n') MG_UART_CHAR_PUT(fd, '\r');
   14317              :           MG_UART_CHAR_PUT(fd, c);
   14318              :         }
   14319              :       }
   14320              : #endif
   14321              :       r = count;
   14322              :       break;
   14323              :     }
   14324              : #ifdef CC3200_FS_SPIFFS
   14325              :     case FD_SPIFFS:
   14326              :       r = fs_spiffs_write(fd - SPIFFS_FD_BASE, buf, count);
   14327              :       break;
   14328              : #endif
   14329              : #ifdef MG_FS_SLFS
   14330              :     case FD_SLFS:
   14331              :       r = fs_slfs_write(fd - SLFS_FD_BASE, buf, count);
   14332              :       break;
   14333              : #endif
   14334              :   }
   14335              :   return r;
   14336              : }
   14337              : 
   14338              : /*
   14339              :  * On Newlib we override rename directly too, because the default
   14340              :  * implementation using _link and _unlink doesn't work for us.
   14341              :  */
   14342              : #if MG_TI_NO_HOST_INTERFACE || defined(_NEWLIB_VERSION)
   14343              : int rename(const char *frompath, const char *topath) {
   14344              :   int r = -1;
   14345              :   bool is_sl_from, is_sl_to;
   14346              :   const char *from = drop_dir(frompath, &is_sl_from);
   14347              :   const char *to = drop_dir(topath, &is_sl_to);
   14348              :   if (is_sl_from || is_sl_to) {
   14349              :     set_errno(ENOTSUP);
   14350              :   } else {
   14351              : #ifdef CC3200_FS_SPIFFS
   14352              :     r = fs_spiffs_rename(from, to);
   14353              : #endif
   14354              :   }
   14355              :   DBG(("rename(%s, %s) = %d", from, to, r));
   14356              :   return r;
   14357              : }
   14358              : #endif /* MG_TI_NO_HOST_INTERFACE || defined(_NEWLIB_VERSION) */
   14359              : 
   14360              : #if MG_TI_NO_HOST_INTERFACE
   14361              : int unlink(const char *pathname) {
   14362              : #else
   14363              : int _unlink(const char *pathname) {
   14364              : #endif
   14365              :   int r = -1;
   14366              :   bool is_sl;
   14367              :   const char *fname = drop_dir(pathname, &is_sl);
   14368              :   if (is_sl) {
   14369              : #ifdef MG_FS_SLFS
   14370              :     r = fs_slfs_unlink(fname);
   14371              : #endif
   14372              :   } else {
   14373              : #ifdef CC3200_FS_SPIFFS
   14374              :     r = fs_spiffs_unlink(fname);
   14375              : #endif
   14376              :   }
   14377              :   DBG(("unlink(%s) = %d, fname = %s", pathname, r, fname));
   14378              :   return r;
   14379              : }
   14380              : 
   14381              : #ifdef CC3200_FS_SPIFFS /* FailFS does not support listing files. */
   14382              : DIR *opendir(const char *dir_name) {
   14383              :   DIR *r = NULL;
   14384              :   bool is_sl;
   14385              :   drop_dir(dir_name, &is_sl);
   14386              :   if (is_sl) {
   14387              :     r = NULL;
   14388              :     set_errno(ENOTSUP);
   14389              :   } else {
   14390              :     r = fs_spiffs_opendir(dir_name);
   14391              :   }
   14392              :   DBG(("opendir(%s) = %p", dir_name, r));
   14393              :   return r;
   14394              : }
   14395              : 
   14396              : struct dirent *readdir(DIR *dir) {
   14397              :   struct dirent *res = fs_spiffs_readdir(dir);
   14398              :   DBG(("readdir(%p) = %p", dir, res));
   14399              :   return res;
   14400              : }
   14401              : 
   14402              : int closedir(DIR *dir) {
   14403              :   int res = fs_spiffs_closedir(dir);
   14404              :   DBG(("closedir(%p) = %d", dir, res));
   14405              :   return res;
   14406              : }
   14407              : 
   14408              : int rmdir(const char *path) {
   14409              :   return fs_spiffs_rmdir(path);
   14410              : }
   14411              : 
   14412              : int mkdir(const char *path, mode_t mode) {
   14413              :   (void) path;
   14414              :   (void) mode;
   14415              :   /* for spiffs supports only root dir, which comes from mongoose as '.' */
   14416              :   return (strlen(path) == 1 && *path == '.') ? 0 : ENOTDIR;
   14417              : }
   14418              : #endif
   14419              : 
   14420              : int sl_fs_init(void) {
   14421              :   int ret = 1;
   14422              : #ifdef __TI_COMPILER_VERSION__
   14423              : #ifdef MG_FS_SLFS
   14424              : #pragma diag_push
   14425              : #pragma diag_suppress 169 /* Nothing we can do about the prototype mismatch. \
   14426              :                              */
   14427              :   ret = (add_device("SL", _MSA, fs_slfs_open, fs_slfs_close, fs_slfs_read,
   14428              :                     fs_slfs_write, fs_slfs_lseek, fs_slfs_unlink,
   14429              :                     fs_slfs_rename) == 0);
   14430              : #pragma diag_pop
   14431              : #endif
   14432              : #endif
   14433              :   return ret;
   14434              : }
   14435              : 
   14436              : #endif /* !defined(MG_FS_NO_VFS) */
   14437              : #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && (defined(MG_FS_SLFS) || \
   14438              :           defined(MG_FS_SPIFFS)) */
   14439              : #ifdef MG_MODULE_LINES
   14440              : #line 1 "common/platforms/simplelink/sl_socket.c"
   14441              : #endif
   14442              : /*
   14443              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   14444              :  * All rights reserved
   14445              :  *
   14446              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   14447              :  * you may not use this file except in compliance with the License.
   14448              :  * You may obtain a copy of the License at
   14449              :  *
   14450              :  *     http://www.apache.org/licenses/LICENSE-2.0
   14451              :  *
   14452              :  * Unless required by applicable law or agreed to in writing, software
   14453              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   14454              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14455              :  * See the License for the specific language governing permissions and
   14456              :  * limitations under the License.
   14457              :  */
   14458              : 
   14459              : #if MG_NET_IF == MG_NET_IF_SIMPLELINK
   14460              : 
   14461              : #include <errno.h>
   14462              : #include <stdio.h>
   14463              : 
   14464              : /* Amalgamated: #include "common/platform.h" */
   14465              : 
   14466              : const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) {
   14467              :   int res;
   14468              :   struct in_addr *in = (struct in_addr *) src;
   14469              :   if (af != AF_INET) {
   14470              :     errno = ENOTSUP;
   14471              :     return NULL;
   14472              :   }
   14473              :   res = snprintf(dst, size, "%lu.%lu.%lu.%lu", SL_IPV4_BYTE(in->s_addr, 0),
   14474              :                  SL_IPV4_BYTE(in->s_addr, 1), SL_IPV4_BYTE(in->s_addr, 2),
   14475              :                  SL_IPV4_BYTE(in->s_addr, 3));
   14476              :   return res > 0 ? dst : NULL;
   14477              : }
   14478              : 
   14479              : char *inet_ntoa(struct in_addr n) {
   14480              :   static char a[16];
   14481              :   return (char *) inet_ntop(AF_INET, &n, a, sizeof(a));
   14482              : }
   14483              : 
   14484              : int inet_pton(int af, const char *src, void *dst) {
   14485              :   uint32_t a0, a1, a2, a3;
   14486              :   uint8_t *db = (uint8_t *) dst;
   14487              :   if (af != AF_INET) {
   14488              :     errno = ENOTSUP;
   14489              :     return 0;
   14490              :   }
   14491              :   if (sscanf(src, "%lu.%lu.%lu.%lu", &a0, &a1, &a2, &a3) != 4) {
   14492              :     return 0;
   14493              :   }
   14494              :   *db = a3;
   14495              :   *(db + 1) = a2;
   14496              :   *(db + 2) = a1;
   14497              :   *(db + 3) = a0;
   14498              :   return 1;
   14499              : }
   14500              : 
   14501              : #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */
   14502              : #ifdef MG_MODULE_LINES
   14503              : #line 1 "common/platforms/simplelink/sl_mg_task.c"
   14504              : #endif
   14505              : #if MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(MG_SIMPLELINK_NO_OSI)
   14506              : 
   14507              : /* Amalgamated: #include "mg_task.h" */
   14508              : 
   14509              : #include <oslib/osi.h>
   14510              : 
   14511              : enum mg_q_msg_type {
   14512              :   MG_Q_MSG_CB,
   14513              : };
   14514              : struct mg_q_msg {
   14515              :   enum mg_q_msg_type type;
   14516              :   void (*cb)(struct mg_mgr *mgr, void *arg);
   14517              :   void *arg;
   14518              : };
   14519              : static OsiMsgQ_t s_mg_q;
   14520              : static void mg_task(void *arg);
   14521              : 
   14522              : bool mg_start_task(int priority, int stack_size, mg_init_cb mg_init) {
   14523              :   if (osi_MsgQCreate(&s_mg_q, "MG", sizeof(struct mg_q_msg), 16) != OSI_OK) {
   14524              :     return false;
   14525              :   }
   14526              :   if (osi_TaskCreate(mg_task, (const signed char *) "MG", stack_size,
   14527              :                      (void *) mg_init, priority, NULL) != OSI_OK) {
   14528              :     return false;
   14529              :   }
   14530              :   return true;
   14531              : }
   14532              : 
   14533              : static void mg_task(void *arg) {
   14534              :   struct mg_mgr mgr;
   14535              :   mg_init_cb mg_init = (mg_init_cb) arg;
   14536              :   mg_mgr_init(&mgr, NULL);
   14537              :   mg_init(&mgr);
   14538              :   while (1) {
   14539              :     struct mg_q_msg msg;
   14540              :     mg_mgr_poll(&mgr, 1);
   14541              :     if (osi_MsgQRead(&s_mg_q, &msg, 1) != OSI_OK) continue;
   14542              :     switch (msg.type) {
   14543              :       case MG_Q_MSG_CB: {
   14544              :         msg.cb(&mgr, msg.arg);
   14545              :       }
   14546              :     }
   14547              :   }
   14548              : }
   14549              : 
   14550              : void mg_run_in_task(void (*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg) {
   14551              :   struct mg_q_msg msg = {MG_Q_MSG_CB, cb, cb_arg};
   14552              :   osi_MsgQWrite(&s_mg_q, &msg, OSI_NO_WAIT);
   14553              : }
   14554              : 
   14555              : #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(MG_SIMPLELINK_NO_OSI) \
   14556              :           */
   14557              : #ifdef MG_MODULE_LINES
   14558              : #line 1 "common/platforms/simplelink/sl_net_if.h"
   14559              : #endif
   14560              : /*
   14561              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   14562              :  * All rights reserved
   14563              :  *
   14564              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   14565              :  * you may not use this file except in compliance with the License.
   14566              :  * You may obtain a copy of the License at
   14567              :  *
   14568              :  *     http://www.apache.org/licenses/LICENSE-2.0
   14569              :  *
   14570              :  * Unless required by applicable law or agreed to in writing, software
   14571              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   14572              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14573              :  * See the License for the specific language governing permissions and
   14574              :  * limitations under the License.
   14575              :  */
   14576              : 
   14577              : #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_
   14578              : #define CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_
   14579              : 
   14580              : /* Amalgamated: #include "mongoose/src/net_if.h" */
   14581              : 
   14582              : #ifdef __cplusplus
   14583              : extern "C" {
   14584              : #endif /* __cplusplus */
   14585              : 
   14586              : #ifndef MG_ENABLE_NET_IF_SIMPLELINK
   14587              : #define MG_ENABLE_NET_IF_SIMPLELINK MG_NET_IF == MG_NET_IF_SIMPLELINK
   14588              : #endif
   14589              : 
   14590              : extern const struct mg_iface_vtable mg_simplelink_iface_vtable;
   14591              : 
   14592              : #ifdef __cplusplus
   14593              : }
   14594              : #endif /* __cplusplus */
   14595              : 
   14596              : #endif /* CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_ */
   14597              : #ifdef MG_MODULE_LINES
   14598              : #line 1 "common/platforms/simplelink/sl_net_if.c"
   14599              : #endif
   14600              : /*
   14601              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   14602              :  * All rights reserved
   14603              :  *
   14604              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   14605              :  * you may not use this file except in compliance with the License.
   14606              :  * You may obtain a copy of the License at
   14607              :  *
   14608              :  *     http://www.apache.org/licenses/LICENSE-2.0
   14609              :  *
   14610              :  * Unless required by applicable law or agreed to in writing, software
   14611              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   14612              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14613              :  * See the License for the specific language governing permissions and
   14614              :  * limitations under the License.
   14615              :  */
   14616              : 
   14617              : /* Amalgamated: #include "common/platforms/simplelink/sl_net_if.h" */
   14618              : 
   14619              : #if MG_ENABLE_NET_IF_SIMPLELINK
   14620              : 
   14621              : /* Amalgamated: #include "mongoose/src/internal.h" */
   14622              : /* Amalgamated: #include "mongoose/src/util.h" */
   14623              : 
   14624              : #define MG_TCP_RECV_BUFFER_SIZE 1024
   14625              : #define MG_UDP_RECV_BUFFER_SIZE 1500
   14626              : 
   14627              : static sock_t mg_open_listening_socket(struct mg_connection *nc,
   14628              :                                        union socket_address *sa, int type,
   14629              :                                        int proto);
   14630              : 
   14631              : static void mg_set_non_blocking_mode(sock_t sock) {
   14632              :   SlSockNonblocking_t opt;
   14633              : #if SL_MAJOR_VERSION_NUM < 2
   14634              :   opt.NonblockingEnabled = 1;
   14635              : #else
   14636              :   opt.NonBlockingEnabled = 1;
   14637              : #endif
   14638              :   sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &opt, sizeof(opt));
   14639              : }
   14640              : 
   14641              : static int mg_is_error(int n) {
   14642              :   return (n < 0 && n != SL_ERROR_BSD_EALREADY && n != SL_ERROR_BSD_EAGAIN);
   14643              : }
   14644              : 
   14645              : static void mg_sl_if_connect_tcp(struct mg_connection *nc,
   14646              :                                  const union socket_address *sa) {
   14647              :   int proto = 0;
   14648              : #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
   14649              :   if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
   14650              : #endif
   14651              :   sock_t sock = sl_Socket(AF_INET, SOCK_STREAM, proto);
   14652              :   if (sock < 0) {
   14653              :     nc->err = sock;
   14654              :     goto out;
   14655              :   }
   14656              :   mg_sock_set(nc, sock);
   14657              : #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
   14658              :   nc->err = sl_set_ssl_opts(sock, nc);
   14659              :   if (nc->err != 0) goto out;
   14660              : #endif
   14661              :   nc->err = sl_Connect(sock, &sa->sa, sizeof(sa->sin));
   14662              : out:
   14663              :   DBG(("%p to %s:%d sock %d %d err %d", nc, inet_ntoa(sa->sin.sin_addr),
   14664              :        ntohs(sa->sin.sin_port), nc->sock, proto, nc->err));
   14665              : }
   14666              : 
   14667              : static void mg_sl_if_connect_udp(struct mg_connection *nc) {
   14668              :   sock_t sock = sl_Socket(AF_INET, SOCK_DGRAM, 0);
   14669              :   if (sock < 0) {
   14670              :     nc->err = sock;
   14671              :     return;
   14672              :   }
   14673              :   mg_sock_set(nc, sock);
   14674              :   nc->err = 0;
   14675              : }
   14676              : 
   14677              : static int mg_sl_if_listen_tcp(struct mg_connection *nc,
   14678              :                                union socket_address *sa) {
   14679              :   int proto = 0;
   14680              :   if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
   14681              :   sock_t sock = mg_open_listening_socket(nc, sa, SOCK_STREAM, proto);
   14682              :   if (sock < 0) return sock;
   14683              :   mg_sock_set(nc, sock);
   14684              :   return 0;
   14685              : }
   14686              : 
   14687              : static int mg_sl_if_listen_udp(struct mg_connection *nc,
   14688              :                                union socket_address *sa) {
   14689              :   sock_t sock = mg_open_listening_socket(nc, sa, SOCK_DGRAM, 0);
   14690              :   if (sock == INVALID_SOCKET) return (errno ? errno : 1);
   14691              :   mg_sock_set(nc, sock);
   14692              :   return 0;
   14693              : }
   14694              : 
   14695              : static int mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf,
   14696              :                              size_t len) {
   14697              :   int n = (int) sl_Send(nc->sock, buf, len, 0);
   14698              :   if (n < 0 && !mg_is_error(n)) n = 0;
   14699              :   return n;
   14700              : }
   14701              : 
   14702              : static int mg_sl_if_udp_send(struct mg_connection *nc, const void *buf,
   14703              :                              size_t len) {
   14704              :   int n = sl_SendTo(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
   14705              :   if (n < 0 && !mg_is_error(n)) n = 0;
   14706              :   return n;
   14707              : }
   14708              : 
   14709              : static int mg_sl_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len) {
   14710              :   int n = sl_Recv(nc->sock, buf, len, 0);
   14711              :   if (n == 0) {
   14712              :     /* Orderly shutdown of the socket, try flushing output. */
   14713              :     nc->flags |= MG_F_SEND_AND_CLOSE;
   14714              :   } else if (n < 0 && !mg_is_error(n)) {
   14715              :     n = 0;
   14716              :   }
   14717              :   return n;
   14718              : }
   14719              : 
   14720              : static int mg_sl_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
   14721              :                              union socket_address *sa, size_t *sa_len) {
   14722              :   SlSocklen_t sa_len_t = *sa_len;
   14723              :   int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0,
   14724              :                       (SlSockAddr_t *) sa, &sa_len_t);
   14725              :   *sa_len = sa_len_t;
   14726              :   if (n < 0 && !mg_is_error(n)) n = 0;
   14727              :   return n;
   14728              : }
   14729              : 
   14730              : static int mg_sl_if_create_conn(struct mg_connection *nc) {
   14731              :   (void) nc;
   14732              :   return 1;
   14733              : }
   14734              : 
   14735              : void mg_sl_if_destroy_conn(struct mg_connection *nc) {
   14736              :   if (nc->sock == INVALID_SOCKET) return;
   14737              :   /* For UDP, only close outgoing sockets or listeners. */
   14738              :   if (!(nc->flags & MG_F_UDP) || nc->listener == NULL) {
   14739              :     sl_Close(nc->sock);
   14740              :   }
   14741              :   nc->sock = INVALID_SOCKET;
   14742              : }
   14743              : 
   14744              : static int mg_accept_conn(struct mg_connection *lc) {
   14745              :   struct mg_connection *nc;
   14746              :   union socket_address sa;
   14747              :   socklen_t sa_len = sizeof(sa);
   14748              :   sock_t sock = sl_Accept(lc->sock, &sa.sa, &sa_len);
   14749              :   if (sock < 0) {
   14750              :     DBG(("%p: failed to accept: %d", lc, sock));
   14751              :     return 0;
   14752              :   }
   14753              :   nc = mg_if_accept_new_conn(lc);
   14754              :   if (nc == NULL) {
   14755              :     sl_Close(sock);
   14756              :     return 0;
   14757              :   }
   14758              :   DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
   14759              :        ntohs(sa.sin.sin_port)));
   14760              :   mg_sock_set(nc, sock);
   14761              :   mg_if_accept_tcp_cb(nc, &sa, sa_len);
   14762              :   return 1;
   14763              : }
   14764              : 
   14765              : /* 'sa' must be an initialized address to bind to */
   14766              : static sock_t mg_open_listening_socket(struct mg_connection *nc,
   14767              :                                        union socket_address *sa, int type,
   14768              :                                        int proto) {
   14769              :   int r;
   14770              :   socklen_t sa_len =
   14771              :       (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
   14772              :   sock_t sock = sl_Socket(sa->sa.sa_family, type, proto);
   14773              :   if (sock < 0) return sock;
   14774              : #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
   14775              :   if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean;
   14776              : #endif
   14777              :   if ((r = sl_Bind(sock, &sa->sa, sa_len)) < 0) goto clean;
   14778              :   if (type != SOCK_DGRAM) {
   14779              :     if ((r = sl_Listen(sock, SOMAXCONN)) < 0) goto clean;
   14780              :   }
   14781              :   mg_set_non_blocking_mode(sock);
   14782              : clean:
   14783              :   if (r < 0) {
   14784              :     sl_Close(sock);
   14785              :     sock = r;
   14786              :   }
   14787              :   return sock;
   14788              : }
   14789              : 
   14790              : #define _MG_F_FD_CAN_READ 1
   14791              : #define _MG_F_FD_CAN_WRITE 1 << 1
   14792              : #define _MG_F_FD_ERROR 1 << 2
   14793              : 
   14794              : void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
   14795              :   DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
   14796              :        fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
   14797              : 
   14798              :   if (!mg_if_poll(nc, now)) return;
   14799              : 
   14800              :   if (nc->flags & MG_F_CONNECTING) {
   14801              :     if ((nc->flags & MG_F_UDP) || nc->err != SL_ERROR_BSD_EALREADY) {
   14802              :       mg_if_connect_cb(nc, nc->err);
   14803              :     } else {
   14804              :       /* In SimpleLink, to get status of non-blocking connect() we need to wait
   14805              :        * until socket is writable and repeat the call to sl_Connect again,
   14806              :        * which will now return the real status. */
   14807              :       if (fd_flags & _MG_F_FD_CAN_WRITE) {
   14808              :         nc->err = sl_Connect(nc->sock, &nc->sa.sa, sizeof(nc->sa.sin));
   14809              :         DBG(("%p conn res=%d", nc, nc->err));
   14810              :         if (nc->err == SL_ERROR_BSD_ESECSNOVERIFY ||
   14811              :             /* TODO(rojer): Provide API to set the date for verification. */
   14812              :             nc->err == SL_ERROR_BSD_ESECDATEERROR
   14813              : #if SL_MAJOR_VERSION_NUM >= 2
   14814              :             /* Per SWRU455, this error does not mean verification failed,
   14815              :              * it only means that the cert used is not present in the trusted
   14816              :              * root CA catalog. Which is perfectly fine. */
   14817              :             ||
   14818              :             nc->err == SL_ERROR_BSD_ESECUNKNOWNROOTCA
   14819              : #endif
   14820              :             ) {
   14821              :           nc->err = 0;
   14822              :         }
   14823              :         mg_if_connect_cb(nc, nc->err);
   14824              :       }
   14825              :     }
   14826              :     /* Ignore read/write in further processing, we've handled it. */
   14827              :     fd_flags &= ~(_MG_F_FD_CAN_READ | _MG_F_FD_CAN_WRITE);
   14828              :   }
   14829              : 
   14830              :   if (fd_flags & _MG_F_FD_CAN_READ) {
   14831              :     if (nc->flags & MG_F_UDP) {
   14832              :       mg_if_can_recv_cb(nc);
   14833              :     } else {
   14834              :       if (nc->flags & MG_F_LISTENING) {
   14835              :         mg_accept_conn(nc);
   14836              :       } else {
   14837              :         mg_if_can_recv_cb(nc);
   14838              :       }
   14839              :     }
   14840              :   }
   14841              : 
   14842              :   if (fd_flags & _MG_F_FD_CAN_WRITE) {
   14843              :     mg_if_can_send_cb(nc);
   14844              :   }
   14845              : 
   14846              :   DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, nc->flags,
   14847              :        (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
   14848              : }
   14849              : 
   14850              : /* Associate a socket to a connection. */
   14851              : void mg_sl_if_sock_set(struct mg_connection *nc, sock_t sock) {
   14852              :   mg_set_non_blocking_mode(sock);
   14853              :   nc->sock = sock;
   14854              :   DBG(("%p %d", nc, sock));
   14855              : }
   14856              : 
   14857              : void mg_sl_if_init(struct mg_iface *iface) {
   14858              :   (void) iface;
   14859              :   DBG(("%p using sl_Select()", iface->mgr));
   14860              : }
   14861              : 
   14862              : void mg_sl_if_free(struct mg_iface *iface) {
   14863              :   (void) iface;
   14864              : }
   14865              : 
   14866              : void mg_sl_if_add_conn(struct mg_connection *nc) {
   14867              :   (void) nc;
   14868              : }
   14869              : 
   14870              : void mg_sl_if_remove_conn(struct mg_connection *nc) {
   14871              :   (void) nc;
   14872              : }
   14873              : 
   14874              : time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) {
   14875              :   struct mg_mgr *mgr = iface->mgr;
   14876              :   double now = mg_time();
   14877              :   double min_timer;
   14878              :   struct mg_connection *nc, *tmp;
   14879              :   struct SlTimeval_t tv;
   14880              :   SlFdSet_t read_set, write_set, err_set;
   14881              :   sock_t max_fd = INVALID_SOCKET;
   14882              :   int num_fds, num_ev = 0, num_timers = 0;
   14883              : 
   14884              :   SL_SOCKET_FD_ZERO(&read_set);
   14885              :   SL_SOCKET_FD_ZERO(&write_set);
   14886              :   SL_SOCKET_FD_ZERO(&err_set);
   14887              : 
   14888              :   /*
   14889              :    * Note: it is ok to have connections with sock == INVALID_SOCKET in the list,
   14890              :    * e.g. timer-only "connections".
   14891              :    */
   14892              :   min_timer = 0;
   14893              :   for (nc = mgr->active_connections, num_fds = 0; nc != NULL; nc = tmp) {
   14894              :     tmp = nc->next;
   14895              : 
   14896              :     if (nc->sock != INVALID_SOCKET) {
   14897              :       num_fds++;
   14898              : 
   14899              :       if (!(nc->flags & MG_F_WANT_WRITE) &&
   14900              :           nc->recv_mbuf.len < nc->recv_mbuf_limit &&
   14901              :           (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
   14902              :         SL_SOCKET_FD_SET(nc->sock, &read_set);
   14903              :         if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock;
   14904              :       }
   14905              : 
   14906              :       if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) ||
   14907              :           (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) {
   14908              :         SL_SOCKET_FD_SET(nc->sock, &write_set);
   14909              :         SL_SOCKET_FD_SET(nc->sock, &err_set);
   14910              :         if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock;
   14911              :       }
   14912              :     }
   14913              : 
   14914              :     if (nc->ev_timer_time > 0) {
   14915              :       if (num_timers == 0 || nc->ev_timer_time < min_timer) {
   14916              :         min_timer = nc->ev_timer_time;
   14917              :       }
   14918              :       num_timers++;
   14919              :     }
   14920              :   }
   14921              : 
   14922              :   /*
   14923              :    * If there is a timer to be fired earlier than the requested timeout,
   14924              :    * adjust the timeout.
   14925              :    */
   14926              :   if (num_timers > 0) {
   14927              :     double timer_timeout_ms = (min_timer - mg_time()) * 1000 + 1 /* rounding */;
   14928              :     if (timer_timeout_ms < timeout_ms) {
   14929              :       timeout_ms = timer_timeout_ms;
   14930              :     }
   14931              :   }
   14932              :   if (timeout_ms < 0) timeout_ms = 0;
   14933              : 
   14934              :   tv.tv_sec = timeout_ms / 1000;
   14935              :   tv.tv_usec = (timeout_ms % 1000) * 1000;
   14936              : 
   14937              :   if (num_fds > 0) {
   14938              :     num_ev = sl_Select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv);
   14939              :   }
   14940              : 
   14941              :   now = mg_time();
   14942              :   DBG(("sl_Select @ %ld num_ev=%d of %d, timeout=%d", (long) now, num_ev,
   14943              :        num_fds, timeout_ms));
   14944              : 
   14945              :   for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
   14946              :     int fd_flags = 0;
   14947              :     if (nc->sock != INVALID_SOCKET) {
   14948              :       if (num_ev > 0) {
   14949              :         fd_flags =
   14950              :             (SL_SOCKET_FD_ISSET(nc->sock, &read_set) &&
   14951              :                      (!(nc->flags & MG_F_UDP) || nc->listener == NULL)
   14952              :                  ? _MG_F_FD_CAN_READ
   14953              :                  : 0) |
   14954              :             (SL_SOCKET_FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE
   14955              :                                                       : 0) |
   14956              :             (SL_SOCKET_FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0);
   14957              :       }
   14958              :       /* SimpleLink does not report UDP sockets as writable. */
   14959              :       if (nc->flags & MG_F_UDP && nc->send_mbuf.len > 0) {
   14960              :         fd_flags |= _MG_F_FD_CAN_WRITE;
   14961              :       }
   14962              :     }
   14963              :     tmp = nc->next;
   14964              :     mg_mgr_handle_conn(nc, fd_flags, now);
   14965              :   }
   14966              : 
   14967              :   return now;
   14968              : }
   14969              : 
   14970              : void mg_sl_if_get_conn_addr(struct mg_connection *nc, int remote,
   14971              :                             union socket_address *sa) {
   14972              :   /* SimpleLink does not provide a way to get socket's peer address after
   14973              :    * accept or connect. Address should have been preserved in the connection,
   14974              :    * so we do our best here by using it. */
   14975              :   if (remote) memcpy(sa, &nc->sa, sizeof(*sa));
   14976              : }
   14977              : 
   14978              : void sl_restart_cb(struct mg_mgr *mgr) {
   14979              :   /*
   14980              :    * SimpleLink has been restarted, meaning all sockets have been invalidated.
   14981              :    * We try our best - we'll restart the listeners, but for outgoing
   14982              :    * connections we have no option but to terminate.
   14983              :    */
   14984              :   struct mg_connection *nc;
   14985              :   for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
   14986              :     if (nc->sock == INVALID_SOCKET) continue; /* Could be a timer */
   14987              :     if (nc->flags & MG_F_LISTENING) {
   14988              :       DBG(("restarting %p %s:%d", nc, inet_ntoa(nc->sa.sin.sin_addr),
   14989              :            ntohs(nc->sa.sin.sin_port)));
   14990              :       int res = (nc->flags & MG_F_UDP ? mg_sl_if_listen_udp(nc, &nc->sa)
   14991              :                                       : mg_sl_if_listen_tcp(nc, &nc->sa));
   14992              :       if (res == 0) continue;
   14993              :       /* Well, we tried and failed. Fall through to closing. */
   14994              :     }
   14995              :     nc->sock = INVALID_SOCKET;
   14996              :     DBG(("terminating %p %s:%d", nc, inet_ntoa(nc->sa.sin.sin_addr),
   14997              :          ntohs(nc->sa.sin.sin_port)));
   14998              :     /* TODO(rojer): Outgoing UDP? */
   14999              :     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   15000              :   }
   15001              : }
   15002              : 
   15003              : /* clang-format off */
   15004              : #define MG_SL_IFACE_VTABLE                                              \
   15005              :   {                                                                     \
   15006              :     mg_sl_if_init,                                                      \
   15007              :     mg_sl_if_free,                                                      \
   15008              :     mg_sl_if_add_conn,                                                  \
   15009              :     mg_sl_if_remove_conn,                                               \
   15010              :     mg_sl_if_poll,                                                      \
   15011              :     mg_sl_if_listen_tcp,                                                \
   15012              :     mg_sl_if_listen_udp,                                                \
   15013              :     mg_sl_if_connect_tcp,                                               \
   15014              :     mg_sl_if_connect_udp,                                               \
   15015              :     mg_sl_if_tcp_send,                                                  \
   15016              :     mg_sl_if_udp_send,                                                  \
   15017              :     mg_sl_if_tcp_recv,                                                  \
   15018              :     mg_sl_if_udp_recv,                                                  \
   15019              :     mg_sl_if_create_conn,                                               \
   15020              :     mg_sl_if_destroy_conn,                                              \
   15021              :     mg_sl_if_sock_set,                                                  \
   15022              :     mg_sl_if_get_conn_addr,                                             \
   15023              :   }
   15024              : /* clang-format on */
   15025              : 
   15026              : const struct mg_iface_vtable mg_simplelink_iface_vtable = MG_SL_IFACE_VTABLE;
   15027              : #if MG_NET_IF == MG_NET_IF_SIMPLELINK
   15028              : const struct mg_iface_vtable mg_default_iface_vtable = MG_SL_IFACE_VTABLE;
   15029              : #endif
   15030              : 
   15031              : #endif /* MG_ENABLE_NET_IF_SIMPLELINK */
   15032              : #ifdef MG_MODULE_LINES
   15033              : #line 1 "common/platforms/simplelink/sl_ssl_if.c"
   15034              : #endif
   15035              : /*
   15036              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   15037              :  * All rights reserved
   15038              :  *
   15039              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   15040              :  * you may not use this file except in compliance with the License.
   15041              :  * You may obtain a copy of the License at
   15042              :  *
   15043              :  *     http://www.apache.org/licenses/LICENSE-2.0
   15044              :  *
   15045              :  * Unless required by applicable law or agreed to in writing, software
   15046              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   15047              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15048              :  * See the License for the specific language governing permissions and
   15049              :  * limitations under the License.
   15050              :  */
   15051              : 
   15052              : #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
   15053              : 
   15054              : /* Amalgamated: #include "common/mg_mem.h" */
   15055              : 
   15056              : #ifndef MG_SSL_IF_SIMPLELINK_SLFS_PREFIX
   15057              : #define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX "SL:"
   15058              : #endif
   15059              : 
   15060              : #define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN \
   15061              :   (sizeof(MG_SSL_IF_SIMPLELINK_SLFS_PREFIX) - 1)
   15062              : 
   15063              : struct mg_ssl_if_ctx {
   15064              :   char *ssl_cert;
   15065              :   char *ssl_key;
   15066              :   char *ssl_ca_cert;
   15067              :   char *ssl_server_name;
   15068              : };
   15069              : 
   15070              : void mg_ssl_if_init() {
   15071              : }
   15072              : 
   15073              : enum mg_ssl_if_result mg_ssl_if_conn_init(
   15074              :     struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
   15075              :     const char **err_msg) {
   15076              :   struct mg_ssl_if_ctx *ctx =
   15077              :       (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
   15078              :   if (ctx == NULL) {
   15079              :     MG_SET_PTRPTR(err_msg, "Out of memory");
   15080              :     return MG_SSL_ERROR;
   15081              :   }
   15082              :   nc->ssl_if_data = ctx;
   15083              : 
   15084              :   if (params->cert != NULL || params->key != NULL) {
   15085              :     if (params->cert != NULL && params->key != NULL) {
   15086              :       ctx->ssl_cert = strdup(params->cert);
   15087              :       ctx->ssl_key = strdup(params->key);
   15088              :     } else {
   15089              :       MG_SET_PTRPTR(err_msg, "Both cert and key are required.");
   15090              :       return MG_SSL_ERROR;
   15091              :     }
   15092              :   }
   15093              :   if (params->ca_cert != NULL && strcmp(params->ca_cert, "*") != 0) {
   15094              :     ctx->ssl_ca_cert = strdup(params->ca_cert);
   15095              :   }
   15096              :   /* TODO(rojer): cipher_suites. */
   15097              :   if (params->server_name != NULL) {
   15098              :     ctx->ssl_server_name = strdup(params->server_name);
   15099              :   }
   15100              :   return MG_SSL_OK;
   15101              : }
   15102              : 
   15103              : enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc,
   15104              :                                             struct mg_connection *lc) {
   15105              :   /* SimpleLink does everything for us, nothing for us to do. */
   15106              :   (void) nc;
   15107              :   (void) lc;
   15108              :   return MG_SSL_OK;
   15109              : }
   15110              : 
   15111              : enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
   15112              :   /* SimpleLink has already performed the handshake, nothing to do. */
   15113              :   return MG_SSL_OK;
   15114              : }
   15115              : 
   15116              : int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
   15117              :   /* SimpelLink handles TLS, so this is just a pass-through. */
   15118              :   int n = nc->iface->vtable->tcp_recv(nc, buf, len);
   15119              :   if (n == 0) nc->flags |= MG_F_WANT_READ;
   15120              :   return n;
   15121              : }
   15122              : 
   15123              : int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
   15124              :   /* SimpelLink handles TLS, so this is just a pass-through. */
   15125              :   return nc->iface->vtable->tcp_send(nc, buf, len);
   15126              : }
   15127              : 
   15128              : void mg_ssl_if_conn_close_notify(struct mg_connection *nc) {
   15129              :   /* Nothing to do */
   15130              :   (void) nc;
   15131              : }
   15132              : 
   15133              : void mg_ssl_if_conn_free(struct mg_connection *nc) {
   15134              :   struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
   15135              :   if (ctx == NULL) return;
   15136              :   nc->ssl_if_data = NULL;
   15137              :   MG_FREE(ctx->ssl_cert);
   15138              :   MG_FREE(ctx->ssl_key);
   15139              :   MG_FREE(ctx->ssl_ca_cert);
   15140              :   MG_FREE(ctx->ssl_server_name);
   15141              :   memset(ctx, 0, sizeof(*ctx));
   15142              :   MG_FREE(ctx);
   15143              : }
   15144              : 
   15145              : bool pem_to_der(const char *pem_file, const char *der_file) {
   15146              :   bool ret = false;
   15147              :   FILE *pf = NULL, *df = NULL;
   15148              :   bool writing = false;
   15149              :   pf = fopen(pem_file, "r");
   15150              :   if (pf == NULL) goto clean;
   15151              :   remove(der_file);
   15152              :   fs_slfs_set_file_size(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN, 2048);
   15153              :   df = fopen(der_file, "w");
   15154              :   fs_slfs_unset_file_flags(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN);
   15155              :   if (df == NULL) goto clean;
   15156              :   while (1) {
   15157              :     char pem_buf[70];
   15158              :     char der_buf[48];
   15159              :     if (!fgets(pem_buf, sizeof(pem_buf), pf)) break;
   15160              :     if (writing) {
   15161              :       if (strstr(pem_buf, "-----END ") != NULL) {
   15162              :         ret = true;
   15163              :         break;
   15164              :       }
   15165              :       int l = 0;
   15166              :       while (!isspace((unsigned int) pem_buf[l])) l++;
   15167              :       int der_len = 0;
   15168              :       cs_base64_decode((const unsigned char *) pem_buf, sizeof(pem_buf),
   15169              :                        der_buf, &der_len);
   15170              :       if (der_len <= 0) break;
   15171              :       if (fwrite(der_buf, 1, der_len, df) != der_len) break;
   15172              :     } else if (strstr(pem_buf, "-----BEGIN ") != NULL) {
   15173              :       writing = true;
   15174              :     }
   15175              :   }
   15176              : 
   15177              : clean:
   15178              :   if (pf != NULL) fclose(pf);
   15179              :   if (df != NULL) {
   15180              :     fclose(df);
   15181              :     if (!ret) remove(der_file);
   15182              :   }
   15183              :   return ret;
   15184              : }
   15185              : 
   15186              : #if MG_ENABLE_FILESYSTEM && defined(MG_FS_SLFS)
   15187              : /* If the file's extension is .pem, convert it to DER format and put on SLFS. */
   15188              : static char *sl_pem2der(const char *pem_file) {
   15189              :   const char *pem_ext = strstr(pem_file, ".pem");
   15190              :   if (pem_ext == NULL || *(pem_ext + 4) != '\0') {
   15191              :     return strdup(pem_file);
   15192              :   }
   15193              :   char *der_file = NULL;
   15194              :   /* DER file must be located on SLFS, add prefix. */
   15195              :   int l = mg_asprintf(&der_file, 0, MG_SSL_IF_SIMPLELINK_SLFS_PREFIX "%.*s.der",
   15196              :                       (int) (pem_ext - pem_file), pem_file);
   15197              :   if (der_file == NULL) return NULL;
   15198              :   bool result = false;
   15199              :   cs_stat_t st;
   15200              :   if (mg_stat(der_file, &st) != 0) {
   15201              :     result = pem_to_der(pem_file, der_file);
   15202              :     LOG(LL_DEBUG, ("%s -> %s = %d", pem_file, der_file, result));
   15203              :   } else {
   15204              :     /* File exists, assume it's already been converted. */
   15205              :     result = true;
   15206              :   }
   15207              :   if (result) {
   15208              :     /* Strip the SL: prefix we added since NWP does not expect it. */
   15209              :     memmove(der_file, der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN,
   15210              :             l - 2 /* including \0 */);
   15211              :   } else {
   15212              :     MG_FREE(der_file);
   15213              :     der_file = NULL;
   15214              :   }
   15215              :   return der_file;
   15216              : }
   15217              : #else
   15218              : static char *sl_pem2der(const char *pem_file) {
   15219              :   return strdup(pem_file);
   15220              : }
   15221              : #endif
   15222              : 
   15223              : int sl_set_ssl_opts(int sock, struct mg_connection *nc) {
   15224              :   int err;
   15225              :   const struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
   15226              :   DBG(("%p ssl ctx: %p", nc, ctx));
   15227              : 
   15228              :   if (ctx == NULL) return 0;
   15229              :   DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"),
   15230              :        (ctx->ssl_key ? ctx->ssl_cert : "-"),
   15231              :        (ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"),
   15232              :        (ctx->ssl_server_name ? ctx->ssl_server_name : "-")));
   15233              :   if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) {
   15234              :     char *ssl_cert = sl_pem2der(ctx->ssl_cert), *ssl_key = NULL;
   15235              :     if (ssl_cert != NULL) {
   15236              :       err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
   15237              :                           SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert,
   15238              :                           strlen(ssl_cert));
   15239              :       MG_FREE(ssl_cert);
   15240              :       LOG(LL_DEBUG, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err));
   15241              :       ssl_key = sl_pem2der(ctx->ssl_key);
   15242              :       if (ssl_key != NULL) {
   15243              :         err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
   15244              :                             SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, ssl_key,
   15245              :                             strlen(ssl_key));
   15246              :         MG_FREE(ssl_key);
   15247              :         LOG(LL_DEBUG, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err));
   15248              :       } else {
   15249              :         err = -1;
   15250              :       }
   15251              :     } else {
   15252              :       err = -1;
   15253              :     }
   15254              :     if (err != 0) return err;
   15255              :   }
   15256              :   if (ctx->ssl_ca_cert != NULL) {
   15257              :     if (ctx->ssl_ca_cert[0] != '\0') {
   15258              :       char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert);
   15259              :       if (ssl_ca_cert != NULL) {
   15260              :         err =
   15261              :             sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME,
   15262              :                           ssl_ca_cert, strlen(ssl_ca_cert));
   15263              :         LOG(LL_DEBUG, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err));
   15264              :       } else {
   15265              :         err = -1;
   15266              :       }
   15267              :       MG_FREE(ssl_ca_cert);
   15268              :       if (err != 0) return err;
   15269              :     }
   15270              :   }
   15271              :   if (ctx->ssl_server_name != NULL) {
   15272              :     err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
   15273              :                         SL_SO_SECURE_DOMAIN_NAME_VERIFICATION,
   15274              :                         ctx->ssl_server_name, strlen(ctx->ssl_server_name));
   15275              :     DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err));
   15276              :     /* Domain name verificationw as added in a NWP service pack, older
   15277              :      * versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do
   15278              :      * about it,
   15279              :      * so we ignore the error. */
   15280              :     if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err;
   15281              :   }
   15282              :   return 0;
   15283              : }
   15284              : 
   15285              : #endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK */
   15286              : #ifdef MG_MODULE_LINES
   15287              : #line 1 "common/platforms/lwip/mg_lwip_net_if.h"
   15288              : #endif
   15289              : /*
   15290              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   15291              :  * All rights reserved
   15292              :  *
   15293              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   15294              :  * you may not use this file except in compliance with the License.
   15295              :  * You may obtain a copy of the License at
   15296              :  *
   15297              :  *     http://www.apache.org/licenses/LICENSE-2.0
   15298              :  *
   15299              :  * Unless required by applicable law or agreed to in writing, software
   15300              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   15301              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15302              :  * See the License for the specific language governing permissions and
   15303              :  * limitations under the License.
   15304              :  */
   15305              : 
   15306              : #ifndef CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_
   15307              : #define CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_
   15308              : 
   15309              : #ifndef MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
   15310              : #define MG_ENABLE_NET_IF_LWIP_LOW_LEVEL MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
   15311              : #endif
   15312              : 
   15313              : #if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
   15314              : 
   15315              : #include <stdint.h>
   15316              : 
   15317              : extern const struct mg_iface_vtable mg_lwip_iface_vtable;
   15318              : 
   15319              : struct mg_lwip_conn_state {
   15320              :   struct mg_connection *nc;
   15321              :   struct mg_connection *lc;
   15322              :   union {
   15323              :     struct tcp_pcb *tcp;
   15324              :     struct udp_pcb *udp;
   15325              :   } pcb;
   15326              :   err_t err;
   15327              :   size_t num_sent; /* Number of acknowledged bytes to be reported to the core */
   15328              :   struct pbuf *rx_chain; /* Chain of incoming data segments. */
   15329              :   size_t rx_offset; /* Offset within the first pbuf (if partially consumed) */
   15330              :   /* Last SSL write size, for retries. */
   15331              :   int last_ssl_write_size;
   15332              :   /* Whether MG_SIG_RECV is already pending for this connection */
   15333              :   int recv_pending;
   15334              :   /* Whether the connection is about to close, just `rx_chain` needs to drain */
   15335              :   int draining_rx_chain;
   15336              : };
   15337              : 
   15338              : enum mg_sig_type {
   15339              :   MG_SIG_CONNECT_RESULT = 1,
   15340              :   MG_SIG_RECV = 2,
   15341              :   MG_SIG_CLOSE_CONN = 3,
   15342              :   MG_SIG_TOMBSTONE = 4,
   15343              :   MG_SIG_ACCEPT = 5,
   15344              : };
   15345              : 
   15346              : void mg_lwip_post_signal(enum mg_sig_type sig, struct mg_connection *nc);
   15347              : 
   15348              : /* To be implemented by the platform. */
   15349              : void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr);
   15350              : 
   15351              : #endif /* MG_ENABLE_NET_IF_LWIP_LOW_LEVEL */
   15352              : 
   15353              : #endif /* CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_ */
   15354              : #ifdef MG_MODULE_LINES
   15355              : #line 1 "common/platforms/lwip/mg_lwip_net_if.c"
   15356              : #endif
   15357              : /*
   15358              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   15359              :  * All rights reserved
   15360              :  *
   15361              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   15362              :  * you may not use this file except in compliance with the License.
   15363              :  * You may obtain a copy of the License at
   15364              :  *
   15365              :  *     http://www.apache.org/licenses/LICENSE-2.0
   15366              :  *
   15367              :  * Unless required by applicable law or agreed to in writing, software
   15368              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   15369              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15370              :  * See the License for the specific language governing permissions and
   15371              :  * limitations under the License.
   15372              :  */
   15373              : 
   15374              : #if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
   15375              : 
   15376              : /* Amalgamated: #include "common/mg_mem.h" */
   15377              : 
   15378              : #include <lwip/init.h>
   15379              : #include <lwip/pbuf.h>
   15380              : #include <lwip/tcp.h>
   15381              : #include <lwip/tcpip.h>
   15382              : #if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
   15383              : #include <lwip/priv/tcp_priv.h>   /* For tcp_seg */
   15384              : #include <lwip/priv/tcpip_priv.h> /* For tcpip_api_call */
   15385              : #else
   15386              : #include <lwip/tcp_impl.h>
   15387              : #endif
   15388              : #include <lwip/udp.h>
   15389              : 
   15390              : /* Amalgamated: #include "common/cs_dbg.h" */
   15391              : 
   15392              : /*
   15393              :  * Newest versions of LWIP have ip_2_ip4, older have ipX_2_ip,
   15394              :  * even older have nothing.
   15395              :  */
   15396              : #ifndef ip_2_ip4
   15397              : #ifdef ipX_2_ip
   15398              : #define ip_2_ip4(addr) ipX_2_ip(addr)
   15399              : #else
   15400              : #define ip_2_ip4(addr) (addr)
   15401              : #endif
   15402              : #endif
   15403              : 
   15404              : /*
   15405              :  * Depending on whether Mongoose is compiled with ipv6 support, use right
   15406              :  * lwip functions
   15407              :  */
   15408              : #if MG_ENABLE_IPV6
   15409              : #define TCP_NEW tcp_new_ip6
   15410              : #define TCP_BIND tcp_bind_ip6
   15411              : #define UDP_BIND udp_bind_ip6
   15412              : #define IPADDR_NTOA(x) ip6addr_ntoa((const ip6_addr_t *)(x))
   15413              : #define SET_ADDR(dst, src)                               \
   15414              :   memcpy((dst)->sin6.sin6_addr.s6_addr, (src)->ip6.addr, \
   15415              :          sizeof((dst)->sin6.sin6_addr.s6_addr))
   15416              : #else
   15417              : #define TCP_NEW tcp_new
   15418              : #define TCP_BIND tcp_bind
   15419              : #define UDP_BIND udp_bind
   15420              : #define IPADDR_NTOA ipaddr_ntoa
   15421              : #define SET_ADDR(dst, src) (dst)->sin.sin_addr.s_addr = ip_2_ip4(src)->addr
   15422              : #endif
   15423              : 
   15424              : #if !NO_SYS
   15425              : #if LWIP_TCPIP_CORE_LOCKING
   15426              : /* With locking tcpip_api_call is just a function call wrapped in lock/unlock,
   15427              :  * so we can get away with just casting. */
   15428              : void mg_lwip_netif_run_on_tcpip(void (*fn)(void *), void *arg) {
   15429              :   tcpip_api_call((tcpip_api_call_fn) fn, (struct tcpip_api_call_data *) arg);
   15430              : }
   15431              : #else
   15432              : static sys_sem_t s_tcpip_call_lock_sem = NULL;
   15433              : static sys_sem_t s_tcpip_call_sync_sem = NULL;
   15434              : struct mg_lwip_netif_tcpip_call_ctx {
   15435              :   void (*fn)(void *);
   15436              :   void *arg;
   15437              : };
   15438              : static void xxx_tcpip(void *arg) {
   15439              :   struct mg_lwip_netif_tcpip_call_ctx *ctx =
   15440              :       (struct mg_lwip_netif_tcpip_call_ctx *) arg;
   15441              :   ctx->fn(ctx->arg);
   15442              :   sys_sem_signal(&s_tcpip_call_sync_sem);
   15443              : }
   15444              : void mg_lwip_netif_run_on_tcpip(void (*fn)(void *), void *arg) {
   15445              :   struct mg_lwip_netif_tcpip_call_ctx ctx = {.fn = fn, .arg = arg};
   15446              :   sys_arch_sem_wait(&s_tcpip_call_lock_sem, 0);
   15447              :   tcpip_send_msg_wait_sem(xxx_tcpip, &ctx, &s_tcpip_call_sync_sem);
   15448              :   sys_sem_signal(&s_tcpip_call_lock_sem);
   15449              : }
   15450              : #endif
   15451              : #else
   15452              : #define mg_lwip_netif_run_on_tcpip(fn, arg) (fn)(arg)
   15453              : #endif
   15454              : 
   15455              : void mg_lwip_if_init(struct mg_iface *iface);
   15456              : void mg_lwip_if_free(struct mg_iface *iface);
   15457              : void mg_lwip_if_add_conn(struct mg_connection *nc);
   15458              : void mg_lwip_if_remove_conn(struct mg_connection *nc);
   15459              : time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms);
   15460              : 
   15461              : // If compiling for Mongoose OS.
   15462              : #ifdef MGOS
   15463              : extern void mgos_lock();
   15464              : extern void mgos_unlock();
   15465              : #else
   15466              : #define mgos_lock()
   15467              : #define mgos_unlock()
   15468              : #endif
   15469              : 
   15470              : static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p);
   15471              : 
   15472              : #if LWIP_TCP_KEEPALIVE
   15473              : void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle,
   15474              :                                   int interval, int count) {
   15475              :   if (nc->sock == INVALID_SOCKET || nc->flags & MG_F_UDP) {
   15476              :     return;
   15477              :   }
   15478              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15479              :   struct tcp_pcb *tpcb = cs->pcb.tcp;
   15480              :   if (idle > 0 && interval > 0 && count > 0) {
   15481              :     tpcb->keep_idle = idle * 1000;
   15482              :     tpcb->keep_intvl = interval * 1000;
   15483              :     tpcb->keep_cnt = count;
   15484              :     tpcb->so_options |= SOF_KEEPALIVE;
   15485              :   } else {
   15486              :     tpcb->so_options &= ~SOF_KEEPALIVE;
   15487              :   }
   15488              : }
   15489              : #elif !defined(MG_NO_LWIP_TCP_KEEPALIVE)
   15490              : #warning LWIP TCP keepalive is disabled. Please consider enabling it.
   15491              : #endif /* LWIP_TCP_KEEPALIVE */
   15492              : 
   15493              : static err_t mg_lwip_tcp_conn_cb(void *arg, struct tcp_pcb *tpcb, err_t err) {
   15494              :   struct mg_connection *nc = (struct mg_connection *) arg;
   15495              :   DBG(("%p connect to %s:%u = %d", nc, IPADDR_NTOA(ipX_2_ip(&tpcb->remote_ip)),
   15496              :        tpcb->remote_port, err));
   15497              :   if (nc == NULL) {
   15498              :     tcp_abort(tpcb);
   15499              :     return ERR_ARG;
   15500              :   }
   15501              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15502              :   cs->err = err;
   15503              : #if LWIP_TCP_KEEPALIVE
   15504              :   if (err == 0) mg_lwip_set_keepalive_params(nc, 60, 10, 6);
   15505              : #endif
   15506              :   mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
   15507              :   return ERR_OK;
   15508              : }
   15509              : 
   15510              : static void mg_lwip_tcp_error_cb(void *arg, err_t err) {
   15511              :   struct mg_connection *nc = (struct mg_connection *) arg;
   15512              :   DBG(("%p conn error %d", nc, err));
   15513              :   if (nc == NULL || (nc->flags & MG_F_CLOSE_IMMEDIATELY)) return;
   15514              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15515              :   cs->pcb.tcp = NULL; /* Has already been deallocated */
   15516              :   if (nc->flags & MG_F_CONNECTING) {
   15517              :     cs->err = err;
   15518              :     mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
   15519              :   } else {
   15520              :     mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
   15521              :   }
   15522              : }
   15523              : 
   15524              : static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
   15525              :                                  struct pbuf *p, err_t err) {
   15526              :   struct mg_connection *nc = (struct mg_connection *) arg;
   15527              :   struct mg_lwip_conn_state *cs =
   15528              :       (nc ? (struct mg_lwip_conn_state *) nc->sock : NULL);
   15529              :   DBG(("%p %p %p %p %u %d", nc, cs, tpcb, p, (p != NULL ? p->tot_len : 0),
   15530              :        err));
   15531              :   if (p == NULL) {
   15532              :     if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
   15533              :       if (cs->rx_chain != NULL) {
   15534              :         /*
   15535              :          * rx_chain still contains non-consumed data, don't close the
   15536              :          * connection
   15537              :          */
   15538              :         cs->draining_rx_chain = 1;
   15539              :       } else {
   15540              :         mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
   15541              :       }
   15542              :     } else {
   15543              :       /* Tombstoned connection, do nothing. */
   15544              :     }
   15545              :     return ERR_OK;
   15546              :   } else if (nc == NULL) {
   15547              :     tcp_abort(tpcb);
   15548              :     return ERR_ARG;
   15549              :   }
   15550              :   /*
   15551              :    * If we get a chain of more than one segment at once, we need to bump
   15552              :    * refcount on the subsequent bufs to make them independent.
   15553              :    */
   15554              :   if (p->next != NULL) {
   15555              :     struct pbuf *q = p->next;
   15556              :     for (; q != NULL; q = q->next) pbuf_ref(q);
   15557              :   }
   15558              :   mgos_lock();
   15559              :   if (cs->rx_chain == NULL) {
   15560              :     cs->rx_offset = 0;
   15561              :   } else if (pbuf_clen(cs->rx_chain) >= 4) {
   15562              :     /* ESP SDK has a limited pool of 5 pbufs. We must not hog them all or RX
   15563              :      * will be completely blocked. We already have at least 4 in the chain,
   15564              :      * this one is the last, so we have to make a copy and release this one. */
   15565              :     struct pbuf *np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
   15566              :     if (np != NULL) {
   15567              :       pbuf_copy(np, p);
   15568              :       pbuf_free(p);
   15569              :       p = np;
   15570              :     }
   15571              :   }
   15572              :   mg_lwip_recv_common(nc, p);
   15573              :   mgos_unlock();
   15574              :   (void) err;
   15575              :   return ERR_OK;
   15576              : }
   15577              : 
   15578              : static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb,
   15579              :                                  u16_t num_sent) {
   15580              :   struct mg_connection *nc = (struct mg_connection *) arg;
   15581              :   DBG(("%p %p %u %p %p", nc, tpcb, num_sent, tpcb->unsent, tpcb->unacked));
   15582              :   if (nc == NULL) return ERR_OK;
   15583              :   if ((nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE) &&
   15584              :       nc->send_mbuf.len == 0 && tpcb->unsent == NULL && tpcb->unacked == NULL) {
   15585              :     mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
   15586              :   }
   15587              :   if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
   15588              :     mg_lwip_mgr_schedule_poll(nc->mgr);
   15589              :   }
   15590              :   (void) num_sent;
   15591              :   return ERR_OK;
   15592              : }
   15593              : 
   15594              : struct mg_lwip_if_connect_tcp_ctx {
   15595              :   struct mg_connection *nc;
   15596              :   const union socket_address *sa;
   15597              : };
   15598              : 
   15599              : static void mg_lwip_if_connect_tcp_tcpip(void *arg) {
   15600              :   struct mg_lwip_if_connect_tcp_ctx *ctx =
   15601              :       (struct mg_lwip_if_connect_tcp_ctx *) arg;
   15602              :   struct mg_connection *nc = ctx->nc;
   15603              :   const union socket_address *sa = ctx->sa;
   15604              : 
   15605              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15606              :   struct tcp_pcb *tpcb = TCP_NEW();
   15607              :   cs->pcb.tcp = tpcb;
   15608              :   ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
   15609              :   u16_t port = ntohs(sa->sin.sin_port);
   15610              :   tcp_arg(tpcb, nc);
   15611              :   tcp_err(tpcb, mg_lwip_tcp_error_cb);
   15612              :   tcp_sent(tpcb, mg_lwip_tcp_sent_cb);
   15613              :   tcp_recv(tpcb, mg_lwip_tcp_recv_cb);
   15614              :   cs->err = TCP_BIND(tpcb, IP_ADDR_ANY, 0 /* any port */);
   15615              :   DBG(("%p tcp_bind = %d", nc, cs->err));
   15616              :   if (cs->err != ERR_OK) {
   15617              :     mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
   15618              :     return;
   15619              :   }
   15620              :   cs->err = tcp_connect(tpcb, ip, port, mg_lwip_tcp_conn_cb);
   15621              :   DBG(("%p tcp_connect %p = %d", nc, tpcb, cs->err));
   15622              :   if (cs->err != ERR_OK) {
   15623              :     mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
   15624              :     return;
   15625              :   }
   15626              : }
   15627              : 
   15628              : void mg_lwip_if_connect_tcp(struct mg_connection *nc,
   15629              :                             const union socket_address *sa) {
   15630              :   struct mg_lwip_if_connect_tcp_ctx ctx = {.nc = nc, .sa = sa};
   15631              :   mg_lwip_netif_run_on_tcpip(mg_lwip_if_connect_tcp_tcpip, &ctx);
   15632              : }
   15633              : 
   15634              : /*
   15635              :  * Lwip included in the SDKs for nRF5x chips has different type for the
   15636              :  * callback of `udp_recv()`
   15637              :  */
   15638              : #if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
   15639              : static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
   15640              :                                 const ip_addr_t *addr, u16_t port)
   15641              : #else
   15642              : static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
   15643              :                                 ip_addr_t *addr, u16_t port)
   15644              : #endif
   15645              : {
   15646              :   struct mg_connection *nc = (struct mg_connection *) arg;
   15647              :   DBG(("%p %s:%u %p %u %u", nc, IPADDR_NTOA(addr), port, p, p->ref, p->len));
   15648              :   /* Put address in a separate pbuf and tack it onto the packet. */
   15649              :   struct pbuf *sap =
   15650              :       pbuf_alloc(PBUF_RAW, sizeof(union socket_address), PBUF_RAM);
   15651              :   if (sap == NULL) {
   15652              :     pbuf_free(p);
   15653              :     return;
   15654              :   }
   15655              :   union socket_address *sa = (union socket_address *) sap->payload;
   15656              : #if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
   15657              :   sa->sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
   15658              : #else
   15659              :   sa->sin.sin_addr.s_addr = addr->addr;
   15660              : #endif
   15661              :   sa->sin.sin_port = htons(port);
   15662              :   /* Logic in the recv handler requires that there be exactly one data pbuf. */
   15663              :   p = pbuf_coalesce(p, PBUF_RAW);
   15664              :   pbuf_chain(sap, p);
   15665              :   mgos_lock();
   15666              :   mg_lwip_recv_common(nc, sap);
   15667              :   mgos_unlock();
   15668              :   (void) pcb;
   15669              : }
   15670              : 
   15671              : static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) {
   15672              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15673              :   if (cs->rx_chain == NULL) {
   15674              :     cs->rx_chain = p;
   15675              :   } else {
   15676              :     pbuf_chain(cs->rx_chain, p);
   15677              :   }
   15678              :   if (!cs->recv_pending) {
   15679              :     cs->recv_pending = 1;
   15680              :     mg_lwip_post_signal(MG_SIG_RECV, nc);
   15681              :   }
   15682              : }
   15683              : 
   15684              : static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
   15685              :                                union socket_address *sa, size_t *sa_len) {
   15686              :   /*
   15687              :    * For UDP, RX chain consists of interleaved address and packet bufs:
   15688              :    * Address pbuf followed by exactly one data pbuf (recv_cb took care of that).
   15689              :    */
   15690              :   int res = 0;
   15691              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15692              :   if (nc->sock == INVALID_SOCKET) return -1;
   15693              :   mgos_lock();
   15694              :   if (cs->rx_chain != NULL) {
   15695              :     struct pbuf *ap = cs->rx_chain;
   15696              :     struct pbuf *dp = ap->next;
   15697              :     cs->rx_chain = pbuf_dechain(dp);
   15698              :     res = MIN(dp->len, len);
   15699              :     pbuf_copy_partial(dp, buf, res, 0);
   15700              :     pbuf_free(dp);
   15701              :     pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0);
   15702              :     pbuf_free(ap);
   15703              :   }
   15704              :   mgos_unlock();
   15705              :   return res;
   15706              : }
   15707              : 
   15708              : static void mg_lwip_if_connect_udp_tcpip(void *arg) {
   15709              :   struct mg_connection *nc = (struct mg_connection *) arg;
   15710              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15711              :   struct udp_pcb *upcb = udp_new();
   15712              :   cs->err = UDP_BIND(upcb, IP_ADDR_ANY, 0 /* any port */);
   15713              :   DBG(("%p udp_bind %p = %d", nc, upcb, cs->err));
   15714              :   if (cs->err == ERR_OK) {
   15715              :     udp_recv(upcb, mg_lwip_udp_recv_cb, nc);
   15716              :     cs->pcb.udp = upcb;
   15717              :   } else {
   15718              :     udp_remove(upcb);
   15719              :   }
   15720              :   mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
   15721              : }
   15722              : 
   15723              : void mg_lwip_if_connect_udp(struct mg_connection *nc) {
   15724              :   mg_lwip_netif_run_on_tcpip(mg_lwip_if_connect_udp_tcpip, nc);
   15725              : }
   15726              : 
   15727              : static void tcp_close_tcpip(void *arg) {
   15728              :   tcp_close((struct tcp_pcb *) arg);
   15729              : }
   15730              : 
   15731              : void mg_lwip_handle_accept(struct mg_connection *nc) {
   15732              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15733              :   if (cs->pcb.tcp == NULL) return;
   15734              :   union socket_address sa;
   15735              :   struct tcp_pcb *tpcb = cs->pcb.tcp;
   15736              :   SET_ADDR(&sa, &tpcb->remote_ip);
   15737              :   sa.sin.sin_port = htons(tpcb->remote_port);
   15738              :   mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin));
   15739              : }
   15740              : 
   15741              : static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) {
   15742              :   struct mg_connection *lc = (struct mg_connection *) arg, *nc;
   15743              :   struct mg_lwip_conn_state *lcs, *cs;
   15744              :   struct tcp_pcb_listen *lpcb;
   15745              :   LOG(LL_DEBUG,
   15746              :       ("%p conn %p from %s:%u", lc, newtpcb,
   15747              :        IPADDR_NTOA(ipX_2_ip(&newtpcb->remote_ip)), newtpcb->remote_port));
   15748              :   if (lc == NULL) {
   15749              :     tcp_abort(newtpcb);
   15750              :     return ERR_ABRT;
   15751              :   }
   15752              :   lcs = (struct mg_lwip_conn_state *) lc->sock;
   15753              :   lpcb = (struct tcp_pcb_listen *) lcs->pcb.tcp;
   15754              : #if TCP_LISTEN_BACKLOG
   15755              :   tcp_accepted(lpcb);
   15756              : #endif
   15757              :   nc = mg_if_accept_new_conn(lc);
   15758              :   if (nc == NULL) {
   15759              :     tcp_abort(newtpcb);
   15760              :     return ERR_ABRT;
   15761              :   }
   15762              :   cs = (struct mg_lwip_conn_state *) nc->sock;
   15763              :   cs->lc = lc;
   15764              :   cs->pcb.tcp = newtpcb;
   15765              :   /* We need to set up callbacks before returning because data may start
   15766              :    * arriving immediately. */
   15767              :   tcp_arg(newtpcb, nc);
   15768              :   tcp_err(newtpcb, mg_lwip_tcp_error_cb);
   15769              :   tcp_sent(newtpcb, mg_lwip_tcp_sent_cb);
   15770              :   tcp_recv(newtpcb, mg_lwip_tcp_recv_cb);
   15771              : #if LWIP_TCP_KEEPALIVE
   15772              :   mg_lwip_set_keepalive_params(nc, 60, 10, 6);
   15773              : #endif
   15774              :   mg_lwip_post_signal(MG_SIG_ACCEPT, nc);
   15775              :   (void) err;
   15776              :   (void) lpcb;
   15777              :   return ERR_OK;
   15778              : }
   15779              : 
   15780              : struct mg_lwip_if_listen_ctx {
   15781              :   struct mg_connection *nc;
   15782              :   union socket_address *sa;
   15783              :   int ret;
   15784              : };
   15785              : 
   15786              : static void mg_lwip_if_listen_tcp_tcpip(void *arg) {
   15787              :   struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg;
   15788              :   struct mg_connection *nc = ctx->nc;
   15789              :   union socket_address *sa = ctx->sa;
   15790              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15791              :   struct tcp_pcb *tpcb = TCP_NEW();
   15792              :   ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
   15793              :   u16_t port = ntohs(sa->sin.sin_port);
   15794              :   cs->err = TCP_BIND(tpcb, ip, port);
   15795              :   DBG(("%p tcp_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err));
   15796              :   if (cs->err != ERR_OK) {
   15797              :     tcp_close(tpcb);
   15798              :     ctx->ret = -1;
   15799              :     return;
   15800              :   }
   15801              :   tcp_arg(tpcb, nc);
   15802              :   tpcb = tcp_listen(tpcb);
   15803              :   cs->pcb.tcp = tpcb;
   15804              :   tcp_accept(tpcb, mg_lwip_accept_cb);
   15805              :   ctx->ret = 0;
   15806              : }
   15807              : 
   15808              : int mg_lwip_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) {
   15809              :   struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa};
   15810              :   mg_lwip_netif_run_on_tcpip(mg_lwip_if_listen_tcp_tcpip, &ctx);
   15811              :   return ctx.ret;
   15812              : }
   15813              : 
   15814              : static void mg_lwip_if_listen_udp_tcpip(void *arg) {
   15815              :   struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg;
   15816              :   struct mg_connection *nc = ctx->nc;
   15817              :   union socket_address *sa = ctx->sa;
   15818              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15819              :   struct udp_pcb *upcb = udp_new();
   15820              :   ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
   15821              :   u16_t port = ntohs(sa->sin.sin_port);
   15822              :   cs->err = UDP_BIND(upcb, ip, port);
   15823              :   DBG(("%p udb_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err));
   15824              :   if (cs->err != ERR_OK) {
   15825              :     udp_remove(upcb);
   15826              :     ctx->ret = -1;
   15827              :   } else {
   15828              :     udp_recv(upcb, mg_lwip_udp_recv_cb, nc);
   15829              :     cs->pcb.udp = upcb;
   15830              :     ctx->ret = 0;
   15831              :   }
   15832              : }
   15833              : 
   15834              : int mg_lwip_if_listen_udp(struct mg_connection *nc, union socket_address *sa) {
   15835              :   struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa};
   15836              :   mg_lwip_netif_run_on_tcpip(mg_lwip_if_listen_udp_tcpip, &ctx);
   15837              :   return ctx.ret;
   15838              : }
   15839              : 
   15840              : struct mg_lwip_tcp_write_ctx {
   15841              :   struct mg_connection *nc;
   15842              :   const void *data;
   15843              :   uint16_t len;
   15844              :   int ret;
   15845              : };
   15846              : 
   15847              : static void tcp_output_tcpip(void *arg) {
   15848              :   tcp_output((struct tcp_pcb *) arg);
   15849              : }
   15850              : 
   15851              : static void mg_lwip_tcp_write_tcpip(void *arg) {
   15852              :   struct mg_lwip_tcp_write_ctx *ctx = (struct mg_lwip_tcp_write_ctx *) arg;
   15853              :   struct mg_connection *nc = ctx->nc;
   15854              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15855              :   struct tcp_pcb *tpcb = cs->pcb.tcp;
   15856              :   size_t len = MIN(tpcb->mss, MIN(ctx->len, tpcb->snd_buf));
   15857              :   size_t unsent, unacked;
   15858              :   if (len == 0) {
   15859              :     DBG(("%p no buf avail %u %u %p %p", tpcb, tpcb->snd_buf, tpcb->snd_queuelen,
   15860              :          tpcb->unsent, tpcb->unacked));
   15861              :     mg_lwip_netif_run_on_tcpip(tcp_output_tcpip, tpcb);
   15862              :     ctx->ret = 0;
   15863              :     return;
   15864              :   }
   15865              :   unsent = (tpcb->unsent != NULL ? tpcb->unsent->len : 0);
   15866              :   unacked = (tpcb->unacked != NULL ? tpcb->unacked->len : 0);
   15867              : /*
   15868              :  * On ESP8266 we only allow one TCP segment in flight at any given time.
   15869              :  * This may increase latency and reduce efficiency of tcp windowing,
   15870              :  * but memory is scarce and precious on that platform so we do this to
   15871              :  * reduce footprint.
   15872              :  */
   15873              : #if CS_PLATFORM == CS_P_ESP8266
   15874              :   if (unacked > 0) {
   15875              :     ctx->ret = 0;
   15876              :     return;
   15877              :   }
   15878              :   len = MIN(len, (TCP_MSS - unsent));
   15879              : #endif
   15880              :   cs->err = tcp_write(tpcb, ctx->data, len, TCP_WRITE_FLAG_COPY);
   15881              :   unsent = (tpcb->unsent != NULL ? tpcb->unsent->len : 0);
   15882              :   unacked = (tpcb->unacked != NULL ? tpcb->unacked->len : 0);
   15883              :   DBG(("%p tcp_write %u = %d, %u %u", tpcb, len, cs->err, unsent, unacked));
   15884              :   if (cs->err != ERR_OK) {
   15885              :     /*
   15886              :      * We ignore ERR_MEM because memory will be freed up when the data is sent
   15887              :      * and we'll retry.
   15888              :      */
   15889              :     ctx->ret = (cs->err == ERR_MEM ? 0 : -1);
   15890              :     return;
   15891              :   }
   15892              :   ctx->ret = len;
   15893              :   (void) unsent;
   15894              :   (void) unacked;
   15895              : }
   15896              : 
   15897              : int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) {
   15898              :   struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = buf, .len = len};
   15899              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15900              :   if (nc->sock == INVALID_SOCKET) return -1;
   15901              :   struct tcp_pcb *tpcb = cs->pcb.tcp;
   15902              :   if (tpcb == NULL) return -1;
   15903              :   if (tpcb->snd_buf <= 0) return 0;
   15904              :   mg_lwip_netif_run_on_tcpip(mg_lwip_tcp_write_tcpip, &ctx);
   15905              :   return ctx.ret;
   15906              : }
   15907              : 
   15908              : struct udp_sendto_ctx {
   15909              :   struct udp_pcb *upcb;
   15910              :   struct pbuf *p;
   15911              :   ip_addr_t *ip;
   15912              :   uint16_t port;
   15913              :   int ret;
   15914              : };
   15915              : 
   15916              : static void udp_sendto_tcpip(void *arg) {
   15917              :   struct udp_sendto_ctx *ctx = (struct udp_sendto_ctx *) arg;
   15918              :   ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port);
   15919              : }
   15920              : 
   15921              : static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data,
   15922              :                                size_t len) {
   15923              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15924              :   if (nc->sock == INVALID_SOCKET || cs->pcb.udp == NULL) return -1;
   15925              :   struct udp_pcb *upcb = cs->pcb.udp;
   15926              :   struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
   15927              : #if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6
   15928              :   ip_addr_t ip = {.u_addr.ip4.addr = nc->sa.sin.sin_addr.s_addr, .type = 0};
   15929              : #else
   15930              :   ip_addr_t ip = {.addr = nc->sa.sin.sin_addr.s_addr};
   15931              : #endif
   15932              :   u16_t port = ntohs(nc->sa.sin.sin_port);
   15933              :   if (p == NULL) return 0;
   15934              :   memcpy(p->payload, data, len);
   15935              :   struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port};
   15936              :   mg_lwip_netif_run_on_tcpip(udp_sendto_tcpip, &ctx);
   15937              :   cs->err = ctx.ret;
   15938              :   pbuf_free(p);
   15939              :   return (cs->err == ERR_OK ? (int) len : -2);
   15940              : }
   15941              : 
   15942              : static int mg_lwip_if_can_send(struct mg_connection *nc,
   15943              :                                struct mg_lwip_conn_state *cs) {
   15944              :   int can_send = 0;
   15945              :   if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
   15946              :     /* We have stuff to send, but can we? */
   15947              :     if (nc->flags & MG_F_UDP) {
   15948              :       /* UDP is always ready for sending. */
   15949              :       can_send = (cs->pcb.udp != NULL);
   15950              :     } else {
   15951              :       can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
   15952              : /* See comment above. */
   15953              : #if CS_PLATFORM == CS_P_ESP8266
   15954              :       if (cs->pcb.tcp->unacked != NULL) can_send = 0;
   15955              : #endif
   15956              :     }
   15957              :   }
   15958              :   return can_send;
   15959              : }
   15960              : 
   15961              : struct tcp_recved_ctx {
   15962              :   struct tcp_pcb *tpcb;
   15963              :   size_t len;
   15964              : };
   15965              : 
   15966              : void tcp_recved_tcpip(void *arg) {
   15967              :   struct tcp_recved_ctx *ctx = (struct tcp_recved_ctx *) arg;
   15968              :   if (ctx->tpcb != NULL) tcp_recved(ctx->tpcb, ctx->len);
   15969              : }
   15970              : 
   15971              : static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf,
   15972              :                                size_t len) {
   15973              :   int res = 0;
   15974              :   char *bufp = buf;
   15975              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   15976              :   if (nc->sock == INVALID_SOCKET) return -1;
   15977              :   mgos_lock();
   15978              :   while (cs->rx_chain != NULL && len > 0) {
   15979              :     struct pbuf *seg = cs->rx_chain;
   15980              :     size_t seg_len = (seg->len - cs->rx_offset);
   15981              :     size_t copy_len = MIN(len, seg_len);
   15982              : 
   15983              :     pbuf_copy_partial(seg, bufp, copy_len, cs->rx_offset);
   15984              :     len -= copy_len;
   15985              :     res += copy_len;
   15986              :     bufp += copy_len;
   15987              :     cs->rx_offset += copy_len;
   15988              :     if (cs->rx_offset == cs->rx_chain->len) {
   15989              :       cs->rx_chain = pbuf_dechain(cs->rx_chain);
   15990              :       pbuf_free(seg);
   15991              :       cs->rx_offset = 0;
   15992              :     }
   15993              :   }
   15994              :   mgos_unlock();
   15995              :   if (res > 0) {
   15996              :     struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = res};
   15997              :     mg_lwip_netif_run_on_tcpip(tcp_recved_tcpip, &ctx);
   15998              :   }
   15999              :   return res;
   16000              : }
   16001              : 
   16002              : int mg_lwip_if_create_conn(struct mg_connection *nc) {
   16003              :   struct mg_lwip_conn_state *cs =
   16004              :       (struct mg_lwip_conn_state *) MG_CALLOC(1, sizeof(*cs));
   16005              :   if (cs == NULL) return 0;
   16006              :   cs->nc = nc;
   16007              :   nc->sock = (intptr_t) cs;
   16008              :   return 1;
   16009              : }
   16010              : 
   16011              : static void udp_remove_tcpip(void *arg) {
   16012              :   udp_remove((struct udp_pcb *) arg);
   16013              : }
   16014              : 
   16015              : void mg_lwip_if_destroy_conn(struct mg_connection *nc) {
   16016              :   if (nc->sock == INVALID_SOCKET) return;
   16017              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   16018              :   if (!(nc->flags & MG_F_UDP)) {
   16019              :     struct tcp_pcb *tpcb = cs->pcb.tcp;
   16020              :     if (tpcb != NULL) {
   16021              :       tcp_arg(tpcb, NULL);
   16022              :       DBG(("%p tcp_close %p", nc, tpcb));
   16023              :       tcp_arg(tpcb, NULL);
   16024              :       mg_lwip_netif_run_on_tcpip(tcp_close_tcpip, tpcb);
   16025              :     }
   16026              :     while (cs->rx_chain != NULL) {
   16027              :       struct pbuf *seg = cs->rx_chain;
   16028              :       cs->rx_chain = pbuf_dechain(cs->rx_chain);
   16029              :       pbuf_free(seg);
   16030              :     }
   16031              :     memset(cs, 0, sizeof(*cs));
   16032              :     MG_FREE(cs);
   16033              :   } else if (nc->listener == NULL) {
   16034              :     /* Only close outgoing UDP pcb or listeners. */
   16035              :     struct udp_pcb *upcb = cs->pcb.udp;
   16036              :     if (upcb != NULL) {
   16037              :       DBG(("%p udp_remove %p", nc, upcb));
   16038              :       mg_lwip_netif_run_on_tcpip(udp_remove_tcpip, upcb);
   16039              :     }
   16040              :     memset(cs, 0, sizeof(*cs));
   16041              :     MG_FREE(cs);
   16042              :   }
   16043              :   nc->sock = INVALID_SOCKET;
   16044              : }
   16045              : 
   16046              : void mg_lwip_if_get_conn_addr(struct mg_connection *nc, int remote,
   16047              :                               union socket_address *sa) {
   16048              :   memset(sa, 0, sizeof(*sa));
   16049              :   if (nc == NULL || nc->sock == INVALID_SOCKET) return;
   16050              :   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   16051              :   if (nc->flags & MG_F_UDP) {
   16052              :     struct udp_pcb *upcb = cs->pcb.udp;
   16053              :     if (remote) {
   16054              :       memcpy(sa, &nc->sa, sizeof(*sa));
   16055              :     } else if (upcb != NULL) {
   16056              :       sa->sin.sin_port = htons(upcb->local_port);
   16057              :       SET_ADDR(sa, &upcb->local_ip);
   16058              :     }
   16059              :   } else {
   16060              :     struct tcp_pcb *tpcb = cs->pcb.tcp;
   16061              :     if (remote) {
   16062              :       memcpy(sa, &nc->sa, sizeof(*sa));
   16063              :     } else if (tpcb != NULL) {
   16064              :       sa->sin.sin_port = htons(tpcb->local_port);
   16065              :       SET_ADDR(sa, &tpcb->local_ip);
   16066              :     }
   16067              :   }
   16068              : }
   16069              : 
   16070              : void mg_lwip_if_sock_set(struct mg_connection *nc, sock_t sock) {
   16071              :   nc->sock = sock;
   16072              : }
   16073              : 
   16074              : /* clang-format off */
   16075              : #define MG_LWIP_IFACE_VTABLE                                          \
   16076              :   {                                                                   \
   16077              :     mg_lwip_if_init,                                                  \
   16078              :     mg_lwip_if_free,                                                  \
   16079              :     mg_lwip_if_add_conn,                                              \
   16080              :     mg_lwip_if_remove_conn,                                           \
   16081              :     mg_lwip_if_poll,                                                  \
   16082              :     mg_lwip_if_listen_tcp,                                            \
   16083              :     mg_lwip_if_listen_udp,                                            \
   16084              :     mg_lwip_if_connect_tcp,                                           \
   16085              :     mg_lwip_if_connect_udp,                                           \
   16086              :     mg_lwip_if_tcp_send,                                              \
   16087              :     mg_lwip_if_udp_send,                                              \
   16088              :     mg_lwip_if_tcp_recv,                                              \
   16089              :     mg_lwip_if_udp_recv,                                              \
   16090              :     mg_lwip_if_create_conn,                                           \
   16091              :     mg_lwip_if_destroy_conn,                                          \
   16092              :     mg_lwip_if_sock_set,                                              \
   16093              :     mg_lwip_if_get_conn_addr,                                         \
   16094              :   }
   16095              : /* clang-format on */
   16096              : 
   16097              : const struct mg_iface_vtable mg_lwip_iface_vtable = MG_LWIP_IFACE_VTABLE;
   16098              : #if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
   16099              : const struct mg_iface_vtable mg_default_iface_vtable = MG_LWIP_IFACE_VTABLE;
   16100              : #endif
   16101              : 
   16102              : #endif /* MG_ENABLE_NET_IF_LWIP_LOW_LEVEL */
   16103              : #ifdef MG_MODULE_LINES
   16104              : #line 1 "common/platforms/lwip/mg_lwip_ev_mgr.c"
   16105              : #endif
   16106              : /*
   16107              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   16108              :  * All rights reserved
   16109              :  *
   16110              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   16111              :  * you may not use this file except in compliance with the License.
   16112              :  * You may obtain a copy of the License at
   16113              :  *
   16114              :  *     http://www.apache.org/licenses/LICENSE-2.0
   16115              :  *
   16116              :  * Unless required by applicable law or agreed to in writing, software
   16117              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   16118              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   16119              :  * See the License for the specific language governing permissions and
   16120              :  * limitations under the License.
   16121              :  */
   16122              : 
   16123              : #if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
   16124              : 
   16125              : #ifndef MG_SIG_QUEUE_LEN
   16126              : #define MG_SIG_QUEUE_LEN 32
   16127              : #endif
   16128              : 
   16129              : struct mg_ev_mgr_lwip_signal {
   16130              :   int sig;
   16131              :   struct mg_connection *nc;
   16132              : };
   16133              : 
   16134              : struct mg_ev_mgr_lwip_data {
   16135              :   struct mg_ev_mgr_lwip_signal sig_queue[MG_SIG_QUEUE_LEN];
   16136              :   int sig_queue_len;
   16137              :   int start_index;
   16138              : };
   16139              : 
   16140              : void mg_lwip_post_signal(enum mg_sig_type sig, struct mg_connection *nc) {
   16141              :   struct mg_ev_mgr_lwip_data *md =
   16142              :       (struct mg_ev_mgr_lwip_data *) nc->iface->data;
   16143              :   mgos_lock();
   16144              :   if (md->sig_queue_len >= MG_SIG_QUEUE_LEN) {
   16145              :     mgos_unlock();
   16146              :     return;
   16147              :   }
   16148              :   int end_index = (md->start_index + md->sig_queue_len) % MG_SIG_QUEUE_LEN;
   16149              :   md->sig_queue[end_index].sig = sig;
   16150              :   md->sig_queue[end_index].nc = nc;
   16151              :   md->sig_queue_len++;
   16152              :   mg_lwip_mgr_schedule_poll(nc->mgr);
   16153              :   mgos_unlock();
   16154              : }
   16155              : 
   16156              : void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
   16157              :   struct mg_ev_mgr_lwip_data *md =
   16158              :       (struct mg_ev_mgr_lwip_data *) mgr->ifaces[MG_MAIN_IFACE]->data;
   16159              :   while (md->sig_queue_len > 0) {
   16160              :     mgos_lock();
   16161              :     int i = md->start_index;
   16162              :     int sig = md->sig_queue[i].sig;
   16163              :     struct mg_connection *nc = md->sig_queue[i].nc;
   16164              :     struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   16165              :     md->start_index = (i + 1) % MG_SIG_QUEUE_LEN;
   16166              :     md->sig_queue_len--;
   16167              :     mgos_unlock();
   16168              :     if (nc->iface == NULL || nc->mgr == NULL) continue;
   16169              :     switch (sig) {
   16170              :       case MG_SIG_CONNECT_RESULT: {
   16171              :         mg_if_connect_cb(nc, cs->err);
   16172              :         break;
   16173              :       }
   16174              :       case MG_SIG_CLOSE_CONN: {
   16175              :         mg_close_conn(nc);
   16176              :         break;
   16177              :       }
   16178              :       case MG_SIG_RECV: {
   16179              :         cs->recv_pending = 0;
   16180              :         mg_if_can_recv_cb(nc);
   16181              :         mbuf_trim(&nc->recv_mbuf);
   16182              :         break;
   16183              :       }
   16184              :       case MG_SIG_TOMBSTONE: {
   16185              :         break;
   16186              :       }
   16187              :       case MG_SIG_ACCEPT: {
   16188              :         mg_lwip_handle_accept(nc);
   16189              :         break;
   16190              :       }
   16191              :     }
   16192              :   }
   16193              : }
   16194              : 
   16195              : void mg_lwip_if_init(struct mg_iface *iface) {
   16196              :   LOG(LL_INFO, ("Mongoose %s, LwIP %u.%u.%u", MG_VERSION, LWIP_VERSION_MAJOR,
   16197              :                 LWIP_VERSION_MINOR, LWIP_VERSION_REVISION));
   16198              :   iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data));
   16199              : #if !NO_SYS && !LWIP_TCPIP_CORE_LOCKING
   16200              :   sys_sem_new(&s_tcpip_call_lock_sem, 1);
   16201              :   sys_sem_new(&s_tcpip_call_sync_sem, 0);
   16202              : #endif
   16203              : }
   16204              : 
   16205              : void mg_lwip_if_free(struct mg_iface *iface) {
   16206              :   MG_FREE(iface->data);
   16207              :   iface->data = NULL;
   16208              : }
   16209              : 
   16210              : void mg_lwip_if_add_conn(struct mg_connection *nc) {
   16211              :   (void) nc;
   16212              : }
   16213              : 
   16214              : void mg_lwip_if_remove_conn(struct mg_connection *nc) {
   16215              :   struct mg_ev_mgr_lwip_data *md =
   16216              :       (struct mg_ev_mgr_lwip_data *) nc->iface->data;
   16217              :   /* Walk the queue and null-out further signals for this conn. */
   16218              :   for (int i = 0; i < MG_SIG_QUEUE_LEN; i++) {
   16219              :     if (md->sig_queue[i].nc == nc) {
   16220              :       md->sig_queue[i].sig = MG_SIG_TOMBSTONE;
   16221              :     }
   16222              :   }
   16223              : }
   16224              : 
   16225              : time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) {
   16226              :   struct mg_mgr *mgr = iface->mgr;
   16227              :   int n = 0;
   16228              :   double now = mg_time();
   16229              :   struct mg_connection *nc, *tmp;
   16230              :   double min_timer = 0;
   16231              :   int num_timers = 0;
   16232              : #if 0
   16233              :   DBG(("begin poll @%u", (unsigned int) (now * 1000)));
   16234              : #endif
   16235              :   mg_ev_mgr_lwip_process_signals(mgr);
   16236              :   for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
   16237              :     struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
   16238              :     tmp = nc->next;
   16239              :     n++;
   16240              :     if (!mg_if_poll(nc, now)) continue;
   16241              :     if (nc->sock != INVALID_SOCKET &&
   16242              :         !(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL &&
   16243              :         cs->pcb.tcp->unsent != NULL) {
   16244              :       mg_lwip_netif_run_on_tcpip(tcp_output_tcpip, cs->pcb.tcp);
   16245              :     }
   16246              :     if (nc->ev_timer_time > 0) {
   16247              :       if (num_timers == 0 || nc->ev_timer_time < min_timer) {
   16248              :         min_timer = nc->ev_timer_time;
   16249              :       }
   16250              :       num_timers++;
   16251              :     }
   16252              : 
   16253              :     if (nc->sock != INVALID_SOCKET) {
   16254              :       if (mg_lwip_if_can_send(nc, cs)) {
   16255              :         mg_if_can_send_cb(nc);
   16256              :         mbuf_trim(&nc->send_mbuf);
   16257              :       }
   16258              :       if (cs->rx_chain != NULL) {
   16259              :         mg_if_can_recv_cb(nc);
   16260              :       } else if (cs->draining_rx_chain) {
   16261              :         /*
   16262              :          * If the connection is about to close, and rx_chain is finally empty,
   16263              :          * send the MG_SIG_CLOSE_CONN signal
   16264              :          */
   16265              :         mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
   16266              :       }
   16267              :     }
   16268              :   }
   16269              : #if 0
   16270              :   DBG(("end poll @%u, %d conns, %d timers (min %u), next in %d ms",
   16271              :        (unsigned int) (now * 1000), n, num_timers,
   16272              :        (unsigned int) (min_timer * 1000), timeout_ms));
   16273              : #endif
   16274              :   (void) timeout_ms;
   16275              :   return now;
   16276              : }
   16277              : 
   16278              : #endif /* MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */
   16279              : #ifdef MG_MODULE_LINES
   16280              : #line 1 "common/platforms/wince/wince_libc.c"
   16281              : #endif
   16282              : /*
   16283              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   16284              :  * All rights reserved
   16285              :  *
   16286              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   16287              :  * you may not use this file except in compliance with the License.
   16288              :  * You may obtain a copy of the License at
   16289              :  *
   16290              :  *     http://www.apache.org/licenses/LICENSE-2.0
   16291              :  *
   16292              :  * Unless required by applicable law or agreed to in writing, software
   16293              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   16294              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   16295              :  * See the License for the specific language governing permissions and
   16296              :  * limitations under the License.
   16297              :  */
   16298              : 
   16299              : #ifdef WINCE
   16300              : 
   16301              : const char *strerror(int err) {
   16302              :   /*
   16303              :    * TODO(alashkin): there is no strerror on WinCE;
   16304              :    * look for similar wce_xxxx function
   16305              :    */
   16306              :   static char buf[10];
   16307              :   snprintf(buf, sizeof(buf), "%d", err);
   16308              :   return buf;
   16309              : }
   16310              : 
   16311              : int open(const char *filename, int oflag, int pmode) {
   16312              :   /*
   16313              :    * TODO(alashkin): mg_open function is not used in mongoose
   16314              :    * but exists in documentation as utility function
   16315              :    * Shall we delete it at all or implement for WinCE as well?
   16316              :    */
   16317              :   DebugBreak();
   16318              :   return 0; /* for compiler */
   16319              : }
   16320              : 
   16321              : int _wstati64(const wchar_t *path, cs_stat_t *st) {
   16322              :   DWORD fa = GetFileAttributesW(path);
   16323              :   if (fa == INVALID_FILE_ATTRIBUTES) {
   16324              :     return -1;
   16325              :   }
   16326              :   memset(st, 0, sizeof(*st));
   16327              :   if ((fa & FILE_ATTRIBUTE_DIRECTORY) == 0) {
   16328              :     HANDLE h;
   16329              :     FILETIME ftime;
   16330              :     st->st_mode |= _S_IFREG;
   16331              :     h = CreateFileW(path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
   16332              :                     FILE_ATTRIBUTE_NORMAL, NULL);
   16333              :     if (h == INVALID_HANDLE_VALUE) {
   16334              :       return -1;
   16335              :     }
   16336              :     st->st_size = GetFileSize(h, NULL);
   16337              :     GetFileTime(h, NULL, NULL, &ftime);
   16338              :     st->st_mtime = (uint32_t)((((uint64_t) ftime.dwLowDateTime +
   16339              :                                 ((uint64_t) ftime.dwHighDateTime << 32)) /
   16340              :                                10000000.0) -
   16341              :                               11644473600);
   16342              :     CloseHandle(h);
   16343              :   } else {
   16344              :     st->st_mode |= _S_IFDIR;
   16345              :   }
   16346              :   return 0;
   16347              : }
   16348              : 
   16349              : /* Windows CE doesn't have neither gmtime nor strftime */
   16350              : static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t) {
   16351              :   FILETIME ft;
   16352              :   SYSTEMTIME systime;
   16353              :   if (t != NULL) {
   16354              :     uint64_t filetime = (*t + 11644473600) * 10000000;
   16355              :     ft.dwLowDateTime = filetime & 0xFFFFFFFF;
   16356              :     ft.dwHighDateTime = (filetime & 0xFFFFFFFF00000000) >> 32;
   16357              :     FileTimeToSystemTime(&ft, &systime);
   16358              :   } else {
   16359              :     GetSystemTime(&systime);
   16360              :   }
   16361              :   /* There is no PRIu16 in WinCE SDK */
   16362              :   snprintf(buf, buf_len, "%d.%d.%d %d:%d:%d GMT", (int) systime.wYear,
   16363              :            (int) systime.wMonth, (int) systime.wDay, (int) systime.wHour,
   16364              :            (int) systime.wMinute, (int) systime.wSecond);
   16365              : }
   16366              : 
   16367              : #endif
   16368              : #ifdef MG_MODULE_LINES
   16369              : #line 1 "common/platforms/pic32/pic32_net_if.h"
   16370              : #endif
   16371              : /*
   16372              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   16373              :  * All rights reserved
   16374              :  *
   16375              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   16376              :  * you may not use this file except in compliance with the License.
   16377              :  * You may obtain a copy of the License at
   16378              :  *
   16379              :  *     http://www.apache.org/licenses/LICENSE-2.0
   16380              :  *
   16381              :  * Unless required by applicable law or agreed to in writing, software
   16382              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   16383              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   16384              :  * See the License for the specific language governing permissions and
   16385              :  * limitations under the License.
   16386              :  */
   16387              : 
   16388              : #ifndef CS_COMMON_PLATFORMS_PIC32_NET_IF_H_
   16389              : #define CS_COMMON_PLATFORMS_PIC32_NET_IF_H_
   16390              : 
   16391              : /* Amalgamated: #include "mongoose/src/net_if.h" */
   16392              : 
   16393              : #ifdef __cplusplus
   16394              : extern "C" {
   16395              : #endif /* __cplusplus */
   16396              : 
   16397              : #ifndef MG_ENABLE_NET_IF_PIC32
   16398              : #define MG_ENABLE_NET_IF_PIC32 MG_NET_IF == MG_NET_IF_PIC32
   16399              : #endif
   16400              : 
   16401              : extern const struct mg_iface_vtable mg_pic32_iface_vtable;
   16402              : 
   16403              : #ifdef __cplusplus
   16404              : }
   16405              : #endif /* __cplusplus */
   16406              : 
   16407              : #endif /* CS_COMMON_PLATFORMS_PIC32_NET_IF_H_ */
   16408              : #ifdef MG_MODULE_LINES
   16409              : #line 1 "common/platforms/pic32/pic32_net_if.c"
   16410              : #endif
   16411              : /*
   16412              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   16413              :  * All rights reserved
   16414              :  *
   16415              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   16416              :  * you may not use this file except in compliance with the License.
   16417              :  * You may obtain a copy of the License at
   16418              :  *
   16419              :  *     http://www.apache.org/licenses/LICENSE-2.0
   16420              :  *
   16421              :  * Unless required by applicable law or agreed to in writing, software
   16422              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   16423              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   16424              :  * See the License for the specific language governing permissions and
   16425              :  * limitations under the License.
   16426              :  */
   16427              : 
   16428              : #if MG_ENABLE_NET_IF_PIC32
   16429              : 
   16430              : int mg_pic32_if_create_conn(struct mg_connection *nc) {
   16431              :   (void) nc;
   16432              :   return 1;
   16433              : }
   16434              : 
   16435              : void mg_pic32_if_recved(struct mg_connection *nc, size_t len) {
   16436              :   (void) nc;
   16437              :   (void) len;
   16438              : }
   16439              : 
   16440              : void mg_pic32_if_add_conn(struct mg_connection *nc) {
   16441              :   (void) nc;
   16442              : }
   16443              : 
   16444              : void mg_pic32_if_init(struct mg_iface *iface) {
   16445              :   (void) iface;
   16446              :   (void) mg_get_errno(); /* Shutup compiler */
   16447              : }
   16448              : 
   16449              : void mg_pic32_if_free(struct mg_iface *iface) {
   16450              :   (void) iface;
   16451              : }
   16452              : 
   16453              : void mg_pic32_if_remove_conn(struct mg_connection *nc) {
   16454              :   (void) nc;
   16455              : }
   16456              : 
   16457              : void mg_pic32_if_destroy_conn(struct mg_connection *nc) {
   16458              :   if (nc->sock == INVALID_SOCKET) return;
   16459              :   /* For UDP, only close outgoing sockets or listeners. */
   16460              :   if (!(nc->flags & MG_F_UDP)) {
   16461              :     /* Close TCP */
   16462              :     TCPIP_TCP_Close((TCP_SOCKET) nc->sock);
   16463              :   } else if (nc->listener == NULL) {
   16464              :     /* Only close outgoing UDP or listeners. */
   16465              :     TCPIP_UDP_Close((UDP_SOCKET) nc->sock);
   16466              :   }
   16467              : 
   16468              :   nc->sock = INVALID_SOCKET;
   16469              : }
   16470              : 
   16471              : int mg_pic32_if_listen_udp(struct mg_connection *nc, union socket_address *sa) {
   16472              :   nc->sock = TCPIP_UDP_ServerOpen(
   16473              :       sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
   16474              :                                     : IP_ADDRESS_TYPE_IPV6,
   16475              :       ntohs(sa->sin.sin_port),
   16476              :       sa->sin.sin_addr.s_addr == 0 ? 0 : (IP_MULTI_ADDRESS *) &sa->sin);
   16477              :   if (nc->sock == INVALID_SOCKET) {
   16478              :     return -1;
   16479              :   }
   16480              :   return 0;
   16481              : }
   16482              : 
   16483              : void mg_pic32_if_udp_send(struct mg_connection *nc, const void *buf,
   16484              :                           size_t len) {
   16485              :   mbuf_append(&nc->send_mbuf, buf, len);
   16486              : }
   16487              : 
   16488              : void mg_pic32_if_tcp_send(struct mg_connection *nc, const void *buf,
   16489              :                           size_t len) {
   16490              :   mbuf_append(&nc->send_mbuf, buf, len);
   16491              : }
   16492              : 
   16493              : int mg_pic32_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) {
   16494              :   nc->sock = TCPIP_TCP_ServerOpen(
   16495              :       sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
   16496              :                                     : IP_ADDRESS_TYPE_IPV6,
   16497              :       ntohs(sa->sin.sin_port),
   16498              :       sa->sin.sin_addr.s_addr == 0 ? 0 : (IP_MULTI_ADDRESS *) &sa->sin);
   16499              :   memcpy(&nc->sa, sa, sizeof(*sa));
   16500              :   if (nc->sock == INVALID_SOCKET) {
   16501              :     return -1;
   16502              :   }
   16503              :   return 0;
   16504              : }
   16505              : 
   16506              : static int mg_accept_conn(struct mg_connection *lc) {
   16507              :   struct mg_connection *nc;
   16508              :   TCP_SOCKET_INFO si;
   16509              :   union socket_address sa;
   16510              : 
   16511              :   nc = mg_if_accept_new_conn(lc);
   16512              : 
   16513              :   if (nc == NULL) {
   16514              :     return 0;
   16515              :   }
   16516              : 
   16517              :   nc->sock = lc->sock;
   16518              :   nc->flags &= ~MG_F_LISTENING;
   16519              : 
   16520              :   if (!TCPIP_TCP_SocketInfoGet((TCP_SOCKET) nc->sock, &si)) {
   16521              :     return 0;
   16522              :   }
   16523              : 
   16524              :   if (si.addressType == IP_ADDRESS_TYPE_IPV4) {
   16525              :     sa.sin.sin_family = AF_INET;
   16526              :     sa.sin.sin_port = htons(si.remotePort);
   16527              :     sa.sin.sin_addr.s_addr = si.remoteIPaddress.v4Add.Val;
   16528              :   } else {
   16529              :     /* TODO(alashkin): do something with _potential_ IPv6 */
   16530              :     memset(&sa, 0, sizeof(sa));
   16531              :   }
   16532              : 
   16533              :   mg_if_accept_tcp_cb(nc, (union socket_address *) &sa, sizeof(sa));
   16534              : 
   16535              :   return mg_pic32_if_listen_tcp(lc, &lc->sa) >= 0;
   16536              : }
   16537              : 
   16538              : char *inet_ntoa(struct in_addr in) {
   16539              :   static char addr[17];
   16540              :   snprintf(addr, sizeof(addr), "%d.%d.%d.%d", (int) in.S_un.S_un_b.s_b1,
   16541              :            (int) in.S_un.S_un_b.s_b2, (int) in.S_un.S_un_b.s_b3,
   16542              :            (int) in.S_un.S_un_b.s_b4);
   16543              :   return addr;
   16544              : }
   16545              : 
   16546              : static void mg_handle_send(struct mg_connection *nc) {
   16547              :   uint16_t bytes_written = 0;
   16548              :   if (nc->flags & MG_F_UDP) {
   16549              :     if (!TCPIP_UDP_RemoteBind(
   16550              :             (UDP_SOCKET) nc->sock,
   16551              :             nc->sa.sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
   16552              :                                              : IP_ADDRESS_TYPE_IPV6,
   16553              :             ntohs(nc->sa.sin.sin_port), (IP_MULTI_ADDRESS *) &nc->sa.sin)) {
   16554              :       nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   16555              :       return;
   16556              :     }
   16557              :     bytes_written = TCPIP_UDP_TxPutIsReady((UDP_SOCKET) nc->sock, 0);
   16558              :     if (bytes_written >= nc->send_mbuf.len) {
   16559              :       if (TCPIP_UDP_ArrayPut((UDP_SOCKET) nc->sock,
   16560              :                              (uint8_t *) nc->send_mbuf.buf,
   16561              :                              nc->send_mbuf.len) != nc->send_mbuf.len) {
   16562              :         nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   16563              :         bytes_written = 0;
   16564              :       }
   16565              :     }
   16566              :   } else {
   16567              :     bytes_written = TCPIP_TCP_FifoTxFreeGet((TCP_SOCKET) nc->sock);
   16568              :     if (bytes_written != 0) {
   16569              :       if (bytes_written > nc->send_mbuf.len) {
   16570              :         bytes_written = nc->send_mbuf.len;
   16571              :       }
   16572              :       if (TCPIP_TCP_ArrayPut((TCP_SOCKET) nc->sock,
   16573              :                              (uint8_t *) nc->send_mbuf.buf,
   16574              :                              bytes_written) != bytes_written) {
   16575              :         nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   16576              :         bytes_written = 0;
   16577              :       }
   16578              :     }
   16579              :   }
   16580              : 
   16581              :   mg_if_sent_cb(nc, bytes_written);
   16582              : }
   16583              : 
   16584              : static void mg_handle_recv(struct mg_connection *nc) {
   16585              :   uint16_t bytes_read = 0;
   16586              :   uint8_t *buf = NULL;
   16587              :   if (nc->flags & MG_F_UDP) {
   16588              :     bytes_read = TCPIP_UDP_GetIsReady((UDP_SOCKET) nc->sock);
   16589              :     if (bytes_read != 0 &&
   16590              :         (nc->recv_mbuf_limit == -1 ||
   16591              :          nc->recv_mbuf.len + bytes_read < nc->recv_mbuf_limit)) {
   16592              :       buf = (uint8_t *) MG_MALLOC(bytes_read);
   16593              :       if (TCPIP_UDP_ArrayGet((UDP_SOCKET) nc->sock, buf, bytes_read) !=
   16594              :           bytes_read) {
   16595              :         nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   16596              :         bytes_read = 0;
   16597              :         MG_FREE(buf);
   16598              :       }
   16599              :     }
   16600              :   } else {
   16601              :     bytes_read = TCPIP_TCP_GetIsReady((TCP_SOCKET) nc->sock);
   16602              :     if (bytes_read != 0) {
   16603              :       if (nc->recv_mbuf_limit != -1 &&
   16604              :           nc->recv_mbuf_limit - nc->recv_mbuf.len > bytes_read) {
   16605              :         bytes_read = nc->recv_mbuf_limit - nc->recv_mbuf.len;
   16606              :       }
   16607              :       buf = (uint8_t *) MG_MALLOC(bytes_read);
   16608              :       if (TCPIP_TCP_ArrayGet((TCP_SOCKET) nc->sock, buf, bytes_read) !=
   16609              :           bytes_read) {
   16610              :         nc->flags |= MG_F_CLOSE_IMMEDIATELY;
   16611              :         MG_FREE(buf);
   16612              :         bytes_read = 0;
   16613              :       }
   16614              :     }
   16615              :   }
   16616              : 
   16617              :   if (bytes_read != 0) {
   16618              :     mg_if_recv_tcp_cb(nc, buf, bytes_read, 1 /* own */);
   16619              :   }
   16620              : }
   16621              : 
   16622              : time_t mg_pic32_if_poll(struct mg_iface *iface, int timeout_ms) {
   16623              :   struct mg_mgr *mgr = iface->mgr;
   16624              :   double now = mg_time();
   16625              :   struct mg_connection *nc, *tmp;
   16626              : 
   16627              :   for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
   16628              :     tmp = nc->next;
   16629              : 
   16630              :     if (nc->flags & MG_F_CONNECTING) {
   16631              :       /* processing connections */
   16632              :       if (nc->flags & MG_F_UDP ||
   16633              :           TCPIP_TCP_IsConnected((TCP_SOCKET) nc->sock)) {
   16634              :         mg_if_connect_cb(nc, 0);
   16635              :       }
   16636              :     } else if (nc->flags & MG_F_LISTENING) {
   16637              :       if (TCPIP_TCP_IsConnected((TCP_SOCKET) nc->sock)) {
   16638              :         /* accept new connections */
   16639              :         mg_accept_conn(nc);
   16640              :       }
   16641              :     } else {
   16642              :       if (nc->send_mbuf.len != 0) {
   16643              :         mg_handle_send(nc);
   16644              :       }
   16645              : 
   16646              :       if (nc->recv_mbuf_limit == -1 ||
   16647              :           nc->recv_mbuf.len < nc->recv_mbuf_limit) {
   16648              :         mg_handle_recv(nc);
   16649              :       }
   16650              :     }
   16651              :   }
   16652              : 
   16653              :   for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
   16654              :     tmp = nc->next;
   16655              :     if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
   16656              :         (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) {
   16657              :       mg_close_conn(nc);
   16658              :     }
   16659              :   }
   16660              : 
   16661              :   return now;
   16662              : }
   16663              : 
   16664              : void mg_pic32_if_sock_set(struct mg_connection *nc, sock_t sock) {
   16665              :   nc->sock = sock;
   16666              : }
   16667              : 
   16668              : void mg_pic32_if_get_conn_addr(struct mg_connection *nc, int remote,
   16669              :                                union socket_address *sa) {
   16670              :   /* TODO(alaskin): not implemented yet */
   16671              : }
   16672              : 
   16673              : void mg_pic32_if_connect_tcp(struct mg_connection *nc,
   16674              :                              const union socket_address *sa) {
   16675              :   nc->sock = TCPIP_TCP_ClientOpen(
   16676              :       sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
   16677              :                                     : IP_ADDRESS_TYPE_IPV6,
   16678              :       ntohs(sa->sin.sin_port), (IP_MULTI_ADDRESS *) &sa->sin);
   16679              :   nc->err = (nc->sock == INVALID_SOCKET) ? -1 : 0;
   16680              : }
   16681              : 
   16682              : void mg_pic32_if_connect_udp(struct mg_connection *nc) {
   16683              :   nc->sock = TCPIP_UDP_ClientOpen(IP_ADDRESS_TYPE_ANY, 0, NULL);
   16684              :   nc->err = (nc->sock == INVALID_SOCKET) ? -1 : 0;
   16685              : }
   16686              : 
   16687              : /* clang-format off */
   16688              : #define MG_PIC32_IFACE_VTABLE                                   \
   16689              :   {                                                             \
   16690              :     mg_pic32_if_init,                                           \
   16691              :     mg_pic32_if_free,                                           \
   16692              :     mg_pic32_if_add_conn,                                       \
   16693              :     mg_pic32_if_remove_conn,                                    \
   16694              :     mg_pic32_if_poll,                                           \
   16695              :     mg_pic32_if_listen_tcp,                                     \
   16696              :     mg_pic32_if_listen_udp,                                     \
   16697              :     mg_pic32_if_connect_tcp,                                    \
   16698              :     mg_pic32_if_connect_udp,                                    \
   16699              :     mg_pic32_if_tcp_send,                                       \
   16700              :     mg_pic32_if_udp_send,                                       \
   16701              :     mg_pic32_if_recved,                                         \
   16702              :     mg_pic32_if_create_conn,                                    \
   16703              :     mg_pic32_if_destroy_conn,                                   \
   16704              :     mg_pic32_if_sock_set,                                       \
   16705              :     mg_pic32_if_get_conn_addr,                                  \
   16706              :   }
   16707              : /* clang-format on */
   16708              : 
   16709              : const struct mg_iface_vtable mg_pic32_iface_vtable = MG_PIC32_IFACE_VTABLE;
   16710              : #if MG_NET_IF == MG_NET_IF_PIC32
   16711              : const struct mg_iface_vtable mg_default_iface_vtable = MG_PIC32_IFACE_VTABLE;
   16712              : #endif
   16713              : 
   16714              : #endif /* MG_ENABLE_NET_IF_PIC32 */
   16715              : #ifdef MG_MODULE_LINES
   16716              : #line 1 "common/platforms/windows/windows_direct.c"
   16717              : #endif
   16718              : /*
   16719              :  * Copyright (c) 2014-2018 Cesanta Software Limited
   16720              :  * All rights reserved
   16721              :  *
   16722              :  * Licensed under the Apache License, Version 2.0 (the ""License"");
   16723              :  * you may not use this file except in compliance with the License.
   16724              :  * You may obtain a copy of the License at
   16725              :  *
   16726              :  *     http://www.apache.org/licenses/LICENSE-2.0
   16727              :  *
   16728              :  * Unless required by applicable law or agreed to in writing, software
   16729              :  * distributed under the License is distributed on an ""AS IS"" BASIS,
   16730              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   16731              :  * See the License for the specific language governing permissions and
   16732              :  * limitations under the License.
   16733              :  */
   16734              : 
   16735              : #ifdef _WIN32
   16736              : 
   16737              : int rmdir(const char *dirname) {
   16738              :   return _rmdir(dirname);
   16739              : }
   16740              : 
   16741              : unsigned int sleep(unsigned int seconds) {
   16742              :   Sleep(seconds * 1000);
   16743              :   return 0;
   16744              : }
   16745              : 
   16746              : #endif /* _WIN32 */
        

Generated by: LCOV version 2.0-1