3 #line 1 "./src/internal.h"
10 #ifndef CS_MONGOOSE_SRC_INTERNAL_H_
11 #define CS_MONGOOSE_SRC_INTERNAL_H_
14 #define MG_MALLOC malloc
18 #define MG_CALLOC calloc
22 #define MG_REALLOC realloc
30 #define MBUF_REALLOC MG_REALLOC
34 #define MBUF_FREE MG_FREE
37 #define MG_SET_PTRPTR(_ptr, _v) \
39 if (_ptr) *(_ptr) = _v; \
43 #define MG_INTERNAL static
48 #define MG_DISABLE_FILESYSTEM
49 #define MG_DISABLE_POPEN
50 #define MG_DISABLE_CGI
51 #define MG_DISABLE_DIRECTORY_LISTING
52 #define MG_DISABLE_SOCKETPAIR
53 #define MG_DISABLE_PFS
59 #define MG_CTL_MSG_MESSAGE_SIZE 8192
67 int *proto,
char *host,
size_t host_len);
76 #ifndef MG_DISABLE_FILESYSTEM
84 int to_wchar(
const char *
path,
wchar_t *wbuf,
size_t wbuf_len);
102 #ifndef MG_DISABLE_FILESYSTEM
112 #ifndef MG_DISABLE_MQTT
118 extern void *(*test_malloc)(
size_t size);
119 extern void *(*test_calloc)(
size_t count,
size_t size);
122 #ifdef MG_MODULE_LINES
123 #line 1 "./src/../../common/base64.c"
130 #ifndef EXCLUDE_COMMON
137 #define NUM_UPPERCASES ('Z' - 'A' + 1)
138 #define NUM_LETTERS (NUM_UPPERCASES * 2)
139 #define NUM_DIGITS ('9' - '0' + 1)
184 const unsigned char *src = (
const unsigned char *) str;
186 for (i = 0; i < len; i++) {
206 #define BASE64_ENCODE_BODY \
207 static const char *b64 = \
208 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
211 for (i = j = 0; i < src_len; i += 3) { \
213 b = i + 1 >= src_len ? 0 : src[i + 1]; \
214 c = i + 2 >= src_len ? 0 : src[i + 2]; \
216 BASE64_OUT(b64[a >> 2]); \
217 BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]); \
218 if (i + 1 < src_len) { \
219 BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]); \
221 if (i + 2 < src_len) { \
222 BASE64_OUT(b64[c & 63]); \
226 while (j % 4 != 0) { \
231 #define BASE64_OUT(ch) \
236 #define BASE64_FLUSH() \
248 #ifndef CS_DISABLE_STDIO
249 #define BASE64_OUT(ch) \
251 fprintf(f, "%c", (ch)); \
255 #define BASE64_FLUSH()
268 static const unsigned char tab[128] = {
302 return tab[ch & 127];
306 unsigned char a,
b,
c, d;
308 while (len >= 4 && (a =
from_b64(s[0])) != 255 &&
313 if (a == 200 || b == 200)
break;
314 *dst++ = a << 2 | b >> 4;
316 *dst++ = b << 4 | c >> 2;
321 return orig_len - len;
325 #ifdef MG_MODULE_LINES
326 #line 1 "./src/../../common/cs_dbg.c"
341 #ifdef CS_ENABLE_DEBUG
347 #ifndef CS_DISABLE_STDIO
351 #ifdef CS_LOG_TS_DIFF
358 #ifdef CS_LOG_TS_DIFF
384 #if defined(CS_LOG_TS_DIFF) && !defined(CS_DISABLE_STDIO)
388 #ifdef MG_MODULE_LINES
389 #line 1 "./src/../../common/cs_dirent.h"
396 #ifndef CS_COMMON_CS_DIRENT_H_
397 #define CS_COMMON_CS_DIRENT_H_
403 #ifdef CS_ENABLE_SPIFFS
409 struct spiffs_dirent de;
413 #define dirent spiffs_dirent
415 int rmdir(
const char *
path);
416 int mkdir(
const char *path, mode_t
mode);
422 char d_name[MAX_PATH];
427 WIN32_FIND_DATAW info;
428 struct dirent result;
432 #if defined(_WIN32) || defined(CS_ENABLE_SPIFFS)
433 DIR *opendir(
const char *dir_name);
434 int closedir(DIR *dir);
435 struct dirent *readdir(DIR *dir);
443 #ifdef MG_MODULE_LINES
444 #line 1 "./src/../../common/cs_dirent.c"
451 #ifndef EXCLUDE_COMMON
465 #define MG_MALLOC malloc
469 DIR *opendir(
const char *
name) {
471 wchar_t wpath[MAX_PATH];
475 SetLastError(ERROR_BAD_ARGUMENTS);
476 }
else if ((dir = (DIR *)
MG_MALLOC(
sizeof(*dir))) == NULL) {
477 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
480 attrs = GetFileAttributesW(wpath);
481 if (attrs != 0xFFFFFFFF && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
482 (void) wcscat(wpath,
L"\\*");
483 dir->handle = FindFirstFileW(wpath, &dir->info);
484 dir->result.d_name[0] =
'\0';
494 int closedir(DIR *dir) {
498 if (dir->handle != INVALID_HANDLE_VALUE)
499 result = FindClose(dir->handle) ? 0 : -1;
503 SetLastError(ERROR_BAD_ARGUMENTS);
509 struct dirent *readdir(DIR *dir) {
510 struct dirent *result = NULL;
513 if (dir->handle != INVALID_HANDLE_VALUE) {
514 result = &dir->result;
515 (void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1,
516 result->d_name,
sizeof(result->d_name), NULL,
519 if (!FindNextFileW(dir->handle, &dir->info)) {
520 (void) FindClose(dir->handle);
521 dir->handle = INVALID_HANDLE_VALUE;
525 SetLastError(ERROR_FILE_NOT_FOUND);
528 SetLastError(ERROR_BAD_ARGUMENTS);
535 #ifdef CS_ENABLE_SPIFFS
537 DIR *opendir(
const char *dir_name) {
541 if (dir_name != NULL && (dir = (DIR *) malloc(
sizeof(*dir))) != NULL &&
542 SPIFFS_opendir(&fs, (
char *) dir_name, &dir->dh) == NULL) {
550 int closedir(DIR *dir) {
552 SPIFFS_closedir(&dir->dh);
558 struct dirent *readdir(DIR *dir) {
559 return SPIFFS_readdir(&dir->dh, &dir->de);
563 int rmdir(
const char *
path) {
568 int mkdir(
const char *
path, mode_t
mode) {
572 return (strlen(path) == 1 && *path ==
'.') ? 0 : ENOTDIR;
581 #ifdef MG_MODULE_LINES
582 #line 1 "./src/../../common/cs_time.c"
593 #if !defined(CS_PLATFORM) || \
594 (CS_PLATFORM != CS_P_CC3200 && CS_PLATFORM != CS_P_MSP432)
595 #include <sys/time.h>
605 if (gettimeofday(&tv, NULL ) != 0)
return 0;
606 now = (
double) tv.tv_sec + (((
double) tv.tv_usec) / 1000000.0);
608 now = GetTickCount() / 1000.0;
612 #ifdef MG_MODULE_LINES
613 #line 1 "./src/../deps/frozen/frozen.c"
634 #ifndef _CRT_SECURE_NO_WARNINGS
635 #define _CRT_SECURE_NO_WARNINGS
645 #define snprintf _snprintf
648 #ifndef FROZEN_REALLOC
649 #define FROZEN_REALLOC realloc
653 #define FROZEN_FREE free
668 #define EXPECT(cond, err_code) \
670 if (!(cond)) return (err_code); \
675 if (_n < 0) return _n; \
677 #define END_OF_STRING (-1)
684 return ch ==
' ' || ch ==
'\t' || ch ==
'\r' || ch ==
'\n';
698 if (ch == expected) {
707 if (ch == expected) {
714 return (ch >=
'a' && ch <=
'z') || (ch >=
'A' && ch <=
'Z');
718 return ch >=
'0' && ch <=
'9';
722 return is_digit(ch) || (ch >=
'a' && ch <= 'f') || (ch >=
'A' && ch <=
'F');
784 if ((ch & 0x80) == 0)
return 1;
797 int n, ch = 0,
len = 0;
801 ch = *(
unsigned char *) f->
cur;
808 }
else if (ch ==
'"') {
821 if (ch ==
'-') f->
cur++;
825 if (f->
cur < f->
end && f->
cur[0] ==
'.') {
831 if (f->
cur < f->
end && (f->
cur[0] ==
'e' || f->
cur[0] ==
'E')) {
834 if ((f->
cur[0] ==
'+' || f->
cur[0] ==
'-')) f->
cur++;
849 while (
cur(f) !=
']') {
851 if (
cur(f) ==
',') f->
cur++;
860 while (i < len && s[i] == str[i]) i++;
861 return i == len ? 1 : 0;
868 for (i = 0; i <
len; i++) {
929 }
else if (ch ==
'"') {
951 while (
cur(f) !=
'}') {
953 if (
cur(f) ==
',') f->
cur++;
983 memset(&frozen, 0,
sizeof(frozen));
984 frozen.
end = s + s_len;
991 return frozen.
cur -
s;
997 memset(&frozen, 0,
sizeof(frozen));
998 frozen.
end = s + s_len;
1002 if (
doit(&frozen) < 0) {
1011 while (p[i] !=
'\0' && p[i] !=
'[' && p[i] !=
'.') i++;
1016 while (path != 0 && path[0] !=
'\0') {
1018 if (path[0] ==
'[') {
1020 for (ind = 0,
n = 1; path[
n] !=
']' && path[
n] !=
'\0';
n++) {
1023 ind += path[
n] -
'0';
1025 if (path[
n++] !=
']')
return 0;
1030 for (i = 0; i < toks[-1].
num_desc; i +=
skip, ind2++) {
1043 if (i == toks[-1].
num_desc)
return 0;
1045 if (path[0] ==
'.') path++;
1046 if (path[0] ==
'\0')
return &toks[
i];
1054 int n = snprintf(tmp,
sizeof(tmp),
"%ld", value);
1055 strncpy(buf, tmp, buf_len > 0 ? buf_len : 0);
1061 int n = snprintf(tmp,
sizeof(tmp),
"%g", value);
1062 strncpy(buf, tmp, buf_len > 0 ? buf_len : 0);
1067 const char *
begin =
s, *
end = s + s_len, *str_end = str +
len;
1072 if (s < end) *s = x; \
1077 while (str < str_end) {
1121 if (buf_len > 0 && len > 0) {
1122 int n = len < buf_len ? len : buf_len;
1123 memcpy(buf, str, n);
1132 const char *
end = s + s_len, *
str, *orig =
s;
1135 while (*fmt !=
'\0') {
1159 str = va_arg(ap,
char *);
1160 len = va_arg(ap,
size_t);
1164 str = va_arg(ap,
char *);
1165 len = va_arg(ap,
size_t);
1169 str = va_arg(ap,
char *);
1173 str = va_arg(ap,
char *);
1199 int json_emit(
char *buf,
int buf_len,
const char *fmt, ...) {
1209 #ifdef MG_MODULE_LINES
1210 #line 1 "./src/../../common/md5.c"
1229 #if !defined(DISABLE_MD5) && !defined(EXCLUDE_COMMON)
1233 #ifndef CS_ENABLE_NATIVE_MD5
1236 #if BYTE_ORDER == BIG_ENDIAN
1238 uint32_t
t = (uint32_t)((
unsigned) buf[3] << 8 | buf[2]) << 16 |
1239 ((
unsigned) buf[1] << 8 | buf[0]);
1240 *(uint32_t *) buf = t;
1249 #define F1(x, y, z) (z ^ (x & (y ^ z)))
1250 #define F2(x, y, z) F1(z, x, y)
1251 #define F3(x, y, z) (x ^ y ^ z)
1252 #define F4(x, y, z) (y ^ (x | ~z))
1254 #define MD5STEP(f, w, x, y, z, data, s) \
1255 (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
1262 ctx->
buf[0] = 0x67452301;
1263 ctx->
buf[1] = 0xefcdab89;
1264 ctx->
buf[2] = 0x98badcfe;
1265 ctx->
buf[3] = 0x10325476;
1272 uint32_t
a,
b,
c, d;
1279 MD5STEP(
F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1280 MD5STEP(
F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1281 MD5STEP(
F1, c, d, a, b, in[2] + 0x242070db, 17);
1282 MD5STEP(
F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1283 MD5STEP(
F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1284 MD5STEP(
F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1285 MD5STEP(
F1, c, d, a, b, in[6] + 0xa8304613, 17);
1286 MD5STEP(
F1, b, c, d, a, in[7] + 0xfd469501, 22);
1287 MD5STEP(
F1, a, b, c, d, in[8] + 0x698098d8, 7);
1288 MD5STEP(
F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1289 MD5STEP(
F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1290 MD5STEP(
F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1291 MD5STEP(
F1, a, b, c, d, in[12] + 0x6b901122, 7);
1292 MD5STEP(
F1, d, a, b, c, in[13] + 0xfd987193, 12);
1293 MD5STEP(
F1, c, d, a, b, in[14] + 0xa679438e, 17);
1294 MD5STEP(
F1, b, c, d, a, in[15] + 0x49b40821, 22);
1296 MD5STEP(
F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1297 MD5STEP(
F2, d, a, b, c, in[6] + 0xc040b340, 9);
1298 MD5STEP(
F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1299 MD5STEP(
F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1300 MD5STEP(
F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1301 MD5STEP(
F2, d, a, b, c, in[10] + 0x02441453, 9);
1302 MD5STEP(
F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1303 MD5STEP(
F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1304 MD5STEP(
F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1305 MD5STEP(
F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1306 MD5STEP(
F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1307 MD5STEP(
F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1308 MD5STEP(
F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1309 MD5STEP(
F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1310 MD5STEP(
F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1311 MD5STEP(
F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1313 MD5STEP(
F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1314 MD5STEP(
F3, d, a, b, c, in[8] + 0x8771f681, 11);
1315 MD5STEP(
F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1316 MD5STEP(
F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1317 MD5STEP(
F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1318 MD5STEP(
F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1319 MD5STEP(
F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1320 MD5STEP(
F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1321 MD5STEP(
F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1322 MD5STEP(
F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1323 MD5STEP(
F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1324 MD5STEP(
F3, b, c, d, a, in[6] + 0x04881d05, 23);
1325 MD5STEP(
F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1326 MD5STEP(
F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1327 MD5STEP(
F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1328 MD5STEP(
F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1330 MD5STEP(
F4, a, b, c, d, in[0] + 0xf4292244, 6);
1331 MD5STEP(
F4, d, a, b, c, in[7] + 0x432aff97, 10);
1332 MD5STEP(
F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1333 MD5STEP(
F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1334 MD5STEP(
F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1335 MD5STEP(
F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1336 MD5STEP(
F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1337 MD5STEP(
F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1338 MD5STEP(
F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1339 MD5STEP(
F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1340 MD5STEP(
F4, c, d, a, b, in[6] + 0xa3014314, 15);
1341 MD5STEP(
F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1342 MD5STEP(
F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1343 MD5STEP(
F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1344 MD5STEP(
F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1345 MD5STEP(
F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1357 if ((ctx->
bits[0] = t + ((uint32_t) len << 3)) < t) ctx->
bits[1]++;
1358 ctx->
bits[1] += (uint32_t) len >> 29;
1360 t = (t >> 3) & 0x3f;
1363 unsigned char *
p = (
unsigned char *) ctx->
in + t;
1367 memcpy(p, buf, len);
1378 memcpy(ctx->
in, buf, 64);
1385 memcpy(ctx->
in, buf, len);
1393 count = (ctx->
bits[0] >> 3) & 0x3F;
1397 count = 64 - 1 -
count;
1399 memset(p, 0, count);
1402 memset(ctx->
in, 0, 56);
1404 memset(p, 0, count - 8);
1408 a = (uint32_t *) ctx->
in;
1409 a[14] = ctx->
bits[0];
1410 a[15] = ctx->
bits[1];
1414 memcpy(digest, ctx->
buf, 16);
1415 memset((
char *) ctx, 0,
sizeof(*ctx));
1425 static const char *hex =
"0123456789abcdef";
1427 for (; len--; p++) {
1428 *to++ = hex[p[0] >> 4];
1429 *to++ = hex[p[0] & 0x0f];
1435 unsigned char hash[16];
1436 const unsigned char *
p;
1443 while ((p = va_arg(ap,
const unsigned char *) ) != NULL) {
1444 size_t len = va_arg(ap,
size_t);
1456 #ifdef MG_MODULE_LINES
1457 #line 1 "./src/../../common/mbuf.c"
1464 #ifndef EXCLUDE_COMMON
1470 #ifndef MBUF_REALLOC
1471 #define MBUF_REALLOC realloc
1475 #define MBUF_FREE free
1485 if (mbuf->
buf != NULL) {
1492 if (new_size > a->
size || (new_size < a->
size && new_size >= a->
len)) {
1499 if (buf == NULL && new_size != 0)
return;
1517 if (~(
size_t) 0 - (
size_t) a->
buf < len)
return 0;
1519 if (a->
len + len <= a->
size) {
1520 memmove(a->
buf + off + len, a->
buf + off, a->
len - off);
1522 memcpy(a->
buf + off, buf, len);
1529 memmove(a->
buf + off + len, a->
buf + off, a->
len - off);
1530 if (buf != NULL) memcpy(a->
buf + off, buf, len);
1546 if (n > 0 && n <= mb->
len) {
1547 memmove(mb->
buf, mb->
buf + n, mb->
len - n);
1553 #ifdef MG_MODULE_LINES
1554 #line 1 "./src/../../common/sha1.c"
1559 #if !defined(DISABLE_SHA1) && !defined(EXCLUDE_COMMON)
1563 #define SHA1HANDSOFF
1569 unsigned char c[64];
1573 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
1577 #if BYTE_ORDER == LITTLE_ENDIAN
1579 (
rol(block->
l[i], 24) & 0xFF00FF00) | (
rol(block->
l[i], 8) & 0x00FF00FF);
1593 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
1594 block->l[(i + 2) & 15] ^ block->l[i & 15], \
1596 #define R0(v, w, x, y, z, i) \
1597 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
1599 #define R1(v, w, x, y, z, i) \
1600 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
1602 #define R2(v, w, x, y, z, i) \
1603 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
1605 #define R3(v, w, x, y, z, i) \
1606 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
1608 #define R4(v, w, x, y, z, i) \
1609 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
1613 uint32_t
a,
b,
c, d,
e;
1616 memcpy(block, buffer, 64);
1622 R0(a, b, c, d, e, 0);
1623 R0(e, a, b, c, d, 1);
1624 R0(d, e, a, b, c, 2);
1625 R0(c, d, e, a, b, 3);
1626 R0(b, c, d, e, a, 4);
1627 R0(a, b, c, d, e, 5);
1628 R0(e, a, b, c, d, 6);
1629 R0(d, e, a, b, c, 7);
1630 R0(c, d, e, a, b, 8);
1631 R0(b, c, d, e, a, 9);
1632 R0(a, b, c, d, e, 10);
1633 R0(e, a, b, c, d, 11);
1634 R0(d, e, a, b, c, 12);
1635 R0(c, d, e, a, b, 13);
1636 R0(b, c, d, e, a, 14);
1637 R0(a, b, c, d, e, 15);
1638 R1(e, a, b, c, d, 16);
1639 R1(d, e, a, b, c, 17);
1640 R1(c, d, e, a, b, 18);
1641 R1(b, c, d, e, a, 19);
1642 R2(a, b, c, d, e, 20);
1643 R2(e, a, b, c, d, 21);
1644 R2(d, e, a, b, c, 22);
1645 R2(c, d, e, a, b, 23);
1646 R2(b, c, d, e, a, 24);
1647 R2(a, b, c, d, e, 25);
1648 R2(e, a, b, c, d, 26);
1649 R2(d, e, a, b, c, 27);
1650 R2(c, d, e, a, b, 28);
1651 R2(b, c, d, e, a, 29);
1652 R2(a, b, c, d, e, 30);
1653 R2(e, a, b, c, d, 31);
1654 R2(d, e, a, b, c, 32);
1655 R2(c, d, e, a, b, 33);
1656 R2(b, c, d, e, a, 34);
1657 R2(a, b, c, d, e, 35);
1658 R2(e, a, b, c, d, 36);
1659 R2(d, e, a, b, c, 37);
1660 R2(c, d, e, a, b, 38);
1661 R2(b, c, d, e, a, 39);
1662 R3(a, b, c, d, e, 40);
1663 R3(e, a, b, c, d, 41);
1664 R3(d, e, a, b, c, 42);
1665 R3(c, d, e, a, b, 43);
1666 R3(b, c, d, e, a, 44);
1667 R3(a, b, c, d, e, 45);
1668 R3(e, a, b, c, d, 46);
1669 R3(d, e, a, b, c, 47);
1670 R3(c, d, e, a, b, 48);
1671 R3(b, c, d, e, a, 49);
1672 R3(a, b, c, d, e, 50);
1673 R3(e, a, b, c, d, 51);
1674 R3(d, e, a, b, c, 52);
1675 R3(c, d, e, a, b, 53);
1676 R3(b, c, d, e, a, 54);
1677 R3(a, b, c, d, e, 55);
1678 R3(e, a, b, c, d, 56);
1679 R3(d, e, a, b, c, 57);
1680 R3(c, d, e, a, b, 58);
1681 R3(b, c, d, e, a, 59);
1682 R4(a, b, c, d, e, 60);
1683 R4(e, a, b, c, d, 61);
1684 R4(d, e, a, b, c, 62);
1685 R4(c, d, e, a, b, 63);
1686 R4(b, c, d, e, a, 64);
1687 R4(a, b, c, d, e, 65);
1688 R4(e, a, b, c, d, 66);
1689 R4(d, e, a, b, c, 67);
1690 R4(c, d, e, a, b, 68);
1691 R4(b, c, d, e, a, 69);
1692 R4(a, b, c, d, e, 70);
1693 R4(e, a, b, c, d, 71);
1694 R4(d, e, a, b, c, 72);
1695 R4(c, d, e, a, b, 73);
1696 R4(b, c, d, e, a, 74);
1697 R4(a, b, c, d, e, 75);
1698 R4(e, a, b, c, d, 76);
1699 R4(d, e, a, b, c, 77);
1700 R4(c, d, e, a, b, 78);
1701 R4(b, c, d, e, a, 79);
1709 memset(block, 0,
sizeof(block));
1710 a = b = c = d = e = 0;
1719 context->
state[0] = 0x67452301;
1720 context->
state[1] = 0xEFCDAB89;
1721 context->
state[2] = 0x98BADCFE;
1722 context->
state[3] = 0x10325476;
1723 context->
state[4] = 0xC3D2E1F0;
1731 j = context->
count[0];
1732 if ((context->
count[0] += len << 3) < j) context->
count[1]++;
1733 context->
count[1] += (len >> 29);
1735 if ((j + len) > 63) {
1736 memcpy(&context->
buffer[j], data, (i = 64 - j));
1738 for (; i + 63 < len; i += 64) {
1744 memcpy(&context->
buffer[j], &data[i], len - i);
1749 unsigned char finalcount[8],
c;
1751 for (i = 0; i < 8; i++) {
1752 finalcount[
i] = (
unsigned char) ((context->
count[(i >= 4 ? 0 : 1)] >>
1753 ((3 - (i & 3)) * 8)) &
1758 while ((context->
count[0] & 504) != 448) {
1763 for (i = 0; i < 20; i++) {
1765 (
unsigned char) ((context->
state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
1767 memset(context,
'\0',
sizeof(*context));
1768 memset(&finalcount,
'\0',
sizeof(finalcount));
1772 const unsigned char *
data,
size_t datalen,
1773 unsigned char out[20]) {
1775 unsigned char buf1[64], buf2[64], tmp_key[20],
i;
1777 if (keylen >
sizeof(buf1)) {
1782 keylen =
sizeof(tmp_key);
1785 memset(buf1, 0,
sizeof(buf1));
1786 memset(buf2, 0,
sizeof(buf2));
1787 memcpy(buf1, key, keylen);
1788 memcpy(buf2, key, keylen);
1790 for (i = 0; i <
sizeof(buf1); i++) {
1807 #ifdef MG_MODULE_LINES
1808 #line 1 "./src/../../common/str_util.c"
1815 #ifndef EXCLUDE_COMMON
1822 for (; l < maxlen && s[
l] !=
'\0'; l++) {
1827 #define C_SNPRINTF_APPEND_CHAR(ch) \
1829 if (i < (int) buf_size) buf[i] = ch; \
1833 #define C_SNPRINTF_FLAG_ZERO 1
1835 #ifdef C_DISABLE_BUILTIN_SNPRINTF
1836 int c_vsnprintf(
char *buf,
size_t buf_size,
const char *fmt, va_list ap) {
1837 return vsnprintf(buf, buf_size, fmt, ap);
1840 static int c_itoa(
char *buf,
size_t buf_size, int64_t num,
int base,
int flags,
1843 int i = 0,
k = 0, neg = 0;
1852 int rem = num % base;
1854 tmp[
k++] =
'0' + rem;
1856 tmp[
k++] =
'a' + (rem - 10);
1863 while (
k < field_width &&
k < (
int)
sizeof(
tmp) - 1) {
1881 int c_vsnprintf(
char *buf,
size_t buf_size,
const char *fmt, va_list ap) {
1882 int ch,
i = 0, len_mod, flags,
precision, field_width;
1884 while ((ch = *fmt++) !=
'\0') {
1896 flags = field_width = precision = len_mod = 0;
1904 while (*fmt >=
'0' && *fmt <=
'9') {
1906 field_width += *fmt++ -
'0';
1910 field_width = va_arg(ap,
int);
1918 precision = va_arg(ap,
int);
1921 while (*fmt >=
'0' && *fmt <=
'9') {
1923 precision += *fmt++ -
'0';
1952 const char *
s = va_arg(ap,
const char *);
1954 int pad = field_width - (precision >= 0 ?
c_strnlen(s, precision) : 0);
1955 for (j = 0; j < pad; j++) {
1962 for (j = 0; (precision <= 0 || j <
precision) && s[j] !=
'\0'; j++) {
1966 }
else if (ch ==
'c') {
1967 ch = va_arg(ap,
int);
1969 }
else if (ch ==
'd' && len_mod == 0) {
1970 i +=
c_itoa(buf + i, buf_size - i, va_arg(ap,
int), 10, flags,
1972 }
else if (ch ==
'd' && len_mod ==
'l') {
1973 i +=
c_itoa(buf + i, buf_size - i, va_arg(ap,
long), 10, flags,
1976 }
else if (ch ==
'd' && len_mod ==
'z') {
1977 i +=
c_itoa(buf + i, buf_size - i, va_arg(ap, ssize_t), 10, flags,
1980 }
else if (ch ==
'd' && len_mod ==
'q') {
1981 i +=
c_itoa(buf + i, buf_size - i, va_arg(ap, int64_t), 10, flags,
1983 }
else if ((ch ==
'x' || ch ==
'u') && len_mod == 0) {
1984 i +=
c_itoa(buf + i, buf_size - i, va_arg(ap,
unsigned),
1985 ch ==
'x' ? 16 : 10, flags, field_width);
1986 }
else if ((ch ==
'x' || ch ==
'u') && len_mod ==
'l') {
1987 i +=
c_itoa(buf + i, buf_size - i, va_arg(ap,
unsigned long),
1988 ch ==
'x' ? 16 : 10, flags, field_width);
1989 }
else if ((ch ==
'x' || ch ==
'u') && len_mod ==
'z') {
1990 i +=
c_itoa(buf + i, buf_size - i, va_arg(ap,
size_t),
1991 ch ==
'x' ? 16 : 10, flags, field_width);
1992 }
else if (ch ==
'p') {
1993 unsigned long num = (
unsigned long) va_arg(ap,
void *);
1996 i +=
c_itoa(buf + i, buf_size - i, num, 16, flags, 0);
2011 buf[i < (int) buf_size ? i : (
int) buf_size - 1] =
'\0';
2018 int c_snprintf(
char *buf,
size_t buf_size,
const char *fmt, ...) {
2028 int to_wchar(
const char *path,
wchar_t *wbuf,
size_t wbuf_len) {
2030 char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *
p;
2032 strncpy(buf, path,
sizeof(buf));
2033 buf[
sizeof(buf) - 1] =
'\0';
2036 p = buf + strlen(buf) - 1;
2037 while (p > buf && p[-1] !=
':' && (p[0] ==
'\\' || p[0] ==
'/')) *p-- =
'\0';
2039 memset(wbuf, 0, wbuf_len *
sizeof(
wchar_t));
2040 ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (
int) wbuf_len);
2046 WideCharToMultiByte(CP_UTF8, 0, wbuf, (
int) wbuf_len, buf2,
sizeof(buf2),
2048 if (strcmp(buf, buf2) != 0) {
2058 const char *
c_strnstr(
const char *
s,
const char *find,
size_t slen) {
2059 size_t find_length = strlen(find);
2062 for (i = 0; i < slen; i++) {
2063 if (i + find_length > slen) {
2067 if (strncmp(&s[i], find, find_length) == 0) {
2076 #ifdef MG_MODULE_LINES
2077 #line 1 "./src/net.c"
2103 #define MG_MAX_HOST_LEN 200
2105 #define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src) \
2106 memcpy(dst, src, sizeof(*dst));
2109 #define _MG_ALLOWED_CONNECT_FLAGS_MASK \
2110 (MG_F_USER_1 | MG_F_USER_2 | MG_F_USER_3 | MG_F_USER_4 | MG_F_USER_5 | \
2111 MG_F_USER_6 | MG_F_WEBSOCKET_NO_DEFRAG)
2113 #define _MG_CALLBACK_MODIFIABLE_FLAGS_MASK \
2114 (MG_F_USER_1 | MG_F_USER_2 | MG_F_USER_3 | MG_F_USER_4 | MG_F_USER_5 | \
2115 MG_F_USER_6 | MG_F_WEBSOCKET_NO_DEFRAG | MG_F_SEND_AND_CLOSE | \
2116 MG_F_CLOSE_IMMEDIATELY | MG_F_IS_WEBSOCKET | MG_F_DELETE_CHUNK)
2119 #define intptr_t long
2131 DBG((
"%p %p", mgr, c));
2149 if (ev_handler == NULL) {
2156 DBG((
"%p %s ev=%d ev_data=%p flags=%lu rmbl=%d smbl=%d", nc,
2157 ev_handler == nc->
handler ?
"user" :
"proto", ev, ev_data, nc->
flags,
2160 #if !defined(NO_LIBC) && !defined(MG_DISABLE_HEXDUMP)
2166 *(
int *) ev_data, ev);
2173 if (ev_handler != NULL) {
2174 unsigned long flags_before = nc->
flags;
2179 if (ev_handler == nc->
handler && nc->
flags != flags_before) {
2187 DBG((
"%p after %s flags=%lu rmbl=%d smbl=%d", nc,
2188 ev_handler == nc->
handler ?
"user" :
"proto", nc->
flags,
2217 #ifdef MG_ENABLE_SSL
2218 if (conn->
ssl != NULL) SSL_free(conn->
ssl);
2224 memset(conn, 0,
sizeof(*conn));
2229 DBG((
"%p %lu", conn, conn->
flags));
2236 memset(m, 0,
sizeof(*m));
2237 #ifndef MG_DISABLE_SOCKETPAIR
2238 m->
ctl[0] = m->
ctl[1] = INVALID_SOCKET;
2245 WSAStartup(MAKEWORD(2, 2), &data);
2247 #elif defined(__unix__)
2250 signal(SIGPIPE, SIG_IGN);
2253 #ifdef MG_ENABLE_SSL
2264 DBG((
"=================================="));
2265 DBG((
"init mgr=%p", m));
2268 #ifdef MG_ENABLE_JAVASCRIPT
2269 static enum v7_err mg_send_js(
struct v7 *v7, v7_val_t *res) {
2270 v7_val_t arg0 = v7_arg(v7, 0);
2271 v7_val_t arg1 = v7_arg(v7, 1);
2275 if (v7_is_string(arg1)) {
2276 const char *
data = v7_get_string(v7, &arg1, &len);
2280 *res = v7_mk_number(len);
2285 enum v7_err mg_enable_javascript(
struct mg_mgr *
m,
struct v7 *v7,
2286 const char *init_file_name) {
2289 v7_set_method(v7, v7_get_global(v7),
"mg_send", mg_send_js);
2290 return v7_exec_file(v7, init_file_name, &v);
2298 if (m == NULL)
return;
2302 #ifndef MG_DISABLE_SOCKETPAIR
2303 if (m->
ctl[0] != INVALID_SOCKET) closesocket(m->
ctl[0]);
2304 if (m->
ctl[1] != INVALID_SOCKET) closesocket(m->
ctl[1]);
2305 m->
ctl[0] = m->
ctl[1] = INVALID_SOCKET;
2309 tmp_conn = conn->
next;
2320 if ((len =
mg_avprintf(&buf,
sizeof(mem), fmt, ap)) > 0) {
2323 if (buf != mem && buf != NULL) {
2339 #ifndef MG_DISABLE_SYNC_RESOLVER
2342 #ifdef MG_ENABLE_GETADDRINFO
2344 struct addrinfo hints, *servinfo, *
p;
2345 struct sockaddr_in *
h = NULL;
2346 memset(&hints, 0,
sizeof hints);
2347 hints.ai_family = AF_INET;
2348 hints.ai_socktype = SOCK_STREAM;
2349 if ((rv = getaddrinfo(host, NULL, NULL, &servinfo)) != 0) {
2350 DBG((
"getaddrinfo(%s) failed: %s", host, strerror(errno)));
2353 for (p = servinfo; p != NULL; p = p->ai_next) {
2354 memcpy(&h, &p->ai_addr,
sizeof(
struct sockaddr_in *));
2355 memcpy(ina, &h->sin_addr,
sizeof(ina));
2357 freeaddrinfo(servinfo);
2361 if ((he = gethostbyname(host)) == NULL) {
2362 DBG((
"gethostbyname(%s) failed: %s", host, strerror(errno)));
2364 memcpy(ina, he->h_addr_list[0],
sizeof(*ina));
2373 return mg_resolve2(host, &ad) ? snprintf(buf, n,
"%s", inet_ntoa(ad)) : 0;
2383 conn->
sock = INVALID_SOCKET;
2430 int *proto,
char *host,
size_t host_len) {
2431 unsigned int a,
b,
c, d, port = 0;
2433 #ifdef MG_ENABLE_IPV6
2442 memset(sa, 0,
sizeof(*sa));
2443 sa->
sin.sin_family = AF_INET;
2445 *proto = SOCK_STREAM;
2447 if (strncmp(str,
"udp://", 6) == 0) {
2449 *proto = SOCK_DGRAM;
2450 }
else if (strncmp(str,
"tcp://", 6) == 0) {
2454 if (sscanf(str,
"%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
2456 sa->
sin.sin_addr.s_addr =
2457 htonl(((uint32_t) a << 24) | ((uint32_t) b << 16) | c << 8 | d);
2458 sa->
sin.sin_port = htons((uint16_t) port);
2459 #ifdef MG_ENABLE_IPV6
2460 }
else if (sscanf(str,
"[%99[^]]]:%u%n", buf, &port, &len) == 2 &&
2461 inet_pton(AF_INET6, buf, &sa->
sin6.sin6_addr)) {
2463 sa->
sin6.sin6_family = AF_INET6;
2464 sa->
sin.sin_port = htons((uint16_t) port);
2466 #ifndef MG_DISABLE_RESOLVER
2467 }
else if (strlen(str) < host_len &&
2468 sscanf(str,
"%[^ :]:%u%n", host, &port, &len) == 2) {
2469 sa->
sin.sin_port = htons((uint16_t) port);
2474 }
else if (sscanf(str,
":%u%n", &port, &len) == 1 ||
2475 sscanf(str,
"%u%n", &port, &len) == 1) {
2477 sa->
sin.sin_port = htons((uint16_t) port);
2483 return port < 0xffffUL && (ch ==
'\0' || ch ==
',' || isspace(ch)) ? len : -1;
2486 #ifdef MG_ENABLE_SSL
2492 #ifndef MG_DISABLE_PFS
2497 static const char mg_s_cipher_list[] =
2498 #if defined(MG_SSL_CRYPTO_MODERN)
2499 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
2500 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
2501 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
2502 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
2503 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
2504 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
2505 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
2506 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:"
2507 "!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
2508 #elif defined(MG_SSL_CRYPTO_OLD)
2509 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
2510 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
2511 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
2512 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
2513 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
2514 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
2515 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
2516 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:"
2517 "ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
2518 "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:"
2519 "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
2520 "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
2522 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
2523 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
2524 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
2525 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
2526 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
2527 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
2528 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
2529 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
2530 "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:"
2531 "DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
2532 "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
2540 static const char mg_s_default_dh_params[] =
2542 -----BEGIN DH PARAMETERS-----\n\
2543 MIIBCAKCAQEAlvbgD/qh9znWIlGFcV0zdltD7rq8FeShIqIhkQ0C7hYFThrBvF2E\n\
2544 Z9bmgaP+sfQwGpVlv9mtaWjvERbu6mEG7JTkgmVUJrUt/wiRzwTaCXBqZkdUO8Tq\n\
2545 +E6VOEQAilstG90ikN1Tfo+K6+X68XkRUIlgawBTKuvKVwBhuvlqTGerOtnXWnrt\n\
2546 ym//hd3cd5PBYGBix0i7oR4xdghvfR2WLVu0LgdThTBb6XP7gLd19cQ1JuBtAajZ\n\
2547 wMuPn7qlUkEFDIkAZy59/Hue/H2Q2vU/JsvVhHWCQBL4F1ofEAt50il6ZxR1QfFK\n\
2548 9VGKDC4oOgm9DlxwwBoC2FjqmvQlqVV3kwIBAg==\n\
2549 -----END DH PARAMETERS-----\n";
2552 static int mg_use_ca_cert(
SSL_CTX *ctx,
const char *cert) {
2555 }
else if (cert == NULL || cert[0] ==
'\0') {
2558 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
2559 return SSL_CTX_load_verify_locations(ctx, cert, NULL) == 1 ? 0 : -2;
2562 static int mg_use_cert(
SSL_CTX *ctx,
const char *pem_file) {
2565 }
else if (pem_file == NULL || pem_file[0] ==
'\0') {
2567 }
else if (SSL_CTX_use_certificate_file(ctx, pem_file, 1) == 0 ||
2568 SSL_CTX_use_PrivateKey_file(ctx, pem_file, 1) == 0) {
2571 #ifndef MG_DISABLE_PFS
2576 bio = BIO_new_file(pem_file,
"r");
2578 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
2586 bio = BIO_new_mem_buf((
void *) mg_s_default_dh_params, -1);
2587 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
2591 SSL_CTX_set_tmp_dh(ctx, dh);
2592 SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
2596 SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
2597 SSL_CTX_use_certificate_chain_file(ctx, pem_file);
2619 const char *ca_cert) {
2620 const char *result = NULL;
2621 DBG((
"%p %s %s", nc, (cert ? cert :
""), (ca_cert ? ca_cert :
"")));
2624 return "SSL for UDP is not supported";
2627 if (nc->
ssl != NULL) {
2637 (nc->
ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
2638 result =
"SSL_CTX_new() failed";
2640 (nc->
ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
2641 result =
"SSL_CTX_new() failed";
2642 }
else if (mg_use_cert(nc->
ssl_ctx, cert) != 0) {
2643 result =
"Invalid ssl cert";
2644 }
else if (mg_use_ca_cert(nc->
ssl_ctx, ca_cert) != 0) {
2645 result =
"Invalid CA cert";
2648 result =
"SSL_new() failed";
2654 SSL_set_fd(nc->
ssl, nc->
sock);
2657 #ifndef MG_DISABLE_PFS
2658 SSL_CTX_set_cipher_list(nc->
ssl_ctx, mg_s_cipher_list);
2667 memset(&opts, 0,
sizeof(opts));
2669 if (nc == NULL)
return NULL;
2694 #if !defined(NO_LIBC) && !defined(MG_DISABLE_HEXDUMP)
2711 DBG((
"%p discarded %d bytes", nc, len));
2739 DBG((
"%p %u", nc, (
unsigned int) len));
2747 if (memcmp(&nc->
sa.
sa, &sa->
sa, sa_len) == 0 && nc->
listener == lc) {
2753 memset(&opts, 0,
sizeof(opts));
2790 DBG((
"%p %s://%s:%hu", nc, proto == SOCK_DGRAM ?
"udp" :
"tcp",
2791 inet_ntoa(sa->
sin.sin_addr), ntohs(sa->
sin.sin_port)));
2794 if (proto == SOCK_DGRAM) {
2804 DBG((
"%p connect, err=%d", nc, err));
2812 #ifndef MG_DISABLE_RESOLVER
2862 memset(&opts, 0,
sizeof(opts));
2879 sizeof(host))) < 0) {
2889 #ifdef MG_ENABLE_SSL
2890 if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
2891 const char *
err =
mg_set_ssl(nc, opts.ssl_cert, opts.ssl_ca_cert);
2897 if (opts.ssl_ca_cert != NULL && (opts.ssl_server_name == NULL ||
2898 strcmp(opts.ssl_server_name,
"*") != 0)) {
2899 if (opts.ssl_server_name == NULL) opts.ssl_server_name = host;
2901 SSL_CTX_kr_set_verify_name(nc->
ssl_ctx, opts.ssl_server_name);
2905 "Server name verification requested but is not supported");
2914 #ifndef MG_DISABLE_RESOLVER
2921 memset(&o, 0,
sizeof(o));
2946 memset(&opts, 0,
sizeof(opts));
2947 return mg_bind_opt(srv, address, event_handler, opts);
2973 if (proto == SOCK_DGRAM) {
2980 DBG((
"Failed to open listener: %d", rc));
2985 #ifdef MG_ENABLE_SSL
2986 if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
2987 const char *
err =
mg_set_ssl(nc, opts.ssl_cert, opts.ssl_ca_cert);
3004 #ifndef MG_DISABLE_SOCKETPAIR
3016 if (mgr->
ctl[0] != INVALID_SOCKET && data != NULL &&
3017 len <
sizeof(ctl_msg.
message)) {
3021 memcpy(ctl_msg.
message, data, len);
3023 offsetof(
struct ctl_msg,
message) + len, 0);
3031 return n >= 0 && n <= 255;
3035 int n,
a,
b,
c, d, slash = 32, len = 0;
3037 if ((sscanf(spec,
"%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
3038 sscanf(spec,
"%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
3043 ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t) c << 8) | d;
3044 *mask = slash ? 0xffffffffU << (32 - slash) : 0;
3056 allowed = (acl == NULL || *acl ==
'\0') ?
'+' :
'-';
3060 if ((flag !=
'+' && flag !=
'-') ||
3065 if (net == (remote_ip & mask)) {
3070 DBG((
"%08x %c", remote_ip, allowed));
3071 return allowed ==
'+';
3089 (
unsigned long) timestamp));
3110 memset(&opts, 0,
sizeof(opts));
3117 #ifdef MG_MODULE_LINES
3118 #line 1 "./src/net_if_socket.c"
3125 #ifndef MG_DISABLE_SOCKET_IF
3130 #define MG_TCP_RECV_BUFFER_SIZE 1024
3131 #define MG_UDP_RECV_BUFFER_SIZE 1500
3134 #ifdef MG_ENABLE_SSL
3141 unsigned long on = 1;
3142 ioctlsocket(sock, FIONBIO, &on);
3143 #elif defined(MG_SOCKET_SIMPLELINK)
3144 SlSockNonblocking_t opt;
3145 opt.NonblockingEnabled = 1;
3146 sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &opt,
sizeof(opt));
3148 int flags = fcntl(sock, F_GETFL, 0);
3149 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
3154 #ifdef MG_SOCKET_SIMPLELINK
3155 DBG((
"n = %d, errno = %d", n, errno));
3156 if (n < 0) errno =
n;
3158 return n == 0 || (n < 0 && errno != EINTR && errno != EINPROGRESS &&
3159 errno != EAGAIN && errno != EWOULDBLOCK
3160 #ifdef MG_SOCKET_SIMPLELINK
3161 && errno != SL_EALREADY
3164 && WSAGetLastError() != WSAEINTR &&
3165 WSAGetLastError() != WSAEWOULDBLOCK
3173 nc->
sock = socket(AF_INET, SOCK_STREAM, 0);
3174 if (nc->
sock == INVALID_SOCKET) {
3175 nc->
err = errno ? errno : 1;
3178 #if !defined(MG_SOCKET_SIMPLELINK) && !defined(MG_ESP8266)
3181 rc = connect(nc->
sock, &sa->
sa,
sizeof(sa->
sin));
3183 DBG((
"%p sock %d err %d", nc, nc->
sock, nc->
err));
3187 nc->
sock = socket(AF_INET, SOCK_DGRAM, 0);
3188 if (nc->
sock == INVALID_SOCKET) {
3189 nc->
err = errno ? errno : 1;
3197 if (sock == INVALID_SOCKET) {
3198 return (errno ? errno : 1);
3206 if (sock == INVALID_SOCKET)
return (errno ? errno : 1);
3230 if (nc->
sock == INVALID_SOCKET)
return;
3232 closesocket(nc->
sock);
3244 nc->
sock = INVALID_SOCKET;
3250 socklen_t sa_len =
sizeof(
sa);
3252 sock_t sock = accept(lc->
sock, &sa.
sa, &sa_len);
3253 if (sock == INVALID_SOCKET) {
3254 if (
mg_is_error(-1))
DBG((
"%p: failed to accept: %d", lc, errno));
3262 DBG((
"%p conn from %s:%d", nc, inet_ntoa(sa.
sin.sin_addr),
3263 ntohs(sa.
sin.sin_port)));
3265 #ifdef MG_ENABLE_SSL
3268 if (nc->
ssl == NULL || SSL_set_fd(nc->
ssl, sock) != 1) {
3283 (sa->
sa.sa_family == AF_INET) ?
sizeof(sa->
sin) :
sizeof(sa->
sin6);
3284 sock_t sock = INVALID_SOCKET;
3285 #if !defined(MG_SOCKET_SIMPLELINK) && !defined(MG_LWIP)
3289 if ((sock = socket(sa->
sa.sa_family, proto, 0)) != INVALID_SOCKET &&
3290 #
if !defined(MG_SOCKET_SIMPLELINK) && \
3292 #if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE)
3294 !setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (
void *) &on,
3298 #if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
3308 !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (
void *) &on,
sizeof(on)) &&
3312 !bind(sock, &sa->
sa, sa_len) &&
3313 (proto == SOCK_DGRAM || listen(sock, SOMAXCONN) == 0)) {
3314 #if !defined(MG_SOCKET_SIMPLELINK) && \
3318 (void) getsockname(sock, &sa->
sa, &sa_len);
3320 }
else if (sock != INVALID_SOCKET) {
3322 sock = INVALID_SOCKET;
3334 if (io->
len == 0)
return;
3342 DBG((
"%p %d %d %d %s:%hu", nc, nc->
sock, n, errno,
3343 inet_ntoa(nc->
sa.
sin.sin_addr), ntohs(nc->
sa.
sin.sin_port)));
3351 #ifdef MG_ENABLE_SSL
3352 if (nc->
ssl != NULL) {
3354 n = SSL_write(nc->
ssl, io->
buf, io->
len);
3355 DBG((
"%p %d bytes -> %d (SSL)", nc, n, nc->
sock));
3357 int ssl_err = mg_ssl_err(nc, n);
3358 if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
3373 DBG((
"%p %d bytes -> %d", nc, n, nc->
sock));
3387 return avail > max ? max : avail;
3399 #ifdef MG_ENABLE_SSL
3400 if (conn->
ssl != NULL) {
3406 DBG((
"%p %d bytes <- %d (SSL)", conn, n, conn->
sock));
3412 if (buf == NULL)
break;
3415 mg_ssl_err(conn, n);
3426 DBG((
"%p %d bytes (PLAIN) <- %d", conn, n, conn->
sock));
3442 socklen_t *sa_len,
char **buf) {
3446 DBG((
"Out of memory"));
3451 DBG((
"%p recvfrom: %s", nc, strerror(errno)));
3460 socklen_t sa_len =
sizeof(
sa);
3462 DBG((
"%p %d bytes from %s:%d", nc, n, inet_ntoa(nc->
sa.
sin.sin_addr),
3463 ntohs(nc->
sa.
sin.sin_port)));
3467 #ifdef MG_ENABLE_SSL
3468 static int mg_ssl_err(
struct mg_connection *conn,
int res) {
3469 int ssl_err = SSL_get_error(conn->
ssl, res);
3470 DBG((
"%p %d -> %d", conn, res, ssl_err));
3471 if (ssl_err == SSL_ERROR_WANT_READ) {
3473 }
else if (ssl_err == SSL_ERROR_WANT_WRITE) {
3477 SSL_write(conn->
ssl,
"", 0);
3484 int server_side = (nc->
listener != NULL);
3485 int res = server_side ? SSL_accept(nc->
ssl) : SSL_connect(nc->ssl);
3486 DBG((
"%p %d res %d %d", nc, server_side, res, errno));
3494 socklen_t sa_len =
sizeof(
sa);
3495 (void) getpeername(nc->
sock, &
sa.sa, &sa_len);
3501 int ssl_err = mg_ssl_err(nc, res);
3502 if (ssl_err != SSL_ERROR_WANT_READ && ssl_err != SSL_ERROR_WANT_WRITE) {
3512 #define _MG_F_FD_CAN_READ 1
3513 #define _MG_F_FD_CAN_WRITE 1 << 1
3514 #define _MG_F_FD_ERROR 1 << 2
3517 DBG((
"%p fd=%d fd_flags=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->
sock,
3521 if (fd_flags != 0) {
3523 #if !defined(MG_SOCKET_SIMPLELINK) && !defined(MG_ESP8266)
3525 socklen_t len =
sizeof(
err);
3527 getsockopt(nc->
sock, SOL_SOCKET, SO_ERROR, (
char *) &err, &len);
3528 if (ret != 0) err = 1;
3536 #ifdef MG_ENABLE_SSL
3537 if (nc->
ssl != NULL && err == 0) {
3538 SSL_set_fd(nc->
ssl, nc->
sock);
3546 }
else if (nc->
err != 0) {
3573 if (!(fd_flags & (_MG_F_FD_CAN_READ | _MG_F_FD_CAN_WRITE))) {
3579 DBG((
"%p after fd=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->
sock, nc->
flags,
3583 #ifndef MG_DISABLE_SOCKETPAIR
3587 (int)
MG_RECV_FUNC(mgr->
ctl[1], (
char *) &ctl_msg,
sizeof(ctl_msg), 0);
3589 DBG((
"read %d from ctl socket", len));
3593 for (nc =
mg_next(mgr, NULL); nc != NULL; nc =
mg_next(mgr, nc)) {
3605 DBG((
"%p %d", nc, sock));
3610 DBG((
"%p using select()", mgr));
3611 #ifndef MG_DISABLE_SOCKETPAIR
3614 }
while (mgr->
ctl[0] == INVALID_SOCKET);
3631 if (sock != INVALID_SOCKET
3633 && sock < FD_SETSIZE
3637 if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
3648 fd_set read_set, write_set, err_set;
3649 sock_t max_fd = INVALID_SOCKET;
3650 int num_fds, num_ev, num_timers = 0;
3656 FD_ZERO(&write_set);
3658 #ifndef MG_DISABLE_SOCKETPAIR
3670 if (nc->
sock != INVALID_SOCKET) {
3675 if (nc->
sock >= FD_SETSIZE && try_dup) {
3676 int new_sock = dup(nc->
sock);
3677 if (new_sock >= 0 && new_sock < FD_SETSIZE) {
3678 closesocket(nc->
sock);
3679 DBG((
"new sock %d -> %d", nc->
sock, new_sock));
3680 nc->
sock = new_sock;
3712 if (num_timers > 0) {
3713 double timer_timeout_ms = (min_timer -
mg_time()) * 1000 + 1 ;
3714 if (timer_timeout_ms < timeout_ms) {
3715 timeout_ms = timer_timeout_ms;
3718 if (timeout_ms < 0) timeout_ms = 0;
3720 tv.tv_sec = timeout_ms / 1000;
3721 tv.tv_usec = (timeout_ms % 1000) * 1000;
3723 num_ev = select((
int) max_fd + 1, &read_set, &write_set, &err_set, &tv);
3725 DBG((
"select @ %ld num_ev=%d of %d, timeout=%d", (
long) now, num_ev, num_fds,
3728 #ifndef MG_DISABLE_SOCKETPAIR
3729 if (num_ev > 0 && mgr->
ctl[1] != INVALID_SOCKET &&
3730 FD_ISSET(mgr->
ctl[1], &read_set)) {
3737 if (nc->
sock != INVALID_SOCKET) {
3739 fd_flags = (FD_ISSET(nc->
sock, &read_set) &&
3746 #ifdef MG_SOCKET_SIMPLELINK
3773 #ifndef MG_DISABLE_SOCKETPAIR
3777 socklen_t len =
sizeof(sa.
sin);
3780 sock = sp[0] = sp[1] = INVALID_SOCKET;
3782 (void) memset(&sa, 0,
sizeof(sa));
3783 sa.
sin.sin_family = AF_INET;
3784 sa.
sin.sin_port = htons(0);
3785 sa.
sin.sin_addr.s_addr = htonl(0x7f000001);
3787 if ((sock = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
3788 }
else if (bind(sock, &sa.
sa, len) != 0) {
3789 }
else if (sock_type == SOCK_STREAM && listen(sock, 1) != 0) {
3790 }
else if (getsockname(sock, &sa.
sa, &len) != 0) {
3791 }
else if ((sp[0] = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
3792 }
else if (connect(sp[0], &sa.
sa, len) != 0) {
3793 }
else if (sock_type == SOCK_DGRAM &&
3794 (getsockname(sp[0], &sa.
sa, &len) != 0 ||
3795 connect(sock, &sa.
sa, len) != 0)) {
3796 }
else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock
3797 : accept(sock, &sa.
sa, &len))) ==
3802 if (sock_type == SOCK_STREAM) closesocket(sock);
3807 if (sp[0] != INVALID_SOCKET) closesocket(sp[0]);
3808 if (sp[1] != INVALID_SOCKET) closesocket(sp[1]);
3809 if (sock != INVALID_SOCKET) closesocket(sock);
3810 sock = sp[0] = sp[1] = INVALID_SOCKET;
3817 #ifndef MG_SOCKET_SIMPLELINK
3820 socklen_t slen =
sizeof(*sa);
3821 memset(sa, 0, slen);
3823 getpeername(sock, &sa->
sa, &slen);
3825 getsockname(sock, &sa->
sa, &slen);
3838 #ifndef MG_SOCKET_SIMPLELINK
3844 if (remote) memcpy(sa, &nc->
sa,
sizeof(*sa));
3849 #ifdef MG_MODULE_LINES
3850 #line 1 "./src/multithreading.c"
3860 #ifdef MG_ENABLE_THREADS
3862 static void multithreaded_ev_handler(
struct mg_connection *c,
int ev,
void *p);
3869 static void *per_connection_thread_function(
void *param) {
3897 static void forwarder_ev_handler(
struct mg_connection *c,
int ev,
void *p) {
3906 static void spawn_handling_thread(
struct mg_connection *nc) {
3922 link_conns(c[0], nc);
3939 mg_start_thread(per_connection_thread_function, c[1]);
3942 static void multithreaded_ev_handler(
struct mg_connection *c,
int ev,
void *p) {
3945 spawn_handling_thread(c);
3946 c->
handler = forwarder_ev_handler;
3953 nc->
handler = multithreaded_ev_handler;
3956 #ifdef MG_MODULE_LINES
3957 #line 1 "./src/uri.c"
3975 for (; *p <
end; (*p)++) {
3980 res->
len = (*p) - res->
p;
3981 if (*p < end) (*p)++;
3986 unsigned int *port,
struct mg_str *path,
struct mg_str *query,
3987 struct mg_str *fragment) {
3988 struct mg_str rscheme = {0, 0}, ruser_info = {0, 0}, rhost = {0, 0},
3989 rpath = {0, 0}, rquery = {0, 0}, rfragment = {0, 0};
3990 unsigned int rport = 0;
4000 const char *p = uri.
p, *
end = p + uri.
len;
4010 for (; p <
end; p++) {
4012 state = P_SCHEME_OR_PORT;
4014 }
else if (*p ==
'/') {
4021 rhost.len = p - uri.
p;
4024 case P_SCHEME_OR_PORT:
4025 if (end - p >= 3 && memcmp(p,
"://", 3) == 0) {
4027 rscheme.
len = p - uri.
p;
4028 state = P_USER_INFO;
4032 rhost.len = p - uri.
p;
4039 for (; p <
end; p++) {
4043 }
else if (*p ==
'/') {
4047 if (p == end || *p ==
'/') {
4052 ruser_info.len = p - ruser_info.p;
4057 for (; p <
end; p++) {
4061 }
else if (*p ==
'/') {
4066 rhost.len = p - rhost.p;
4070 for (; p <
end; p++) {
4088 if (scheme != 0) *scheme = rscheme;
4089 if (user_info != 0) *user_info = ruser_info;
4090 if (host != 0) *host = rhost;
4091 if (port != 0) *port = rport;
4092 if (path != 0) *path = rpath;
4093 if (query != 0) *query = rquery;
4094 if (fragment != 0) *fragment = rfragment;
4101 const char *
s = in->
p, *se = s + in->
len;
4102 char *cp = (
char *) out->
p, *d;
4104 if (in->
len == 0 || *s !=
'/') {
4112 const char *
next =
s;
4115 if (
mg_vcmp(&component,
".") == 0) {
4117 }
else if (
mg_vcmp(&component,
"..") == 0) {
4119 if (d > cp + 1 && *(d - 1) ==
'/') d--;
4120 while (d > cp && *(d - 1) !=
'/') d--;
4122 memmove(d, s, next - s);
4127 if (d == cp) *d++ =
'/';
4133 #ifdef MG_MODULE_LINES
4134 #line 1 "./src/http.c"
4141 #ifndef MG_DISABLE_HTTP
4148 #ifndef MG_DISABLE_HTTP_WEBSOCKET
4149 #define MG_WS_NO_HOST_HEADER_MAGIC ((char *) 0x1)
4153 #if defined(MG_DISABLE_SOCKETPAIR) && !defined(MG_DISABLE_CGI)
4154 #define MG_DISABLE_CGI 1
4206 #ifndef MG_DISABLE_FILESYSTEM
4209 #ifndef MG_DISABLE_CGI
4212 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4232 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4233 static void mg_http_free_proto_data_mp_stream(
4244 #ifndef MG_DISABLE_FILESYSTEM
4247 if (d->
fp != NULL) {
4255 #ifndef MG_DISABLE_CGI
4267 while (current != NULL) {
4269 free((
void *) current->
name);
4279 #ifndef MG_DISABLE_FILESYSTEM
4282 #ifndef MG_DISABLE_CGI
4285 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4286 mg_http_free_proto_data_mp_stream(&pd->mp_stream);
4310 #ifndef MG_DISABLE_FILESYSTEM
4312 #define MIME_ENTRY(_ext, _type) \
4313 { _ext, sizeof(_ext) - 1, _type }
4314 static const struct {
4325 MIME_ENTRY(
"js",
"application/x-javascript"),
4333 MIME_ENTRY(
"torrent",
"application/x-bittorrent"),
4347 MIME_ENTRY(
"exe",
"application/octet-stream"),
4348 MIME_ENTRY(
"zip",
"application/x-zip-compressed"),
4353 MIME_ENTRY(
"arj",
"application/x-arj-compressed"),
4354 MIME_ENTRY(
"rar",
"application/x-rar-compressed"),
4357 MIME_ENTRY(
"swf",
"application/x-shockwave-flash"),
4369 #ifndef MG_DISABLE_DAV
4372 return mkdir(path, mode);
4375 return _mkdir(path);
4382 const char *ext, *overrides;
4386 path_len = strlen(path);
4388 overrides =
opts->custom_mime_types;
4390 ext = path + (path_len - k.
len);
4401 r.
len = strlen(r.
p);
4407 r.
len = strlen(r.
p);
4419 const unsigned char *buf = (
unsigned char *) s;
4422 for (i = 0; i < buf_len; i++) {
4423 if (!isprint(buf[i]) && buf[
i] !=
'\r' && buf[
i] !=
'\n' && buf[
i] < 128) {
4425 }
else if (buf[i] ==
'\n' && i + 1 < buf_len && buf[i + 1] ==
'\n') {
4427 }
else if (buf[i] ==
'\n' && i + 2 < buf_len && buf[i + 1] ==
'\r' &&
4428 buf[i + 2] ==
'\n') {
4443 s =
mg_skip(s, end,
"\r\n", v);
4445 while (v->len > 0 && v->p[v->len - 1] ==
' ') {
4449 if (k->
len == 0 || v->len == 0) {
4451 k->
len = v->len = 0;
4465 const char *
end, *qs;
4468 if (len <= 0)
return len;
4470 memset(hm, 0,
sizeof(*hm));
4477 while (s < end && isspace(*(
unsigned char *) s)) s++;
4487 if ((qs = (
char *) memchr(hm->
uri.
p,
'?', hm->
uri.
len)) != NULL) {
4494 if (end - s < 4 || s[3] !=
' ')
return -1;
4518 if (hm->
body.
len == (
size_t) ~0 && is_req &&
4529 size_t i, len = strlen(name);
4540 #ifndef MG_DISABLE_HTTP_WEBSOCKET
4543 return (flags & 0x80) == 0 || (flags & 0x0f) == 0;
4547 return (flags & 0x80) == 0 && (flags & 0x0f) != 0;
4552 if (wsm->
flags & 0x8) {
4562 mask_len = 0, header_len = 0;
4563 unsigned char *p = (
unsigned char *) nc->
recv_mbuf.
buf, *buf = p,
4565 unsigned *sizep = (
unsigned *) &p[1];
4571 buf_len >= 1 +
sizeof(*sizep) && buf_len >= 1 +
sizeof(*sizep) + *sizep) {
4572 buf += 1 +
sizeof(*sizep) + *sizep;
4573 buf_len -= 1 +
sizeof(*sizep) + *sizep;
4578 mask_len = buf[1] & 128 ? 4 : 0;
4579 if (len < 126 && buf_len >= mask_len) {
4581 header_len = 2 + mask_len;
4582 }
else if (len == 126 && buf_len >= 4 + mask_len) {
4583 header_len = 4 + mask_len;
4584 data_len = ntohs(*(uint16_t *) &buf[2]);
4585 }
else if (buf_len >= 10 + mask_len) {
4586 header_len = 10 + mask_len;
4587 data_len = (((uint64_t) ntohl(*(uint32_t *) &buf[2])) << 32) +
4588 ntohl(*(uint32_t *) &buf[6]);
4592 frame_len = header_len + data_len;
4593 ok = frame_len > 0 && frame_len <= buf_len;
4598 wsm.
size = (size_t) data_len;
4599 wsm.
data = buf + header_len;
4604 for (i = 0; i < data_len; i++) {
4605 buf[i + header_len] ^= (buf + header_len - mask_len)[i % 4];
4614 buf = p + 1 +
sizeof(*sizep);
4620 (*sizep) += wsm.
size;
4624 if (wsm.
flags & 0x80) {
4625 wsm.
data = p + 1 +
sizeof(*sizep);
4666 #ifdef MG_DISABLE_WS_RANDOM_MASK
4669 if (
sizeof(
long) >= 4) {
4670 mask = (uint32_t) random();
4671 }
else if (
sizeof(
long) == 2) {
4672 mask = (uint32_t) random() << 16 | (uint32_t) random();
4681 unsigned char header[10];
4687 }
else if (len < 65535) {
4688 uint16_t
tmp = htons((uint16_t) len);
4690 memcpy(&header[2], &tmp,
sizeof(tmp));
4695 tmp = htonl((uint32_t)((uint64_t) len >> 32));
4696 memcpy(&header[2], &tmp,
sizeof(tmp));
4697 tmp = htonl((uint32_t)(len & 0xffffffff));
4698 memcpy(&header[6], &tmp,
sizeof(tmp));
4704 header[1] |= 1 << 7;
4705 mg_send(nc, header, header_len);
4710 mg_send(nc, header, header_len);
4717 if (ctx->
pos == 0)
return;
4718 for (i = 0; i < (mbuf->
len - ctx->
pos); i++) {
4719 mbuf->
buf[ctx->
pos +
i] ^= ((
char *) &ctx->
mask)[i % 4];
4726 DBG((
"%p %d %d", nc, op, (
int) len));
4738 const struct mg_str *strv,
int strvcnt) {
4742 for (i = 0; i < strvcnt; i++) {
4748 for (i = 0; i < strvcnt; i++) {
4749 mg_send(nc, strv[i].p, strv[i].len);
4760 const char *fmt, ...) {
4766 if ((len =
mg_avprintf(&buf,
sizeof(mem), fmt, ap)) > 0) {
4771 if (buf != mem && buf != NULL) {
4788 time_t now = *(time_t *) ev_data;
4801 const struct mg_str *key) {
4802 static const char *magic =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
4806 snprintf(buf,
sizeof(buf),
"%.*s%s", (
int) key->
len, key->
p, magic);
4814 "HTTP/1.1 101 Switching Protocols\r\n"
4815 "Upgrade: websocket\r\n"
4816 "Connection: Upgrade\r\n"
4817 "Sec-WebSocket-Accept: ",
4818 b64_sha,
"\r\n\r\n");
4819 DBG((
"%p %.*s %s", nc, (
int) key->
len, key->
p, b64_sha));
4824 #ifndef MG_DISABLE_FILESYSTEM
4829 size_t n = 0, to_read = 0;
4833 if (io->
len <
sizeof(buf)) {
4834 to_read =
sizeof(
buf) - io->
len;
4837 if (left > 0 && to_read > (
size_t)
left) {
4844 (n = fread(buf, 1, to_read, pd->
file.
fp)) > 0) {
4854 left <= 0 ? 0 : left < (int64_t) io->
len ? (
size_t) left : io->
len;
4855 size_t n = fwrite(io->
buf, 1, to_write, pd->
file.
fp);
4865 #ifndef MG_DISABLE_CGI
4884 size_t *chunk_len) {
4885 unsigned char *
s = (
unsigned char *) buf;
4890 while (i < len && isxdigit(s[i])) {
4892 n += (s[
i] >=
'0' && s[
i] <=
'9') ? s[i] -
'0' : tolower(s[i]) -
'a' + 10;
4897 if (i == 0 || i + 2 > len || s[i] !=
'\r' || s[i + 1] !=
'\n') {
4903 *chunk_data = (
char *) s + i;
4910 if (i == 0 || i + 2 > len || s[i] !=
'\r' || s[i + 1] !=
'\n') {
4921 size_t i,
n, data_len, body_len, zero_chunk_received = 0;
4925 assert(blen >= body_len);
4932 memmove(buf + body_len, data, data_len);
4933 body_len += data_len;
4936 if (data_len == 0) {
4937 zero_chunk_received = 1;
4946 memmove(buf + body_len, buf + i, blen - i);
4947 memset(buf + body_len + blen - i, 0, i - body_len);
4957 memset(buf, 0, body_len);
4958 memmove(buf, buf + body_len, blen - i);
4963 if (zero_chunk_received) {
4975 int matched, matched_max = 0;
4985 while (ep != NULL) {
4988 if (matched > matched_max) {
4991 matched_max = matched;
5015 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5016 static void mg_http_multipart_continue(
struct mg_connection *nc);
5018 static void mg_http_multipart_begin(
struct mg_connection *nc,
5029 static void mg_http_handler2(
struct mg_connection *nc,
int ev,
void *ev_data,
5034 mg_http_handler2(nc, ev, ev_data, &hm);
5037 static void mg_http_handler2(
struct mg_connection *nc,
int ev,
void *ev_data,
5047 const int is_req = (nc->
listener != NULL);
5048 #ifndef MG_DISABLE_HTTP_WEBSOCKET
5052 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5053 if (pd->mp_stream.boundary != NULL) {
5059 memset(&mp, 0,
sizeof(mp));
5062 mp.
var_name = pd->mp_stream.var_name;
5065 MG_EV_HTTP_PART_END, &mp);
5080 #ifndef MG_DISABLE_FILESYSTEM
5081 if (pd->
file.
fp != NULL) {
5091 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5092 if (pd->mp_stream.boundary != NULL) {
5093 mg_http_multipart_continue(nc);
5106 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5108 s->
len >= 9 && strncmp(s->
p,
"multipart", 9) == 0) {
5109 mg_http_multipart_begin(nc, hm, req_len);
5110 mg_http_multipart_continue(nc);
5118 DBG((
"invalid request"));
5120 }
else if (req_len == 0) {
5123 #ifndef MG_DISABLE_HTTP_WEBSOCKET
5155 #ifdef MG_ENABLE_JAVASCRIPT
5157 struct v7 *v7 = nc->
mgr->v7;
5159 int i, js_callback_handled_request = 0;
5163 v1 = v7_get(v7, v7_get_global(v7),
"Http", ~0);
5164 v2 = v7_get(v7, v1, ev_name, ~0);
5167 args = v7_mk_array(v7);
5168 req = v7_mk_object(v7);
5169 headers = v7_mk_object(v7);
5172 v7_set(v7, req,
"method", ~0,
5174 v7_set(v7, req,
"uri", ~0, v7_mk_string(v7, hm->
uri.
p, hm->
uri.
len, 1));
5175 v7_set(v7, req,
"body", ~0,
5177 v7_set(v7, req,
"headers", ~0, headers);
5181 v7_set(v7, headers, name->
p, name->
len,
5182 v7_mk_string(v7, value->
p, value->
len, 1));
5186 v7_array_push(v7, args, v7_mk_foreign(nc));
5187 v7_array_push(v7, args, req);
5188 if (v7_apply(v7, v2, v7_mk_undefined(), args, &res) == V7_OK &&
5189 v7_is_truthy(v7, res)) {
5190 js_callback_handled_request++;
5195 if (js_callback_handled_request) {
5211 while (len < buf_len && buf[len] !=
'\n') len++;
5212 return len == buf_len ? 0 : len + 1;
5215 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5216 static void mg_http_multipart_begin(
struct mg_connection *nc,
5237 if (ct->
len < 9 || strncmp(ct->
p,
"multipart", 9) != 0) {
5243 if (boundary_len == 0) {
5249 DBG((
"invalid request"));
5255 if (pd->mp_stream.boundary != NULL) {
5262 pd->mp_stream.boundary =
strdup(boundary);
5263 pd->mp_stream.boundary_len = strlen(boundary);
5264 pd->mp_stream.var_name = pd->mp_stream.file_name = NULL;
5279 #define CONTENT_DISPOSITION "Content-Disposition: "
5281 static void mg_http_multipart_call_handler(
struct mg_connection *c,
int ev,
5282 const char *
data,
size_t data_len) {
5285 memset(&mp, 0,
sizeof(mp));
5287 mp.
var_name = pd->mp_stream.var_name;
5291 mp.data.len = data_len;
5296 static int mg_http_multipart_got_chunk(
struct mg_connection *c) {
5300 mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->
buf,
5301 pd->mp_stream.prev_io_len);
5303 pd->mp_stream.prev_io_len = 0;
5309 static int mg_http_multipart_finalize(
struct mg_connection *c) {
5312 mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0);
5313 mg_http_free_proto_data_mp_stream(&pd->mp_stream);
5319 static int mg_http_multipart_wait_for_boundary(
struct mg_connection *c) {
5320 const char *boundary;
5324 if ((
int) io->
len < pd->mp_stream.boundary_len + 2) {
5329 if (boundary != NULL) {
5330 if (io->
len - (boundary - io->
buf) < 4) {
5333 if (memcmp(boundary + pd->mp_stream.boundary_len,
"--", 2) == 0) {
5345 static int mg_http_multipart_process_boundary(
struct mg_connection *c) {
5347 const char *boundary, *block_begin;
5350 char file_name[100], var_name[100];
5353 block_begin = boundary + pd->mp_stream.boundary_len + 2;
5354 data_size = io->
len - (block_begin - io->
buf);
5356 while (data_size > 0 &&
5358 if (line_len > (
int)
sizeof(CONTENT_DISPOSITION) &&
5360 sizeof(CONTENT_DISPOSITION) - 1) == 0) {
5363 header.
p = block_begin +
sizeof(CONTENT_DISPOSITION) - 1;
5364 header.len = line_len -
sizeof(CONTENT_DISPOSITION) - 1;
5367 sizeof(file_name) - 2);
5368 block_begin += line_len;
5369 data_size -= line_len;
5373 if (line_len == 2 &&
mg_ncasecmp(block_begin,
"\r\n", 2) == 0) {
5376 if (pd->mp_stream.processing_part != 0) {
5377 mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0);
5380 free((
void *) pd->mp_stream.file_name);
5381 pd->mp_stream.file_name =
strdup(file_name);
5382 free((
void *) pd->mp_stream.var_name);
5383 pd->mp_stream.var_name =
strdup(var_name);
5385 mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_BEGIN, NULL, 0);
5387 pd->mp_stream.processing_part++;
5391 block_begin += line_len;
5399 static int mg_http_multipart_continue_wait_for_chunk(
struct mg_connection *c) {
5403 const char *boundary;
5404 if ((
int) io->
len < pd->mp_stream.boundary_len + 6 ) {
5409 if (boundary == NULL && pd->mp_stream.prev_io_len == 0) {
5410 pd->mp_stream.prev_io_len = io->
len;
5412 }
else if (boundary == NULL &&
5414 pd->mp_stream.prev_io_len + pd->mp_stream.boundary_len + 4) {
5417 }
else if (boundary != NULL) {
5418 int data_size = (boundary - io->
buf - 4);
5419 mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->
buf, data_size);
5421 pd->mp_stream.prev_io_len = 0;
5429 static void mg_http_multipart_continue(
struct mg_connection *c) {
5432 switch (pd->mp_stream.state) {
5438 if (mg_http_multipart_wait_for_boundary(c) == 0) {
5444 if (mg_http_multipart_process_boundary(c) == 0) {
5450 if (mg_http_multipart_continue_wait_for_chunk(c) == 0) {
5456 if (mg_http_multipart_got_chunk(c) == 0) {
5462 if (mg_http_multipart_finalize(c) == 0) {
5475 struct file_upload_state {
5481 void mg_file_upload_handler(
struct mg_connection *nc,
int ev,
void *ev_data,
5482 mg_fu_fname_fn local_name_fn) {
5484 case MG_EV_HTTP_PART_BEGIN: {
5487 struct file_upload_state *fus =
5488 (
struct file_upload_state *) calloc(1,
sizeof(*fus));
5492 if (lfn.
p == NULL || lfn.
len == 0) {
5495 "HTTP/1.1 403 Not Allowed\r\n"
5496 "Content-Type: text/plain\r\n"
5497 "Connection: close\r\n\r\n"
5498 "Not allowed to upload %s\r\n",
5503 fus->lfn = (
char *) malloc(lfn.
len + 1);
5504 memcpy(fus->lfn, lfn.
p, lfn.
len);
5505 fus->lfn[lfn.
len] =
'\0';
5508 (
"%p Receiving file %s -> %s", nc, mp->
file_name, fus->lfn));
5509 fus->fp = fopen(fus->lfn,
"w");
5510 if (fus->fp == NULL) {
5512 "HTTP/1.1 500 Internal Server Error\r\n"
5513 "Content-Type: text/plain\r\n"
5514 "Connection: close\r\n\r\n");
5515 LOG(
LL_ERROR, (
"Failed to open %s: %d\n", fus->lfn, errno));
5516 mg_printf(nc,
"Failed to open %s: %d\n", fus->lfn, errno);
5524 case MG_EV_HTTP_PART_DATA: {
5527 struct file_upload_state *fus =
5528 (
struct file_upload_state *) mp->
user_data;
5529 if (fus == NULL || fus->fp == NULL)
break;
5531 LOG(
LL_ERROR, (
"Failed to write to %s: %d, wrote %d", fus->lfn, errno,
5532 (
int) fus->num_recd));
5534 #ifdef SPIFFS_ERR_FULL
5535 || errno == SPIFFS_ERR_FULL
5539 "HTTP/1.1 413 Payload Too Large\r\n"
5540 "Content-Type: text/plain\r\n"
5541 "Connection: close\r\n\r\n");
5542 mg_printf(nc,
"Failed to write to %s: no space left; wrote %d\r\n",
5543 fus->lfn, (
int) fus->num_recd);
5546 "HTTP/1.1 500 Internal Server Error\r\n"
5547 "Content-Type: text/plain\r\n"
5548 "Connection: close\r\n\r\n");
5550 errno, (
int) fus->num_recd);
5560 fus->num_recd += mp->
data.
len;
5562 (
int) fus->num_recd));
5565 case MG_EV_HTTP_PART_END: {
5568 struct file_upload_state *fus =
5569 (
struct file_upload_state *) mp->
user_data;
5570 if (fus == NULL)
break;
5571 if (mp->
status >= 0 && fus->fp != NULL) {
5573 fus->lfn, (
int) fus->num_recd));
5575 "HTTP/1.1 200 OK\r\n"
5576 "Content-Type: text/plain\r\n"
5577 "Connection: close\r\n\r\n"
5578 "Ok, %s - %d bytes.\r\n",
5587 if (fus->fp != NULL)
fclose(fus->fp);
5603 #ifndef MG_DISABLE_HTTP_WEBSOCKET
5606 const char *host,
const char *protocol,
5607 const char *extra_headers) {
5609 unsigned long random = (
unsigned long) path;
5610 char key[
sizeof(random) * 3];
5614 "GET %s HTTP/1.1\r\n"
5615 "Upgrade: websocket\r\n"
5616 "Connection: Upgrade\r\n"
5617 "Sec-WebSocket-Version: 13\r\n"
5618 "Sec-WebSocket-Key: %s\r\n",
5625 if (protocol != NULL) {
5626 mg_printf(nc,
"Sec-WebSocket-Protocol: %s\r\n", protocol);
5628 if (extra_headers != NULL) {
5635 const char *extra_headers) {
5643 const char *extra_headers) {
5644 const char *status_message =
"OK";
5645 switch (status_code) {
5647 status_message =
"Partial Content";
5650 status_message =
"Moved";
5653 status_message =
"Found";
5656 status_message =
"Unauthorized";
5659 status_message =
"Forbidden";
5662 status_message =
"Not Found";
5665 status_message =
"Requested range not satisfiable";
5668 status_message =
"I'm a teapot";
5671 status_message =
"Internal Server Error";
5674 mg_printf(nc,
"HTTP/1.1 %d %s\r\nServer: %s\r\n", status_code, status_message,
5676 if (extra_headers != NULL) {
5682 int64_t content_length,
const char *extra_headers) {
5684 if (content_length < 0) {
5685 mg_printf(c,
"%s",
"Transfer-Encoding: chunked\r\n");
5687 mg_printf(c,
"Content-Length: %" INT64_FMT
"\r\n", content_length);
5692 #ifdef MG_DISABLE_FILESYSTEM
5699 const char *reason) {
5700 if (!reason) reason =
"";
5701 DBG((
"%p %d %s", nc, code, reason));
5703 "Content-Type: text/plain\r\nConnection: close");
5704 mg_send(nc, reason, strlen(reason));
5707 #ifndef MG_DISABLE_SSI
5714 while ((n = fread(buf, 1,
sizeof(buf), fp)) > 0) {
5720 char *tag,
int include_level,
5729 if (sscanf(tag,
" virtual=\"%[^\"]\"", file_name) == 1) {
5731 snprintf(path,
sizeof(path),
"%s/%s", opts->
document_root, file_name);
5732 }
else if (sscanf(tag,
" abspath=\"%[^\"]\"", file_name) == 1) {
5737 snprintf(path,
sizeof(path),
"%s", file_name);
5738 }
else if (sscanf(tag,
" file=\"%[^\"]\"", file_name) == 1 ||
5739 sscanf(tag,
" \"%[^\"]\"", file_name) == 1) {
5741 snprintf(path,
sizeof(path),
"%s", ssi);
5742 if ((p = strrchr(path, DIRSEP)) != NULL) {
5745 snprintf(path + strlen(path),
sizeof(path) - strlen(path),
"%s", file_name);
5747 mg_printf(nc,
"Bad SSI #include: [%s]", tag);
5751 if ((fp = fopen(path,
"rb")) == NULL) {
5752 mg_printf(nc,
"SSI include error: fopen(%s): %s", path, strerror(errno));
5765 #ifndef MG_DISABLE_POPEN
5770 if (sscanf(tag,
" \"%[^\"]\"", cmd) != 1) {
5771 mg_printf(nc,
"Bad SSI #exec: [%s]", tag);
5772 }
else if ((fp = popen(cmd,
"r")) == NULL) {
5773 mg_printf(nc,
"Cannot SSI #exec: [%s]: %s", cmd, strerror(errno));
5790 FILE *fp,
int include_level,
5795 #ifndef MG_DISABLE_POPEN
5798 char buf[BUFSIZ], *p = buf + btag.
len;
5799 int ch,
len, in_ssi_tag;
5801 if (include_level > 10) {
5802 mg_printf(nc,
"SSI #include level is too deep (%s)", path);
5806 in_ssi_tag = len = 0;
5807 while ((ch = fgetc(fp)) != EOF) {
5808 if (in_ssi_tag && ch ==
'>' && buf[len - 1] ==
'-' && buf[len - 2] ==
'-') {
5814 while (i > 0 && buf[i] ==
' ') {
5819 if (memcmp(p, d_include.
p, d_include.
len) == 0) {
5821 }
else if (memcmp(p, d_call.
p, d_call.
len) == 0) {
5823 #ifndef MG_DISABLE_POPEN
5824 }
else if (memcmp(p, d_exec.
p, d_exec.
len) == 0) {
5831 }
else if (ch ==
'<') {
5834 mg_send(nc, buf, (
size_t) len);
5837 buf[len++] = ch & 0xff;
5838 }
else if (in_ssi_tag) {
5839 if (len == (
int) btag.
len && memcmp(buf, btag.
p, btag.
len) != 0) {
5842 }
else if (len == (
int)
sizeof(buf) - 2) {
5843 mg_printf(nc,
"%s: SSI tag is too large", path);
5846 buf[len++] = ch & 0xff;
5848 buf[len++] = ch & 0xff;
5849 if (len == (
int)
sizeof(buf)) {
5850 mg_send(nc, buf, (
size_t) len);
5858 mg_send(nc, buf, (
size_t) len);
5867 if ((fp = fopen(path,
"rb")) == NULL) {
5875 "Content-Type: %.*s\r\n"
5876 "Connection: close\r\n\r\n",
5877 (
int) mime_type.
len, mime_type.
p);
5893 const cs_stat_t *st) {
5894 snprintf(buf, buf_len,
"\"%lx.%" INT64_FMT
"\"", (
unsigned long) st->st_mtime,
5895 (int64_t) st->st_size);
5898 strftime(buf, buf_len,
"%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
5909 if (p == NULL)
return 0;
5910 memcpy(p, header->
p, header->
len);
5911 p[header->
len] =
'\0';
5912 result = sscanf(p,
"bytes=%" INT64_FMT
"-%" INT64_FMT, a, b);
5923 DBG((
"%p [%s]", nc, path));
5925 if ((pd->
file.
fp = fopen(path,
"rb")) == NULL) {
5942 char etag[50],
current_time[50], last_modified[50], range[70];
5943 time_t
t =
time(NULL);
5944 int64_t
r1 = 0,
r2 = 0, cl = st->st_size;
5946 int n, status_code = 200;
5950 if (range_hdr != NULL &&
5957 if (r1 >
r2 ||
r2 >= cl) {
5960 snprintf(range,
sizeof(range),
5961 "Content-Range: bytes */%" INT64_FMT
"\r\n",
5962 (int64_t) st->st_size);
5966 snprintf(range,
sizeof(range),
"Content-Range: bytes %" INT64_FMT
5967 "-%" INT64_FMT
"/%" INT64_FMT
"\r\n",
5968 r1, r1 + cl - 1, (int64_t) st->st_size);
5969 #if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \
5970 _XOPEN_SOURCE >= 600
5971 fseeko(pd->
file.
fp, r1, SEEK_SET);
5973 fseek(pd->
file.
fp, r1, SEEK_SET);
5978 #ifndef MG_DISABLE_HTTP_KEEP_ALIVE
5981 if (conn_hdr != NULL) {
6003 "Last-Modified: %s\r\n"
6004 "Accept-Ranges: bytes\r\n"
6005 "Content-Type: %.*s\r\n"
6006 "Connection: %s\r\n"
6007 "Content-Length: %" SIZE_T_FMT
6009 "%sEtag: %s\r\n\r\n",
6010 current_time, last_modified, (
int) mime_type.
len, mime_type.
p,
6011 (pd->
file.
keepalive ?
"keep-alive" :
"close"), (
size_t) cl, range,
6023 int is_form_url_encoded) {
6025 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
6027 for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
6028 if (src[i] ==
'%') {
6029 if (i < src_len - 2 && isxdigit(*(
const unsigned char *) (src + i + 1)) &&
6030 isxdigit(*(
const unsigned char *) (src + i + 2))) {
6031 a = tolower(*(
const unsigned char *) (src + i + 1));
6032 b = tolower(*(
const unsigned char *) (src + i + 2));
6038 }
else if (is_form_url_encoded && src[i] ==
'+') {
6047 return i >= src_len ? j : -1;
6052 const char *
p, *
e, *
s;
6056 if (dst == NULL || dst_len == 0) {
6058 }
else if (buf->
p == NULL || name == NULL || buf->
len == 0) {
6062 name_len = strlen(name);
6063 e = buf->
p + buf->
len;
6067 for (p = buf->
p; p + name_len < e; p++) {
6068 if ((p == buf->
p || p[-1] ==
'&') && p[name_len] ==
'=' &&
6071 s = (
const char *) memchr(p,
'&', (
size_t)(e -
p));
6088 char chunk_size[50];
6091 n = snprintf(chunk_size,
sizeof(chunk_size),
"%lX\r\n", (
unsigned long) len);
6111 if (buf != mem && buf != NULL) {
6127 for (i = j = 0; i <
len; i++) {
6128 if (buf[i] ==
'<' || buf[i] ==
'>') {
6130 mg_send(nc, buf[i] ==
'<' ?
"<" :
">", 4);
6138 if (buf != mem && buf != NULL) {
6146 int ch =
' ', ch1 =
',', len = 0,
n = strlen(var_name);
6147 const char *
p, *
end = hdr ? hdr->
p + hdr->
len : NULL, *
s = NULL;
6149 if (buf != NULL && buf_size > 0) buf[0] =
'\0';
6150 if (hdr == NULL)
return 0;
6153 for (s = hdr->
p; s != NULL && s +
n < end; s++) {
6154 if ((s == hdr->
p || s[-1] == ch || s[-1] == ch1) && s[
n] ==
'=' &&
6155 !memcmp(s, var_name,
n))
6159 if (s != NULL && &s[
n + 1] < end) {
6161 if (*s ==
'"' || *s ==
'\'') {
6165 while (p < end && p[0] != ch && p[0] != ch1 && len < (
int) buf_size) {
6166 if (ch !=
' ' && p[0] ==
'\\' && p[1] == ch) p++;
6169 if (len >= (
int) buf_size || (ch !=
' ' && *p != ch)) {
6172 if (len > 0 && s[len - 1] ==
',') len--;
6173 if (len > 0 && s[len - 1] ==
';') len--;
6181 #ifndef MG_DISABLE_FILESYSTEM
6184 int exclude_specials) {
6189 const char *pdir = strrchr(path, DIRSEP);
6194 return (exclude_specials && (!strcmp(path,
".") || !strcmp(path,
".."))) ||
6200 #ifndef MG_DISABLE_HTTP_DIGEST_AUTH
6201 static void mg_mkmd5resp(
const char *method,
size_t method_len,
const char *uri,
6202 size_t uri_len,
const char *ha1,
size_t ha1_len,
6203 const char *nonce,
size_t nonce_len,
const char *nc,
6204 size_t nc_len,
const char *cnonce,
size_t cnonce_len,
6205 const char *qop,
size_t qop_len,
char *resp) {
6206 static const char colon[] =
":";
6207 static const size_t one = 1;
6210 cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL);
6211 cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc,
6212 nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len,
6213 colon, one, ha2,
sizeof(ha2) - 1, NULL);
6217 const char *method,
const char *uri,
6218 const char *auth_domain,
const char *user,
6219 const char *passwd) {
6220 static const char colon[] =
":", qop[] =
"auth";
6221 static const size_t one = 1;
6222 char ha1[33], resp[33], cnonce[40];
6224 snprintf(cnonce,
sizeof(cnonce),
"%x", (
unsigned int)
time(NULL));
6225 cs_md5(ha1, user, (
size_t) strlen(user), colon, one, auth_domain,
6226 (
size_t) strlen(auth_domain), colon, one, passwd,
6227 (
size_t) strlen(passwd), NULL);
6228 mg_mkmd5resp(method, strlen(method), uri, strlen(uri), ha1,
sizeof(ha1) - 1,
6229 cnonce, strlen(cnonce),
"1", one, cnonce, strlen(cnonce), qop,
6230 sizeof(qop) - 1, resp);
6231 return snprintf(buf, buf_len,
6232 "Authorization: Digest username=\"%s\","
6233 "realm=\"%s\",uri=\"%s\",qop=%s,nc=1,cnonce=%s,"
6234 "nonce=%s,response=%s\r\n",
6235 user, auth_domain, uri, qop, cnonce, cnonce, resp);
6245 unsigned long now = (
unsigned long)
time(NULL);
6246 unsigned long val = (
unsigned long) strtoul(nonce, NULL, 16);
6247 return now < val || now - val < 3600;
6253 char buf[128], f_user[
sizeof(buf)], f_ha1[
sizeof(buf)], f_domain[
sizeof(buf)];
6254 char user[50], cnonce[33], response[40], uri[200], qop[20], nc[20], nonce[30];
6255 char expected_response[33];
6258 if (hm == NULL || fp == NULL ||
6276 while (fgets(buf,
sizeof(buf), fp) != NULL) {
6277 if (sscanf(buf,
"%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3 &&
6278 strcmp(user, f_user) == 0 &&
6280 strcmp(auth_domain, f_domain) == 0) {
6285 f_ha1, strlen(f_ha1), nonce, strlen(nonce), nc, strlen(nc), cnonce,
6286 strlen(cnonce), qop, strlen(qop), expected_response);
6287 return mg_casecmp(response, expected_response) == 0;
6296 int is_directory,
const char *domain,
6297 const char *passwords_file,
6298 int is_global_pass_file) {
6304 if (domain != NULL && passwords_file != NULL) {
6305 if (is_global_pass_file) {
6306 fp = fopen(passwords_file,
"r");
6307 }
else if (is_directory) {
6308 snprintf(buf,
sizeof(buf),
"%s%c%s", path, DIRSEP, passwords_file);
6309 fp = fopen(buf,
"r");
6311 p = strrchr(path, DIRSEP);
6312 if (p == NULL) p =
path;
6313 snprintf(buf,
sizeof(buf),
"%.*s%c%s", (
int) (p - path), path, DIRSEP,
6315 fp = fopen(buf,
"r");
6324 DBG((
"%s %s %d %d", path, passwords_file ? passwords_file :
"",
6325 is_global_pass_file, authorized));
6330 int is_directory,
const char *domain,
6331 const char *passwords_file,
6332 int is_global_pass_file) {
6335 (void) is_directory;
6337 (void) passwords_file;
6338 (void) is_global_pass_file;
6343 #ifndef MG_DISABLE_DIRECTORY_LISTING
6346 static const char *dont_escape =
"._-$,;~()/";
6347 static const char *hex =
"0123456789abcdef";
6348 size_t i = 0,
j = 0;
6350 for (i =
j = 0; dst_len > 0 && i < s_len &&
j + 2 < dst_len - 1; i++,
j++) {
6351 if (isalnum(*(
const unsigned char *) (src + i)) ||
6352 strchr(dont_escape, *(
const unsigned char *) (src + i)) != NULL) {
6354 }
else if (
j + 3 < dst_len) {
6356 dst[
j + 1] = hex[(*(
const unsigned char *) (src + i)) >> 4];
6357 dst[
j + 2] = hex[(*(
const unsigned char *) (src + i)) & 0xf];
6366 static void mg_escape(
const char *src,
char *dst,
size_t dst_len) {
6368 while (*src !=
'\0' && n + 5 < dst_len) {
6369 unsigned char ch = *(
unsigned char *) src++;
6371 n += snprintf(dst + n, dst_len - n,
"%s",
"<");
6382 int64_t fsize = stp->st_size;
6383 int is_dir = S_ISDIR(stp->st_mode);
6384 const char *slash = is_dir ?
"/" :
"";
6387 snprintf(size,
sizeof(size),
"%s",
"[DIRECTORY]");
6394 snprintf(size,
sizeof(size),
"%d", (
int) fsize);
6395 }
else if (fsize < 0x100000) {
6396 snprintf(size,
sizeof(size),
"%.1fk", (
double) fsize / 1024.0);
6397 }
else if (fsize < 0x40000000) {
6398 snprintf(size,
sizeof(size),
"%.1fM", (
double) fsize / 1048576);
6400 snprintf(size,
sizeof(size),
"%.1fG", (
double) fsize / 1073741824);
6403 strftime(mod,
sizeof(mod),
"%d-%b-%Y %H:%M", localtime(&stp->st_mtime));
6404 mg_escape(file_name, path,
sizeof(path));
6405 mg_url_encode(file_name, strlen(file_name), href,
sizeof(href));
6407 "<tr><td><a href=\"%s%s\">%s%s</a></td>"
6408 "<td>%s</td><td name=%" INT64_FMT
">%s</td></tr>\n",
6409 href, slash, path, slash, mod, is_dir ? -1 : fsize,
6422 DBG((
"%p [%s]", nc, dir));
6423 if ((dirp = (opendir(dir))) != NULL) {
6424 while ((dp = readdir(dirp)) != NULL) {
6429 snprintf(path,
sizeof(path),
"%s/%s", dir, dp->d_name);
6430 if (
mg_stat(path, &st) == 0) {
6431 func(nc, (
const char *) dp->d_name, &st);
6436 DBG((
"%p opendir(%s) -> %d", nc, dir, errno));
6443 static const char *sort_js_code =
6444 "<script>function srt(tb, col) {"
6445 "var tr = Array.prototype.slice.call(tb.rows, 0),"
6446 "tr = tr.sort(function (a, b) { var c1 = a.cells[col], c2 = b.cells[col],"
6447 "n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), "
6448 "t1 = a.cells[2].getAttribute('name'), "
6449 "t2 = b.cells[2].getAttribute('name'); "
6450 "return t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : "
6451 "n1 ? parseInt(n2) - parseInt(n1) : "
6452 "c1.textContent.trim().localeCompare(c2.textContent.trim()); });";
6453 static const char *sort_js_code2 =
6454 "for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]);}"
6455 "window.onload = function() { "
6456 "var tb = document.getElementById('tb');"
6457 "document.onclick = function(ev){ "
6458 "var c = ev.target.rel; if (c) srt(tb, c)}; srt(tb, 2); };</script>";
6461 mg_printf(nc,
"%s: %s\r\n%s: %s\r\n\r\n",
"Transfer-Encoding",
"chunked",
6462 "Content-Type",
"text/html; charset=utf-8");
6466 "<html><head><title>Index of %.*s</title>%s%s"
6467 "<style>th,td {text-align: left; padding-right: 1em; "
6468 "font-family: monospace; }</style></head>\n"
6469 "<body><h1>Index of %.*s</h1>\n<table cellpadding=0><thead>"
6470 "<tr><th><a href=# rel=0>Name</a></th><th>"
6471 "<a href=# rel=1>Modified</a</th>"
6472 "<th><a href=# rel=2>Size</a></th></tr>"
6473 "<tr><td colspan=3><hr></td></tr>\n"
6476 (
int) hm->
uri.
len, hm->
uri.
p, sort_js_code, sort_js_code2,
6480 "<tr><td colspan=3><hr></td></tr>\n"
6481 "</tbody></table>\n"
6482 "<address>%s</address>\n"
6491 #ifndef MG_DISABLE_DAV
6495 time_t
t = stp->st_mtime;
6500 "<d:href>%s</d:href>"
6503 "<d:resourcetype>%s</d:resourcetype>"
6504 "<d:getcontentlength>%" INT64_FMT
6505 "</d:getcontentlength>"
6506 "<d:getlastmodified>%s</d:getlastmodified>"
6508 "<d:status>HTTP/1.1 200 OK</d:status>"
6511 buf, S_ISDIR(stp->st_mode) ?
"<d:collection/>" :
"",
6512 (int64_t) stp->st_size, mtime);
6518 static const char header[] =
6519 "HTTP/1.1 207 Multi-Status\r\n"
6520 "Connection: close\r\n"
6521 "Content-Type: text/xml; charset=utf-8\r\n\r\n"
6522 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
6523 "<d:multistatus xmlns:d='DAV:'>\n";
6524 static const char footer[] =
"</d:multistatus>\n";
6528 if (S_ISDIR(stp->st_mode) &&
6530 mg_printf(nc,
"%s",
"HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
6533 mg_send(nc, header,
sizeof(header) - 1);
6534 snprintf(uri,
sizeof(uri),
"%.*s", (
int) hm->
uri.
len, hm->
uri.
p);
6536 if (S_ISDIR(stp->st_mode) && (depth == NULL ||
mg_vcmp(depth,
"0") != 0)) {
6539 mg_send(nc, footer,
sizeof(footer) - 1);
6544 #ifdef MG_ENABLE_FAKE_DAVLOCK
6556 static void mg_handle_lock(
struct mg_connection *nc,
const char *path) {
6557 static const char *reply =
6558 "HTTP/1.1 207 Multi-Status\r\n"
6559 "Connection: close\r\n"
6560 "Content-Type: text/xml; charset=utf-8\r\n\r\n"
6561 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
6562 "<d:multistatus xmlns:d='DAV:'>\n"
6563 "<D:lockdiscovery>\n"
6567 "opaquelocktoken:%s%u"
6571 "</D:lockdiscovery>"
6572 "</d:multistatus>\n";
6580 int status_code = 500;
6583 }
else if (!
mg_mkdir(path, 0755)) {
6585 }
else if (errno == EEXIST) {
6587 }
else if (errno == EACCES) {
6589 }
else if (errno == ENOENT) {
6604 if ((dirp = opendir(dir)) == NULL)
return 0;
6606 while ((dp = readdir(dirp)) != NULL) {
6610 snprintf(path,
sizeof(path),
"%s%c%s", dir,
'/', dp->d_name);
6612 if (S_ISDIR(st.st_mode)) {
6631 const char *p = (
char *) memchr(dest->
p,
'/', dest->
len);
6632 if (p != NULL && p[1] ==
'/' &&
6633 (p = (
char *) memchr(p + 2,
'/', dest->
p + dest->
len - p)) != NULL) {
6636 (
int) (dest->
p + dest->
len - p), p);
6637 if (rename(path, buf) == 0) {
6652 if (
mg_stat(path, &st) != 0) {
6654 }
else if (S_ISDIR(st.st_mode)) {
6657 }
else if (
remove(path) == 0) {
6669 for (s = path + 1; *s !=
'\0'; s++) {
6673 snprintf(buf,
sizeof(buf),
"%.*s", (
int) (s - path), path);
6674 buf[
sizeof(buf) - 1] =
'\0';
6689 int rc, status_code =
mg_stat(path, &st) == 0 ? 200 : 201;
6693 mg_printf(nc,
"HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
6694 }
else if (rc == -1) {
6696 }
else if (cl_hdr == NULL) {
6698 }
else if ((pd->
file.
fp = fopen(path,
"w+b")) == NULL) {
6702 int64_t
r1 = 0,
r2 = 0;
6705 pd->
file.
cl = to64(cl_hdr->
p);
6706 if (range_hdr != NULL &&
6709 fseeko(pd->
file.
fp, r1, SEEK_SET);
6712 mg_printf(nc,
"HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
6721 static const char *methods[] = {
"PUT",
"DELETE",
"MKCOL",
"PROPFIND",
"MOVE"
6722 #ifdef MG_ENABLE_FAKE_DAVLOCK
6730 if (
mg_vcmp(s, methods[i]) == 0) {
6746 char **index_file, cs_stat_t *stp) {
6748 size_t path_len = strlen(path);
6756 size_t len = path_len + 1 + vec.
len + 1;
6757 *index_file = (
char *)
MG_REALLOC(*index_file, len);
6758 if (*index_file == NULL)
break;
6759 snprintf(*index_file, len,
"%s%c%.*s", path, DIRSEP, (
int) vec.
len, vec.
p);
6762 if (
mg_stat(*index_file, &st) == 0 && S_ISREG(st.st_mode)) {
6773 DBG((
"[%s] [%s]", path, (*index_file ? *index_file :
"")));
6781 char local_port[20] = {
'%'};
6787 if (
mg_vcmp(&a, local_port) == 0) {
6789 mg_printf(c,
"Content-Length: 0\r\nLocation: %.*s%.*s\r\n\r\n",
6802 struct mg_str *remainder) {
6805 struct mg_str root = {NULL, 0};
6806 const char *file_uri_start = cp;
6808 remainder->
p = NULL;
6817 if (a.
len > 1 && a.
p[0] ==
'@') {
6819 if (hh != NULL && hh->
len == a.
len - 1 &&
6827 if (match_len > 0) {
6828 file_uri_start = hm->
uri.
p + match_len;
6829 if (*file_uri_start ==
'/' || file_uri_start == cp_end) {
6831 }
else if (*(file_uri_start - 1) ==
'/') {
6844 if (root.
p == NULL) {
6845 #ifndef MG_DISABLE_DAV
6860 const char *
u = file_uri_start + 1;
6862 char *lp_end = lp + root.
len + hm->
uri.
len + 1;
6869 memcpy(p, root.
p, root.
len);
6871 if (*(p - 1) == DIRSEP) p--;
6876 while (u <= cp_end) {
6877 const char *
next =
u;
6881 exists = (
mg_stat(lp, &st) == 0);
6882 if (exists && S_ISREG(st.st_mode)) {
6885 if (*(u - 1) ==
'/') u--;
6889 if (u >= cp_end)
break;
6891 if (component.
len > 0) {
6893 memmove(p + 1, component.
p, component.
len);
6899 component.
p = p + 1;
6901 if (
mg_vcmp(&component,
".") == 0) {
6903 }
else if (
mg_vcmp(&component,
"..") == 0) {
6904 while (p > ps && *p != DIRSEP) p--;
6912 DBG((
"[%.*s] smells funny", (
int) component.
len, component.
p));
6919 for (i = 0; i < component.
len; i++, p++) {
6920 if (*p ==
'\0' || *p == DIRSEP
6938 remainder->
len = cp_end -
u;
6945 DBG((
"'%.*s' -> '%s' + '%.*s'", (
int) hm->
uri.
len, hm->
uri.
p,
6946 *local_path ? *local_path :
"", (
int) remainder->
len, remainder->
p));
6950 #ifndef MG_DISABLE_CGI
6952 struct mg_threadparam {
6957 static int mg_wait_until_ready(sock_t sock,
int for_read) {
6961 return select(sock + 1, for_read ? &
set : 0, for_read ? 0 : &
set, 0, 0) == 1;
6964 static void *mg_push_to_stdin(
void *arg) {
6965 struct mg_threadparam *
tp = (
struct mg_threadparam *) arg;
6966 int n, sent, stop = 0;
6970 while (!stop && mg_wait_until_ready(tp->s, 1) &&
6971 (n = recv(tp->s, buf,
sizeof(buf), 0)) > 0) {
6972 if (n == -1 && GetLastError() == WSAEWOULDBLOCK)
continue;
6973 for (sent = 0; !stop && sent <
n; sent +=
k) {
6974 if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1;
6977 DBG((
"%s",
"FORWARED EVERYTHING TO CGI"));
6978 CloseHandle(tp->hPipe);
6984 static void *mg_pull_from_stdout(
void *arg) {
6985 struct mg_threadparam *tp = (
struct mg_threadparam *) arg;
6986 int k = 0, stop = 0;
6990 while (!stop &&
ReadFile(tp->hPipe, buf,
sizeof(buf), &n, NULL)) {
6991 for (sent = 0; !stop && sent <
n; sent +=
k) {
6992 if (mg_wait_until_ready(tp->s, 0) &&
6993 (k = send(tp->s, buf + sent, n - sent, 0)) <= 0)
6997 DBG((
"%s",
"EOF FROM CGI"));
6998 CloseHandle(tp->hPipe);
7006 static void mg_spawn_stdio_thread(sock_t sock, HANDLE hPipe,
7007 void *(*func)(
void *)) {
7008 struct mg_threadparam *tp = (
struct mg_threadparam *)
MG_MALLOC(
sizeof(*tp));
7012 mg_start_thread(func, tp);
7016 static void mg_abs_path(
const char *utf8_path,
char *abs_path,
size_t len) {
7019 GetFullPathNameW(buf,
ARRAY_SIZE(buf2), buf2, NULL);
7020 WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0);
7024 const char *
env,
const char *envp[],
7025 const char *dir, sock_t sock) {
7027 PROCESS_INFORMATION
pi;
7028 HANDLE
a[2],
b[2], me = GetCurrentProcess();
7032 DWORD flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
7035 memset(&si, 0,
sizeof(si));
7036 memset(&pi, 0,
sizeof(pi));
7039 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
7040 si.wShowWindow = SW_HIDE;
7041 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
7043 CreatePipe(&a[0], &a[1], NULL, 0);
7044 CreatePipe(&b[0], &b[1], NULL, 0);
7045 DuplicateHandle(me, a[0], me, &si.hStdInput, 0,
TRUE, flags);
7046 DuplicateHandle(me, b[1], me, &si.hStdOutput, 0,
TRUE, flags);
7048 if (interp == NULL && (fp = fopen(cmd,
"r")) != NULL) {
7049 buf[0] = buf[1] =
'\0';
7050 fgets(buf,
sizeof(buf), fp);
7051 buf[
sizeof(buf) - 1] =
'\0';
7052 if (buf[0] ==
'#' && buf[1] ==
'!') {
7055 while (*interp !=
'\0' && isspace(*(
unsigned char *) interp)) {
7062 snprintf(buf,
sizeof(buf),
"%s/%s", dir, cmd);
7066 to_wchar(dir, full_dir,
ARRAY_SIZE(full_dir));
7068 if (interp != NULL) {
7070 snprintf(cmdline,
sizeof(cmdline),
"%s \"%s\"", buf4, buf2);
7072 snprintf(cmdline,
sizeof(cmdline),
"\"%s\"", buf2);
7076 if (CreateProcessW(NULL, wcmd, NULL, NULL,
TRUE, CREATE_NEW_PROCESS_GROUP,
7077 (
void *) env, full_dir, &si, &pi) != 0) {
7078 mg_spawn_stdio_thread(sock, a[1], mg_push_to_stdin);
7079 mg_spawn_stdio_thread(sock, b[0], mg_pull_from_stdout);
7085 DBG((
"CGI command: [%ls] -> %p", wcmd, pi.hProcess));
7088 CloseHandle(si.hStdOutput);
7089 CloseHandle(si.hStdInput);
7098 const char *env,
const char *envp[],
7099 const char *dir, sock_t sock) {
7109 int tmp = chdir(dir);
7111 (void) dup2(sock, 0);
7112 (void) dup2(sock, 1);
7121 signal(SIGCHLD, SIG_DFL);
7123 if (interp == NULL) {
7124 execle(cmd, cmd, (
char *) 0, envp);
7126 execle(interp, interp, cmd, (
char *) 0, envp);
7128 snprintf(buf,
sizeof(buf),
7129 "Status: 500\r\n\r\n"
7130 "500 Server Error: %s%s%s: %s",
7131 interp == NULL ?
"" : interp, interp == NULL ?
"" :
" ", cmd,
7133 send(1, buf, strlen(buf), 0);
7147 char *added = block->
buf + block->
len;
7151 space =
sizeof(block->
buf) - (block->
len + 2);
7155 n = vsnprintf(added, (
size_t) space, fmt, ap);
7159 if (n > 0 && n + 1 < space &&
7164 block->
len += n + 1;
7173 if ((s = getenv(name)) != NULL)
mg_addenv(blk,
"%s=%s", name, s);
7178 const struct mg_str *path_info,
7191 if ((s = getenv(
"SERVER_NAME")) != NULL) {
7202 mg_addenv(blk,
"%s",
"GATEWAY_INTERFACE=CGI/1.1");
7203 mg_addenv(blk,
"%s",
"SERVER_PROTOCOL=HTTP/1.1");
7204 mg_addenv(blk,
"%s",
"REDIRECT_STATUS=200");
7220 const char *base_name = strrchr(prog, DIRSEP);
7222 (base_name != NULL ? base_name + 1 : prog));
7226 mg_addenv(blk,
"SCRIPT_FILENAME=%s", prog);
7228 if (path_info != NULL && path_info->
len > 0) {
7229 mg_addenv(blk,
"PATH_INFO=%.*s", (
int) path_info->
len, path_info->
p);
7231 mg_addenv(blk,
"PATH_TRANSLATED=%.*s", (
int) path_info->
len, path_info->
p);
7234 mg_addenv(blk,
"HTTPS=%s", nc->
ssl != NULL ?
"on" :
"off");
7276 for (; *p !=
'=' && *p !=
'\0'; p++) {
7277 if (*p ==
'-') *p =
'_';
7278 *p = (char) toupper(*(
unsigned char *)
p);
7283 blk->
buf[blk->
len++] =
'\0';
7291 if (nc == NULL)
return;
7312 if (len == 0)
break;
7321 mg_printf(nc,
"%s",
"HTTP/1.1 302 Moved\r\n");
7325 mg_printf(nc,
"%s",
"HTTP/1.1 200 OK\r\n");
7342 const struct mg_str *path_info,
7350 DBG((
"%p [%s]", nc, prog));
7357 if ((p = strrchr(prog, DIRSEP)) == NULL) {
7358 snprintf(dir,
sizeof(dir),
"%s",
".");
7360 snprintf(dir,
sizeof(dir),
"%.*s", (
int) (p - prog), prog);
7371 }
while (fds[0] == INVALID_SOCKET);
7383 if (n > 0 && n < nc->recv_mbuf.len) {
7388 closesocket(fds[0]);
7393 closesocket(fds[1]);
7399 static const char *month_names[] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
7400 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"};
7403 for (i = 0; i <
ARRAY_SIZE(month_names); i++)
7404 if (!strcmp(s, month_names[i]))
return (
int)
i;
7410 return year / 4 - year / 100 + year / 400;
7415 static const unsigned short days_before_month[] = {
7416 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
7418 int second, minute, hour, day, month, year, leap_days, days;
7419 time_t result = (time_t) 0;
7421 if (((sscanf(datetime,
"%d/%3s/%d %d:%d:%d", &day, month_str, &year, &hour,
7422 &minute, &second) == 6) ||
7423 (sscanf(datetime,
"%d %3s %d %d:%d:%d", &day, month_str, &year, &hour,
7424 &minute, &second) == 6) ||
7425 (sscanf(datetime,
"%*3s, %d %3s %d %d:%d:%d", &day, month_str, &year,
7426 &hour, &minute, &second) == 6) ||
7427 (sscanf(datetime,
"%d-%3s-%d %d:%d:%d", &day, month_str, &year, &hour,
7428 &minute, &second) == 6)) &&
7432 days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
7433 result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
7453 const char *domain) {
7455 "HTTP/1.1 401 Unauthorized\r\n"
7456 "WWW-Authenticate: Digest qop=\"auth\", "
7457 "realm=\"%s\", nonce=\"%lu\"\r\n"
7458 "Content-Length: 0\r\n\r\n",
7459 domain, (
unsigned long)
time(NULL));
7464 "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, OPTIONS"
7465 #ifndef MG_DISABLE_DAV
7466 ", MKCOL, PUT, DELETE, PROPFIND, MOVE\r\nDAV: 1,2"
7477 const struct mg_str *path_info,
7482 char *index_file = NULL;
7485 exists = (
mg_stat(path, &st) == 0);
7486 is_directory = exists && S_ISDIR(st.st_mode);
7493 index_file ? index_file : path) > 0);
7495 DBG((
"%p %.*s [%s] exists=%d is_dir=%d is_dav=%d is_cgi=%d index=%s", nc,
7497 is_cgi, index_file ? index_file :
""));
7499 if (is_directory && hm->
uri.
p[hm->
uri.
len - 1] !=
'/' && !is_dav) {
7501 "HTTP/1.1 301 Moved\r\nLocation: %.*s/\r\n"
7502 "Content-Length: 0\r\n\r\n",
7509 if (path_info->
len > 0 && !is_cgi) {
7522 }
else if (is_cgi) {
7523 #if !defined(MG_DISABLE_CGI)
7524 mg_handle_cgi(nc, index_file ? index_file : path, path_info, hm, opts);
7528 }
else if ((!exists ||
7532 #ifndef MG_DISABLE_DAV
7535 #ifndef MG_DISABLE_DAV_AUTH
7536 }
else if (is_dav &&
7551 #ifdef MG_ENABLE_FAKE_DAVLOCK
7553 mg_handle_lock(nc, path);
7558 }
else if (is_directory && index_file == NULL) {
7559 #ifndef MG_DISABLE_DIRECTORY_LISTING
7579 struct mg_str *hdr, path_info;
7580 uint32_t remote_ip = ntohl(*(uint32_t *) &nc->
sa.
sin.sin_addr);
7609 opts.
index_files =
"index.html,index.htm,index.shtml,index.cgi,index.php";
7628 mg_vcmp(hdr,
"keep-alive") != 0)) {
7639 const char *schema_tls,
int *use_ssl,
7640 char **addr,
int *port_i,
7641 const char **path) {
7644 if (memcmp(url, schema, strlen(schema)) == 0) {
7645 url += strlen(schema);
7646 }
else if (memcmp(url, schema_tls, strlen(schema_tls)) == 0) {
7647 url += strlen(schema_tls);
7649 #ifndef MG_ENABLE_SSL
7654 while (*url !=
'\0') {
7655 *addr = (
char *)
MG_REALLOC(*addr, addr_len + 5 );
7656 if (*addr == NULL) {
7663 if (*url ==
':') *port_i = addr_len;
7664 (*addr)[addr_len++] = *
url;
7665 (*addr)[addr_len] =
'\0';
7668 if (addr_len == 0)
goto cleanup;
7671 strcpy(*addr + *port_i, *use_ssl ?
":443" :
":80");
7676 if (*path == NULL) *path =
url;
7678 if (**path ==
'\0') *path =
"/";
7680 DBG((
"%s %s", *addr, *path));
7691 struct mg_connect_opts opts,
const char *schema,
const char *schema_ssl,
7692 const char *
url,
const char **path,
char **addr) {
7702 #ifndef MG_ENABLE_SSL
7710 if ((nc =
mg_connect_opt(mgr, *addr, ev_handler, opts)) != NULL) {
7711 #ifdef MG_ENABLE_SSL
7712 if (use_ssl && nc->
ssl_ctx == NULL) {
7724 if (port_i >= 0) (*addr)[port_i] =
'\0';
7734 const char *extra_headers,
7735 const char *post_data) {
7737 const char *path = NULL;
7739 mgr, ev_handler, opts,
"http://",
"https://", url, &path, &addr);
7745 mg_printf(nc,
"%s %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %" SIZE_T_FMT
7747 post_data == NULL ?
"GET" :
"POST", path, addr,
7748 post_data == NULL ? 0 : strlen(post_data),
7749 extra_headers == NULL ?
"" : extra_headers,
7750 post_data == NULL ?
"" : post_data);
7759 const char *extra_headers,
7760 const char *post_data) {
7762 memset(&opts, 0,
sizeof(opts));
7770 const char *
url,
const char *protocol,
7771 const char *extra_headers) {
7773 const char *path = NULL;
7775 mgr, ev_handler, opts,
"ws://",
"wss://", url, &path, &addr);
7789 const char *
url,
const char *protocol,
7790 const char *extra_headers) {
7792 memset(&opts, 0,
sizeof(opts));
7797 size_t var_name_len,
char *file_name,
7798 size_t file_name_len,
const char **data,
7800 static const char cd[] =
"Content-Disposition: ";
7801 size_t hl, bl,
n, ll,
pos, cdl =
sizeof(
cd) - 1;
7803 if (buf == NULL || buf_len <= 0)
return 0;
7805 if (buf[0] !=
'-' || buf[1] !=
'-' || buf[2] ==
'\n')
return 0;
7811 var_name[0] = file_name[0] =
'\0';
7815 header.
p = buf + n + cdl;
7816 header.
len = ll - (cdl + 2);
7823 for (pos = hl; pos + (bl - 2) < buf_len; pos++) {
7824 if (buf[pos] ==
'-' && !memcmp(buf, &buf[pos], bl - 2)) {
7825 if (data_len != NULL) *data_len = (pos - 2) - hl;
7826 if (data != NULL) *data = buf + hl;
7847 #ifdef MG_MODULE_LINES
7848 #line 1 "./src/util.c"
7859 const char *
mg_skip(
const char *
s,
const char *
end,
const char *delims,
7862 while (s < end && strchr(delims, *(
unsigned char *) s) == NULL) s++;
7864 while (s < end && strchr(delims, *(
unsigned char *) s) != NULL) s++;
7869 return tolower(*(
const unsigned char *) s);
7877 }
while (diff == 0 && s1[-1] !=
'\0' && --len > 0);
7887 size_t n2 = strlen(str2), n1 = str1->
len;
7896 size_t n2 = strlen(str2), n1 = str1->
len;
7897 int r = memcmp(str1->
p, str2, (n1 < n2) ? n1 : n2);
7904 #ifndef MG_DISABLE_FILESYSTEM
7909 DBG((
"[%ls] -> %d", wpath, _wstati64(wpath, st)));
7910 return _wstati64(wpath, (
struct _stati64 *) st);
7912 return stat(path, st);
7921 return _wfopen(wpath, wmode);
7923 return fopen(path, mode);
7927 int mg_open(
const char *path,
int flag,
int mode) {
7931 return _wopen(wpath, flag, mode);
7933 return open(path, flag, mode);
7946 #ifdef MG_ENABLE_THREADS
7947 void *mg_start_thread(
void *(*
f)(
void *),
void *p) {
7949 return (
void *) _beginthread((
void(__cdecl *) (
void *) )
f, 0, p);
7951 pthread_t thread_id = (pthread_t) 0;
7952 pthread_attr_t attr;
7954 (void) pthread_attr_init(&attr);
7955 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
7957 #if defined(MG_STACK_SIZE) && MG_STACK_SIZE > 1
7958 (void) pthread_attr_setstacksize(&attr, MG_STACK_SIZE);
7961 pthread_create(&thread_id, &attr,
f, p);
7962 pthread_attr_destroy(&attr);
7964 return (
void *) thread_id;
7972 (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
7973 #elif defined(__unix__)
7974 fcntl(sock, F_SETFD, FD_CLOEXEC);
7983 if (buf == NULL || len <= 0)
return;
7985 #if defined(MG_ENABLE_IPV6)
7986 is_v6 = sa->
sa.sa_family == AF_INET6;
7991 #if defined(MG_ENABLE_IPV6)
7992 const void *addr = NULL;
7994 socklen_t capacity = len;
7996 addr = &sa->
sin.sin_addr;
7998 addr = (
void *) &sa->
sin6.sin6_addr;
8005 if (inet_ntop(sa->
sa.sa_family, addr, start, capacity) == NULL) {
8008 #elif defined(_WIN32) || defined(MG_LWIP)
8010 strncpy(buf, inet_ntoa(sa->
sin.sin_addr), len);
8012 inet_ntop(AF_INET, (
void *) &sa->
sin.sin_addr, buf, len);
8016 int port = ntohs(sa->
sin.sin_port);
8017 if (flags & MG_SOCK_STRINGIFY_IP) {
8018 snprintf(buf + strlen(buf), len - (strlen(buf) + 1),
"%s:%d",
8019 (is_v6 ?
"]" :
""), port);
8021 snprintf(buf, len,
"%d", port);
8029 memset(&sa, 0,
sizeof(sa));
8034 #ifndef MG_DISABLE_HEXDUMP
8035 int mg_hexdump(
const void *buf,
int len,
char *dst,
int dst_len) {
8036 const unsigned char *p = (
const unsigned char *) buf;
8037 char ascii[17] =
"";
8040 for (i = 0; i < len; i++) {
8043 if (i > 0) n += snprintf(dst + n, dst_len - n,
" %s\n", ascii);
8044 n += snprintf(dst + n, dst_len - n,
"%04x ", i);
8046 n += snprintf(dst + n, dst_len - n,
" %02x", p[i]);
8047 ascii[
idx] = p[
i] < 0x20 || p[
i] > 0x7e ?
'.' : p[
i];
8048 ascii[idx + 1] =
'\0';
8051 while (i++ % 16) n += snprintf(dst + n, dst_len - n,
"%s",
" ");
8052 n += snprintf(dst + n, dst_len - n,
" %s\n\n", ascii);
8062 va_copy(ap_copy, ap);
8063 len = vsnprintf(*buf, size, fmt, ap_copy);
8074 if ((*buf = (
char *)
MG_MALLOC(size)) == NULL)
break;
8075 va_copy(ap_copy, ap);
8076 len = vsnprintf(*buf, size, fmt, ap_copy);
8080 }
else if (len >= (
int) size) {
8082 if ((*buf = (
char *)
MG_MALLOC(len + 1)) == NULL) {
8085 va_copy(ap_copy, ap);
8086 len = vsnprintf(*buf, len + 1, fmt, ap_copy);
8094 #if !defined(MG_DISABLE_HEXDUMP)
8096 const void *buf,
int num_bytes,
int ev) {
8097 #if !defined(NO_LIBC) && !defined(MG_DISABLE_STDIO)
8099 char *hexbuf, src[60], dst[60];
8100 int buf_size = num_bytes * 5 + 100;
8102 if (strcmp(path,
"-") == 0) {
8104 }
else if (strcmp(path,
"--") == 0) {
8106 #ifndef MG_DISABLE_FILESYSTEM
8108 fp = fopen(path,
"a");
8111 if (fp == NULL)
return;
8119 fp,
"%lu %p %s %s %s %d\n", (
unsigned long)
time(NULL), (
void *) nc, src,
8126 if (num_bytes > 0 && (hexbuf = (
char *)
MG_MALLOC(buf_size)) != NULL) {
8127 mg_hexdump(buf, num_bytes, hexbuf, buf_size);
8137 static const int n = 1;
8139 return ((
char *) &n)[0] == 0;
8144 if (list == NULL || *list ==
'\0') {
8149 if ((list = strchr(val->
p,
',')) != NULL) {
8151 val->
len = list - val->
p;
8155 list = val->
p + strlen(val->
p);
8156 val->
len = list - val->
p;
8159 if (eq_val != NULL) {
8163 eq_val->
p = (
const char *) memchr(val->
p,
'=', val->
len);
8164 if (eq_val->
p != NULL) {
8166 eq_val->
len = val->
p + val->
len - eq_val->
p;
8167 val->
len = (eq_val->
p - val->
p) - 1;
8177 size_t len,
i = 0,
j = 0;
8180 if ((or_str = (
const char *) memchr(pattern.
p,
'|', pattern.
len)) != NULL) {
8181 struct mg_str pstr = {pattern.
p, (size_t)(or_str - pattern.
p)};
8183 if (res > 0)
return res;
8184 pstr.
p = or_str + 1;
8185 pstr.
len = (pattern.
p + pattern.
len) - (or_str + 1);
8189 for (; i < pattern.
len; i++,
j++) {
8190 if (pattern.
p[i] ==
'?' &&
j != str.
len) {
8192 }
else if (pattern.
p[i] ==
'$') {
8193 return j == str.
len ? (int)
j : -1;
8194 }
else if (pattern.
p[i] ==
'*') {
8196 if (pattern.
p[i] ==
'*') {
8201 while (
j + len != str.
len && str.
p[len] !=
'/') {
8205 if (i == pattern.
len) {
8209 const struct mg_str pstr = {pattern.
p +
i, pattern.
len - i};
8212 }
while (res == -1 && len-- > 0);
8213 return res == -1 ? -1 : (int) (
j + res + len);
8222 const struct mg_str pstr = {pattern, (size_t) pattern_len};
8228 if (
s != NULL) ret.
len = strlen(
s);
8231 #ifdef MG_MODULE_LINES
8232 #line 1 "./src/json-rpc.c"
8237 #ifndef MG_DISABLE_JSON_RPC
8244 const char *result_fmt, ...) {
8246 const struct json_token *
id = req->
id == NULL ? &null_tok : req->
id;
8250 n +=
json_emit(buf + n, len - n,
"{s:s,s:",
"jsonrpc",
"2.0",
"id");
8256 n +=
json_emit(buf + n, len - n,
",s:",
"result");
8258 va_start(ap, result_fmt);
8268 const char *
id,
const char *params_fmt, ...) {
8272 n +=
json_emit(buf + n, len - n,
"{s:s,s:s,s:s,s:",
"jsonrpc",
"2.0",
"id",
8273 id,
"method", method,
"params");
8274 va_start(ap, params_fmt);
8284 int code,
const char *
message,
const char *fmt, ...) {
8288 n +=
json_emit(buf + n, len - n,
"{s:s,s:V,s:{s:i,s:s,s:",
"jsonrpc",
"2.0",
8289 "id", req->
id == NULL ?
"null" : req->
id->
ptr,
8290 req->
id == NULL ? 4 : req->
id->
len,
"error",
"code",
8291 (
long) code,
"message", message,
"data");
8307 message =
"parse error";
8310 message =
"invalid request";
8313 message =
"method not found";
8316 message =
"invalid parameters";
8319 message =
"server error";
8322 message =
"unspecified error";
8335 memset(&req, 0,
sizeof(req));
8336 n =
parse_json(buf, len, tokens,
sizeof(tokens) /
sizeof(tokens[0]));
8348 if (req.
id == NULL || req.
method == NULL) {
8353 for (i = 0; methods[
i] != NULL; i++) {
8354 int mlen = strlen(methods[i]);
8356 memcmp(methods[i], req.
method->
ptr, mlen) == 0)
8360 if (methods[i] == NULL) {
8365 return handlers[
i](dst, dst_len, &req);
8371 int n =
parse_json(buf, len, toks, max_toks);
8373 memset(rep, 0,
sizeof(*rep));
8374 memset(er, 0,
sizeof(*er));
8392 #ifdef MG_MODULE_LINES
8393 #line 1 "./src/mqtt.c"
8400 #ifndef MG_DISABLE_MQTT
8412 char *vlen = &io->
buf[1];
8414 if (io->
len < 2)
return -1;
8416 header = io->
buf[0];
8421 len += (*vlen & 127) << 7 * (vlen - &io->
buf[1]);
8422 }
while ((*vlen++ & 128) != 0 && ((size_t)(vlen - io->
buf) <= io->
len));
8424 if (len != 0 && io->
len < (
size_t)(len - 1))
return -1;
8447 uint16_t topic_len = ntohs(*(uint16_t *) io->
buf);
8449 mm->
topic[topic_len] = 0;
8450 strncpy(mm->
topic, io->
buf + 2, topic_len);
8451 var_len = topic_len + 2;
8472 return len - var_len;
8479 memset(&mm, 0,
sizeof(mm));
8486 if (len == -1)
break;
8521 rem_len = 9 + 1 + 2 + 2 + strlen(client_id);
8529 rem_len += strlen(opts.
password) + 2;
8534 mg_send(nc,
"\00\06MQIsdp\03", 9);
8543 len = htons(strlen(client_id));
8545 mg_send(nc, client_id, strlen(client_id));
8553 len = htons(strlen(opts.
password));
8560 uint8_t flags,
size_t len) {
8562 uint8_t header = cmd << 4 | (uint8_t) flags;
8564 uint8_t buf[1 +
sizeof(size_t)];
8565 uint8_t *vlen = &buf[1];
8575 if (len > 0) *vlen |= 0x80;
8583 uint16_t message_id,
int flags,
const void *data,
8587 uint16_t topic_len = htons(strlen(topic));
8588 uint16_t message_id_net = htons(message_id);
8591 mg_send(nc, topic, strlen(topic));
8593 mg_send(nc, &message_id_net, 2);
8603 size_t topics_len, uint16_t message_id) {
8606 uint16_t message_id_n = htons(message_id);
8609 mg_send(nc, (
char *) &message_id_n, 2);
8610 for (i = 0; i < topics_len; i++) {
8611 uint16_t topic_len_n = htons(strlen(topics[i].topic));
8613 mg_send(nc, topics[i].topic, strlen(topics[i].topic));
8614 mg_send(nc, &topics[i].qos, 1);
8622 struct mg_str *topic, uint8_t *qos,
int pos) {
8623 unsigned char *buf = (
unsigned char *) msg->
payload.
p + pos;
8628 topic->
len = buf[0] << 8 | buf[1];
8629 topic->
p = (
char *) buf + 2;
8630 *qos = buf[2 + topic->
len];
8631 return pos + 2 + topic->
len + 1;
8635 size_t topics_len, uint16_t message_id) {
8638 uint16_t message_id_n = htons(message_id);
8641 mg_send(nc, (
char *) &message_id_n, 2);
8642 for (i = 0; i < topics_len; i++) {
8643 uint16_t topic_len_n = htons(strlen(topics[i]));
8645 mg_send(nc, topics[i], strlen(topics[i]));
8665 uint16_t message_id) {
8666 uint16_t message_id_net = htons(message_id);
8667 mg_send(nc, &message_id_net, 2);
8688 uint16_t message_id) {
8690 uint16_t message_id_net = htons(message_id);
8691 mg_send(nc, &message_id_net, 2);
8692 for (i = 0; i < qoss_len; i++) {
8715 #ifdef MG_MODULE_LINES
8716 #line 1 "./src/mqtt-broker.c"
8726 #ifdef MG_ENABLE_MQTT_BROKER
8728 static void mg_mqtt_session_init(
struct mg_mqtt_broker *brk,
8729 struct mg_mqtt_session *
s,
8732 s->subscriptions = NULL;
8733 s->num_subscriptions = 0;
8737 static void mg_mqtt_add_session(
struct mg_mqtt_session *
s) {
8738 s->
next = s->brk->sessions;
8739 s->brk->sessions =
s;
8741 if (s->next != NULL) s->next->prev =
s;
8744 static void mg_mqtt_remove_session(
struct mg_mqtt_session *s) {
8745 if (s->prev == NULL) s->brk->sessions = s->next;
8746 if (s->prev) s->prev->next = s->next;
8747 if (s->next) s->next->prev = s->prev;
8750 static void mg_mqtt_destroy_session(
struct mg_mqtt_session *s) {
8752 for (i = 0; i < s->num_subscriptions; i++) {
8753 MG_FREE((
void *) s->subscriptions[i].topic);
8759 static void mg_mqtt_close_session(
struct mg_mqtt_session *s) {
8760 mg_mqtt_remove_session(s);
8761 mg_mqtt_destroy_session(s);
8764 void mg_mqtt_broker_init(
struct mg_mqtt_broker *brk,
void *user_data) {
8765 brk->sessions = NULL;
8766 brk->user_data = user_data;
8769 static void mg_mqtt_broker_handle_connect(
struct mg_mqtt_broker *brk,
8771 struct mg_mqtt_session *s = (
struct mg_mqtt_session *) malloc(
sizeof *s);
8781 mg_mqtt_session_init(brk, s, nc);
8784 mg_mqtt_add_session(s);
8789 static void mg_mqtt_broker_handle_subscribe(
struct mg_connection *nc,
8791 struct mg_mqtt_session *ss = (
struct mg_mqtt_session *) nc->
user_data;
8793 size_t qoss_len = 0;
8801 qoss[qoss_len++] = qos;
8805 ss->subscriptions,
sizeof(*ss->subscriptions) * qoss_len);
8808 ss->num_subscriptions++) {
8809 te = &ss->subscriptions[ss->num_subscriptions];
8810 te->topic = (
char *) malloc(
topic.len + 1);
8812 strncpy((
char *) te->topic,
topic.p,
topic.len + 1);
8825 static int mg_mqtt_match_topic_expression(
const char *exp,
const char *
topic) {
8827 int len = strlen(exp);
8828 if (strchr(exp,
'#')) {
8831 return strncmp(exp, topic, len) == 0;
8834 static void mg_mqtt_broker_handle_publish(
struct mg_mqtt_broker *brk,
8836 struct mg_mqtt_session *
s;
8839 for (s = mg_mqtt_next(brk, NULL); s != NULL; s = mg_mqtt_next(brk, s)) {
8840 for (i = 0; i < s->num_subscriptions; i++) {
8841 if (mg_mqtt_match_topic_expression(s->subscriptions[i].topic,
8851 void mg_mqtt_broker(
struct mg_connection *nc,
int ev,
void *data) {
8853 struct mg_mqtt_broker *brk;
8858 brk = (
struct mg_mqtt_broker *) nc->
user_data;
8866 mg_mqtt_broker_handle_connect(brk, nc);
8869 mg_mqtt_broker_handle_subscribe(nc, msg);
8872 mg_mqtt_broker_handle_publish(brk, msg);
8876 mg_mqtt_close_session((
struct mg_mqtt_session *) nc->
user_data);
8882 struct mg_mqtt_session *mg_mqtt_next(
struct mg_mqtt_broker *brk,
8883 struct mg_mqtt_session *s) {
8884 return s == NULL ? brk->sessions : s->next;
8888 #ifdef MG_MODULE_LINES
8889 #line 1 "./src/dns.c"
8896 #ifndef MG_DISABLE_DNS
8917 for (rr = (prev == NULL ? msg->
answers : prev + 1);
8919 if (rr->
rtype == query) {
8929 switch (rr->
rtype) {
8931 if (data_len <
sizeof(
struct in_addr)) {
8937 memcpy(data, rr->
rdata.
p, data_len);
8939 #ifdef MG_ENABLE_IPV6
8941 if (data_len <
sizeof(
struct in6_addr)) {
8944 memcpy(data, rr->
rdata.
p, data_len);
8959 memset(&header, 0,
sizeof(header));
8965 return mbuf_insert(io, pos, &header,
sizeof(header));
8974 end = (
unsigned char *) last_q->
name.
p + last_q->
name.
len + 4;
8984 if ((s = strchr(name,
'.')) == NULL) {
8988 if (s - name > 127) {
9001 }
while (*s !=
'\0');
9008 const char *name,
size_t nlen,
const void *
rdata,
9022 u16 = htons(rr->
rtype);
9028 u32 = htonl(rr->
ttl);
9034 size_t off = io->
len;
9040 io->
buf[off] = u16 >> 8;
9041 io->
buf[off + 1] = u16 & 0xff;
9059 DBG((
"%s %d", name, query_type));
9069 rr->
rtype = query_type;
9080 uint16_t len = htons(pkt.
len);
9094 unsigned char *name =
data;
9095 int chunk_len, data_len;
9097 while (data < end && (chunk_len = *data)) {
9098 if (((
unsigned char *) data)[0] & 0xc0) {
9102 data += chunk_len + 1;
9105 if (data > end - 5) {
9109 rr->
name.
p = (
char *) name;
9110 rr->
name.
len = data - name + 1;
9113 rr->
rtype = data[0] << 8 | data[1];
9116 rr->
rclass = data[0] << 8 | data[1];
9121 if (data >= end - 6) {
9125 rr->
ttl = (uint32_t) data[0] << 24 | (uint32_t) data[1] << 16 |
9126 data[2] << 8 | data[3];
9129 data_len = *data << 8 | *(data + 1);
9132 rr->
rdata.
p = (
char *) data;
9141 unsigned char *data = (
unsigned char *) buf +
sizeof(*header);
9142 unsigned char *
end = (
unsigned char *) buf + len;
9145 memset(msg, 0,
sizeof(*msg));
9149 if (len < (
int)
sizeof(*header))
return -1;
9164 if (data == NULL)
return -1;
9169 if (data == NULL)
return -1;
9176 char *dst,
int dst_len) {
9178 char *old_dst = dst;
9179 const unsigned char *data = (
unsigned char *) name->
p;
9180 const unsigned char *
end = (
unsigned char *) msg->
pkt.
p + msg->
pkt.
len;
9186 while ((chunk_len = *data++)) {
9187 int leeway = dst_len - (dst - old_dst);
9192 if (chunk_len & 0xc0) {
9193 uint16_t off = (data[-1] & (~0xc0)) << 8 | data[0];
9194 if (off >= msg->
pkt.
len) {
9197 data = (
unsigned char *) msg->
pkt.
p + off;
9200 if (chunk_len > leeway) {
9204 if (data + chunk_len >=
end) {
9208 memcpy(dst, data, chunk_len);
9211 leeway -= chunk_len;
9213 return dst - old_dst;
9218 if (dst != old_dst) {
9221 return dst - old_dst;
9238 memset(&msg, 0,
sizeof(msg));
9242 uint16_t len = htons(io->
len);
9260 #ifdef MG_MODULE_LINES
9261 #line 1 "./src/dns-server.c"
9268 #ifdef MG_ENABLE_DNS_SERVER
9273 struct mg_dns_reply mg_dns_create_reply(struct
mbuf *io,
9275 struct mg_dns_reply rep;
9278 rep.start = io->len;
9281 msg->flags |= 0x8080;
9284 msg->num_answers = 0;
9288 void mg_dns_send_reply(
struct mg_connection *nc,
struct mg_dns_reply *
r) {
9289 size_t sent = r->io->len - r->start;
9292 uint16_t len = htons(sent);
9297 mg_send(nc, r->io->buf + r->start, r->io->len - r->start);
9298 r->io->len = r->start;
9302 int mg_dns_reply_record(
struct mg_dns_reply *reply,
9304 const char *name,
int rtype,
int ttl,
const void *rdata,
9334 #ifdef MG_MODULE_LINES
9335 #line 1 "./src/resolv.c"
9342 #ifndef MG_DISABLE_RESOLVER
9347 #ifndef MG_DEFAULT_NAMESERVER
9348 #define MG_DEFAULT_NAMESERVER "8.8.8.8"
9381 char subkey[512],
value[128],
9382 *key =
"SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces";
9384 if ((err = RegOpenKeyA(HKEY_LOCAL_MACHINE, key, &hKey)) != ERROR_SUCCESS) {
9385 fprintf(stderr,
"cannot open reg key %s: %d\n", key, err);
9388 for (ret = -1, i = 0;
9389 RegEnumKeyA(hKey, i, subkey,
sizeof(subkey)) == ERROR_SUCCESS; i++) {
9391 if (RegOpenKeyA(hKey, subkey, &hSub) == ERROR_SUCCESS &&
9392 (RegQueryValueExA(hSub,
"NameServer", 0, &type, (
void *) value,
9393 &len) == ERROR_SUCCESS ||
9394 RegQueryValueExA(hSub,
"DhcpNameServer", 0, &type, (
void *) value,
9395 &len) == ERROR_SUCCESS)) {
9403 char *comma = strchr(value,
',');
9404 if (value[0] ==
'\0') {
9407 if (comma != NULL) {
9410 snprintf(name, name_len,
"udp://%s:53", value);
9418 #elif !defined(MG_DISABLE_FILESYSTEM)
9422 if ((fp = fopen(
"/etc/resolv.conf",
"r")) == NULL) {
9426 for (ret = -1; fgets(line,
sizeof(line), fp) != NULL;) {
9428 if (sscanf(line,
"nameserver %255[^\n\t #]s", buf) == 1) {
9429 snprintf(name, name_len,
"udp://%s:53", buf);
9437 snprintf(name, name_len,
"%s", mg_default_dns_server);
9444 #ifndef MG_DISABLE_FILESYSTEM
9450 unsigned int a,
b,
c, d;
9453 if ((fp = fopen(
"/etc/hosts",
"r")) == NULL) {
9457 for (; fgets(line,
sizeof(line), fp) != NULL;) {
9458 if (line[0] ==
'#')
continue;
9460 if (sscanf(line,
"%u.%u.%u.%u%n", &a, &b, &c, &d, &len) == 0) {
9464 for (p = line + len; sscanf(p,
"%s%n", alias, &len) == 1; p += len) {
9465 if (strcmp(alias, name) == 0) {
9466 usa->
sin.sin_addr.s_addr = htonl(a << 24 | b << 16 | c << 8 | d);
9480 time_t now =
time(NULL);
9545 memset(&opts, 0,
sizeof(opts));
9564 strncpy(req->
name, name,
sizeof(req->
name));
9573 if (nameserver == NULL && mg_dns_server[0] ==
'\0' &&
9576 strncpy(mg_dns_server, mg_default_dns_server,
sizeof(mg_dns_server));
9579 if (nameserver == NULL) {
9584 if (dns_nc == NULL) {
9597 #ifdef MG_MODULE_LINES
9598 #line 1 "./src/coap.c"
9620 #ifdef MG_ENABLE_COAP
9622 void mg_coap_free_options(
struct mg_coap_message *
cm) {
9623 while (cm->options != NULL) {
9624 struct mg_coap_option *
next = cm->options->
next;
9630 struct mg_coap_option *mg_coap_add_option(
struct mg_coap_message *cm,
9631 uint32_t number,
char *
value,
9633 struct mg_coap_option *new_option =
9634 (
struct mg_coap_option *)
MG_CALLOC(1,
sizeof(*new_option));
9636 new_option->number = number;
9637 new_option->value.p =
value;
9638 new_option->value.len = len;
9640 if (cm->options == NULL) {
9641 cm->options = cm->optiomg_tail = new_option;
9648 if (cm->optiomg_tail->number <= new_option->number) {
9650 cm->optiomg_tail = cm->optiomg_tail->next = new_option;
9653 struct mg_coap_option *current_opt = cm->options;
9654 struct mg_coap_option *prev_opt = 0;
9656 while (current_opt != NULL) {
9657 if (current_opt->number > new_option->number) {
9660 prev_opt = current_opt;
9661 current_opt = current_opt->next;
9664 if (prev_opt != NULL) {
9665 prev_opt->next = new_option;
9666 new_option->next = current_opt;
9669 new_option->next = cm->options;
9670 cm->options = new_option;
9683 static char *coap_parse_header(
char *ptr,
struct mbuf *io,
9684 struct mg_coap_message *cm) {
9685 if (io->
len <
sizeof(uint32_t)) {
9686 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9696 if (((uint8_t) *ptr >> 6) != 1) {
9697 cm->flags |= MG_COAP_IGNORE;
9706 cm->msg_type = ((uint8_t) *ptr & 0x30) >> 4;
9707 cm->flags |= MG_COAP_MSG_TYPE_FIELD;
9715 cm->token.len = *ptr & 0x0F;
9716 if (cm->token.len > 8) {
9717 cm->flags |= MG_COAP_FORMAT_ERROR;
9727 cm->code_class = (uint8_t) *ptr >> 5;
9728 cm->code_detail = *ptr & 0x1F;
9729 cm->flags |= (MG_COAP_CODE_CLASS_FIELD | MG_COAP_CODE_DETAIL_FIELD);
9734 cm->msg_id = (uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1);
9735 cm->flags |= MG_COAP_MSG_ID_FIELD;
9747 static char *coap_get_token(
char *ptr,
struct mbuf *io,
9748 struct mg_coap_message *cm) {
9749 if (cm->token.len != 0) {
9750 if (ptr + cm->token.len > io->
buf + io->
len) {
9751 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9755 ptr += cm->token.len;
9756 cm->flags |= MG_COAP_TOKEN_FIELD;
9768 static int coap_get_ext_opt(
char *ptr,
struct mbuf *io, uint16_t *opt_info) {
9771 if (*opt_info == 13) {
9776 if (ptr < io->buf + io->
len) {
9777 *opt_info = (uint8_t) *ptr + 13;
9778 ret =
sizeof(uint8_t);
9782 }
else if (*opt_info == 14) {
9787 if (ptr +
sizeof(uint8_t) < io->
buf + io->
len) {
9788 *opt_info = ((uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1)) + 269;
9789 ret =
sizeof(uint16_t);
9814 static char *coap_get_options(
char *ptr,
struct mbuf *io,
9815 struct mg_coap_message *cm) {
9816 uint16_t prev_opt = 0;
9818 if (ptr == io->
buf + io->
len) {
9824 while (ptr < io->buf + io->
len && (uint8_t) *ptr != 0xFF) {
9825 uint16_t option_delta, option_lenght;
9829 option_delta = ((uint8_t) *ptr & 0xF0) >> 4;
9831 option_lenght = *ptr & 0x0F;
9833 if (option_delta == 15 || option_lenght == 15) {
9838 cm->flags |= MG_COAP_FORMAT_ERROR;
9845 optinfo_len = coap_get_ext_opt(ptr, io, &option_delta);
9846 if (optinfo_len == -1) {
9847 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9854 optinfo_len = coap_get_ext_opt(ptr, io, &option_lenght);
9855 if (optinfo_len == -1) {
9856 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9867 option_delta += prev_opt;
9869 mg_coap_add_option(cm, option_delta, ptr, option_lenght);
9871 prev_opt = option_delta;
9873 if (ptr + option_lenght > io->
buf + io->
len) {
9874 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9878 ptr += option_lenght;
9881 if ((cm->flags & MG_COAP_ERROR) != 0) {
9882 mg_coap_free_options(cm);
9886 cm->flags |= MG_COAP_OPTIOMG_FIELD;
9888 if (ptr == io->
buf + io->
len) {
9898 uint32_t mg_coap_parse(
struct mbuf *io,
struct mg_coap_message *cm) {
9901 memset(cm, 0,
sizeof(*cm));
9903 if ((ptr = coap_parse_header(io->
buf, io, cm)) == NULL) {
9907 if ((ptr = coap_get_token(ptr, io, cm)) == NULL) {
9911 if ((ptr = coap_get_options(ptr, io, cm)) == NULL) {
9916 cm->payload.len = io->
len - (ptr - io->
buf);
9917 if (cm->payload.len != 0) {
9918 cm->payload.p = ptr;
9919 cm->flags |= MG_COAP_PAYLOAD_FIELD;
9930 static size_t coap_get_ext_opt_size(uint32_t value) {
9933 if (value >= 13 && value <= 0xFF + 13) {
9934 ret =
sizeof(uint8_t);
9935 }
else if (value > 0xFF + 13 && value <= 0xFFFF + 269) {
9936 ret =
sizeof(uint16_t);
9947 static int coap_split_opt(uint32_t value, uint8_t *base, uint16_t *ext) {
9952 }
else if (value >= 13 && value <= 0xFF + 13) {
9955 ret =
sizeof(uint8_t);
9956 }
else if (value > 0xFF + 13 && value <= 0xFFFF + 269) {
9959 ret =
sizeof(uint16_t);
9970 static char *coap_add_uint16(
char *ptr, uint16_t val) {
9973 *ptr = val & 0x00FF;
9983 static char *coap_add_opt_info(
char *ptr, uint16_t val,
size_t len) {
9984 if (len ==
sizeof(uint8_t)) {
9987 }
else if (len ==
sizeof(uint16_t)) {
9988 ptr = coap_add_uint16(ptr, val);
9999 static uint32_t coap_calculate_packet_size(
struct mg_coap_message *cm,
10001 struct mg_coap_option *opt;
10002 uint32_t prev_opt_number;
10005 if (cm->msg_type > MG_COAP_MSG_MAX) {
10006 return MG_COAP_ERROR | MG_COAP_MSG_TYPE_FIELD;
10008 if (cm->token.len > 8) {
10009 return MG_COAP_ERROR | MG_COAP_TOKEN_FIELD;
10011 if (cm->code_class > 7) {
10012 return MG_COAP_ERROR | MG_COAP_CODE_CLASS_FIELD;
10014 if (cm->code_detail > 31) {
10015 return MG_COAP_ERROR | MG_COAP_CODE_DETAIL_FIELD;
10018 *len += cm->token.len;
10019 if (cm->payload.len != 0) {
10020 *len += cm->payload.len + 1;
10024 prev_opt_number = 0;
10025 while (opt != NULL) {
10027 *len += coap_get_ext_opt_size(opt->number);
10028 *len += coap_get_ext_opt_size((uint32_t) opt->value.len);
10035 if ((opt->next != NULL && opt->number > opt->next->number) ||
10036 opt->value.len > 0xFFFF + 269 ||
10037 opt->number - prev_opt_number > 0xFFFF + 269) {
10038 return MG_COAP_ERROR | MG_COAP_OPTIOMG_FIELD;
10040 *len += opt->value.len;
10047 uint32_t mg_coap_compose(
struct mg_coap_message *cm,
struct mbuf *io) {
10048 struct mg_coap_option *opt;
10049 uint32_t res, prev_opt_number;
10050 size_t prev_io_len, packet_size;
10053 res = coap_calculate_packet_size(cm, &packet_size);
10059 prev_io_len = io->
len;
10061 ptr = io->
buf + prev_io_len;
10069 *ptr = (1 << 6) | (cm->msg_type << 4) | (cm->token.len);
10073 *ptr = (cm->code_class << 5) | (cm->code_detail);
10076 ptr = coap_add_uint16(ptr, cm->msg_id);
10078 if (cm->token.len != 0) {
10079 memcpy(ptr, cm->token.p, cm->token.len);
10080 ptr += cm->token.len;
10084 prev_opt_number = 0;
10085 while (opt != NULL) {
10086 uint8_t delta_base = 0, length_base = 0;
10087 uint16_t delta_ext, length_ext;
10089 size_t opt_delta_len =
10090 coap_split_opt(opt->number - prev_opt_number, &delta_base, &delta_ext);
10091 size_t opt_lenght_len =
10092 coap_split_opt((uint32_t) opt->value.len, &length_base, &length_ext);
10094 *ptr = (delta_base << 4) | length_base;
10097 ptr = coap_add_opt_info(ptr, delta_ext, opt_delta_len);
10098 ptr = coap_add_opt_info(ptr, length_ext, opt_lenght_len);
10100 if (opt->value.len != 0) {
10101 memcpy(ptr, opt->value.p, opt->value.len);
10102 ptr += opt->value.len;
10105 prev_opt_number = opt->number;
10109 if (cm->payload.len != 0) {
10112 memcpy(ptr, cm->payload.p, cm->payload.len);
10119 struct mg_coap_message *cm) {
10120 struct mbuf packet_out;
10121 uint32_t compose_res;
10124 compose_res = mg_coap_compose(cm, &packet_out);
10125 if (compose_res != 0) {
10126 return compose_res;
10129 mg_send(nc, packet_out.buf, (
int) packet_out.len);
10135 uint32_t mg_coap_send_ack(
struct mg_connection *nc, uint16_t msg_id) {
10136 struct mg_coap_message cm;
10137 memset(&cm, 0,
sizeof(cm));
10138 cm.msg_type = MG_COAP_MSG_ACK;
10139 cm.msg_id = msg_id;
10141 return mg_coap_send_message(nc, &cm);
10144 static void coap_handler(
struct mg_connection *nc,
int ev,
void *ev_data) {
10146 struct mg_coap_message cm;
10147 uint32_t parse_res;
10149 memset(&cm, 0,
sizeof(cm));
10151 nc->
handler(nc, ev, ev_data);
10155 parse_res = mg_coap_parse(io, &cm);
10156 if ((parse_res & MG_COAP_IGNORE) == 0) {
10157 if ((cm.flags & MG_COAP_NOT_ENOUGH_DATA) != 0) {
10162 cm.flags |= MG_COAP_FORMAT_ERROR;
10164 nc->
handler(nc, MG_COAP_EVENT_BASE + cm.msg_type, &cm);
10167 mg_coap_free_options(&cm);
10194 #ifdef MG_MODULE_LINES
10195 #line 1 "./src/../../common/platforms/cc3200/cc3200_libc.c"
10202 #if CS_PLATFORM == CS_P_CC3200
10205 #include <string.h>
10207 #ifndef __TI_COMPILER_VERSION__
10209 #include <sys/stat.h>
10210 #include <sys/time.h>
10211 #include <unistd.h>
10214 #include <inc/hw_types.h>
10215 #include <inc/hw_memmap.h>
10216 #include <driverlib/prcm.h>
10217 #include <driverlib/rom.h>
10218 #include <driverlib/rom_map.h>
10219 #include <driverlib/uart.h>
10220 #include <driverlib/utils.h>
10222 #define CONSOLE_UART UARTA0_BASE
10224 #ifdef __TI_COMPILER_VERSION__
10225 int asprintf(
char **strp,
const char *fmt, ...) {
10229 *strp = malloc(BUFSIZ);
10230 if (*strp == NULL)
return -1;
10233 len = vsnprintf(*strp, BUFSIZ, fmt, ap);
10237 *strp = realloc(*strp, len);
10238 if (*strp == NULL)
return -1;
10241 if (len >= BUFSIZ) {
10243 len = vsnprintf(*strp, len, fmt, ap);
10251 #ifndef __TI_COMPILER_VERSION__
10252 int _gettimeofday_r(
struct _reent *r,
struct timeval *tp,
void *tzp) {
10254 int gettimeofday(
struct timeval *tp,
void *tzp) {
10256 unsigned long long r1 = 0,
r2;
10260 r1 = PRCMSlowClkCtrFastGet();
10261 }
while (r1 !=
r2);
10263 tp->tv_sec = (r1 >> 15);
10266 tp->tv_usec = (r1 & 0x7FFF) * 30;
10270 long int random(
void) {
10274 void fprint_str(FILE *fp,
const char *str) {
10275 while (*str !=
'\0') {
10276 if (*str ==
'\n') MAP_UARTCharPut(CONSOLE_UART,
'\r');
10277 MAP_UARTCharPut(CONSOLE_UART, *str++);
10281 void _exit(
int status) {
10282 fprint_str(stderr,
"_exit\n");
10284 *(
int *) 1 = status;
10289 void _not_implemented(
const char *what) {
10290 fprint_str(stderr, what);
10291 fprint_str(stderr,
" is not implemented\n");
10295 int _kill(
int pid,
int sig) {
10298 _not_implemented(
"_kill");
10303 fprint_str(stderr,
"_getpid is not implemented\n");
10307 int _isatty(
int fd) {
10313 #ifdef MG_MODULE_LINES
10314 #line 1 "./src/../../common/platforms/msp432/msp432_libc.c"
10321 #if CS_PLATFORM == CS_P_MSP432
10323 #include <ti/sysbios/BIOS.h>
10324 #include <ti/sysbios/knl/Clock.h>
10326 int gettimeofday(
struct timeval *tp,
void *tzp) {
10327 uint32_t ticks = Clock_getTicks();
10328 tp->tv_sec = ticks / 1000;
10329 tp->tv_usec = (ticks % 1000) * 1000;
10333 long int random(
void) {
10338 #ifdef MG_MODULE_LINES
10339 #line 1 "./src/../../common/platforms/simplelink/sl_fs_slfs.h"
10346 #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
10347 #define CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
10349 #if defined(MG_FS_SLFS)
10352 #ifndef __TI_COMPILER_VERSION__
10353 #include <unistd.h>
10354 #include <sys/stat.h>
10357 #define MAX_OPEN_SLFS_FILES 8
10360 int fs_slfs_open(
const char *pathname,
int flags, mode_t mode);
10361 int fs_slfs_close(
int fd);
10362 ssize_t fs_slfs_read(
int fd,
void *buf,
size_t count);
10363 ssize_t fs_slfs_write(
int fd,
const void *buf,
size_t count);
10364 int fs_slfs_stat(
const char *pathname,
struct stat *s);
10365 int fs_slfs_fstat(
int fd,
struct stat *s);
10366 off_t fs_slfs_lseek(
int fd, off_t
offset,
int whence);
10367 int fs_slfs_unlink(
const char *
filename);
10368 int fs_slfs_rename(
const char *from,
const char *to);
10370 void fs_slfs_set_new_file_size(
const char *name,
size_t size);
10375 #ifdef MG_MODULE_LINES
10376 #line 1 "./src/../../common/platforms/simplelink/sl_fs_slfs.c"
10385 #if defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS)
10391 #if CS_PLATFORM == CS_P_CC3200
10392 #include <inc/hw_types.h>
10394 #include <simplelink/include/simplelink.h>
10395 #include <simplelink/include/fs.h>
10399 extern int set_errno(
int e);
10405 #ifndef FS_SLFS_MAX_FILE_SIZE
10406 #define FS_SLFS_MAX_FILE_SIZE (64 * 1024)
10409 struct sl_file_size_hint {
10414 struct sl_fd_info {
10420 static struct sl_fd_info s_sl_fds[MAX_OPEN_SLFS_FILES];
10421 static struct sl_file_size_hint s_sl_file_size_hints[MAX_OPEN_SLFS_FILES];
10423 static int sl_fs_to_errno(_i32 r) {
10424 DBG((
"SL error: %d", (
int) r));
10428 case SL_FS_FILE_NAME_EXIST:
10430 case SL_FS_WRONG_FILE_NAME:
10432 case SL_FS_ERR_NO_AVAILABLE_NV_INDEX:
10433 case SL_FS_ERR_NO_AVAILABLE_BLOCKS:
10435 case SL_FS_ERR_FAILED_TO_ALLOCATE_MEM:
10437 case SL_FS_ERR_FILE_NOT_EXISTS:
10439 case SL_FS_ERR_NOT_SUPPORTED:
10445 int fs_slfs_open(
const char *pathname,
int flags, mode_t mode) {
10447 for (fd = 0; fd < MAX_OPEN_SLFS_FILES; fd++) {
10448 if (s_sl_fds[fd].fh <= 0)
break;
10450 if (fd >= MAX_OPEN_SLFS_FILES)
return set_errno(ENOMEM);
10451 struct sl_fd_info *fi = &s_sl_fds[
fd];
10454 fi->size = (size_t) -1;
10455 if (pathname[0] ==
'/') pathname++;
10456 int rw = (flags & 3);
10457 if (rw == O_RDONLY) {
10458 SlFsFileInfo_t sl_fi;
10459 _i32 r = sl_FsGetInfo((
const _u8 *) pathname, 0, &sl_fi);
10460 if (r == SL_FS_OK) {
10461 fi->size = sl_fi.FileLen;
10463 am = FS_MODE_OPEN_READ;
10465 if (!(flags & O_TRUNC) || (flags & O_APPEND)) {
10468 return set_errno(ENOTSUP);
10470 if (flags & O_CREAT) {
10471 size_t i,
size = FS_SLFS_MAX_FILE_SIZE;
10472 for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
10473 if (s_sl_file_size_hints[i].name != NULL &&
10474 strcmp(s_sl_file_size_hints[i].name, pathname) == 0) {
10475 size = s_sl_file_size_hints[
i].size;
10476 free(s_sl_file_size_hints[i].name);
10477 s_sl_file_size_hints[
i].name = NULL;
10481 DBG((
"creating %s with max size %d", pathname, (
int) size));
10482 am = FS_MODE_OPEN_CREATE(size, 0);
10484 am = FS_MODE_OPEN_WRITE;
10487 _i32 r = sl_FsOpen((_u8 *) pathname, am, NULL, &fi->fh);
10488 DBG((
"sl_FsOpen(%s, 0x%x) = %d, %d", pathname, (
int) am, (
int) r,
10490 if (r == SL_FS_OK) {
10495 r = set_errno(sl_fs_to_errno(r));
10500 int fs_slfs_close(
int fd) {
10501 struct sl_fd_info *fi = &s_sl_fds[
fd];
10502 if (fi->fh <= 0)
return set_errno(EBADF);
10503 _i32 r = sl_FsClose(fi->fh, NULL, NULL, 0);
10504 DBG((
"sl_FsClose(%d) = %d", (
int) fi->fh, (
int) r));
10505 s_sl_fds[
fd].fh = -1;
10506 return set_errno(sl_fs_to_errno(r));
10509 ssize_t fs_slfs_read(
int fd,
void *buf,
size_t count) {
10510 struct sl_fd_info *fi = &s_sl_fds[
fd];
10511 if (fi->fh <= 0)
return set_errno(EBADF);
10514 if (fi->pos == fi->size)
return 0;
10515 _i32 r = sl_FsRead(fi->fh, fi->pos, buf, count);
10516 DBG((
"sl_FsRead(%d, %d, %d) = %d", (
int) fi->fh, (
int) fi->pos, (
int) count,
10522 return set_errno(sl_fs_to_errno(r));
10525 ssize_t fs_slfs_write(
int fd,
const void *buf,
size_t count) {
10526 struct sl_fd_info *fi = &s_sl_fds[
fd];
10527 if (fi->fh <= 0)
return set_errno(EBADF);
10528 _i32 r = sl_FsWrite(fi->fh, fi->pos, (_u8 *) buf, count);
10529 DBG((
"sl_FsWrite(%d, %d, %d) = %d", (
int) fi->fh, (
int) fi->pos, (
int) count,
10535 return set_errno(sl_fs_to_errno(r));
10538 int fs_slfs_stat(
const char *pathname,
struct stat *s) {
10539 SlFsFileInfo_t sl_fi;
10540 _i32 r = sl_FsGetInfo((
const _u8 *) pathname, 0, &sl_fi);
10541 if (r == SL_FS_OK) {
10542 s->st_mode = S_IFREG | 0666;
10544 s->st_size = sl_fi.FileLen;
10547 return set_errno(sl_fs_to_errno(r));
10550 int fs_slfs_fstat(
int fd,
struct stat *s) {
10551 struct sl_fd_info *fi = &s_sl_fds[
fd];
10552 if (fi->fh <= 0)
return set_errno(EBADF);
10554 s->st_mode = S_IFREG | 0666;
10556 s->st_size = fi->size;
10560 off_t fs_slfs_lseek(
int fd, off_t
offset,
int whence) {
10561 if (s_sl_fds[fd].fh <= 0)
return set_errno(EBADF);
10570 return set_errno(ENOTSUP);
10575 int fs_slfs_unlink(
const char *
filename) {
10576 return set_errno(sl_fs_to_errno(sl_FsDel((
const _u8 *) filename, 0)));
10579 int fs_slfs_rename(
const char *from,
const char *to) {
10580 return set_errno(ENOTSUP);
10583 void fs_slfs_set_new_file_size(
const char *name,
size_t size) {
10585 for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
10586 if (s_sl_file_size_hints[i].name == NULL) {
10587 DBG((
"File size hint: %s %d", name, (
int) size));
10588 s_sl_file_size_hints[
i].name =
strdup(name);
10589 s_sl_file_size_hints[
i].size =
size;
10596 #ifdef MG_MODULE_LINES
10597 #line 1 "./src/../../common/platforms/simplelink/sl_fs.c"
10604 #if defined(MG_SOCKET_SIMPLELINK) && \
10605 (defined(MG_FS_SLFS) || defined(MG_FS_SPIFFS))
10609 #include <stdlib.h>
10610 #include <string.h>
10611 #ifdef __TI_COMPILER_VERSION__
10615 #if CS_PLATFORM == CS_P_CC3200
10616 #include <inc/hw_types.h>
10617 #include <inc/hw_memmap.h>
10618 #include <driverlib/rom.h>
10619 #include <driverlib/rom_map.h>
10620 #include <driverlib/uart.h>
10626 #ifdef CC3200_FS_SPIFFS
10634 #define NUM_SYS_FDS 3
10635 #define SPIFFS_FD_BASE 10
10636 #define SLFS_FD_BASE 100
10638 #define CONSOLE_UART UARTA0_BASE
10640 int set_errno(
int e) {
10645 static int is_sl_fname(
const char *
fname) {
10646 return strncmp(fname,
"SL:", 3) == 0;
10649 static const char *sl_fname(
const char *
fname) {
10653 static const char *drop_dir(
const char *
fname) {
10654 if (*fname ==
'.') fname++;
10655 if (*fname ==
'/') fname++;
10662 #ifdef CC3200_FS_SPIFFS
10669 static int fd_type(
int fd) {
10670 if (fd >= 0 && fd < NUM_SYS_FDS)
return FD_SYS;
10671 #ifdef CC3200_FS_SPIFFS
10672 if (fd >= SPIFFS_FD_BASE && fd < SPIFFS_FD_BASE + MAX_OPEN_SPIFFS_FILES) {
10677 if (fd >= SLFS_FD_BASE && fd < SLFS_FD_BASE + MAX_OPEN_SLFS_FILES) {
10684 int _open(
const char *pathname,
int flags, mode_t mode) {
10686 pathname = drop_dir(pathname);
10687 if (is_sl_fname(pathname)) {
10689 fd = fs_slfs_open(sl_fname(pathname), flags, mode);
10690 if (fd >= 0) fd += SLFS_FD_BASE;
10693 #ifdef CC3200_FS_SPIFFS
10694 fd = fs_spiffs_open(pathname, flags, mode);
10695 if (fd >= 0) fd += SPIFFS_FD_BASE;
10698 DBG((
"open(%s, 0x%x) = %d", pathname, flags, fd));
10702 int _stat(
const char *pathname,
struct stat *st) {
10704 const char *fname = pathname;
10705 int is_sl = is_sl_fname(pathname);
10706 if (is_sl) fname = sl_fname(pathname);
10707 fname = drop_dir(fname);
10708 memset(st, 0,
sizeof(*st));
10710 if (strcmp(fname,
"") == 0) {
10712 st->st_mode = S_IFDIR | 0777;
10719 res = fs_slfs_stat(fname, st);
10722 #ifdef CC3200_FS_SPIFFS
10723 res = fs_spiffs_stat(fname, st);
10726 DBG((
"stat(%s) = %d; fname = %s", pathname, res, fname));
10730 int _close(
int fd) {
10732 switch (fd_type(fd)) {
10734 r = set_errno(EBADF);
10737 r = set_errno(EACCES);
10739 #ifdef CC3200_FS_SPIFFS
10741 r = fs_spiffs_close(fd - SPIFFS_FD_BASE);
10746 r = fs_slfs_close(fd - SLFS_FD_BASE);
10750 DBG((
"close(%d) = %d", fd, r));
10754 off_t _lseek(
int fd, off_t offset,
int whence) {
10756 switch (fd_type(fd)) {
10758 r = set_errno(EBADF);
10761 r = set_errno(ESPIPE);
10763 #ifdef CC3200_FS_SPIFFS
10765 r = fs_spiffs_lseek(fd - SPIFFS_FD_BASE, offset, whence);
10770 r = fs_slfs_lseek(fd - SLFS_FD_BASE, offset, whence);
10774 DBG((
"lseek(%d, %d, %d) = %d", fd, (
int) offset, whence, r));
10778 int _fstat(
int fd,
struct stat *s) {
10780 memset(s, 0,
sizeof(*s));
10781 switch (fd_type(fd)) {
10783 r = set_errno(EBADF);
10787 memset(s, 0,
sizeof(*s));
10789 s->st_mode = S_IFCHR | 0666;
10793 #ifdef CC3200_FS_SPIFFS
10795 r = fs_spiffs_fstat(fd - SPIFFS_FD_BASE, s);
10800 r = fs_slfs_fstat(fd - SLFS_FD_BASE, s);
10804 DBG((
"fstat(%d) = %d", fd, r));
10808 ssize_t _read(
int fd,
void *buf,
size_t count) {
10810 switch (fd_type(fd)) {
10812 r = set_errno(EBADF);
10816 r = set_errno(EACCES);
10820 r = set_errno(ENOTSUP);
10823 #ifdef CC3200_FS_SPIFFS
10825 r = fs_spiffs_read(fd - SPIFFS_FD_BASE, buf, count);
10830 r = fs_slfs_read(fd - SLFS_FD_BASE, buf, count);
10834 DBG((
"read(%d, %u) = %d", fd, count, r));
10838 ssize_t _write(
int fd,
const void *buf,
size_t count) {
10841 switch (fd_type(fd)) {
10843 r = set_errno(EBADF);
10847 r = set_errno(EACCES);
10850 #if CS_PLATFORM == CS_P_CC3200
10851 for (i = 0; i <
count; i++) {
10852 const char c = ((
const char *) buf)[
i];
10853 if (c ==
'\n') MAP_UARTCharPut(CONSOLE_UART,
'\r');
10854 MAP_UARTCharPut(CONSOLE_UART, c);
10862 #ifdef CC3200_FS_SPIFFS
10864 r = fs_spiffs_write(fd - SPIFFS_FD_BASE, buf, count);
10869 r = fs_slfs_write(fd - SLFS_FD_BASE, buf, count);
10876 int _rename(
const char *from,
const char *to) {
10878 from = drop_dir(from);
10880 if (is_sl_fname(from) || is_sl_fname(to)) {
10882 r = fs_slfs_rename(sl_fname(from), sl_fname(to));
10885 #ifdef CC3200_FS_SPIFFS
10886 r = fs_spiffs_rename(from, to);
10889 DBG((
"rename(%s, %s) = %d", from, to, r));
10893 int _link(
const char *from,
const char *to) {
10894 DBG((
"link(%s, %s)", from, to));
10895 return set_errno(ENOTSUP);
10898 int _unlink(
const char *filename) {
10900 filename = drop_dir(filename);
10901 if (is_sl_fname(filename)) {
10903 r = fs_slfs_unlink(sl_fname(filename));
10906 #ifdef CC3200_FS_SPIFFS
10907 r = fs_spiffs_unlink(filename);
10910 DBG((
"unlink(%s) = %d", filename, r));
10914 #ifdef CC3200_FS_SPIFFS
10915 DIR *opendir(
const char *dir_name) {
10917 if (is_sl_fname(dir_name)) {
10919 set_errno(ENOTSUP);
10921 r = fs_spiffs_opendir(dir_name);
10923 DBG((
"opendir(%s) = %p", dir_name, r));
10927 struct dirent *readdir(DIR *dir) {
10928 struct dirent *res = fs_spiffs_readdir(dir);
10929 DBG((
"readdir(%p) = %p", dir, res));
10933 int closedir(DIR *dir) {
10934 int res = fs_spiffs_closedir(dir);
10935 DBG((
"closedir(%p) = %d", dir, res));
10939 int rmdir(
const char *path) {
10940 return fs_spiffs_rmdir(path);
10943 int mkdir(
const char *path, mode_t mode) {
10947 return (strlen(path) == 1 && *path ==
'.') ? 0 : ENOTDIR;
10953 #ifdef __TI_COMPILER_VERSION__
10956 #pragma diag_suppress 169
10957 ret = (add_device(
"SL", _MSA, fs_slfs_open, fs_slfs_close, fs_slfs_read,
10958 fs_slfs_write, fs_slfs_lseek, fs_slfs_unlink,
10959 fs_slfs_rename) == 0);
10968 #ifdef MG_MODULE_LINES
10969 #line 1 "./src/../../common/platforms/simplelink/sl_socket.c"
10976 #ifdef MG_SOCKET_SIMPLELINK
10983 #include <simplelink/include/netapp.h>
10985 const char *inet_ntop(
int af,
const void *src,
char *dst, socklen_t size) {
10987 struct in_addr *
in = (
struct in_addr *) src;
10988 if (af != AF_INET) {
10989 errno = EAFNOSUPPORT;
10992 res = snprintf(dst, size,
"%lu.%lu.%lu.%lu", SL_IPV4_BYTE(in->s_addr, 0),
10993 SL_IPV4_BYTE(in->s_addr, 1), SL_IPV4_BYTE(in->s_addr, 2),
10994 SL_IPV4_BYTE(in->s_addr, 3));
10995 return res > 0 ? dst : NULL;
10998 char *inet_ntoa(
struct in_addr n) {
11000 return (
char *) inet_ntop(AF_INET, &n, a,
sizeof(n));
11003 int inet_pton(
int af,
const char *src,
void *dst) {
11004 uint32_t a0, a1,
a2, a3;
11005 uint8_t *
db = (uint8_t *) dst;
11006 if (af != AF_INET) {
11007 errno = EAFNOSUPPORT;
11010 if (sscanf(src,
"%lu.%lu.%lu.%lu", &a0, &a1, &a2, &a3) != 4) {
11021 #ifdef MG_MODULE_LINES
11022 #line 1 "./src/../../common/platforms/simplelink/sl_mg_task.c"
11024 #if defined(MG_SOCKET_SIMPLELINK)
11028 #include <oslib/osi.h>
11030 enum mg_q_msg_type {
11034 enum mg_q_msg_type
type;
11035 void (*
cb)(
struct mg_mgr *mgr,
void *arg);
11038 static OsiMsgQ_t s_mg_q;
11039 static void mg_task(
void *arg);
11041 bool mg_start_task(
int priority,
int stack_size, mg_init_cb mg_init) {
11042 if (osi_MsgQCreate(&s_mg_q,
"MG",
sizeof(
struct mg_q_msg), 16) != OSI_OK) {
11045 if (osi_TaskCreate(mg_task, (
const signed char *)
"MG", stack_size,
11046 (
void *) mg_init, priority, NULL) != OSI_OK) {
11052 static void mg_task(
void *arg) {
11054 mg_init_cb mg_init = (mg_init_cb) arg;
11058 struct mg_q_msg msg;
11060 if (osi_MsgQRead(&s_mg_q, &msg, 1) != OSI_OK)
continue;
11061 switch (msg.type) {
11062 case MG_Q_MSG_CB: {
11063 msg.cb(&mgr, msg.arg);
11069 void mg_run_in_task(
void (*
cb)(
struct mg_mgr *mgr,
void *arg),
void *cb_arg) {
11070 struct mg_q_msg msg = {MG_Q_MSG_CB,
cb, cb_arg};
11071 osi_MsgQWrite(&s_mg_q, &msg, OSI_NO_WAIT);