2073 {
2074 DBG((
"%p %p", mgr,
c));
2075
2077 c->next = mgr->active_connections;
2078 mgr->active_connections =
c;
2080 if (
c->next != NULL)
c->next->prev =
c;
2082}
2083
2089}
2090
2093 if (ev_handler == NULL) {
2094
2095
2096
2097
2099 }
2100 DBG((
"%p %s ev=%d ev_data=%p flags=%lu rmbl=%d smbl=%d", nc,
2101 ev_handler == nc->
handler ?
"user" :
"proto", ev, ev_data, nc->flags,
2102 (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
2103
2104#if !defined(NO_LIBC) && !defined(MG_DISABLE_HEXDUMP)
2105
2110 *(int *) ev_data, ev);
2111 } else {
2113 }
2114 }
2115
2116#endif
2117 if (ev_handler != NULL) {
2118 unsigned long flags_before = nc->
flags;
2120 ev_handler(nc, ev, ev_data);
2122
2123 if (ev_handler == nc->
handler && nc->
flags != flags_before) {
2124 nc->
flags = (flags_before & ~_MG_CALLBACK_MODIFIABLE_FLAGS_MASK) |
2126 }
2129 }
2130 }
2131 DBG((
"%p after %s flags=%lu rmbl=%d smbl=%d", nc,
2132 ev_handler == nc->
handler ?
"user" :
"proto", nc->flags,
2133 (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
2134}
2135
2137 if (
c->ev_timer_time > 0 && now >=
c->ev_timer_time) {
2138 double old_value =
c->ev_timer_time;
2140
2141
2142
2143
2144 if (
c->ev_timer_time == old_value) {
2145 c->ev_timer_time = 0;
2146 }
2147 }
2148}
2149
2153 }
2154}
2155
2159 }
2161#ifdef MG_ENABLE_SSL
2162 if (conn->
ssl != NULL) SSL_free(conn->
ssl);
2164#endif
2167
2168 memset(conn, 0, sizeof(*conn));
2170}
2171
2173 DBG((
"%p %lu", conn, conn->
flags));
2177}
2178
2180 memset(m, 0, sizeof(*m));
2181#ifndef MG_DISABLE_SOCKETPAIR
2183#endif
2185
2186#ifdef _WIN32
2187 {
2189 WSAStartup(MAKEWORD(2, 2), &
data);
2190 }
2191#elif defined(__unix__)
2192
2193
2194 signal(SIGPIPE, SIG_IGN);
2195#endif
2196
2197#ifdef MG_ENABLE_SSL
2198 {
2199 static int init_done;
2200 if (!init_done) {
2201 SSL_library_init();
2202 init_done++;
2203 }
2204 }
2205#endif
2206
2208 DBG((
"=================================="));
2209 DBG((
"init mgr=%p", m));
2210}
2211
2212#ifdef MG_ENABLE_JAVASCRIPT
2213static enum v7_err mg_send_js(struct v7 *v7, v7_val_t *res) {
2214 v7_val_t arg0 = v7_arg(v7, 0);
2215 v7_val_t arg1 = v7_arg(v7, 1);
2217 size_t len = 0;
2218
2219 if (v7_is_string(arg1)) {
2220 const char *
data = v7_get_string_data(v7, &arg1, &len);
2222 }
2223
2224 *res = v7_mk_number(len);
2225
2226 return V7_OK;
2227}
2228
2229enum v7_err mg_enable_javascript(
struct mg_mgr *m,
struct v7 *v7,
2230 const char *init_file_name) {
2232 m->v7 = v7;
2233 v7_set_method(v7, v7_get_global(v7), "mg_send", mg_send_js);
2234 return v7_exec_file(v7, init_file_name, &
v);
2235}
2236#endif
2237
2240
2242 if (m == NULL) return;
2243
2245
2246#ifndef MG_DISABLE_SOCKETPAIR
2250#endif
2251
2253 tmp_conn = conn->
next;
2255 }
2256
2258}
2259
2262 int len;
2263
2266 }
2267 if (
buf != mem &&
buf != NULL) {
2269 }
2270
2271 return len;
2272}
2273
2275 int len;
2276 va_list ap;
2277 va_start(ap, fmt);
2279 va_end(ap);
2280 return len;
2281}
2282
2283#ifndef MG_DISABLE_SYNC_RESOLVER
2284
2285static int mg_resolve2(
const char *host,
struct in_addr *ina) {
2286#ifdef MG_ENABLE_GETADDRINFO
2287 int rv = 0;
2288 struct addrinfo hints, *servinfo, *p;
2289 struct sockaddr_in *h = NULL;
2290 memset(&hints, 0, sizeof hints);
2291 hints.ai_family = AF_INET;
2292 hints.ai_socktype = SOCK_STREAM;
2293 if ((rv = getaddrinfo(host, NULL, NULL, &servinfo)) != 0) {
2294 DBG((
"getaddrinfo(%s) failed: %s", host, strerror(errno)));
2295 return 0;
2296 }
2297 for (p = servinfo; p != NULL; p = p->ai_next) {
2298 memcpy(&h, &p->ai_addr, sizeof(struct sockaddr_in *));
2299 memcpy(ina, &h->sin_addr, sizeof(ina));
2300 }
2301 freeaddrinfo(servinfo);
2302 return 1;
2303#else
2304 struct hostent *he;
2305 if ((he = gethostbyname(host)) == NULL) {
2306 DBG((
"gethostbyname(%s) failed: %s", host, strerror(errno)));
2307 } else {
2308 memcpy(ina, he->h_addr_list[0], sizeof(*ina));
2309 return 1;
2310 }
2311 return 0;
2312#endif
2313}
2314
2315int mg_resolve(
const char *host,
char *buf,
size_t n) {
2316 struct in_addr ad;
2318}
2319#endif
2320
2325
2333
2334
2335
2336
2337
2339 } else {
2341 }
2342
2343 return conn;
2344}
2345
2350
2353 conn = NULL;
2355 }
2356
2357 return conn;
2358}
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2374 int *proto, char *host, size_t host_len) {
2375 unsigned int a, b,
c,
d, port = 0;
2376 int ch, len = 0;
2377#ifdef MG_ENABLE_IPV6
2379#endif
2380
2381
2382
2383
2384
2385
2386 memset(
sa, 0,
sizeof(*
sa));
2387 sa->
sin.sin_family = AF_INET;
2388
2389 *proto = SOCK_STREAM;
2390
2391 if (strncmp(
str,
"udp://", 6) == 0) {
2393 *proto = SOCK_DGRAM;
2394 }
else if (strncmp(
str,
"tcp://", 6) == 0) {
2396 }
2397
2398 if (sscanf(
str,
"%u.%u.%u.%u:%u%n", &a, &b, &
c, &
d, &port, &len) == 5) {
2399
2400 sa->
sin.sin_addr.s_addr =
2401 htonl(((uint32_t) a << 24) | ((uint32_t) b << 16) |
c << 8 |
d);
2402 sa->
sin.sin_port = htons((uint16_t) port);
2403#ifdef MG_ENABLE_IPV6
2404 }
else if (sscanf(
str,
"[%99[^]]]:%u%n",
buf, &port, &len) == 2 &&
2406
2407 sa->
sin6.sin6_family = AF_INET6;
2408 sa->
sin.sin_port = htons((uint16_t) port);
2409#endif
2410#ifndef MG_DISABLE_RESOLVER
2411 }
else if (strlen(
str) < host_len &&
2412 sscanf(
str,
"%[^ :]:%u%n", host, &port, &len) == 2) {
2413 sa->
sin.sin_port = htons((uint16_t) port);
2415 return 0;
2416 }
2417#endif
2418 }
else if (sscanf(
str,
":%u%n", &port, &len) == 1 ||
2419 sscanf(
str,
"%u%n", &port, &len) == 1) {
2420
2421 sa->
sin.sin_port = htons((uint16_t) port);
2422 } else {
2423 return -1;
2424 }
2425
2427 return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1;
2428}
2429
2430#ifdef MG_ENABLE_SSL
2431
2432
2433
2434
2435
2436#ifndef MG_DISABLE_PFS
2437
2438
2439
2440
2441static const char mg_s_cipher_list[] =
2442#if defined(MG_SSL_CRYPTO_MODERN)
2443 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
2444 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
2445 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
2446 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
2447 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
2448 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
2449 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
2450 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:"
2451 "!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
2452#elif defined(MG_SSL_CRYPTO_OLD)
2453 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
2454 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
2455 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
2456 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
2457 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
2458 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
2459 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
2460 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:"
2461 "ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
2462 "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:"
2463 "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
2464 "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
2465#else
2466 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
2467 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
2468 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
2469
2470 "ECDHE-ECDSA-AES128-SHA256:"
2471
2472 "ECDHE-ECDSA-AES128-SHA:"
2473
2474 "ECDHE-ECDSA-AES256-SHA384:"
2475
2476 "ECDHE-ECDSA-AES256-SHA:"
2477
2478
2479
2480 "AES128-GCM-SHA256:AES256-GCM-SHA384:"
2481 "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:"
2482 "AES:"
2483 "!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!RSA:!CBC-SHA:!CAMELLIA:"
2484 "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
2485#endif
2486 ;
2487
2488
2489
2490
2491
2492static const char mg_s_default_dh_params[] =
2493 "\
2494-----BEGIN DH PARAMETERS-----\n\
2495MIIBCAKCAQEAlvbgD/qh9znWIlGFcV0zdltD7rq8FeShIqIhkQ0C7hYFThrBvF2E\n\
2496Z9bmgaP+sfQwGpVlv9mtaWjvERbu6mEG7JTkgmVUJrUt/wiRzwTaCXBqZkdUO8Tq\n\
2497+E6VOEQAilstG90ikN1Tfo+K6+X68XkRUIlgawBTKuvKVwBhuvlqTGerOtnXWnrt\n\
2498ym//hd3cd5PBYGBix0i7oR4xdghvfR2WLVu0LgdThTBb6XP7gLd19cQ1JuBtAajZ\n\
2499wMuPn7qlUkEFDIkAZy59/Hue/H2Q2vU/JsvVhHWCQBL4F1ofEAt50il6ZxR1QfFK\n\
25009VGKDC4oOgm9DlxwwBoC2FjqmvQlqVV3kwIBAg==\n\
2501-----END DH PARAMETERS-----\n";
2502#endif
2503
2504static int mg_use_ca_cert(
SSL_CTX *
ctx,
const char *cert) {
2506 return -1;
2507 } else if (cert == NULL || cert[0] == '\0') {
2508 return 0;
2509 }
2510 SSL_CTX_set_verify(
ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
2511 return SSL_CTX_load_verify_locations(
ctx, cert, NULL) == 1 ? 0 : -2;
2512}
2513
2514static int mg_use_cert(
SSL_CTX *
ctx,
const char *pem_file) {
2516 return -1;
2517 } else if (pem_file == NULL || pem_file[0] == '\0') {
2518 return 0;
2519 }
else if (SSL_CTX_use_certificate_file(
ctx, pem_file, 1) == 0 ||
2520 SSL_CTX_use_PrivateKey_file(
ctx, pem_file, 1) == 0) {
2521 return -2;
2522 } else {
2523#ifndef MG_DISABLE_PFS
2524 BIO *bio = NULL;
2525 DH *dh = NULL;
2526
2527
2528 bio = BIO_new_file(pem_file, "r");
2529 if (bio != NULL) {
2530 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
2531 BIO_free(bio);
2532 }
2533
2534
2535
2536
2537 if (dh == NULL) {
2538 bio = BIO_new_mem_buf((void *) mg_s_default_dh_params, -1);
2539 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
2540 BIO_free(bio);
2541 }
2542 if (dh != NULL) {
2543 SSL_CTX_set_tmp_dh(
ctx, dh);
2544 SSL_CTX_set_options(
ctx, SSL_OP_SINGLE_DH_USE);
2545 DH_free(dh);
2546 }
2547#endif
2548 SSL_CTX_set_mode(
ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
2549 SSL_CTX_use_certificate_chain_file(
ctx, pem_file);
2550 return 0;
2551 }
2552}
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2571 const char *ca_cert) {
2572 const char *result = NULL;
2573 DBG((
"%p %s %s", nc, (cert ? cert :
""), (ca_cert ? ca_cert :
"")));
2574
2576 return "SSL for UDP is not supported";
2577 }
2578
2579 if (nc->
ssl != NULL) {
2582 }
2586 }
2587
2589 (nc->
ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
2590 result = "SSL_CTX_new() failed";
2592 (nc->
ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
2593 result = "SSL_CTX_new() failed";
2594 }
else if (mg_use_cert(nc->
ssl_ctx, cert) != 0) {
2595 result = "Invalid ssl cert";
2596 }
else if (mg_use_ca_cert(nc->
ssl_ctx, ca_cert) != 0) {
2597 result = "Invalid CA cert";
2600 result = "SSL_new() failed";
2602
2603
2604
2605
2606 SSL_set_fd(nc->
ssl, nc->
sock);
2607 }
2608
2609 SSL_CTX_set_options(nc->
ssl_ctx, SSL_OP_NO_SSLv2);
2610 SSL_CTX_set_options(nc->
ssl_ctx, SSL_OP_NO_SSLv3);
2611
2612#ifndef MG_DISABLE_PFS
2613 SSL_CTX_set_cipher_list(nc->
ssl_ctx, mg_s_cipher_list);
2614#endif
2615 return result;
2616}
2617#endif
2618
2622 memset(&opts, 0, sizeof(opts));
2624 if (nc == NULL) return NULL;
2632 return nc;
2633}
2634
2636 size_t sa_len) {
2637 (void) sa_len;
2640}
2641
2646 } else {
2648 }
2649#if !defined(NO_LIBC) && !defined(MG_DISABLE_HEXDUMP)
2652 }
2653#endif
2654}
2655
2657 if (num_sent < 0) {
2659 }
2661}
2662
2666 DBG((
"%p discarded %d bytes", nc, len));
2667
2668
2669
2670
2672 return;
2673 }
2676
2680 } else {
2683 }
2685}
2686
2689}
2690
2694 DBG((
"%p %u", nc, (
unsigned int) len));
2697
2698
2699
2700
2703 break;
2704 }
2705 }
2706 if (nc == NULL) {
2708 memset(&opts, 0, sizeof(opts));
2709
2711 if (nc != NULL) {
2721 } else {
2723
2724 }
2725 }
2726 }
2727 if (nc != NULL) {
2729 } else {
2730
2733 }
2734}
2735
2736
2737
2738
2739
2740
2741
2743 int proto,
2745 DBG((
"%p %s://%s:%hu", nc, proto == SOCK_DGRAM ?
"udp" :
"tcp",
2747
2749 if (proto == SOCK_DGRAM) {
2751 } else {
2753 }
2755 return nc;
2756}
2757
2759 DBG((
"%p connect, err=%d", nc,
err));
2760 nc->
flags &= ~MG_F_CONNECTING;
2763 }
2765}
2766
2767#ifndef MG_DISABLE_RESOLVER
2768
2769
2770
2771
2772
2773
2778 int failure = -1;
2779
2780 nc->
flags &= ~MG_F_RESOLVING;
2781 if (msg != NULL) {
2782
2783
2784
2787
2788
2789
2790
2792 4);
2795 return;
2796 }
2797 }
2798 }
2799
2803 }
2804
2805
2806
2807
2811}
2812#endif
2813
2817 memset(&opts, 0, sizeof(opts));
2819}
2820
2825 int proto, rc;
2828
2830
2832 return NULL;
2834 sizeof(host))) < 0) {
2835
2838 return NULL;
2839 }
2843
2844#ifdef MG_ENABLE_SSL
2845 if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
2846 const char *err =
mg_set_ssl(nc, opts.ssl_cert, opts.ssl_ca_cert);
2847 if (err != NULL) {
2850 return NULL;
2851 }
2852 if (opts.ssl_ca_cert != NULL && (opts.ssl_server_name == NULL ||
2853 strcmp(opts.ssl_server_name, "*") != 0)) {
2854 if (opts.ssl_server_name == NULL) opts.ssl_server_name = host;
2855#ifdef SSL_KRYPTON
2856 SSL_CTX_kr_set_verify_name(nc->
ssl_ctx, opts.ssl_server_name);
2857#else
2858
2860 "Server name verification requested but is not supported");
2862 return NULL;
2863#endif
2864 }
2865 }
2866#endif
2867
2868 if (rc == 0) {
2869#ifndef MG_DISABLE_RESOLVER
2870
2871
2872
2873
2876 memset(&o, 0, sizeof(o));
2879 o) != 0) {
2882 return NULL;
2883 }
2886 return nc;
2887#else
2890 return NULL;
2891#endif
2892 } else {
2893
2895 }
2896}
2897
2901 memset(&opts, 0, sizeof(opts));
2902 return mg_bind_opt(srv, address, event_handler, opts);
2903}
2904
2910 int proto, rc;
2913
2915
2918 return NULL;
2919 }
2920
2922 if (nc == NULL) {
2923 return NULL;
2924 }
2925
2928 if (proto == SOCK_DGRAM) {
2931 } else {
2933 }
2934 if (rc != 0) {
2935 DBG((
"Failed to open listener: %d", rc));
2938 return NULL;
2939 }
2940#ifdef MG_ENABLE_SSL
2941 if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
2942 const char *err =
mg_set_ssl(nc, opts.ssl_cert, opts.ssl_ca_cert);
2943 if (err != NULL) {
2946 return NULL;
2947 }
2948 }
2949#endif
2951
2952 return nc;
2953}
2954
2957}
2958
2959#ifndef MG_DISABLE_SOCKETPAIR
2961 size_t len) {
2963
2964
2965
2966
2967
2968
2969
2970
2973 size_t dummy;
2974
2980 (void) dummy;
2981 }
2982}
2983#endif
2984
2986 return n >= 0 &&
n <= 255;
2987}
2988
2989static int parse_net(
const char *spec, uint32_t *net, uint32_t *
mask) {
2990 int n, a, b,
c,
d, slash = 32, len = 0;
2991
2992 if ((sscanf(spec,
"%d.%d.%d.%d/%d%n", &a, &b, &
c, &
d, &slash, &
n) == 5 ||
2993 sscanf(spec,
"%d.%d.%d.%d%n", &a, &b, &
c, &
d, &
n) == 4) &&
2995 slash < 33) {
2997 *net =
2998 ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t)
c << 8) |
d;
2999 *
mask = slash ? 0xffffffffU << (32 - slash) : 0;
3000 }
3001
3002 return len;
3003}
3004
3006 int allowed, flag;
3009
3010
3011 allowed = (acl == NULL || *acl == '\0') ? '+' : '-';
3012
3015 if ((flag != '+' && flag != '-') ||
3017 return -1;
3018 }
3019
3020 if (net == (remote_ip &
mask)) {
3021 allowed = flag;
3022 }
3023 }
3024
3025 DBG((
"%08x %c", remote_ip, allowed));
3026 return allowed == '+';
3027}
3028
3029
3033}
3034
3036 double result =
c->ev_timer_time;
3037 c->ev_timer_time = timestamp;
3038
3039
3040
3041
3042
3044 (unsigned long) timestamp));
3047 }
3048 return result;
3049}
3050
3055 if (nc != NULL) {
3058 }
3059 return nc;
3060}
3061
3065 memset(&opts, 0, sizeof(opts));
3067}
3068
3071}
3072#ifdef MG_MODULE_LINES
3073#line 1 "./src/net_if_socket.c"
3074#endif
3075
3076
3077
3078
3079
3080#ifndef MG_DISABLE_SOCKET_IF
3081
3082
3083
3084
3085#define MG_TCP_RECV_BUFFER_SIZE 1024
3086#define MG_UDP_RECV_BUFFER_SIZE 1500
3087
3089#ifdef MG_ENABLE_SSL
3092#endif
3093
3095#ifdef _WIN32
3096 unsigned long on = 1;
3097 ioctlsocket(sock, FIONBIO, &on);
3098#elif defined(MG_SOCKET_SIMPLELINK)
3099 SlSockNonblocking_t opt;
3100 opt.NonblockingEnabled = 1;
3101 sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &opt, sizeof(opt));
3102#else
3103 int flags = fcntl(sock, F_GETFL, 0);
3104 fcntl(sock, F_SETFL,
flags | O_NONBLOCK);
3105#endif
3106}
3107
3109#ifdef MG_SOCKET_SIMPLELINK
3110 DBG((
"n = %d, errno = %d",
n, errno));
3111 if (
n < 0) errno =
n;
3112#endif
3113 return n == 0 || (
n < 0 && errno != EINTR && errno != EINPROGRESS &&
3114 errno != EAGAIN && errno != EWOULDBLOCK
3115#ifdef MG_SOCKET_SIMPLELINK
3116 && errno != SL_EALREADY
3117#endif
3118#ifdef _WIN32
3119 && WSAGetLastError() != WSAEINTR &&
3120 WSAGetLastError() != WSAEWOULDBLOCK
3121#endif
3122 );
3123}
3124
3127 int rc;
3131 nc->
err = errno ? errno : 1;
3132 return;
3133 }
3134#if !defined(MG_SOCKET_SIMPLELINK) && !defined(MG_ESP8266)
3136#endif
3137 rc = connect(nc->
sock, &sa->
sa,
sizeof(sa->
sin));
3139 DBG((
"%p sock %d err %d", nc, nc->
sock, nc->
err));
3140}
3141
3146 nc->
err = errno ? errno : 1;
3147 return;
3148 }
3150}
3151
3155 return (errno ? errno : 1);
3156 }
3158 return 0;
3159}
3160
3163 if (sock < 0) return (errno ? errno : 1);
3165 return 0;
3166}
3167
3170}
3171
3174}
3175
3177 (void) nc;
3178 (void) len;
3179}
3180
3182 (void) nc;
3183 return 1;
3184}
3185
3190 } else {
3191
3193 }
3194
3195
3196
3197
3198
3199
3200
3202}
3203
3207 socklen_t sa_len =
sizeof(
sa);
3208 extern int check_midas_acl(
const struct sockaddr *
sa,
int len);
3209
3210 sock_t sock = accept(lc->
sock, &
sa.sa, &sa_len);
3211 if (sock < 0) {
3212 DBG((
"%p: failed to accept: %d", lc, errno));
3213 return;
3214 }
3215 if (!check_midas_acl(&
sa.sa, sa_len)) {
3217 return;
3218 }
3220 if (nc == NULL) {
3222 return;
3223 }
3225#ifdef MG_ENABLE_SSL
3228 if (nc->
ssl == NULL || SSL_set_fd(nc->
ssl, sock) != 1) {
3231 }
3232 } else
3233#endif
3234 {
3236 }
3237}
3238
3239
3241 socklen_t sa_len =
3242 (
sa->sa.sa_family == AF_INET) ?
sizeof(
sa->sin) :
sizeof(
sa->sin6);
3244#if !defined(MG_SOCKET_SIMPLELINK) && !defined(MG_LWIP)
3245 int on = 1;
3246#endif
3247
3249#if !defined(MG_SOCKET_SIMPLELINK) && \
3251#if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE)
3252
3253 !setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
3254 sizeof(on)) &&
3255#endif
3256
3257#if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267 !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
3268#endif
3269#endif
3270
3271 !bind(sock, &
sa->sa, sa_len) &&
3272 (proto == SOCK_DGRAM || listen(sock,
SOMAXCONN) == 0)) {
3273#if !defined(MG_SOCKET_SIMPLELINK) && \
3274 !defined(MG_LWIP)
3276
3277 (void) getsockname(sock, &
sa->sa, &sa_len);
3278#endif
3282 }
3283
3284 return sock;
3285}
3286
3290
3291#ifdef MG_LWIP
3292
3293 if (io->
len == 0)
return;
3294#endif
3295
3296 assert(io->
len > 0);
3297
3301 DBG((
"%p %d %d %d %s:%hu", nc, nc->
sock,
n, errno,
3305 }
3307 return;
3308 }
3309
3310#ifdef MG_ENABLE_SSL
3311 if (nc->
ssl != NULL) {
3314 DBG((
"%p %d bytes -> %d (SSL)", nc,
n, nc->
sock));
3316 int ssl_err = mg_ssl_err(nc,
n);
3317 if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
3318 return;
3319 }
3320 } else {
3321
3323 }
3324 } else {
3325 mg_ssl_begin(nc);
3326 return;
3327 }
3328 } else
3329#endif
3330 {
3332 DBG((
"%p %d bytes -> %d", nc,
n, nc->
sock));
3333 }
3334
3337 }
3339}
3340
3342 size_t avail;
3345 return avail > max ? max : avail;
3346}
3347
3351
3354 return;
3355 }
3356
3357#ifdef MG_ENABLE_SSL
3358 if (conn->
ssl != NULL) {
3360
3361
3362
3364 DBG((
"%p %d bytes <- %d (SSL)", conn,
n, conn->
sock));
3368
3370 if (
buf == NULL)
break;
3371 }
3373 mg_ssl_err(conn,
n);
3374 } else {
3376 mg_ssl_begin(conn);
3377 return;
3378 }
3379 } else
3380#endif
3381 {
3385 DBG((
"%p %d bytes (PLAIN) <- %d", conn,
n, conn->
sock));
3387 } else {
3389 }
3392 }
3393 }
3394}
3395
3397 socklen_t *sa_len,
char **
buf) {
3401 DBG((
"Out of memory"));
3402 return -ENOMEM;
3403 }
3406 DBG((
"%p recvfrom: %s", nc, strerror(errno)));
3408 }
3410}
3411
3415 socklen_t sa_len =
sizeof(
sa);
3418 ntohs(nc->
sa.
sin.sin_port)));
3420}
3421
3422#ifdef MG_ENABLE_SSL
3424 int ssl_err = SSL_get_error(conn->
ssl, res);
3425 DBG((
"%p %d -> %d", conn, res, ssl_err));
3426 if (ssl_err == SSL_ERROR_WANT_READ) {
3428 } else if (ssl_err == SSL_ERROR_WANT_WRITE) {
3430 } else {
3431
3432 SSL_write(conn->
ssl,
"", 0);
3434 }
3435 return ssl_err;
3436}
3437
3439 int server_side = (nc->
listener != NULL);
3440 int res = server_side ? SSL_accept(nc->
ssl) : SSL_connect(nc->ssl);
3441 DBG((
"%p %d res %d %d", nc, server_side, res, errno));
3442
3443 if (res == 1) {
3446
3447 if (server_side) {
3449 socklen_t sa_len =
sizeof(
sa);
3450 (void) getpeername(nc->
sock, &
sa.sa, &sa_len);
3452 } else {
3454 }
3455 } else {
3456 int ssl_err = mg_ssl_err(nc, res);
3457 if (ssl_err != SSL_ERROR_WANT_READ && ssl_err != SSL_ERROR_WANT_WRITE) {
3458 if (!server_side) {
3460 }
3462 }
3463 }
3464}
3465#endif
3466
3467#define _MG_F_FD_CAN_READ 1
3468#define _MG_F_FD_CAN_WRITE 1 << 1
3469#define _MG_F_FD_ERROR 1 << 2
3470
3472 DBG((
"%p fd=%d fd_flags=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->
sock,
3474
3476 if (fd_flags != 0) {
3477 int err = 0;
3478#if !defined(MG_SOCKET_SIMPLELINK) && !defined(MG_ESP8266)
3480 socklen_t len = sizeof(err);
3481 int ret =
3482 getsockopt(nc->
sock, SOL_SOCKET, SO_ERROR, (
char *) &err, &len);
3483 if (ret != 0) err = 1;
3484 }
3485#else
3486
3487
3488
3489
3490#endif
3491#ifdef MG_ENABLE_SSL
3492 if (nc->
ssl != NULL && err == 0) {
3493 SSL_set_fd(nc->
ssl, nc->
sock);
3494 mg_ssl_begin(nc);
3495 } else {
3497 }
3498#else
3500#endif
3501 }
else if (nc->
err != 0) {
3503 }
3504 }
3505
3509 } else {
3511
3512
3513
3514
3515
3517 return;
3518 } else {
3520 }
3521 }
3523 }
3524
3527 }
3528
3531 }
3533
3534 DBG((
"%p after fd=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->
sock, nc->
flags,
3536}
3537
3538#ifndef MG_DISABLE_SOCKETPAIR
3541 int len =
3544 DBG((
"read %d from ctl socket", len));
3545 (void) dummy;
3550 }
3551 }
3552}
3553#endif
3554
3555
3561}
3562
3565 DBG((
"%p using select()",
mgr));
3566#ifndef MG_DISABLE_SOCKETPAIR
3567 do {
3570#endif
3571}
3572
3575}
3576
3578 (void) nc;
3579}
3580
3582 (void) nc;
3583}
3584
3590 }
3591 }
3592}
3593
3596 double min_timer;
3599 fd_set read_set, write_set, err_set;
3601 int num_fds, num_ev, num_timers = 0;
3602
3603 FD_ZERO(&read_set);
3604 FD_ZERO(&write_set);
3605 FD_ZERO(&err_set);
3606#ifndef MG_DISABLE_SOCKETPAIR
3608#endif
3609
3610
3611
3612
3613
3614 min_timer = 0;
3617
3618
3619
3621 num_fds++;
3622
3627 }
3628
3633 }
3634 }
3635
3639 }
3640 num_timers++;
3641 }
3642 }
3643
3644
3645
3646
3647
3648 if (num_timers > 0) {
3649 double timer_timeout_ms = (min_timer -
mg_time()) * 1000 + 1 ;
3650 if (timer_timeout_ms < timeout_ms) {
3651 timeout_ms = timer_timeout_ms;
3652 }
3653 }
3654 if (timeout_ms < 0) timeout_ms = 0;
3655
3656 tv.tv_sec = timeout_ms / 1000;
3657 tv.tv_usec = (timeout_ms % 1000) * 1000;
3658
3659 num_ev = select((
int) max_fd + 1, &read_set, &write_set, &err_set, &
tv);
3661 DBG((
"select @ %ld num_ev=%d of %d, timeout=%d", (
long) now, num_ev, num_fds,
3662 timeout_ms));
3663
3664#ifndef MG_DISABLE_SOCKETPAIR
3666 FD_ISSET(mgr->
ctl[1], &read_set)) {
3668 }
3669#endif
3670
3672 int fd_flags = 0;
3674 if (num_ev > 0) {
3675 fd_flags = (FD_ISSET(nc->
sock, &read_set) &&
3678 : 0) |
3681 }
3682#ifdef MG_SOCKET_SIMPLELINK
3683
3687 }
3688#endif
3689#ifdef MG_LWIP
3690
3692#endif
3693 }
3696 }
3697
3702
3704 }
3705 }
3706
3707 return now;
3708}
3709
3710#ifndef MG_DISABLE_SOCKETPAIR
3713 sock_t sock;
3714 socklen_t len =
sizeof(
sa.sin);
3715 int ret = 0;
3716
3718
3719 (void) memset(&
sa, 0,
sizeof(
sa));
3720 sa.
sin.sin_family = AF_INET;
3721 sa.sin.sin_port = htons(0);
3722 sa.sin.sin_addr.s_addr = htonl(0x7f000001);
3723
3725 }
else if (bind(sock, &
sa.sa, len) != 0) {
3726 } else if (sock_type == SOCK_STREAM && listen(sock, 1) != 0) {
3727 }
else if (getsockname(sock, &
sa.sa, &len) != 0) {
3729 }
else if (connect(sp[0], &
sa.sa, len) != 0) {
3730 } else if (sock_type == SOCK_DGRAM &&
3731 (getsockname(sp[0], &
sa.sa, &len) != 0 ||
3732 connect(sock, &
sa.sa, len) != 0)) {
3733 } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock
3734 : accept(sock, &
sa.
sa, &len))) ==
3736 } else {
3740 ret = 1;
3741 }
3742
3743 if (!ret) {
3748 }
3749
3750 return ret;
3751}
3752#endif
3753
3754#ifndef MG_SOCKET_SIMPLELINK
3757 socklen_t slen = sizeof(*sa);
3758 memset(
sa, 0, slen);
3759 if (remote) {
3760 getpeername(sock, &
sa->sa, &slen);
3761 } else {
3762 getsockname(sock, &
sa->sa, &slen);
3763 }
3764}
3765
3766void mg_sock_to_str(sock_t sock,
char *buf,
size_t len,
int flags) {
3770}
3771#endif
3772
3775#ifndef MG_SOCKET_SIMPLELINK
3777#else
3778
3779
3780
3781 if (remote) memcpy(
sa, &nc->
sa,
sizeof(*
sa));
3782#endif
3783}
3784
3785#endif
3786#ifdef MG_MODULE_LINES
3787#line 1 "./src/multithreading.c"
3788#endif
3789
3790
3791
3792
3793
3794
3795
3796
3797#ifdef MG_ENABLE_THREADS
3798
3799static void multithreaded_ev_handler(
struct mg_connection *
c,
int ev,
void *p);
3800
3801
3802
3803
3804
3805
3806static void *per_connection_thread_function(
void *
param) {
3809
3814 }
3816
3818}
3819
3823}
3824
3827 if (peer != NULL) {
3829 peer->priv_2 = NULL;
3830 }
3832}
3833
3834static void forwarder_ev_handler(
struct mg_connection *
c,
int ev,
void *p) {
3835 (void) p;
3840 }
3841}
3842
3843static void spawn_handling_thread(
struct mg_connection *nc) {
3845 sock_t sp[2];
3847
3848
3849
3850
3851
3852
3854 memset(&dummy, 0, sizeof(dummy));
3855 c[0] =
mg_add_sock(&dummy, sp[0], forwarder_ev_handler);
3857
3858
3859 link_conns(
c[0], nc);
3860
3861
3862
3863
3864
3866
3867
3868
3869
3870
3875
3876
3877
3878
3880
3882}
3883
3884static void multithreaded_ev_handler(
struct mg_connection *
c,
int ev,
void *p) {
3885 (void) p;
3887 spawn_handling_thread(
c);
3888 c->handler = forwarder_ev_handler;
3889 }
3890}
3891
3893
3895 nc->
handler = multithreaded_ev_handler;
3896}
3897#endif
3898#ifdef MG_MODULE_LINES
3899#line 1 "./src/uri.c"
3900#endif
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3917 for (; *p <
end; (*p)++) {
3918 if (**p == sep) {
3919 break;
3920 }
3921 }
3922 res->
len = (*p) - res->
p;
3923 if (*p <
end) (*p)++;
3924}
3925
3928 unsigned int *port,
struct mg_str *path,
struct mg_str *query,
3929 struct mg_str *fragment) {
3930 struct mg_str rscheme = {0, 0}, ruser_info = {0, 0}, rhost = {0, 0},
3931 rpath = {0, 0}, rquery = {0, 0}, rfragment = {0, 0};
3932 unsigned int rport = 0;
3933 enum {
3934 P_START,
3935 P_SCHEME_OR_PORT,
3936 P_USER_INFO,
3937 P_HOST,
3938 P_PORT,
3939 P_REST
3941
3942 const char *
p = uri.
p, *
end =
p + uri.
len;
3945 case P_START:
3946
3947
3948
3949
3950
3951
3952 for (;
p <
end;
p++) {
3954 state = P_SCHEME_OR_PORT;
3955 break;
3956 }
else if (*
p ==
'/') {
3958 break;
3959 }
3960 }
3963 rhost.len =
p - uri.
p;
3964 }
3965 break;
3966 case P_SCHEME_OR_PORT:
3967 if (
end -
p >= 3 && memcmp(
p,
"://", 3) == 0) {
3969 rscheme.
len =
p - uri.
p;
3970 state = P_USER_INFO;
3972 } else {
3974 rhost.len =
p - uri.
p;
3976 }
3977 break;
3978 case P_USER_INFO:
3981 for (;
p <
end;
p++) {
3984 break;
3985 }
else if (*
p ==
'/') {
3986 break;
3987 }
3988 }
3989 if (
p ==
end || *
p ==
'/') {
3990
3993 }
3994 ruser_info.len =
p - ruser_info.p;
3995 break;
3996 case P_HOST:
3999 for (;
p <
end;
p++) {
4002 break;
4003 }
else if (*
p ==
'/') {
4005 break;
4006 }
4007 }
4008 rhost.len =
p - rhost.p;
4009 break;
4010 case P_PORT:
4012 for (;
p <
end;
p++) {
4015 break;
4016 }
4017 rport *= 10;
4019 }
4020 break;
4021 case P_REST:
4022
4026 break;
4027 }
4028 }
4029
4030 if (scheme != 0) *scheme = rscheme;
4031 if (user_info != 0) *user_info = ruser_info;
4032 if (host != 0) *host = rhost;
4033 if (port != 0) *port = rport;
4034 if (path != 0) *path = rpath;
4035 if (query != 0) *query = rquery;
4036 if (fragment != 0) *fragment = rfragment;
4037
4038 return 0;
4039}
4040
4041
4043 const char *s = in->
p, *se = s + in->
len;
4044 char *cp = (
char *) out->
p, *
d;
4045
4046 if (in->len == 0 || *s != '/') {
4047 out->len = 0;
4048 return 0;
4049 }
4050
4052
4053 while (s < se) {
4054 const char *next = s;
4057 if (
mg_vcmp(&component,
".") == 0) {
4058
4059 }
else if (
mg_vcmp(&component,
"..") == 0) {
4060
4061 if (
d > cp + 1 && *(
d - 1) ==
'/')
d--;
4062 while (
d > cp && *(
d - 1) !=
'/')
d--;
4063 } else {
4064 memmove(
d, s, next - s);
4066 }
4067 s = next;
4068 }
4069 if (
d == cp) *
d++ =
'/';
4070
4071 out->p = cp;
4073 return 1;
4074}
4075#ifdef MG_MODULE_LINES
4076#line 1 "./src/http.c"
4077#endif
4078
4079
4080
4081
4082
4083#ifndef MG_DISABLE_HTTP
4084
4085
4086
4087
4088
4089
4090#ifndef MG_DISABLE_HTTP_WEBSOCKET
4091#define MG_WS_NO_HOST_HEADER_MAGIC ((char *) 0x1)
4092#endif
4093
4095
4101};
4102
4105};
4106
4109};
4110
4116};
4117
4126};
4127
4137};
4138
4140#ifndef MG_DISABLE_FILESYSTEM
4142#endif
4143#ifndef MG_DISABLE_CGI
4145#endif
4146#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4148#endif
4152};
4153
4155
4158 if (
c->proto_data == NULL) {
4161
4162 }
4163
4164
4165
4167}
4168
4169#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4170static void mg_http_free_proto_data_mp_stream(
4178}
4179#endif
4180
4181#ifndef MG_DISABLE_FILESYSTEM
4184 if (
d->fp != NULL) {
4186 }
4188 }
4189}
4190#endif
4191
4192#ifndef MG_DISABLE_CGI
4197 }
4198}
4199#endif
4200
4203
4204 while (current != NULL) {
4206 free((
void *) current->
name);
4207 free(current);
4208 current = tmp;
4209 }
4210
4211 ep = NULL;
4212}
4213
4216
4217#ifndef MG_DISABLE_FILESYSTEM
4219#endif
4220#ifndef MG_DISABLE_CGI
4222#endif
4223#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4224 mg_http_free_proto_data_mp_stream(&pd->mp_stream);
4225#endif
4227 free(proto_data);
4228}
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4246};
4247
4248#define MIME_ENTRY(_ext, _type) \
4249 { _ext, sizeof(_ext) - 1, _type }
4250static const struct {
4261 MIME_ENTRY(
"js",
"application/x-javascript"),
4269 MIME_ENTRY(
"torrent",
"application/x-bittorrent"),
4283 MIME_ENTRY(
"exe",
"application/octet-stream"),
4284 MIME_ENTRY(
"zip",
"application/x-zip-compressed"),
4289 MIME_ENTRY(
"arj",
"application/x-arj-compressed"),
4290 MIME_ENTRY(
"rar",
"application/x-rar-compressed"),
4293 MIME_ENTRY(
"swf",
"application/x-shockwave-flash"),
4303 {NULL, 0, NULL}};
4304
4305#ifndef MG_DISABLE_FILESYSTEM
4306
4307#ifndef MG_DISABLE_DAV
4308static int mg_mkdir(
const char *path, uint32_t mode) {
4309#ifndef _WIN32
4310 return mkdir(path, mode);
4311#else
4312 (void) mode;
4313 return _mkdir(path);
4314#endif
4315}
4316#endif
4317
4320 const char *ext, *overrides;
4323
4324 path_len = strlen(path);
4325
4326 overrides = opts->custom_mime_types;
4328 ext = path + (path_len -
k.len);
4330 return v;
4331 }
4332 }
4333
4339 r.len = strlen(r.p);
4340 return r;
4341 }
4342 }
4343
4344 r.p = dflt;
4345 r.len = strlen(r.p);
4346 return r;
4347}
4348#endif
4349
4350
4351
4352
4353
4354
4355
4357 const unsigned char *buf = (unsigned char *) s;
4359
4360 for (
i = 0;
i < buf_len;
i++) {
4361 if (!isprint(buf[
i]) && buf[
i] !=
'\r' && buf[
i] !=
'\n' && buf[
i] < 128) {
4362 return -1;
4363 }
else if (buf[
i] ==
'\n' &&
i + 1 < buf_len && buf[
i + 1] ==
'\n') {
4365 }
else if (buf[
i] ==
'\n' &&
i + 2 < buf_len && buf[
i + 1] ==
'\r' &&
4366 buf[
i + 2] ==
'\n') {
4368 }
4369 }
4370
4371 return 0;
4372}
4373
4379
4382
4383 while (v->len > 0 && v->p[v->len - 1] == ' ') {
4384 v->len--;
4385 }
4386
4387 if (
k->len == 0 || v->len == 0) {
4389 k->len = v->len = 0;
4390 break;
4391 }
4392
4396 }
4397 }
4398
4399 return s;
4400}
4401
4403 const char *
end, *qs;
4405
4406 if (
len <= 0)
return len;
4407
4408 memset(hm, 0, sizeof(*hm));
4413
4414
4415 while (s <
end && isspace(*(
unsigned char *) s)) s++;
4416
4417 if (is_req) {
4418
4423
4424
4425 if ((qs = (
char *) memchr(hm->
uri.
p,
'?', hm->
uri.
len)) != NULL) {
4429 }
4430 } else {
4432 if (
end - s < 4 || s[3] !=
' ')
return -1;
4435 s += 4;
4437 }
4438
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456 if (hm->
body.
len == (
size_t) ~0 && is_req &&
4461 }
4462
4464}
4465
4468
4472 return v;
4473 }
4474
4475 return NULL;
4476}
4477
4478#ifndef MG_DISABLE_HTTP_WEBSOCKET
4479
4481 return (flags & 0x80) == 0 || (flags & 0x0f) == 0;
4482}
4483
4485 return (flags & 0x80) == 0 && (flags & 0x0f) != 0;
4486}
4487
4490 if (wsm->
flags & 0x8) {
4492 } else {
4494 }
4495}
4496
4498
4500 mask_len = 0, header_len = 0;
4501 unsigned char *
p = (
unsigned char *) nc->
recv_mbuf.
buf, *buf =
p,
4503 unsigned *sizep = (
unsigned *) &
p[1];
4506
4507
4509 buf_len >= 1 + sizeof(*sizep) && buf_len >= 1 + sizeof(*sizep) + *sizep) {
4510 buf += 1 + sizeof(*sizep) + *sizep;
4511 buf_len -= 1 + sizeof(*sizep) + *sizep;
4512 }
4513
4514 if (buf_len >= 2) {
4516 mask_len = buf[1] & 128 ? 4 : 0;
4517 if (len < 126 && buf_len >= mask_len) {
4519 header_len = 2 + mask_len;
4520 }
else if (
len == 126 && buf_len >= 4 + mask_len) {
4521 header_len = 4 + mask_len;
4522 data_len = ntohs(*(uint16_t *) &buf[2]);
4523 } else if (buf_len >= 10 + mask_len) {
4524 header_len = 10 + mask_len;
4525 data_len = (((uint64_t) ntohl(*(uint32_t *) &buf[2])) << 32) +
4526 ntohl(*(uint32_t *) &buf[6]);
4527 }
4528 }
4529
4530 frame_len = header_len + data_len;
4531 ok = frame_len > 0 && frame_len <= buf_len;
4532
4533 if (ok) {
4535
4536 wsm.
size = (size_t) data_len;
4537 wsm.
data = buf + header_len;
4539
4540
4541 if (mask_len > 0) {
4542 for (
i = 0;
i < data_len;
i++) {
4543 buf[
i + header_len] ^= (buf + header_len - mask_len)[
i % 4];
4544 }
4545 }
4546
4547 if (reass) {
4548
4551 p[0] &= ~0x0f;
4552 buf = p + 1 + sizeof(*sizep);
4553 *sizep = 0;
4554 }
4555
4556
4558 (*sizep) += wsm.
size;
4560
4561
4562 if (wsm.
flags & 0x80) {
4563 wsm.
data = p + 1 +
sizeof(*sizep);
4567 }
4568 } else {
4569
4572 }
4573
4574
4577 }
4578 }
4579
4580 return ok;
4581}
4582
4586};
4587
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604#ifdef MG_DISABLE_WS_RANDOM_MASK
4606#else
4607 if (sizeof(long) >= 4) {
4609 } else if (sizeof(long) == 2) {
4611 }
4612#endif
4614}
4615
4618 int header_len;
4619 unsigned char header[10];
4620
4622 if (len < 126) {
4623 header[1] = len;
4624 header_len = 2;
4625 } else if (len < 65535) {
4626 uint16_t tmp = htons((uint16_t) len);
4627 header[1] = 126;
4628 memcpy(&header[2], &tmp, sizeof(tmp));
4629 header_len = 4;
4630 } else {
4631 uint32_t tmp;
4632 header[1] = 127;
4633 tmp = htonl((uint32_t)((uint64_t) len >> 32));
4634 memcpy(&header[2], &tmp, sizeof(tmp));
4635 tmp = htonl((uint32_t)(len & 0xffffffff));
4636 memcpy(&header[6], &tmp, sizeof(tmp));
4637 header_len = 10;
4638 }
4639
4640
4642 header[1] |= 1 << 7;
4643 mg_send(nc, header, header_len);
4647 } else {
4648 mg_send(nc, header, header_len);
4650 }
4651}
4652
4655 if (ctx->
pos == 0)
return;
4658 }
4659}
4660
4662 size_t len) {
4664 DBG((
"%p %d %d", nc, op, (
int) len));
4667
4669
4672 }
4673}
4674
4676 const struct mg_str *strv,
int strvcnt) {
4679 int len = 0;
4680 for (
i = 0;
i < strvcnt;
i++) {
4682 }
4683
4685
4686 for (
i = 0;
i < strvcnt;
i++) {
4688 }
4689
4691
4694 }
4695}
4696
4698 const char *fmt, ...) {
4700 va_list ap;
4701 int len;
4702
4703 va_start(ap, fmt);
4704 if ((len =
mg_avprintf(&buf,
sizeof(mem), fmt, ap)) > 0) {
4706 }
4707 va_end(ap);
4708
4709 if (buf != mem && buf != NULL) {
4711 }
4712}
4713
4715 void *ev_data) {
4717
4718 switch (ev) {
4720 do {
4722 break;
4724
4725 {
4726 time_t now = *(time_t *) ev_data;
4730 }
4731 }
4732 break;
4733 default:
4734 break;
4735 }
4736}
4737
4740 static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
4743
4744 snprintf(buf,
sizeof(buf),
"%.*s%s", (
int)
key->len,
key->p, magic);
4745
4749
4752 "HTTP/1.1 101 Switching Protocols\r\n"
4753 "Upgrade: websocket\r\n"
4754 "Connection: Upgrade\r\n"
4755 "Sec-WebSocket-Accept: ",
4756 b64_sha, "\r\n\r\n");
4757 DBG((
"%p %.*s %s", nc, (
int)
key->len,
key->p, b64_sha));
4758}
4759
4760#endif
4761
4762#ifndef MG_DISABLE_FILESYSTEM
4767 size_t n = 0, to_read = 0;
4768
4771 if (io->
len <
sizeof(
buf)) {
4772 to_read =
sizeof(
buf) - io->
len;
4773 }
4774
4775 if (
left > 0 && to_read > (
size_t)
left) {
4777 }
4778
4779 if (to_read == 0) {
4780
4782 (
n = fread(
buf, 1, to_read, pd->
file.
fp)) > 0) {
4785 } else {
4787#ifdef MG_DISABLE_HTTP_KEEP_ALIVE
4789#endif
4790 }
4793 size_t to_write =
4795 size_t n = fwrite(io->
buf, 1, to_write, pd->
file.
fp);
4799 }
4802#ifdef MG_DISABLE_HTTP_KEEP_ALIVE
4804#endif
4805 }
4806 }
4807#ifndef MG_DISABLE_CGI
4809
4812 } else {
4814 }
4815 }
4816#endif
4817}
4818#endif
4819
4820
4821
4822
4823
4824
4826 size_t *chunk_len) {
4827 unsigned char *s = (
unsigned char *)
buf;
4830
4831
4832 while (
i <
len && isxdigit(s[
i])) {
4834 n += (s[
i] >=
'0' && s[
i] <=
'9') ? s[
i] -
'0' : tolower(s[
i]) -
'a' + 10;
4836 }
4837
4838
4839 if (
i == 0 ||
i + 2 >
len || s[
i] !=
'\r' || s[
i + 1] !=
'\n') {
4840 return 0;
4841 }
4843
4844
4845 *chunk_data = (
char *) s +
i;
4847
4848
4850
4851
4852 if (
i == 0 ||
i + 2 >
len || s[
i] !=
'\r' || s[
i + 1] !=
'\n') {
4853 return 0;
4854 }
4856}
4857
4860 size_t blen) {
4863 size_t i,
n, data_len, body_len, zero_chunk_received = 0;
4864
4865
4867 assert(blen >= body_len);
4868
4869
4873
4874 memmove(buf + body_len,
data, data_len);
4875 body_len += data_len;
4877
4878 if (data_len == 0) {
4879 zero_chunk_received = 1;
4881 break;
4882 }
4883 }
4884
4886
4888 memmove(buf + body_len, buf +
i, blen -
i);
4889 memset(buf + body_len + blen -
i, 0,
i - body_len);
4892
4893
4894 nc->
flags &= ~MG_F_DELETE_CHUNK;
4896
4897
4899 memset(buf, 0, body_len);
4900 memmove(buf, buf + body_len, blen -
i);
4903 }
4904
4905 if (zero_chunk_received) {
4907 }
4908 }
4909
4910 return body_len;
4911}
4912
4917 int matched, matched_max = 0;
4919
4920 if (nc == NULL) {
4921 return NULL;
4922 }
4923
4925
4927 while (ep != NULL) {
4930 if (matched > matched_max) {
4931
4933 matched_max = matched;
4934 }
4935 }
4936
4938 }
4939
4940 return ret;
4941}
4942
4946
4951 : NULL;
4952 }
4954 hm);
4955}
4956
4957#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4958static void mg_http_multipart_continue(
struct mg_connection *nc);
4959
4960static void mg_http_multipart_begin(
struct mg_connection *nc,
4962
4963#endif
4964
4965
4966
4967
4968
4969
4970#ifdef __xtensa__
4971static void mg_http_handler2(
struct mg_connection *nc,
int ev,
void *ev_data,
4973
4976 mg_http_handler2(nc, ev, ev_data, &hm);
4977}
4978
4979static void mg_http_handler2(
struct mg_connection *nc,
int ev,
void *ev_data,
4981#else
4985#endif
4988 int req_len;
4989 const int is_req = (nc->
listener != NULL);
4990#ifndef MG_DISABLE_HTTP_WEBSOCKET
4992#endif
4994#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4995 if (pd->mp_stream.boundary != NULL) {
4996
4997
4998
4999
5001 memset(&mp, 0, sizeof(mp));
5002
5003 mp.status = -1;
5004 mp.
var_name = pd->mp_stream.var_name;
5007 MG_EV_HTTP_PART_END, &mp);
5008 } else
5009#endif
5011
5012
5013
5014
5019 }
5020 }
5021
5022#ifndef MG_DISABLE_FILESYSTEM
5024 printf(
"nc %p, pd %p, file fp %p cl %d\n", nc, pd, pd->
file.
fp, (
int)pd->
file.
cl);
5025
5026 assert(pd->
file.
fp == NULL);
5027 if (pd->
file.
fp != NULL) {
5029 }
5030#endif
5031
5033
5036
5037#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5038 if (pd->mp_stream.boundary != NULL) {
5039 mg_http_multipart_continue(nc);
5040 return;
5041 }
5042#endif
5043
5045
5046 if (req_len > 0 &&
5050 }
5051
5052#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5054 s->
len >= 9 && strncmp(s->
p,
"multipart", 9) == 0) {
5055 mg_http_multipart_begin(nc, hm, req_len);
5056 mg_http_multipart_continue(nc);
5057 return;
5058 }
5059#endif
5060
5061
5062 if ((req_len < 0 ||
5064 DBG((
"invalid request"));
5066 } else if (req_len == 0) {
5067
5068 }
5069#ifndef MG_DISABLE_HTTP_WEBSOCKET
5072
5073
5081
5085
5086
5091 }
5094 }
5095#endif
5098
5099
5100
5101#ifdef MG_ENABLE_JAVASCRIPT
5102 v7_val_t v1, v2, headers, req, args, res;
5103 struct v7 *v7 = nc->
mgr->v7;
5105 int i, js_callback_handled_request = 0;
5106
5107 if (v7 != NULL) {
5108
5109 v1 = v7_get(v7, v7_get_global(v7), "Http", ~0);
5110 v2 = v7_get(v7, v1, ev_name, ~0);
5111
5112
5113 args = v7_mk_array(v7);
5114 req = v7_mk_object(v7);
5115 headers = v7_mk_object(v7);
5116
5117
5118 v7_set(v7, req, "method", ~0,
5120 v7_set(v7, req,
"uri", ~0, v7_mk_string(v7, hm->
uri.
p, hm->
uri.
len, 1));
5121 v7_set(v7, req, "body", ~0,
5123 v7_set(v7, req, "headers", ~0, headers);
5127 v7_set(v7, headers,
name->p,
name->len,
5129 }
5130
5131
5132 v7_array_push(v7, args, v7_mk_foreign(nc));
5133 v7_array_push(v7, args, req);
5134 if (v7_apply(v7, v2, v7_mk_undefined(), args, &res) == V7_OK &&
5135 v7_is_truthy(v7, res)) {
5136 js_callback_handled_request++;
5137 }
5138 }
5139
5140
5141 if (js_callback_handled_request) {
5143 } else {
5145 }
5146#else
5148#endif
5150 }
5151 }
5152 (void) pd;
5153}
5154
5157 while (
len < buf_len && buf[
len] !=
'\n')
len++;
5158 return len == buf_len ? 0 :
len + 1;
5159}
5160
5161#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5162static void mg_http_multipart_begin(
struct mg_connection *nc,
5167
5168 char boundary[100];
5169 int boundary_len;
5170
5172
5173 goto exit_mp;
5174 }
5175
5177 if (ct == NULL) {
5178
5179 goto exit_mp;
5180 }
5181
5182
5183 if (ct->
len < 9 || strncmp(ct->
p,
"multipart", 9) != 0) {
5184 goto exit_mp;
5185 }
5186
5187 boundary_len =
5189 if (boundary_len == 0) {
5190
5191
5192
5193
5195 DBG((
"invalid request"));
5196 goto exit_mp;
5197 }
5198
5199
5200
5201 if (pd->mp_stream.boundary != NULL) {
5202
5203
5204
5205
5207 } else {
5208 pd->mp_stream.boundary = strdup(boundary);
5209 pd->mp_stream.boundary_len = strlen(boundary);
5210 pd->mp_stream.var_name = pd->mp_stream.file_name = NULL;
5211
5215 }
5216
5218
5220 }
5221exit_mp:
5222 ;
5223}
5224
5225#define CONTENT_DISPOSITION "Content-Disposition: "
5226
5227static void mg_http_multipart_call_handler(
struct mg_connection *
c,
int ev,
5228 const char *
data,
size_t data_len) {
5231 memset(&mp, 0, sizeof(mp));
5232
5233 mp.
var_name = pd->mp_stream.var_name;
5237 mp.data.len = data_len;
5240}
5241
5244 struct mbuf *io = &
c->recv_mbuf;
5245
5246 mg_http_multipart_call_handler(
c, MG_EV_HTTP_PART_DATA, io->
buf,
5247 pd->mp_stream.prev_io_len);
5249 pd->mp_stream.prev_io_len = 0;
5251
5252 return 0;
5253}
5254
5257
5258 mg_http_multipart_call_handler(
c, MG_EV_HTTP_PART_END, NULL, 0);
5259 mg_http_free_proto_data_mp_stream(&pd->mp_stream);
5261
5262 return 1;
5263}
5264
5265static int mg_http_multipart_wait_for_boundary(
struct mg_connection *
c) {
5266 const char *boundary;
5267 struct mbuf *io = &
c->recv_mbuf;
5269
5270 if ((
int) io->
len < pd->mp_stream.boundary_len + 2) {
5271 return 0;
5272 }
5273
5275 if (boundary != NULL) {
5276 if (io->
len - (boundary - io->
buf) < 4) {
5277 return 0;
5278 }
5279 if (memcmp(boundary + pd->mp_stream.boundary_len, "--", 2) == 0) {
5281 } else {
5283 }
5284 } else {
5285 return 0;
5286 }
5287
5288 return 1;
5289}
5290
5291static int mg_http_multipart_process_boundary(
struct mg_connection *
c) {
5292 int data_size;
5293 const char *boundary, *block_begin;
5294 struct mbuf *io = &
c->recv_mbuf;
5297 int line_len;
5299 block_begin = boundary + pd->mp_stream.boundary_len + 2;
5300 data_size = io->
len - (block_begin - io->
buf);
5301
5302 while (data_size > 0 &&
5304 if (line_len > (int) sizeof(CONTENT_DISPOSITION) &&
5306 sizeof(CONTENT_DISPOSITION) - 1) == 0) {
5308
5309 header.
p = block_begin +
sizeof(CONTENT_DISPOSITION) - 1;
5310 header.len = line_len - sizeof(CONTENT_DISPOSITION) - 1;
5314 block_begin += line_len;
5315 data_size -= line_len;
5316 continue;
5317 }
5318
5319 if (line_len == 2 &&
mg_ncasecmp(block_begin,
"\r\n", 2) == 0) {
5321
5322 if (pd->mp_stream.processing_part != 0) {
5323 mg_http_multipart_call_handler(
c, MG_EV_HTTP_PART_END, NULL, 0);
5324 }
5325
5326 free((void *) pd->mp_stream.file_name);
5327 pd->mp_stream.file_name = strdup(
file_name);
5328 free((void *) pd->mp_stream.var_name);
5329 pd->mp_stream.var_name = strdup(
var_name);
5330
5331 mg_http_multipart_call_handler(
c, MG_EV_HTTP_PART_BEGIN, NULL, 0);
5333 pd->mp_stream.processing_part++;
5334 return 1;
5335 }
5336
5337 block_begin += line_len;
5338 }
5339
5341
5342 return 0;
5343}
5344
5345static int mg_http_multipart_continue_wait_for_chunk(
struct mg_connection *
c) {
5347 struct mbuf *io = &
c->recv_mbuf;
5348
5349 const char *boundary;
5350 if ((
int) io->
len < pd->mp_stream.boundary_len + 6 ) {
5351 return 0;
5352 }
5353
5355 if (boundary == NULL && pd->mp_stream.prev_io_len == 0) {
5356 pd->mp_stream.prev_io_len = io->
len;
5357 return 0;
5358 } else if (boundary == NULL &&
5360 pd->mp_stream.prev_io_len + pd->mp_stream.boundary_len + 4) {
5362 return 1;
5363 } else if (boundary != NULL) {
5364 int data_size = (boundary - io->
buf - 4);
5365 mg_http_multipart_call_handler(
c, MG_EV_HTTP_PART_DATA, io->
buf, data_size);
5367 pd->mp_stream.prev_io_len = 0;
5369 return 1;
5370 } else {
5371 return 0;
5372 }
5373}
5374
5377 while (1) {
5378 switch (pd->mp_stream.state) {
5381 break;
5382 }
5384 if (mg_http_multipart_wait_for_boundary(
c) == 0) {
5385 return;
5386 }
5387 break;
5388 }
5390 if (mg_http_multipart_process_boundary(
c) == 0) {
5391 return;
5392 }
5393 break;
5394 }
5396 if (mg_http_multipart_continue_wait_for_chunk(
c) == 0) {
5397 return;
5398 }
5399 break;
5400 }
5402 if (mg_http_multipart_got_chunk(
c) == 0) {
5403 return;
5404 }
5405 break;
5406 }
5408 if (mg_http_multipart_finalize(
c) == 0) {
5409 return;
5410 }
5411 break;
5412 }
5415 return;
5416 }
5417 }
5418 }
5419}
5420
5421struct file_upload_state {
5422 char *lfn;
5423 size_t num_recd;
5425};
5426
5427void mg_file_upload_handler(
struct mg_connection *nc,
int ev,
void *ev_data,
5428 mg_fu_fname_fn local_name_fn) {
5429 switch (ev) {
5430 case MG_EV_HTTP_PART_BEGIN: {
5433 struct file_upload_state *fus =
5434 (struct file_upload_state *) calloc(1, sizeof(*fus));
5436
5438 if (lfn.
p == NULL || lfn.
len == 0) {
5441 "HTTP/1.1 403 Not Allowed\r\n"
5442 "Content-Type: text/plain\r\n"
5443 "Connection: close\r\n\r\n"
5444 "Not allowed to upload %s\r\n",
5447 return;
5448 }
5449 fus->lfn = (
char *) malloc(lfn.
len + 1);
5450 memcpy(fus->lfn, lfn.
p, lfn.
len);
5451 fus->lfn[lfn.
len] =
'\0';
5454 (
"%p Receiving file %s -> %s", nc, mp->
file_name, fus->lfn));
5455 fus->fp = fopen(fus->lfn, "w");
5456 if (fus->fp == NULL) {
5458 "HTTP/1.1 500 Internal Server Error\r\n"
5459 "Content-Type: text/plain\r\n"
5460 "Connection: close\r\n\r\n");
5461 LOG(
LL_ERROR, (
"Failed to open %s: %d\n", fus->lfn, errno));
5462 mg_printf(nc,
"Failed to open %s: %d\n", fus->lfn, errno);
5463
5464
5465
5466 }
5468 break;
5469 }
5470 case MG_EV_HTTP_PART_DATA: {
5473 struct file_upload_state *fus =
5474 (
struct file_upload_state *) mp->
user_data;
5475 if (fus == NULL || fus->fp == NULL) break;
5477 LOG(
LL_ERROR, (
"Failed to write to %s: %d, wrote %d", fus->lfn, errno,
5478 (int) fus->num_recd));
5479 if (errno == ENOSPC
5480#ifdef SPIFFS_ERR_FULL
5481 || errno == SPIFFS_ERR_FULL
5482#endif
5483 ) {
5485 "HTTP/1.1 413 Payload Too Large\r\n"
5486 "Content-Type: text/plain\r\n"
5487 "Connection: close\r\n\r\n");
5488 mg_printf(nc,
"Failed to write to %s: no space left; wrote %d\r\n",
5489 fus->lfn, (int) fus->num_recd);
5490 } else {
5492 "HTTP/1.1 500 Internal Server Error\r\n"
5493 "Content-Type: text/plain\r\n"
5494 "Connection: close\r\n\r\n");
5496 errno, (int) fus->num_recd);
5497 }
5498 fclose(fus->fp);
5499 remove(fus->lfn);
5500 fus->fp = NULL;
5501
5502
5503
5504 return;
5505 }
5506 fus->num_recd += mp->
data.
len;
5508 (int) fus->num_recd));
5509 break;
5510 }
5511 case MG_EV_HTTP_PART_END: {
5514 struct file_upload_state *fus =
5515 (
struct file_upload_state *) mp->
user_data;
5516 if (fus == NULL) break;
5517 if (mp->
status >= 0 && fus->fp != NULL) {
5519 fus->lfn, (int) fus->num_recd));
5521 "HTTP/1.1 200 OK\r\n"
5522 "Content-Type: text/plain\r\n"
5523 "Connection: close\r\n\r\n"
5524 "Ok, %s - %d bytes.\r\n",
5526 } else {
5528
5529
5530
5531
5532 }
5533 if (fus->fp != NULL) fclose(fus->fp);
5534 free(fus->lfn);
5535 free(fus);
5538 break;
5539 }
5540 }
5541}
5542
5543#endif
5544
5547}
5548
5549#ifndef MG_DISABLE_HTTP_WEBSOCKET
5550
5552 const char *host, const char *protocol,
5553 const char *extra_headers) {
5554
5555 unsigned long random = (
unsigned long) path;
5557
5560 "GET %s HTTP/1.1\r\n"
5561 "Upgrade: websocket\r\n"
5562 "Connection: Upgrade\r\n"
5563 "Sec-WebSocket-Version: 13\r\n"
5564 "Sec-WebSocket-Key: %s\r\n",
5566
5567
5570 }
5571 if (protocol != NULL) {
5572 mg_printf(nc,
"Sec-WebSocket-Protocol: %s\r\n", protocol);
5573 }
5574 if (extra_headers != NULL) {
5576 }
5578}
5579
5581 const char *extra_headers) {
5583 extra_headers);
5584}
5585
5586#endif
5587
5589 const char *extra_headers) {
5590 const char *status_message = "OK";
5591 switch (status_code) {
5592 case 206:
5593 status_message = "Partial Content";
5594 break;
5595 case 301:
5596 status_message = "Moved";
5597 break;
5598 case 302:
5599 status_message = "Found";
5600 break;
5601 case 401:
5602 status_message = "Unauthorized";
5603 break;
5604 case 403:
5605 status_message = "Forbidden";
5606 break;
5607 case 404:
5608 status_message = "Not Found";
5609 break;
5610 case 416:
5611 status_message = "Requested range not satisfiable";
5612 break;
5613 case 418:
5614 status_message = "I'm a teapot";
5615 break;
5616 case 500:
5617 status_message = "Internal Server Error";
5618 break;
5619 }
5620 mg_printf(nc,
"HTTP/1.1 %d %s\r\n", status_code, status_message);
5621 if (extra_headers != NULL) {
5623 }
5624}
5625
5627 int64_t content_length, const char *extra_headers) {
5629 if (content_length < 0) {
5630 mg_printf(
c,
"%s",
"Transfer-Encoding: chunked\r\n");
5631 } else {
5633 }
5635}
5636
5637#ifdef MG_DISABLE_FILESYSTEM
5641}
5642#else
5644 const char *reason) {
5645 if (!reason) reason = "";
5646 DBG((
"%p %d %s", nc, code, reason));
5648 "Content-Type: text/plain\r\nConnection: close");
5649 mg_send(nc, reason, strlen(reason));
5651}
5652#ifndef MG_DISABLE_SSI
5655
5657 char buf[BUFSIZ];
5659 while ((
n = fread(buf, 1,
sizeof(buf),
fp)) > 0) {
5661 }
5662}
5663
5664#if 0
5665static void mg_do_ssi_include(
struct mg_connection *nc,
const char *ssi,
5666 char *tag, int include_level,
5670
5671
5672
5673
5674
5675 if (sscanf(tag,
" virtual=\"%[^\"]\"",
file_name) == 1) {
5676
5678 }
else if (sscanf(tag,
" abspath=\"%[^\"]\"",
file_name) == 1) {
5679
5680
5681
5682
5683 snprintf(path,
sizeof(path),
"%s",
file_name);
5684 }
else if (sscanf(tag,
" file=\"%[^\"]\"",
file_name) == 1 ||
5685 sscanf(tag,
" \"%[^\"]\"",
file_name) == 1) {
5686
5687 snprintf(path, sizeof(path), "%s", ssi);
5688 if ((p = strrchr(path, DIRSEP)) != NULL) {
5689 p[1] = '\0';
5690 }
5691 snprintf(path + strlen(path),
sizeof(path) - strlen(path),
"%s",
file_name);
5692 } else {
5693 mg_printf(nc,
"Bad SSI #include: [%s]", tag);
5694 return;
5695 }
5696
5697 if ((
fp = fopen(path,
"rb")) == NULL) {
5698 mg_printf(nc,
"SSI include error: fopen(%s): %s", path, strerror(errno));
5699 } else {
5702 0) {
5704 } else {
5706 }
5708 }
5709}
5710#endif
5711
5712#ifndef MG_DISABLE_POPEN
5714 char cmd[BUFSIZ];
5716
5717 if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
5718 mg_printf(nc,
"Bad SSI #exec: [%s]", tag);
5719 }
else if ((
fp = popen(cmd,
"r")) == NULL) {
5720 mg_printf(nc,
"Cannot SSI #exec: [%s]: %s", cmd, strerror(errno));
5721 } else {
5724 }
5725}
5726#endif
5727
5730}
5731
5732
5733
5734
5735
5737 FILE *
fp,
int include_level,
5739 abort();
5740#if 0
5744#ifndef MG_DISABLE_POPEN
5746#endif
5747 char buf[BUFSIZ], *
p = buf + btag.
len;
5748 int ch,
len, in_ssi_tag;
5749
5750 if (include_level > 10) {
5751 mg_printf(nc,
"SSI #include level is too deep (%s)", path);
5752 return;
5753 }
5754
5755 in_ssi_tag =
len = 0;
5756 while ((ch = fgetc(
fp)) != EOF) {
5757 if (in_ssi_tag && ch ==
'>' && buf[
len - 1] ==
'-' && buf[
len - 2] ==
'-') {
5759 in_ssi_tag = 0;
5760
5761
5763 while (
i > 0 && buf[
i] ==
' ') {
5765 }
5766
5767
5768 if (memcmp(
p, d_include.
p, d_include.
len) == 0) {
5769 mg_do_ssi_include(nc, path,
p + d_include.
len + 1, include_level, opts);
5770 }
else if (memcmp(
p, d_call.
p, d_call.
len) == 0) {
5772#ifndef MG_DISABLE_POPEN
5773 }
else if (memcmp(
p, d_exec.
p, d_exec.
len) == 0) {
5775#endif
5776 } else {
5777
5778 }
5780 } else if (ch == '<') {
5781 in_ssi_tag = 1;
5784 }
5786 buf[
len++] = ch & 0xff;
5787 } else if (in_ssi_tag) {
5788 if (
len == (
int) btag.
len && memcmp(buf, btag.
p, btag.
len) != 0) {
5789
5790 in_ssi_tag = 0;
5791 }
else if (
len == (
int)
sizeof(buf) - 2) {
5792 mg_printf(nc,
"%s: SSI tag is too large", path);
5794 }
5795 buf[
len++] = ch & 0xff;
5796 } else {
5797 buf[
len++] = ch & 0xff;
5798 if (
len == (
int)
sizeof(buf)) {
5801 }
5802 }
5803 }
5804
5805
5808 }
5809#endif
5810}
5811
5816
5817 if ((
fp = fopen(path,
"rb")) == NULL) {
5819 } else {
5821
5825 "Content-Type: %.*s\r\n"
5826 "Connection: close\r\n\r\n",
5831 }
5832}
5833#else
5836 (void) path;
5837 (void) opts;
5839}
5840#endif
5841
5843 const cs_stat_t *st) {
5844 snprintf(buf, buf_len,
"\"%lx.%" INT64_FMT "\"", (
unsigned long) st->st_mtime,
5845 (int64_t) st->st_size);
5846}
5848 strftime(buf, buf_len,
"%a, %d %b %Y %H:%M:%S GMT",
gmtime(t));
5849}
5850
5852 int64_t *b) {
5853
5854
5855
5856
5857 int result;
5859 if (
p == NULL)
return 0;
5860 memcpy(
p, header->
p, header->
len);
5861 p[header->
len] =
'\0';
5864 return result;
5865}
5866
5872
5873 DBG((
"%p [%s]", nc, path));
5875 if ((pd->
file.
fp = fopen(path,
"rb")) == NULL) {
5876 int code;
5877 switch (errno) {
5878 case EACCES:
5879 code = 403;
5880 break;
5881 case ENOENT:
5882 code = 404;
5883 break;
5884 default:
5885 code = 500;
5886 };
5889 path) > 0) {
5891 } else {
5892 char etag[50], current_time[50], last_modified[50], range[70];
5893 time_t t = time(NULL);
5894 int64_t r1 = 0, r2 = 0, cl = st->st_size;
5896 int n, status_code = 200;
5897
5898
5899 range[0] = '\0';
5900 if (range_hdr != NULL &&
5902 r2 >= 0) {
5903
5905 r2 = cl - 1;
5906 }
5907 if (r1 > r2 || r2 >= cl) {
5908 status_code = 416;
5909 cl = 0;
5910 snprintf(range, sizeof(range),
5911 "Content-Range: bytes */%" INT64_FMT "\r\n",
5912 (int64_t) st->st_size);
5913 } else {
5914 status_code = 206;
5915 cl = r2 - r1 + 1;
5916 snprintf(range,
sizeof(range),
"Content-Range: bytes %" INT64_FMT
5918 r1, r1 + cl - 1, (int64_t) st->st_size);
5919#if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \
5920 _XOPEN_SOURCE >= 600
5921 fseeko(pd->
file.
fp, r1, SEEK_SET);
5922#else
5923 fseek(pd->
file.
fp, r1, SEEK_SET);
5924#endif
5925 }
5926 }
5927
5932
5933
5934
5935
5936
5937
5938
5941 "Date: %s\r\n"
5942 "Last-Modified: %s\r\n"
5943 "Accept-Ranges: bytes\r\n"
5944 "Content-Type: %.*s\r\n"
5946 "Connection: close\r\n"
5947#endif
5948 "Content-Length: %" SIZE_T_FMT
5949 "\r\n"
5950 "%sEtag: %s\r\n\r\n",
5952 (size_t) cl, range, etag);
5953
5957 }
5958}
5959
5960#endif
5961
5962int mg_url_decode(
const char *src,
int src_len,
char *dst,
int dst_len,
5963 int is_form_url_encoded) {
5965#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
5966
5967 for (
i =
j = 0;
i < src_len &&
j < dst_len - 1;
i++,
j++) {
5968 if (src[
i] ==
'%') {
5969 if (
i < src_len - 2 && isxdigit(*(
const unsigned char *) (src +
i + 1)) &&
5970 isxdigit(*(
const unsigned char *) (src +
i + 2))) {
5971 a = tolower(*(
const unsigned char *) (src +
i + 1));
5972 b = tolower(*(
const unsigned char *) (src +
i + 2));
5975 } else {
5976 return -1;
5977 }
5978 }
else if (is_form_url_encoded && src[
i] ==
'+') {
5980 } else {
5982 }
5983 }
5984
5986
5987 return i >= src_len ?
j : -1;
5988}
5989
5991 size_t dst_len) {
5992 const char *
p, *
e, *s;
5993 size_t name_len;
5995
5996 if (dst == NULL || dst_len == 0) {
5998 }
else if (buf->
p == NULL ||
name == NULL || buf->
len == 0) {
6000 dst[0] = '\0';
6001 } else {
6002 name_len = strlen(
name);
6003 e = buf->
p + buf->
len;
6005 dst[0] = '\0';
6006
6007 for (
p = buf->
p;
p + name_len <
e;
p++) {
6008 if ((
p == buf->
p ||
p[-1] ==
'&') &&
p[name_len] ==
'=' &&
6011 s = (
const char *) memchr(
p,
'&', (
size_t)(
e -
p));
6012 if (s == NULL) {
6014 }
6018 }
6019 break;
6020 }
6021 }
6022 }
6023
6025}
6026
6028 char chunk_size[50];
6030
6031 n = snprintf(chunk_size,
sizeof(chunk_size),
"%lX\r\n", (
unsigned long)
len);
6035}
6036
6040 va_list ap;
6041
6042 va_start(ap, fmt);
6044 va_end(ap);
6045
6048 }
6049
6050
6051 if (buf != mem && buf != NULL) {
6053 }
6054
6055}
6056
6060 va_list ap;
6061
6062 va_start(ap, fmt);
6064 va_end(ap);
6065
6067 for (
i =
j = 0;
i <
len;
i++) {
6068 if (buf[
i] ==
'<' || buf[
i] ==
'>') {
6070 mg_send(nc, buf[
i] ==
'<' ?
"<" :
">", 4);
6072 }
6073 }
6075 }
6076
6077
6078 if (buf != mem && buf != NULL) {
6080 }
6081
6082}
6083
6085 size_t buf_size) {
6086 int ch =
' ', ch1 =
',',
len = 0,
n = strlen(
var_name);
6087 const char *
p, *
end = hdr ? hdr->
p + hdr->
len : NULL, *s = NULL;
6088
6089 if (buf != NULL && buf_size > 0) buf[0] = '\0';
6090 if (hdr == NULL) return 0;
6091
6092
6093 for (s = hdr->
p; s != NULL && s +
n <
end; s++) {
6094 if ((s == hdr->
p || s[-1] == ch || s[-1] == ch1) && s[
n] ==
'=' &&
6096 break;
6097 }
6098
6099 if (s != NULL && &s[
n + 1] <
end) {
6101 if (*s == '"' || *s == '\'') {
6102 ch = ch1 = *s++;
6103 }
6105 while (
p <
end &&
p[0] != ch &&
p[0] != ch1 &&
len < (
int) buf_size) {
6106 if (ch !=
' ' &&
p[0] ==
'\\' &&
p[1] == ch)
p++;
6108 }
6109 if (
len >= (
int) buf_size || (ch !=
' ' && *
p != ch)) {
6111 } else {
6112 if (
len > 0 && s[
len - 1] ==
',')
len--;
6113 if (
len > 0 && s[
len - 1] ==
';')
len--;
6115 }
6116 }
6117
6119}
6120
6121#ifndef MG_DISABLE_FILESYSTEM
6124 int exclude_specials) {
6127
6128
6129 const char *pdir = strrchr(path, DIRSEP);
6130 if (pdir != NULL) {
6131 path = pdir + 1;
6132 }
6133
6134 return (exclude_specials && (!strcmp(path, ".") || !strcmp(path, ".."))) ||
6135 (p1 != NULL &&
6138}
6139
6140#ifndef MG_DISABLE_HTTP_DIGEST_AUTH
6141static void mg_mkmd5resp(
const char *method,
size_t method_len,
const char *uri,
6142 size_t uri_len, const char *ha1, size_t ha1_len,
6143 const char *nonce, size_t nonce_len, const char *nc,
6144 size_t nc_len, const char *cnonce, size_t cnonce_len,
6145 const char *qop, size_t qop_len, char *resp) {
6146 static const char colon[] = ":";
6147 static const size_t one = 1;
6148 char ha2[33];
6149
6150 cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL);
6151 cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc,
6152 nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len,
6153 colon, one, ha2, sizeof(ha2) - 1, NULL);
6154}
6155
6157 const char *method, const char *uri,
6158 const char *auth_domain, const char *user,
6159 const char *passwd) {
6160 static const char colon[] = ":", qop[] = "auth";
6161 static const size_t one = 1;
6162 char ha1[33], resp[33], cnonce[40];
6163
6164 snprintf(cnonce, sizeof(cnonce), "%x", (unsigned int) time(NULL));
6165 cs_md5(ha1, user, (
size_t) strlen(user), colon, one, auth_domain,
6166 (size_t) strlen(auth_domain), colon, one, passwd,
6167 (size_t) strlen(passwd), NULL);
6168 mg_mkmd5resp(method, strlen(method), uri, strlen(uri), ha1,
sizeof(ha1) - 1,
6169 cnonce, strlen(cnonce), "1", one, cnonce, strlen(cnonce), qop,
6170 sizeof(qop) - 1, resp);
6171 return snprintf(buf, buf_len,
6172 "Authorization: Digest username=\"%s\","
6173 "realm=\"%s\",uri=\"%s\",qop=%s,nc=1,cnonce=%s,"
6174 "nonce=%s,response=%s\r\n",
6175 user, auth_domain, uri, qop, cnonce, cnonce, resp);
6176}
6177
6178
6179
6180
6181
6182
6183
6185 unsigned long now = (unsigned long) time(NULL);
6186 unsigned long val = (unsigned long) strtoul(nonce, NULL, 16);
6187 return now < val || now - val < 3600;
6188}
6189
6190
6191
6192
6193
6195 const char *auth_domain, FILE *
fp) {
6197 char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)];
6198 char user[50], cnonce[33],
response[40], uri[200], qop[20], nc[20], nonce[30];
6199 char expected_response[33];
6200
6201
6202 if (hm == NULL ||
fp == NULL ||
6212 return 0;
6213 }
6214
6215
6216
6217
6218
6219
6220 while (fgets(buf,
sizeof(buf),
fp) != NULL) {
6221 if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3 &&
6222 strcmp(user, f_user) == 0 &&
6223
6224 strcmp(auth_domain, f_domain) == 0) {
6225
6229 f_ha1, strlen(f_ha1), nonce, strlen(nonce), nc, strlen(nc), cnonce,
6230 strlen(cnonce), qop, strlen(qop), expected_response);
6232 }
6233 }
6234
6235
6236 return 0;
6237}
6238
6240 int is_directory, const char *domain,
6241 const char *passwords_file,
6242 int is_global_pass_file) {
6246 int authorized = 1;
6247
6248 if (domain != NULL && passwords_file != NULL) {
6249 if (is_global_pass_file) {
6250 fp = fopen(passwords_file,
"r");
6251 } else if (is_directory) {
6252 snprintf(buf, sizeof(buf), "%s%c%s", path, DIRSEP, passwords_file);
6253 fp = fopen(buf,
"r");
6254 } else {
6255 p = strrchr(path, DIRSEP);
6256 if (
p == NULL)
p = path;
6257 snprintf(buf,
sizeof(buf),
"%.*s%c%s", (
int) (
p - path), path, DIRSEP,
6258 passwords_file);
6259 fp = fopen(buf,
"r");
6260 }
6261
6265 }
6266 }
6267
6268 DBG((
"%s %s %d %d", path, passwords_file ? passwords_file :
"",
6269 is_global_pass_file, authorized));
6270 return authorized;
6271}
6272#else
6274 int is_directory, const char *domain,
6275 const char *passwords_file,
6276 int is_global_pass_file) {
6277 (void) hm;
6278 (void) path;
6279 (void) is_directory;
6280 (void) domain;
6281 (void) passwords_file;
6282 (void) is_global_pass_file;
6283 return 1;
6284}
6285#endif
6286
6287#ifndef MG_DISABLE_DIRECTORY_LISTING
6288static size_t mg_url_encode(
const char *src,
size_t s_len,
char *dst,
6289 size_t dst_len) {
6290 static const char *dont_escape = "._-$,;~()/";
6291 static const char *hex = "0123456789abcdef";
6292 size_t i = 0,
j = 0;
6293
6294 for (
i =
j = 0; dst_len > 0 &&
i < s_len &&
j + 2 < dst_len - 1;
i++,
j++) {
6295 if (isalnum(*(
const unsigned char *) (src +
i)) ||
6296 strchr(dont_escape, *(
const unsigned char *) (src +
i)) != NULL) {
6298 }
else if (
j + 3 < dst_len) {
6300 dst[
j + 1] = hex[(*(
const unsigned char *) (src +
i)) >> 4];
6301 dst[
j + 2] = hex[(*(
const unsigned char *) (src +
i)) & 0xf];
6303 }
6304 }
6305
6308}
6309
6310static void mg_escape(
const char *src,
char *dst,
size_t dst_len) {
6312 while (*src !=
'\0' &&
n + 5 < dst_len) {
6313 unsigned char ch = *(unsigned char *) src++;
6314 if (ch == '<') {
6315 n += snprintf(dst +
n, dst_len -
n,
"%s",
"<");
6316 } else {
6318 }
6319 }
6321}
6322
6324 cs_stat_t *stp) {
6326 int64_t fsize = stp->st_size;
6327 int is_dir = S_ISDIR(stp->st_mode);
6328 const char *slash = is_dir ? "/" : "";
6329
6330 if (is_dir) {
6331 snprintf(size, sizeof(size), "%s", "[DIRECTORY]");
6332 } else {
6333
6334
6335
6336
6337 if (fsize < 1024) {
6338 snprintf(size, sizeof(size), "%d", (int) fsize);
6339 } else if (fsize < 0x100000) {
6340 snprintf(size, sizeof(size), "%.1fk", (double) fsize / 1024.0);
6341 } else if (fsize < 0x40000000) {
6342 snprintf(size, sizeof(size), "%.1fM", (double) fsize / 1048576);
6343 } else {
6344 snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824);
6345 }
6346 }
6347 strftime(mod,
sizeof(mod),
"%d-%b-%Y %H:%M",
localtime(&stp->st_mtime));
6351 "<tr><td><a href=\"%s%s\">%s%s</a></td>"
6352 "<td>%s</td><td name=%" INT64_FMT ">%s</td></tr>\n",
6353 href, slash, path, slash, mod, is_dir ? -1 : fsize,
6354 size);
6355}
6356
6360 cs_stat_t *)) {
6362 cs_stat_t st;
6363 struct dirent *dp;
6365
6366 DBG((
"%p [%s]", nc, dir));
6367 if ((dirp = (opendir(dir))) != NULL) {
6368 while ((dp = readdir(dirp)) != NULL) {
6369
6371 continue;
6372 }
6373 snprintf(path, sizeof(path), "%s/%s", dir, dp->d_name);
6374 if (
mg_stat(path, &st) == 0) {
6375 func(nc, (const char *) dp->d_name, &st);
6376 }
6377 }
6378 closedir(dirp);
6379 } else {
6380 DBG((
"%p opendir(%s) -> %d", nc, dir, errno));
6381 }
6382}
6383
6387 static const char *sort_js_code =
6388 "<script>function srt(tb, col) {"
6389 "var tr = Array.prototype.slice.call(tb.rows, 0),"
6390 "tr = tr.sort(function (a, b) { var c1 = a.cells[col], c2 = b.cells[col],"
6391 "n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), "
6392 "t1 = a.cells[2].getAttribute('name'), "
6393 "t2 = b.cells[2].getAttribute('name'); "
6394 "return t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : "
6395 "n1 ? parseInt(n2) - parseInt(n1) : "
6396 "c1.textContent.trim().localeCompare(c2.textContent.trim()); });";
6397 static const char *sort_js_code2 =
6398 "for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]);}"
6399 "window.onload = function() { "
6400 "var tb = document.getElementById('tb');"
6401 "document.onclick = function(ev){ "
6402 "var c = ev.target.rel; if (c) srt(tb, c)}; srt(tb, 2); };</script>";
6403
6405 mg_printf(nc,
"%s: %s\r\n%s: %s\r\n\r\n",
"Transfer-Encoding",
"chunked",
6406 "Content-Type", "text/html; charset=utf-8");
6407
6409 nc,
6410 "<html><head><title>Index of %.*s</title>%s%s"
6411 "<style>th,td {text-align: left; padding-right: 1em; }</style></head>"
6412 "<body><h1>Index of %.*s</h1><pre><table cellpadding=\"0\"><thead>"
6413 "<tr><th><a href=# rel=0>Name</a></th><th>"
6414 "<a href=# rel=1>Modified</a</th>"
6415 "<th><a href=# rel=2>Size</a></th></tr>"
6416 "<tr><td colspan=\"3\"><hr></td></tr></thead><tbody id=tb>",
6417 (
int) hm->
uri.
len, hm->
uri.
p, sort_js_code, sort_js_code2,
6422
6424}
6425#endif
6426
6427#ifndef MG_DISABLE_DAV
6429 cs_stat_t *stp) {
6431 time_t t = stp->st_mtime;
6435 "<d:response>"
6436 "<d:href>%s</d:href>"
6437 "<d:propstat>"
6438 "<d:prop>"
6439 "<d:resourcetype>%s</d:resourcetype>"
6441 "</d:getcontentlength>"
6442 "<d:getlastmodified>%s</d:getlastmodified>"
6443 "</d:prop>"
6444 "<d:status>HTTP/1.1 200 OK</d:status>"
6445 "</d:propstat>"
6446 "</d:response>\n",
6447 buf, S_ISDIR(stp->st_mode) ? "<d:collection/>" : "",
6448 (int64_t) stp->st_size, mtime);
6449}
6450
6454 static const char header[] =
6455 "HTTP/1.1 207 Multi-Status\r\n"
6456 "Connection: close\r\n"
6457 "Content-Type: text/xml; charset=utf-8\r\n\r\n"
6458 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
6459 "<d:multistatus xmlns:d='DAV:'>\n";
6460 static const char footer[] = "</d:multistatus>\n";
6462
6463
6464 if (S_ISDIR(stp->st_mode) &&
6466 mg_printf(nc,
"%s",
"HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
6467 } else {
6469 mg_send(nc, header,
sizeof(header) - 1);
6470 snprintf(uri,
sizeof(uri),
"%.*s", (
int) hm->
uri.
len, hm->
uri.
p);
6472 if (S_ISDIR(stp->st_mode) && (depth == NULL ||
mg_vcmp(depth,
"0") != 0)) {
6474 }
6475 mg_send(nc, footer,
sizeof(footer) - 1);
6477 }
6478}
6479
6480#ifdef MG_ENABLE_FAKE_DAVLOCK
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492static void mg_handle_lock(
struct mg_connection *nc,
const char *path) {
6493 static const char *reply =
6494 "HTTP/1.1 207 Multi-Status\r\n"
6495 "Connection: close\r\n"
6496 "Content-Type: text/xml; charset=utf-8\r\n\r\n"
6497 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
6498 "<d:multistatus xmlns:d='DAV:'>\n"
6499 "<D:lockdiscovery>\n"
6500 "<D:activelock>\n"
6501 "<D:locktoken>\n"
6502 "<D:href>\n"
6503 "opaquelocktoken:%s%u"
6504 "</D:href>"
6505 "</D:locktoken>"
6506 "</D:activelock>\n"
6507 "</D:lockdiscovery>"
6508 "</d:multistatus>\n";
6509 mg_printf(nc, reply, path, (
unsigned int) time(NULL));
6511}
6512#endif
6513
6516 int status_code = 500;
6518 status_code = 415;
6519 }
else if (!
mg_mkdir(path, 0755)) {
6520 status_code = 201;
6521 } else if (errno == EEXIST) {
6522 status_code = 405;
6523 } else if (errno == EACCES) {
6524 status_code = 403;
6525 } else if (errno == ENOENT) {
6526 status_code = 409;
6527 } else {
6528 status_code = 500;
6529 }
6531}
6532
6534 const char *dir) {
6536 struct dirent *dp;
6537 cs_stat_t st;
6539
6540 if ((dirp = opendir(dir)) == NULL) return 0;
6541
6542 while ((dp = readdir(dirp)) != NULL) {
6544 continue;
6545 }
6546 snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
6548 if (S_ISDIR(st.st_mode)) {
6550 } else {
6551 remove(path);
6552 }
6553 }
6554 closedir(dirp);
6556
6557 return 1;
6558}
6559
6564 if (dest == NULL) {
6566 } else {
6567 const char *
p = (
char *) memchr(dest->
p,
'/', dest->
len);
6568 if (
p != NULL &&
p[1] ==
'/' &&
6569 (
p = (
char *) memchr(
p + 2,
'/', dest->
p + dest->
len -
p)) != NULL) {
6572 (
int) (dest->
p + dest->
len -
p),
p);
6573 if (rename(path, buf) == 0) {
6575 } else {
6577 }
6578 } else {
6580 }
6581 }
6582}
6583
6586 const char *path) {
6587 cs_stat_t st;
6588 if (
mg_stat(path, &st) != 0) {
6590 } else if (S_ISDIR(st.st_mode)) {
6593 } else if (remove(path) == 0) {
6595 } else {
6597 }
6598}
6599
6600
6602 const char *s;
6603
6604
6605 for (s = path + 1; *s != '\0'; s++) {
6606 if (*s == '/') {
6608 cs_stat_t st;
6609 snprintf(buf, sizeof(buf), "%.*s", (int) (s - path), path);
6610 buf[sizeof(buf) - 1] = '\0';
6612 return -1;
6613 }
6614 }
6615 }
6616
6617 return 1;
6618}
6619
6623 cs_stat_t st;
6625 int rc, status_code =
mg_stat(path, &st) == 0 ? 200 : 201;
6626
6629 mg_printf(nc,
"HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
6630 } else if (rc == -1) {
6632 } else if (cl_hdr == NULL) {
6634 }
else if ((pd->
file.
fp = fopen(path,
"w+b")) == NULL) {
6636 } else {
6638 int64_t r1 = 0, r2 = 0;
6641 pd->
file.
cl = to64(cl_hdr->
p);
6642 if (range_hdr != NULL &&
6644 status_code = 206;
6645 fseeko(pd->
file.
fp, r1, SEEK_SET);
6646 pd->
file.
cl = r2 > r1 ? r2 - r1 + 1 : pd->
file.
cl - r1;
6647 }
6648 mg_printf(nc,
"HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
6649
6652 }
6653}
6654#endif
6655
6657 static const char *methods[] = {"PUT", "DELETE", "MKCOL", "PROPFIND", "MOVE"
6658#ifdef MG_ENABLE_FAKE_DAVLOCK
6659 ,
6660 "LOCK", "UNLOCK"
6661#endif
6662 };
6664
6667 return 1;
6668 }
6669 }
6670
6671 return 0;
6672}
6673
6674
6675
6676
6677
6678
6679
6680
6682 char **index_file, cs_stat_t *stp) {
6684 size_t path_len = strlen(path);
6685 int found = 0;
6686 *index_file = NULL;
6687
6688
6689
6691 cs_stat_t st;
6692 size_t len = path_len + 1 +
vec.
len + 1;
6694 if (*index_file == NULL) break;
6695 snprintf(*index_file,
len,
"%s%c%.*s", path, DIRSEP, (
int)
vec.
len,
vec.p);
6696
6697
6698 if (
mg_stat(*index_file, &st) == 0 && S_ISREG(st.st_mode)) {
6699
6700 *stp = st;
6701 found = 1;
6702 break;
6703 }
6704 }
6705 if (!found) {
6707 *index_file = NULL;
6708 }
6709 DBG((
"[%s] [%s]", path, (*index_file ? *index_file :
"")));
6710}
6711
6717 char local_port[20] = {'%'};
6718
6721
6723 if (
mg_vcmp(&a, local_port) == 0) {
6725 mg_printf(
c,
"Content-Length: 0\r\nLocation: %.*s%.*s\r\n\r\n",
6726 (
int) b.len, b.p, (
int) (hm->
proto.
p - hm->
uri.
p - 1),
6728 return 1;
6729 }
6730 }
6731
6732 return 0;
6733}
6734
6737 char **local_path,
6738 struct mg_str *remainder) {
6739 int ok = 1;
6741 struct mg_str root = {NULL, 0};
6742 const char *file_uri_start = cp;
6743 *local_path = NULL;
6744 remainder->
p = NULL;
6746
6747 {
6751
6753 if (a.len > 1 && a.p[0] == '@') {
6754
6755 if (hh != NULL && hh->
len == a.len - 1 &&
6757 root = b;
6758 break;
6759 }
6760 } else {
6761
6763 if (match_len > 0) {
6764 file_uri_start = hm->
uri.
p + match_len;
6765 if (*file_uri_start == '/' || file_uri_start == cp_end) {
6766
6767 } else if (*(file_uri_start - 1) == '/') {
6768
6769 file_uri_start--;
6770 } else {
6771
6772 continue;
6773 }
6774 root = b;
6775 break;
6776 }
6777 }
6778 }
6779
6780 if (root.
p == NULL) {
6781#ifndef MG_DISABLE_DAV
6785 } else
6786#endif
6787 {
6790 }
6791 }
6792 assert(root.
p != NULL && root.
len > 0);
6793 }
6794
6795 {
6796 const char *u = file_uri_start + 1;
6798 char *lp_end = lp + root.
len + hm->
uri.
len + 1;
6800 int exists = 1;
6801 if (lp == NULL) {
6802 ok = 0;
6803 goto out;
6804 }
6805 memcpy(
p, root.
p, root.
len);
6807 if (*(
p - 1) == DIRSEP)
p--;
6810
6811
6812 while (u <= cp_end) {
6813 const char *next = u;
6815 if (exists) {
6816 cs_stat_t st;
6817 exists = (
mg_stat(lp, &st) == 0);
6818 if (exists && S_ISREG(st.st_mode)) {
6819
6820
6821 if (*(u - 1) == '/') u--;
6822 break;
6823 }
6824 }
6825 if (u >= cp_end) break;
6827 if (component.len > 0) {
6829 memmove(
p + 1, component.p, component.len);
6832 ok = 0;
6833 break;
6834 }
6835 component.p =
p + 1;
6836 component.len =
len;
6837 if (
mg_vcmp(&component,
".") == 0) {
6838
6839 }
else if (
mg_vcmp(&component,
"..") == 0) {
6840 while (
p > ps && *
p != DIRSEP)
p--;
6842 } else {
6844#ifdef _WIN32
6845
6847 if (to_wchar(component.p, buf,
MG_MAX_PATH) == 0) {
6848 DBG((
"[%.*s] smells funny", (
int) component.len, component.p));
6849 ok = 0;
6850 break;
6851 }
6852#endif
6854
6855 for (
i = 0;
i < component.len;
i++,
p++) {
6856 if (*
p ==
'\0' || *
p == DIRSEP
6857#ifdef _WIN32
6858
6859 ||
6861#endif
6862 ) {
6863 ok = 0;
6864 break;
6865 }
6866 }
6867 }
6868 }
6869 u = next;
6870 }
6871 if (ok) {
6872 *local_path = lp;
6874 remainder->
len = cp_end - u;
6875 } else {
6877 }
6878 }
6879
6880out:
6881 DBG((
"'%.*s' -> '%s' + '%.*s'", (
int) hm->
uri.
len, hm->
uri.
p,
6882 *local_path ? *local_path :
"", (int) remainder->
len, remainder->
p));
6883 return ok;
6884}
6885
6886#ifndef MG_DISABLE_CGI
6887#ifdef _WIN32
6888struct mg_threadparam {
6889 sock_t s;
6890 HANDLE hPipe;
6891};
6892
6893static int mg_wait_until_ready(sock_t sock, int for_read) {
6894 fd_set set;
6895 FD_ZERO(&set);
6896 FD_SET(sock, &set);
6897 return select(sock + 1, for_read ? &
set : 0, for_read ? 0 : &
set, 0, 0) == 1;
6898}
6899
6900static void *mg_push_to_stdin(void *arg) {
6901 struct mg_threadparam *tp = (struct mg_threadparam *) arg;
6902 int n, sent, stop = 0;
6904 char buf[BUFSIZ];
6905
6906 while (!stop && mg_wait_until_ready(tp->s, 1) &&
6907 (
n = recv(tp->s, buf,
sizeof(buf), 0)) > 0) {
6908 if (
n == -1 && GetLastError() == WSAEWOULDBLOCK)
continue;
6909 for (sent = 0; !stop && sent <
n; sent +=
k) {
6910 if (!WriteFile(tp->hPipe, buf + sent,
n - sent, &
k, 0)) stop = 1;
6911 }
6912 }
6913 DBG((
"%s",
"FORWARED EVERYTHING TO CGI"));
6914 CloseHandle(tp->hPipe);
6916 _endthread();
6917 return NULL;
6918}
6919
6920static void *mg_pull_from_stdout(void *arg) {
6921 struct mg_threadparam *tp = (struct mg_threadparam *) arg;
6922 int k = 0, stop = 0;
6924 char buf[BUFSIZ];
6925
6926 while (!stop && ReadFile(tp->hPipe, buf,
sizeof(buf), &
n, NULL)) {
6927 for (sent = 0; !stop && sent <
n; sent +=
k) {
6928 if (mg_wait_until_ready(tp->s, 0) &&
6929 (
k = send(tp->s, buf + sent,
n - sent, 0)) <= 0)
6930 stop = 1;
6931 }
6932 }
6933 DBG((
"%s",
"EOF FROM CGI"));
6934 CloseHandle(tp->hPipe);
6935 shutdown(tp->s, 2);
6938 _endthread();
6939 return NULL;
6940}
6941
6942static void mg_spawn_stdio_thread(sock_t sock, HANDLE hPipe,
6943 void *(*func)(void *)) {
6944 struct mg_threadparam *tp = (
struct mg_threadparam *)
MG_MALLOC(
sizeof(*tp));
6945 if (tp != NULL) {
6946 tp->s = sock;
6947 tp->hPipe = hPipe;
6949 }
6950}
6951
6952static void mg_abs_path(const char *utf8_path, char *abs_path, size_t len) {
6955 GetFullPathNameW(buf,
ARRAY_SIZE(buf2), buf2, NULL);
6956 WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0);
6957}
6958
6960 const char *env, const char *envp[],
6961 const char *dir, sock_t sock) {
6962 STARTUPINFOW si;
6963 PROCESS_INFORMATION
pi;
6964 HANDLE a[2], b[2], me = GetCurrentProcess();
6968 DWORD flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
6970
6971 memset(&si, 0, sizeof(si));
6972 memset(&
pi, 0,
sizeof(
pi));
6973
6974 si.cb = sizeof(si);
6975 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
6976 si.wShowWindow = SW_HIDE;
6977 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
6978
6979 CreatePipe(&a[0], &a[1], NULL, 0);
6980 CreatePipe(&b[0], &b[1], NULL, 0);
6981 DuplicateHandle(me, a[0], me, &si.hStdInput, 0,
TRUE, flags);
6982 DuplicateHandle(me, b[1], me, &si.hStdOutput, 0,
TRUE, flags);
6983
6984 if (interp == NULL && (
fp = fopen(cmd,
"r")) != NULL) {
6985 buf[0] = buf[1] = '\0';
6986 fgets(buf,
sizeof(buf),
fp);
6987 buf[sizeof(buf) - 1] = '\0';
6988 if (buf[0] == '#' && buf[1] == '!') {
6989 interp = buf + 2;
6990
6991 while (*interp != '\0' && isspace(*(unsigned char *) interp)) {
6992 interp++;
6993 }
6994 }
6996 }
6997
6998 snprintf(buf, sizeof(buf), "%s/%s", dir, cmd);
7000
7002 to_wchar(dir, full_dir,
ARRAY_SIZE(full_dir));
7003
7004 if (interp != NULL) {
7006 snprintf(cmdline, sizeof(cmdline), "%s \"%s\"", buf4, buf2);
7007 } else {
7008 snprintf(cmdline, sizeof(cmdline), "\"%s\"", buf2);
7009 }
7011
7012 if (CreateProcessW(NULL, wcmd, NULL, NULL,
TRUE, CREATE_NEW_PROCESS_GROUP,
7013 (
void *) env, full_dir, &si, &
pi) != 0) {
7014 mg_spawn_stdio_thread(sock, a[1], mg_push_to_stdin);
7015 mg_spawn_stdio_thread(sock, b[0], mg_pull_from_stdout);
7016 } else {
7017 CloseHandle(a[1]);
7018 CloseHandle(b[0]);
7020 }
7021 DBG((
"CGI command: [%ls] -> %p", wcmd,
pi.hProcess));
7022
7023
7024 CloseHandle(si.hStdOutput);
7025 CloseHandle(si.hStdInput);
7026
7027
7028
7029
7031}
7032#else
7034 const char *env, const char *envp[],
7035 const char *dir, sock_t sock) {
7036 char buf[500];
7037 pid_t pid = fork();
7038 (void) env;
7039
7040 if (pid == 0) {
7041
7042
7043
7044
7045 int tmp = chdir(dir);
7046 (void) tmp;
7047 (void) dup2(sock, 0);
7048 (void) dup2(sock, 1);
7050
7051
7052
7053
7054
7055
7056
7057 signal(SIGCHLD, SIG_DFL);
7058
7059 if (interp == NULL) {
7060 execle(cmd, cmd, (char *) 0, envp);
7061 } else {
7062 execle(interp, interp, cmd, (char *) 0, envp);
7063 }
7064 snprintf(buf, sizeof(buf),
7065 "Status: 500\r\n\r\n"
7066 "500 Server Error: %s%s%s: %s",
7067 interp == NULL ? "" : interp, interp == NULL ? "" : " ", cmd,
7068 strerror(errno));
7069 send(1, buf, strlen(buf), 0);
7070 exit(EXIT_FAILURE);
7071 }
7072
7073 return pid;
7074}
7075#endif
7076
7077
7078
7079
7080
7083 char *added = block->
buf + block->
len;
7084 va_list ap;
7085
7086
7087 space =
sizeof(block->
buf) - (block->
len + 2);
7088 if (space > 0) {
7089
7090 va_start(ap, fmt);
7091 n = vsnprintf(added, (
size_t) space, fmt, ap);
7092 va_end(ap);
7093
7094
7095 if (
n > 0 &&
n + 1 < space &&
7097
7099
7100 block->
len +=
n + 1;
7101 }
7102 }
7103
7104 return added;
7105}
7106
7108 const char *s;
7110}
7111
7113 const char *prog,
7114 const struct mg_str *path_info,
7118 const char *s;
7122
7125
7126 if ((s = getenv("SERVER_NAME")) != NULL) {
7128 } else {
7129 char buf[100];
7132 }
7136
7137
7141
7142
7143
7144
7146#if 0
7147 addenv(
blk,
"REMOTE_ADDR=%s", ri->remote_ip);
7148 addenv(
blk,
"REMOTE_PORT=%d", ri->remote_port);
7149#endif
7152 hm->query_string.
p);
7153
7155 if (*s == '/') {
7156 const char *base_name = strrchr(prog, DIRSEP);
7158 (base_name != NULL ? base_name + 1 : prog));
7159 } else {
7161 }
7163
7164 if (path_info != NULL && path_info->
len > 0) {
7166
7167 mg_addenv(
blk,
"PATH_TRANSLATED=%.*s", (
int) path_info->
len, path_info->
p);
7168 }
7169
7171
7173 NULL) {
7175 }
7176
7180 }
7181
7183 NULL) {
7185 }
7186
7193
7194#if defined(_WIN32)
7201#else
7203#endif
7204
7205
7210
7211
7212 for (; *
p !=
'=' && *
p !=
'\0';
p++) {
7213 if (*
p ==
'-') *
p =
'_';
7214 *
p = (char) toupper(*(
unsigned char *)
p);
7215 }
7216 }
7217
7218 blk->vars[
blk->nvars++] = NULL;
7219 blk->buf[
blk->len++] =
'\0';
7220}
7221
7223 void *ev_data) {
7225 (void) ev_data;
7226
7227 if (nc == NULL) return;
7228
7229 switch (ev) {
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7245 struct mbuf *io = &cgi_nc->recv_mbuf;
7247
7248 if (
len == 0)
break;
7252 } else {
7257 mg_printf(nc,
"%s",
"HTTP/1.1 302 Moved\r\n");
7260 } else {
7261 mg_printf(nc,
"%s",
"HTTP/1.1 200 OK\r\n");
7262 }
7263 }
7264 nc->
flags &= ~MG_F_USER_1;
7265 }
7268 }
7269 break;
7273 break;
7274 }
7275}
7276
7278 const struct mg_str *path_info,
7283 const char *p;
7284 sock_t fds[2];
7285
7286 DBG((
"%p [%s]",
nc, prog));
7288
7289
7290
7291
7292
7293 if ((p = strrchr(prog, DIRSEP)) == NULL) {
7294 snprintf(dir, sizeof(dir), "%s", ".");
7295 } else {
7296 snprintf(dir, sizeof(dir), "%.*s", (int) (p - prog), prog);
7297 prog = p + 1;
7298 }
7299
7300
7301
7302
7303
7304
7305 do {
7308
7310 fds[1]) != 0) {
7318
7319 if (
n > 0 && n < nc->recv_mbuf.len) {
7321 }
7323 } else {
7326 }
7327
7328#ifndef _WIN32
7330#endif
7331}
7332#endif
7333
7335 static const char *
month_names[] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
7336 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
7338
7341
7342 return -1;
7343}
7344
7346 return year / 4 - year / 100 + year / 400;
7347}
7348
7349
7351 static const unsigned short days_before_month[] = {
7352 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
7353 char month_str[32];
7354 int second, minute, hour, day, month, year, leap_days, days;
7355 time_t result = (time_t) 0;
7356
7357 if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d", &day, month_str, &year, &hour,
7358 &minute, &second) == 6) ||
7359 (sscanf(datetime, "%d %3s %d %d:%d:%d", &day, month_str, &year, &hour,
7360 &minute, &second) == 6) ||
7361 (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d", &day, month_str, &year,
7362 &hour, &minute, &second) == 6) ||
7363 (sscanf(datetime, "%d-%3s-%d %d:%d:%d", &day, month_str, &year, &hour,
7364 &minute, &second) == 6)) &&
7367 year -= 1970;
7368 days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
7369 result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
7370 }
7371
7372 return result;
7373}
7374
7378 char etag[64];
7383 } else {
7384 return 0;
7385 }
7386}
7387
7389 const char *domain) {
7391 "HTTP/1.1 401 Unauthorized\r\n"
7392 "WWW-Authenticate: Digest qop=\"auth\", "
7393 "realm=\"%s\", nonce=\"%lu\"\r\n"
7394 "Content-Length: 0\r\n\r\n",
7395 domain, (unsigned long) time(NULL));
7396}
7397
7400 "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, OPTIONS"
7401#ifndef MG_DISABLE_DAV
7402 ", MKCOL, PUT, DELETE, PROPFIND, MOVE\r\nDAV: 1,2"
7403#endif
7404 "\r\n\r\n");
7406}
7407
7410}
7411
7413 const struct mg_str *path_info,
7417 int is_cgi;
7418 char *index_file = NULL;
7419 cs_stat_t st;
7420
7421 exists = (
mg_stat(path, &st) == 0);
7422 is_directory = exists && S_ISDIR(st.st_mode);
7423
7424 if (is_directory)
7426
7427 is_cgi =
7429 index_file ? index_file : path) > 0);
7430
7431 DBG((
"%p %.*s [%s] exists=%d is_dir=%d is_dav=%d is_cgi=%d index=%s", nc,
7433 is_cgi, index_file ? index_file : ""));
7434
7435 if (is_directory && hm->
uri.
p[hm->
uri.
len - 1] !=
'/' && !is_dav) {
7437 "HTTP/1.1 301 Moved\r\nLocation: %.*s/\r\n"
7438 "Content-Length: 0\r\n\r\n",
7441 return;
7442 }
7443
7444
7445 if (path_info->
len > 0 && !is_cgi) {
7448 return;
7449 }
7450
7458 } else if (is_cgi) {
7459#if !defined(MG_DISABLE_CGI)
7460 mg_handle_cgi(nc, index_file ? index_file : path, path_info, hm, opts);
7461#else
7463#endif
7464 } else if ((!exists ||
7468#ifndef MG_DISABLE_DAV
7471#ifndef MG_DISABLE_DAV_AUTH
7472 } else if (is_dav &&
7478#endif
7487#ifdef MG_ENABLE_FAKE_DAVLOCK
7489 mg_handle_lock(nc, path);
7490#endif
7491#endif
7494 } else if (is_directory && index_file == NULL) {
7495#ifndef MG_DISABLE_DIRECTORY_LISTING
7498 } else {
7500 }
7501#else
7503#endif
7506 } else {
7508 }
7510}
7511
7514 char *path = NULL;
7515 struct mg_str *hdr, path_info;
7516 uint32_t remote_ip = ntohl(*(uint32_t *) &nc->
sa.
sin.sin_addr);
7517
7519
7522 return;
7523 }
7524
7526 return;
7527 }
7528
7531 }
7534 }
7537 }
7540 }
7543 }
7545 opts.
index_files =
"index.html,index.htm,index.shtml,index.cgi,index.php";
7546 }
7547
7550 return;
7551 }
7554 return;
7555 }
7557
7559 path = NULL;
7560
7561
7564 mg_vcmp(hdr,
"keep-alive") != 0)) {
7565#if 0
7567#endif
7568 }
7569}
7570
7571#endif
7572
7573
7575 const char *schema_tls, int *use_ssl,
7576 char **
addr,
int *port_i,
7577 const char **path) {
7578 int addr_len = 0;
7579
7580 if (memcmp(url, schema, strlen(schema)) == 0) {
7581 url += strlen(schema);
7582 } else if (memcmp(url, schema_tls, strlen(schema_tls)) == 0) {
7583 url += strlen(schema_tls);
7584 *use_ssl = 1;
7585#ifndef MG_ENABLE_SSL
7586 return -1;
7587#endif
7588 }
7589
7590 while (*url != '\0') {
7592 if (*
addr == NULL) {
7594 return -1;
7595 }
7596 if (*url == '/') {
7597 break;
7598 }
7599 if (*url == ':') *port_i = addr_len;
7600 (*addr)[addr_len++] = *url;
7601 (*addr)[addr_len] = '\0';
7602 url++;
7603 }
7604 if (addr_len == 0) goto cleanup;
7605 if (*port_i < 0) {
7606 *port_i = addr_len;
7607 strcpy(*
addr + *port_i, *use_ssl ?
":443" :
":80");
7608 } else {
7609 *port_i = -1;
7610 }
7611
7612 if (*path == NULL) *path = url;
7613
7614 if (**path == '\0') *path = "/";
7615
7617
7618 return 0;
7619
7620cleanup:
7622 return -1;
7623}
7624
7627 struct mg_connect_opts opts,
const char *schema,
const char *schema_ssl,
7628 const char *url,
const char **path,
char **
addr) {
7630 int port_i = -1;
7631 int use_ssl = 0;
7632
7634 path) < 0) {
7635 return NULL;
7636 }
7637
7638#ifndef MG_ENABLE_SSL
7639 if (use_ssl) {
7642 return NULL;
7643 }
7644#endif
7645
7647#ifdef MG_ENABLE_SSL
7648 if (use_ssl && nc->
ssl_ctx == NULL) {
7649
7650
7651
7652
7653
7655 }
7656#endif
7658
7659
7660 if (port_i >= 0) (*addr)[port_i] = '\0';
7661 }
7662
7663 return nc;
7664}
7665
7669 const char *url,
7670 const char *extra_headers,
7671 const char *post_data) {
7673 const char *path = NULL;
7675 mgr, ev_handler, opts,
"http://",
"https://", url, &path, &
addr);
7676
7677 if (nc == NULL) {
7678 return NULL;
7679 }
7680
7681 mg_printf(nc,
"%s %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %" SIZE_T_FMT
7682 "\r\n%s\r\n%s",
7683 post_data == NULL ?
"GET" :
"POST", path,
addr,
7684 post_data == NULL ? 0 : strlen(post_data),
7685 extra_headers == NULL ? "" : extra_headers,
7686 post_data == NULL ? "" : post_data);
7687
7689 return nc;
7690}
7691
7694 const char *url,
7695 const char *extra_headers,
7696 const char *post_data) {
7698 memset(&opts, 0, sizeof(opts));
7700 post_data);
7701}
7702
7706 const char *url, const char *protocol,
7707 const char *extra_headers) {
7709 const char *path = NULL;
7711 mgr, ev_handler, opts,
"ws://",
"wss://", url, &path, &
addr);
7712
7713 if (nc == NULL) {
7714 return NULL;
7715 }
7716
7718
7720 return nc;
7721}
7722
7725 const char *url, const char *protocol,
7726 const char *extra_headers) {
7728 memset(&opts, 0, sizeof(opts));
7730}
7731
7734 size_t file_name_len,
const char **
data,
7735 size_t *data_len) {
7736 static const char cd[] = "Content-Disposition: ";
7737 size_t hl,
bl,
n, ll, pos, cdl =
sizeof(cd) - 1;
7738
7739 if (buf == NULL || buf_len <= 0) return 0;
7741 if (buf[0] != '-' || buf[1] != '-' || buf[2] == '\n') return 0;
7742
7743
7745
7746
7751 header.
p = buf +
n + cdl;
7752 header.len = ll - (cdl + 2);
7755 }
7756 }
7757
7758
7759 for (pos = hl; pos + (
bl - 2) < buf_len; pos++) {
7760 if (buf[pos] ==
'-' && !memcmp(buf, &buf[pos],
bl - 2)) {
7761 if (data_len != NULL) *data_len = (pos - 2) - hl;
7762 if (
data != NULL) *
data = buf + hl;
7763 return pos;
7764 }
7765 }
7766
7767 return 0;
7768}
7769
7775 new_ep->
name = strdup(uri_path);
7780}
7781
7782#endif
7783#ifdef MG_MODULE_LINES
7784#line 1 "./src/util.c"
7785#endif
7786
7787
7788
7789
7790
7791
7792
7793
7794
7795const char *
mg_skip(
const char *s,
const char *
end,
const char *delims,
7798 while (s <
end && strchr(delims, *(
unsigned char *) s) == NULL) s++;
7800 while (s <
end && strchr(delims, *(
unsigned char *) s) != NULL) s++;
7801 return s;
7802}
7803
7805 return tolower(*(const unsigned char *) s);
7806}
7807
7808int mg_ncasecmp(
const char *s1,
const char *s2,
size_t len) {
7809 int diff = 0;
7810
7811 if (len > 0) do {
7813 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
7814
7815 return diff;
7816}
7817
7818int mg_casecmp(
const char *s1,
const char *s2) {
7820}
7821
7823 size_t n2 = strlen(str2), n1 = str1->
len;
7824 int r =
mg_ncasecmp(str1->
p, str2, (n1 < n2) ? n1 : n2);
7825 if (r == 0) {
7826 return n1 - n2;
7827 }
7828 return r;
7829}
7830
7832 size_t n2 = strlen(str2), n1 = str1->
len;
7833 int r = memcmp(str1->
p, str2, (n1 < n2) ? n1 : n2);
7834 if (r == 0) {
7835 return n1 - n2;
7836 }
7837 return r;
7838}
7839
7840#ifndef MG_DISABLE_FILESYSTEM
7841int mg_stat(
const char *path, cs_stat_t *st) {
7842#ifdef _WIN32
7845 DBG((
"[%ls] -> %d", wpath, _wstati64(wpath, st)));
7846 return _wstati64(wpath, (struct _stati64 *) st);
7847#else
7848 return stat(path, st);
7849#endif
7850}
7851
7852FILE *
mg_fopen(
const char *path,
const char *mode) {
7853#ifdef _WIN32
7857 return _wfopen(wpath, wmode);
7858#else
7859 return fopen(path, mode);
7860#endif
7861}
7862
7863int mg_open(
const char *path,
int flag,
int mode) {
7864#ifdef _WIN32
7867 return _wopen(wpath, flag, mode);
7868#else
7869 return open(path, flag, mode);
7870#endif
7871}
7872#endif
7873
7876}
7877
7880}
7881
7882#ifdef MG_ENABLE_THREADS
7884#ifdef _WIN32
7885 return (void *) _beginthread((void(__cdecl *) (void *) ) f, 0, p);
7886#else
7887 pthread_t thread_id = (pthread_t) 0;
7888 pthread_attr_t attr;
7889
7890 (void) pthread_attr_init(&attr);
7891 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
7892
7893#if defined(MG_STACK_SIZE) && MG_STACK_SIZE > 1
7894 (void) pthread_attr_setstacksize(&attr, MG_STACK_SIZE);
7895#endif
7896
7897 pthread_create(&thread_id, &attr, f, p);
7898 pthread_attr_destroy(&attr);
7899
7900 return (void *) thread_id;
7901#endif
7902}
7903#endif
7904
7905
7907#ifdef _WIN32
7908 (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
7909#elif defined(__unix__)
7910 fcntl(sock, F_SETFD, FD_CLOEXEC);
7911#else
7912 (void) sock;
7913#endif
7914}
7915
7917 int flags) {
7918 int is_v6;
7919 if (buf == NULL || len <= 0) return;
7920 buf[0] = '\0';
7921#if defined(MG_ENABLE_IPV6)
7922 is_v6 = sa->
sa.sa_family == AF_INET6;
7923#else
7924 is_v6 = 0;
7925#endif
7927#if defined(MG_ENABLE_IPV6)
7928 const void *
addr = NULL;
7929 char *start = buf;
7930 socklen_t capacity = len;
7931 if (!is_v6) {
7933 } else {
7934 addr = (
void *) &sa->
sin6.sin6_addr;
7936 *buf = '[';
7937 start++;
7938 capacity--;
7939 }
7940 }
7942 *buf = '\0';
7943 }
7944#elif defined(_WIN32) || defined(MG_LWIP)
7945
7947#else
7948 inet_ntop(AF_INET, (
void *) &sa->
sin.sin_addr, buf, len);
7949#endif
7950 }
7952 int port = ntohs(sa->
sin.sin_port);
7954 snprintf(buf + strlen(buf), len - (strlen(buf) + 1), "%s:%d",
7955 (is_v6 ? "]" : ""), port);
7956 } else {
7957 snprintf(buf, len, "%d", port);
7958 }
7959 }
7960}
7961
7963 int flags) {
7965 memset(&
sa, 0,
sizeof(
sa));
7968}
7969
7970#ifndef MG_DISABLE_HEXDUMP
7971int mg_hexdump(
const void *buf,
int len,
char *dst,
int dst_len) {
7972 const unsigned char *p = (const unsigned char *) buf;
7973 char ascii[17] = "";
7975
7976 for (
i = 0;
i < len;
i++) {
7978 if (idx == 0) {
7979 if (
i > 0)
n += snprintf(dst +
n, dst_len -
n,
" %s\n", ascii);
7980 n += snprintf(dst +
n, dst_len -
n,
"%04x ",
i);
7981 }
7982 n += snprintf(dst +
n, dst_len -
n,
" %02x", p[
i]);
7983 ascii[idx] = p[
i] < 0x20 || p[
i] > 0x7e ?
'.' : p[
i];
7984 ascii[idx + 1] = '\0';
7985 }
7986
7987 while (
i++ % 16)
n += snprintf(dst +
n, dst_len -
n,
"%s",
" ");
7988 n += snprintf(dst +
n, dst_len -
n,
" %s\n\n", ascii);
7989
7991}
7992#endif
7993
7994int mg_avprintf(
char **buf,
size_t size,
const char *fmt, va_list ap) {
7995 va_list ap_copy;
7996 int len;
7997
7998 va_copy(ap_copy, ap);
7999 len = vsnprintf(*buf, size, fmt, ap_copy);
8000 va_end(ap_copy);
8001
8002 if (len < 0) {
8003
8004
8005
8006 *buf = NULL;
8007 while (len < 0) {
8009 size *= 2;
8010 if ((*buf = (
char *)
MG_MALLOC(size)) == NULL)
break;
8011 va_copy(ap_copy, ap);
8012 len = vsnprintf(*buf, size, fmt, ap_copy);
8013 va_end(ap_copy);
8014 }
8015
8016 } else if (len >= (int) size) {
8017
8018 if ((*buf = (
char *)
MG_MALLOC(len + 1)) == NULL) {
8019 len = -1;
8020 } else {
8021 va_copy(ap_copy, ap);
8022 len = vsnprintf(*buf, len + 1, fmt, ap_copy);
8023 va_end(ap_copy);
8024 }
8025 }
8026
8027 return len;
8028}
8029
8030#if !defined(MG_DISABLE_HEXDUMP)
8032 const void *buf, int num_bytes, int ev) {
8033#if !defined(NO_LIBC) && !defined(MG_DISABLE_STDIO)
8035 char *hexbuf, src[60], dst[60];
8036 int buf_size = num_bytes * 5 + 100;
8037
8038 if (strcmp(path, "-") == 0) {
8040 } else if (strcmp(path, "--") == 0) {
8042#ifndef MG_DISABLE_FILESYSTEM
8043 } else {
8044 fp = fopen(path,
"a");
8045#endif
8046 }
8047 if (
fp == NULL)
return;
8048
8054 fprintf(
8055 fp,
"%lu %p %s %s %s %d\n", (
unsigned long) time(NULL), (
void *) nc, src,
8057 ? "->"
8059 ? "<A"
8061 dst, num_bytes);
8062 if (num_bytes > 0 && (hexbuf = (
char *)
MG_MALLOC(buf_size)) != NULL) {
8063 mg_hexdump(buf, num_bytes, hexbuf, buf_size);
8064 fprintf(
fp,
"%s", hexbuf);
8066 }
8067 if (
fp != stdin &&
fp != stdout) fclose(
fp);
8068#endif
8069}
8070#endif
8071
8073 static const int n = 1;
8074
8075 return ((
char *) &
n)[0] == 0;
8076}
8077
8080 if (
list == NULL || *
list ==
'\0') {
8081
8083 } else {
8085 if ((
list = strchr(val->
p,
',')) != NULL) {
8086
8089 } else {
8090
8091 list = val->
p + strlen(val->
p);
8093 }
8094
8095 if (eq_val != NULL) {
8096
8097
8099 eq_val->
p = (
const char *) memchr(val->
p,
'=', val->
len);
8100 if (eq_val->
p != NULL) {
8102 eq_val->
len = val->
p + val->
len - eq_val->
p;
8103 val->
len = (eq_val->
p - val->
p) - 1;
8104 }
8105 }
8106 }
8107
8109}
8110
8112 const char *or_str;
8113 size_t len,
i = 0,
j = 0;
8114 int res;
8115
8116 if ((or_str = (
const char *) memchr(pattern.
p,
'|', pattern.
len)) != NULL) {
8117 struct mg_str pstr = {pattern.
p, (size_t)(or_str - pattern.
p)};
8119 if (res > 0) return res;
8120 pstr.
p = or_str + 1;
8121 pstr.
len = (pattern.
p + pattern.
len) - (or_str + 1);
8123 }
8124
8125 for (;
i < pattern.
len;
i++,
j++) {
8126 if (pattern.
p[
i] ==
'?' &&
j !=
str.len) {
8127 continue;
8128 }
else if (pattern.
p[
i] ==
'$') {
8129 return j ==
str.len ? (int)
j : -1;
8130 }
else if (pattern.
p[
i] ==
'*') {
8132 if (pattern.
p[
i] ==
'*') {
8135 } else {
8139 }
8140 }
8141 if (
i == pattern.
len) {
8143 }
8144 do {
8145 const struct mg_str pstr = {pattern.
p +
i, pattern.
len -
i};
8148 }
while (res == -1 &&
len-- > 0);
8149 return res == -1 ? -1 : (int) (
j + res +
len);
8151 return -1;
8152 }
8153 }
8155}
8156
8158 const struct mg_str pstr = {pattern, (size_t) pattern_len};
8160}
8161
8163 struct mg_str ret = {s, 0};
8164 if (s != NULL) ret.
len = strlen(s);
8165 return ret;
8166}
8167#ifdef MG_MODULE_LINES
8168#line 1 "./src/json-rpc.c"
8169#endif
8170
8171
8172
8173#ifndef MG_DISABLE_JSON_RPC
8174
8175
8176
8177
8178
8180 const char *result_fmt, ...) {
8182 const struct json_token *
id = req->
id == NULL ? &null_tok : req->
id;
8183 va_list ap;
8185
8189 } else {
8191 }
8193
8194 va_start(ap, result_fmt);
8196 va_end(ap);
8197
8199
8201}
8202
8204 const char *id, const char *params_fmt, ...) {
8205 va_list ap;
8207
8208 n +=
json_emit(buf +
n,
len -
n,
"{s:s,s:s,s:s,s:",
"jsonrpc",
"2.0",
"id",
8209 id, "method", method, "params");
8210 va_start(ap, params_fmt);
8212 va_end(ap);
8213
8215
8217}
8218
8220 int code,
const char *
message,
const char *fmt, ...) {
8221 va_list ap;
8223
8224 n +=
json_emit(buf +
n,
len -
n,
"{s:s,s:V,s:{s:i,s:s,s:",
"jsonrpc",
"2.0",
8225 "id", req->
id == NULL ?
"null" : req->id->
ptr,
8226 req->id == NULL ? 4 : req->id->
len,
"error",
"code",
8227 (long) code,
"message",
message,
"data");
8228 va_start(ap, fmt);
8230 va_end(ap);
8231
8233
8235}
8236
8238 int code) {
8240
8241 switch (code) {
8244 break;
8247 break;
8250 break;
8252 message =
"invalid parameters";
8253 break;
8256 break;
8257 default:
8258 message =
"unspecified error";
8259 break;
8260 }
8261
8263}
8264
8270
8271 memset(&req, 0, sizeof(req));
8272 n =
parse_json(buf, len, tokens,
sizeof(tokens) /
sizeof(tokens[0]));
8277 }
8278
8283
8284 if (req.
id == NULL || req.
method == NULL) {
8287 }
8288
8289 for (
i = 0; methods[
i] != NULL;
i++) {
8290 int mlen = strlen(methods[
i]);
8292 memcmp(methods[
i], req.
method->
ptr, mlen) == 0)
8293 break;
8294 }
8295
8296 if (methods[
i] == NULL) {
8299 }
8300
8301 return handlers[
i](dst, dst_len, &req);
8302}
8303
8308
8309 memset(rep, 0, sizeof(*rep));
8310 memset(er, 0, sizeof(*er));
8311
8316 } else {
8322 }
8323 }
8325}
8326
8327#endif
8328#ifdef MG_MODULE_LINES
8329#line 1 "./src/mqtt.c"
8330#endif
8331
8332
8333
8334
8335
8336#ifndef MG_DISABLE_MQTT
8337
8338
8339
8340
8342 uint8_t header;
8343 int cmd;
8344 size_t len = 0;
8345 int var_len = 0;
8346 char *vlen = &io->
buf[1];
8347
8348 if (io->
len < 2)
return -1;
8349
8350 header = io->
buf[0];
8351 cmd = header >> 4;
8352
8353
8354 do {
8355 len += (*vlen & 127) << 7 * (vlen - &io->
buf[1]);
8356 }
while ((*vlen++ & 128) != 0 && ((size_t)(vlen - io->
buf) <= io->
len));
8357
8358 if (len != 0 && io->
len < (
size_t)(len - 1))
return -1;
8359
8363
8364 switch (cmd) {
8366
8367 break;
8370 var_len = 2;
8371 break;
8378 var_len = 2;
8379 break;
8381 uint16_t topic_len = ntohs(*(uint16_t *) io->
buf);
8383 mm->
topic[topic_len] = 0;
8384 strncpy(mm->
topic, io->
buf + 2, topic_len);
8385 var_len = topic_len + 2;
8386
8389 var_len += 2;
8390 }
8391 } break;
8393
8394
8395
8396
8398 var_len = 2;
8399 break;
8400 default:
8401
8402 break;
8403 }
8404
8406 return len - var_len;
8407}
8408
8410 int len;
8413 memset(&mm, 0, sizeof(mm));
8414
8416
8417 switch (ev) {
8420 if (
len == -1)
break;
8423
8425
8428 }
8430 break;
8431 }
8432}
8433
8436}
8437
8441}
8442
8446 uint8_t rem_len;
8448 uint16_t client_id_len;
8449
8450
8451
8452
8453
8454
8455 rem_len = 9 + 1 + 2 + 2 + strlen(client_id);
8456
8459 mg_send(nc,
"\00\06MQIsdp\03", 9);
8461
8464 }
8467
8468 client_id_len = htons(strlen(client_id));
8469 mg_send(nc, &client_id_len, 2);
8470 mg_send(nc, client_id, strlen(client_id));
8471}
8472
8474 uint8_t
flags,
size_t len) {
8476 uint8_t header = cmd << 4 | (uint8_t)
flags;
8477
8478 uint8_t buf[1 + sizeof(size_t)];
8479 uint8_t *vlen = &buf[1];
8480
8482
8483 buf[0] = header;
8484
8485
8486 do {
8487 *vlen = len % 0x80;
8488 len /= 0x80;
8489 if (len > 0) *vlen |= 0x80;
8490 vlen++;
8491 } while (len > 0);
8492
8494}
8495
8497 uint16_t message_id,
int flags,
const void *
data,
8498 size_t len) {
8500
8501 uint16_t topic_len = htons(strlen(topic));
8502 uint16_t message_id_net = htons(message_id);
8503
8505 mg_send(nc, topic, strlen(topic));
8507 mg_send(nc, &message_id_net, 2);
8508 }
8510
8513}
8514
8517 size_t topics_len, uint16_t message_id) {
8519
8520 uint16_t message_id_n = htons(message_id);
8522
8523 mg_send(nc, (
char *) &message_id_n, 2);
8524 for (
i = 0;
i < topics_len;
i++) {
8525 uint16_t topic_len_n = htons(strlen(topics[
i].topic));
8527 mg_send(nc, topics[
i].topic, strlen(topics[
i].topic));
8529 }
8530
8533}
8534
8536 struct mg_str *topic, uint8_t *qos,
int pos) {
8537 unsigned char *buf = (
unsigned char *) msg->
payload.
p + pos;
8538 if ((size_t) pos >= msg->payload.len) {
8539 return -1;
8540 }
8541
8542 topic->len = buf[0] << 8 | buf[1];
8543 topic->p = (char *) buf + 2;
8544 *qos = buf[2 + topic->len];
8545 return pos + 2 + topic->len + 1;
8546}
8547
8549 size_t topics_len, uint16_t message_id) {
8551
8552 uint16_t message_id_n = htons(message_id);
8554
8555 mg_send(nc, (
char *) &message_id_n, 2);
8556 for (
i = 0;
i < topics_len;
i++) {
8557 uint16_t topic_len_n = htons(strlen(topics[
i]));
8559 mg_send(nc, topics[
i], strlen(topics[
i]));
8560 }
8561
8564}
8565
8567 uint8_t unused = 0;
8571}
8572
8573
8574
8575
8576
8577
8579 uint16_t message_id) {
8580 uint16_t message_id_net = htons(message_id);
8581 mg_send(nc, &message_id_net, 2);
8583}
8584
8587}
8588
8591}
8592
8595}
8596
8599}
8600
8602 uint16_t message_id) {
8604 uint16_t message_id_net = htons(message_id);
8605 mg_send(nc, &message_id_net, 2);
8606 for (
i = 0;
i < qoss_len;
i++) {
8608 }
8610}
8611
8614}
8615
8618}
8619
8622}
8623
8626}
8627
8628#endif
8629#ifdef MG_MODULE_LINES
8630#line 1 "./src/mqtt-broker.c"
8631#endif
8632
8633
8634
8635
8636
8637
8638
8639
8640#ifdef MG_ENABLE_MQTT_BROKER
8641
8642static void mg_mqtt_session_init(struct mg_mqtt_broker *brk,
8643 struct mg_mqtt_session *s,
8645 s->brk = brk;
8646 s->subscriptions = NULL;
8647 s->num_subscriptions = 0;
8648 s->nc = nc;
8649}
8650
8651static void mg_mqtt_add_session(struct mg_mqtt_session *s) {
8652 s->
next = s->brk->sessions;
8653 s->brk->sessions = s;
8655 if (s->next != NULL) s->
next->
prev = s;
8656}
8657
8658static void mg_mqtt_remove_session(struct mg_mqtt_session *s) {
8659 if (s->prev == NULL) s->brk->sessions = s->
next;
8662}
8663
8664static void mg_mqtt_destroy_session(struct mg_mqtt_session *s) {
8666 for (
i = 0;
i < s->num_subscriptions;
i++) {
8667 MG_FREE((
void *) s->subscriptions[
i].topic);
8668 }
8671}
8672
8673static void mg_mqtt_close_session(struct mg_mqtt_session *s) {
8674 mg_mqtt_remove_session(s);
8675 mg_mqtt_destroy_session(s);
8676}
8677
8678void mg_mqtt_broker_init(struct mg_mqtt_broker *brk, void *user_data) {
8679 brk->sessions = NULL;
8680 brk->user_data = user_data;
8681}
8682
8683static void mg_mqtt_broker_handle_connect(struct mg_mqtt_broker *brk,
8685 struct mg_mqtt_session *s = (struct mg_mqtt_session *) malloc(sizeof *s);
8686 if (s == NULL) {
8687
8689 return;
8690
8691 }
8692
8693
8694
8695 mg_mqtt_session_init(brk, s, nc);
8698 mg_mqtt_add_session(s);
8699
8701}
8702
8703static void mg_mqtt_broker_handle_subscribe(
struct mg_connection *nc,
8705 struct mg_mqtt_session *ss = (
struct mg_mqtt_session *) nc->
user_data;
8706 uint8_t qoss[512];
8707 size_t qoss_len = 0;
8709 uint8_t qos;
8710 int pos;
8712
8713 for (pos = 0;
8715 qoss[qoss_len++] =
qos;
8716 }
8717
8719 ss->subscriptions, sizeof(*ss->subscriptions) * qoss_len);
8720 for (pos = 0;
8722 ss->num_subscriptions++) {
8723 te = &ss->subscriptions[ss->num_subscriptions];
8727 }
8728
8730}
8731
8732
8733
8734
8735
8736
8737
8738
8740
8741 int len = strlen(exp);
8742 if (strchr(exp, '#')) {
8743 len -= 2;
8744 }
8745 return strncmp(exp,
topic, len) == 0;
8746}
8747
8748static void mg_mqtt_broker_handle_publish(struct mg_mqtt_broker *brk,
8750 struct mg_mqtt_session *s;
8752
8753 for (s = mg_mqtt_next(brk, NULL); s != NULL; s = mg_mqtt_next(brk, s)) {
8754 for (
i = 0;
i < s->num_subscriptions;
i++) {
8759 break;
8760 }
8761 }
8762 }
8763}
8764
8767 struct mg_mqtt_broker *brk;
8768
8771 } else {
8772 brk = (
struct mg_mqtt_broker *) nc->
user_data;
8773 }
8774
8775 switch (ev) {
8778 break;
8780 mg_mqtt_broker_handle_connect(brk, nc);
8781 break;
8783 mg_mqtt_broker_handle_subscribe(nc, msg);
8784 break;
8786 mg_mqtt_broker_handle_publish(brk, msg);
8787 break;
8790 mg_mqtt_close_session((
struct mg_mqtt_session *) nc->
user_data);
8791 }
8792 break;
8793 }
8794}
8795
8796struct mg_mqtt_session *mg_mqtt_next(struct mg_mqtt_broker *brk,
8797 struct mg_mqtt_session *s) {
8798 return s == NULL ? brk->sessions : s->next;
8799}
8800
8801#endif
8802#ifdef MG_MODULE_LINES
8803#line 1 "./src/dns.c"
8804#endif
8805
8806
8807
8808
8809
8810#ifndef MG_DISABLE_DNS
8811
8812
8813
8814
8816
8824};
8825
8830
8831 for (rr = (prev == NULL ? msg->
answers : prev + 1);
8833 if (rr->
rtype == query) {
8834 return rr;
8835 }
8836 }
8837 return NULL;
8838}
8839
8842 size_t data_len) {
8843 switch (rr->
rtype) {
8845 if (data_len < sizeof(struct in_addr)) {
8846 return -1;
8847 }
8849 return -1;
8850 }
8852 return 0;
8853#ifdef MG_ENABLE_IPV6
8855 if (data_len < sizeof(struct in6_addr)) {
8856 return -1;
8857 }
8859 return 0;
8860#endif
8863 return 0;
8864 }
8865
8866 return -1;
8867}
8868
8872
8873 memset(&header, 0, sizeof(header));
8875 header.flags = htons(msg->
flags);
8878
8879 return mbuf_insert(io, pos, &header,
sizeof(header));
8880}
8881
8885}
8886
8888 const char *s;
8890 size_t pos = io->
len;
8891
8892 do {
8893 if ((s = strchr(
name,
'.')) == NULL) {
8895 }
8896
8897 if (s -
name > 127) {
8898 return -1;
8899 }
8903
8904 if (*s == '.') {
8906 }
8907
8910 } while (*s != '\0');
8912
8913 return io->
len - pos;
8914}
8915
8917 const char *
name,
size_t nlen,
const void *rdata,
8918 size_t rlen) {
8919 size_t pos = io->
len;
8920 uint16_t u16;
8921 uint32_t u32;
8922
8924 return -1;
8925 }
8926
8928 return -1;
8929 }
8930
8931 u16 = htons(rr->
rtype);
8935
8937 u32 = htonl(rr->
ttl);
8939
8941 int clen;
8942
8943 size_t off = io->
len;
8946 return -1;
8947 }
8948 u16 = clen;
8949 io->
buf[off] = u16 >> 8;
8950 io->
buf[off + 1] = u16 & 0xff;
8951 } else {
8952 u16 = htons(rlen);
8955 }
8956 }
8957
8958 return io->
len - pos;
8959}
8960
8962 int query_type) {
8967
8968 DBG((
"%s %d",
name, query_type));
8969
8971
8975
8977
8978 rr->
rtype = query_type;
8981
8983
8984 goto cleanup;
8985 }
8986
8987
8989 uint16_t len = htons(pkt.len);
8991 }
8992
8993 mg_send(nc, pkt.buf, pkt.len);
8995
8996cleanup:
8998}
8999
9002 int reply) {
9004 int chunk_len, data_len;
9005
9007 if (((
unsigned char *)
data)[0] & 0xc0) {
9009 break;
9010 }
9011 data += chunk_len + 1;
9012 }
9013
9015 return NULL;
9016 }
9017
9021
9024
9027
9029 if (reply) {
9031 return NULL;
9032 }
9033
9034 rr->
ttl = (uint32_t)
data[0] << 24 | (uint32_t)
data[1] << 16 |
9037
9038 data_len = *
data << 8 | *(
data + 1);
9040
9044 }
9046}
9047
9050 unsigned char *
data = (
unsigned char *) buf +
sizeof(*header);
9051 unsigned char *
end = (
unsigned char *) buf + len;
9053
9054 memset(msg, 0, sizeof(*msg));
9057
9058 if (len < (int) sizeof(*header)) return -1;
9059
9065 }
9069 }
9070
9073 if (
data == NULL)
return -1;
9074 }
9075
9078 if (
data == NULL)
return -1;
9079 }
9080
9081 return 0;
9082}
9083
9085 char *dst, int dst_len) {
9086 int chunk_len;
9087 char *old_dst = dst;
9088 const unsigned char *
data = (
unsigned char *)
name->p;
9089 const unsigned char *
end = (
unsigned char *) msg->
pkt.
p + msg->
pkt.
len;
9090
9092 return 0;
9093 }
9094
9095 while ((chunk_len = *
data++)) {
9096 int leeway = dst_len - (dst - old_dst);
9098 return 0;
9099 }
9100
9101 if (chunk_len & 0xc0) {
9102 uint16_t off = (
data[-1] & (~0xc0)) << 8 |
data[0];
9103 if (off >= msg->
pkt.
len) {
9104 return 0;
9105 }
9106 data = (
unsigned char *) msg->
pkt.
p + off;
9107 continue;
9108 }
9109 if (chunk_len > leeway) {
9110 chunk_len = leeway;
9111 }
9112
9113 if (
data + chunk_len >=
end) {
9114 return 0;
9115 }
9116
9117 memcpy(dst,
data, chunk_len);
9119 dst += chunk_len;
9120 leeway -= chunk_len;
9121 if (leeway == 0) {
9122 return dst - old_dst;
9123 }
9124 *dst++ = '.';
9125 }
9126
9127 if (dst != old_dst) {
9128 *--dst = 0;
9129 }
9130 return dst - old_dst;
9131}
9132
9136
9137
9139
9140 switch (ev) {
9144 }
9146
9147 memset(&msg, 0, sizeof(msg));
9151 uint16_t len = htons(io->
len);
9153 }
9155 } else {
9156
9158 }
9160 break;
9161 }
9162}
9163
9166}
9167
9168#endif
9169#ifdef MG_MODULE_LINES
9170#line 1 "./src/dns-server.c"
9171#endif
9172
9173
9174
9175
9176
9177#ifdef MG_ENABLE_DNS_SERVER
9178
9179
9180
9181
9182struct mg_dns_reply mg_dns_create_reply(struct
mbuf *io,
9184 struct mg_dns_reply rep;
9185 rep.msg = msg;
9186 rep.io = io;
9187 rep.start = io->len;
9188
9189
9190 msg->
flags |= 0x8080;
9192
9194 return rep;
9195}
9196
9197void mg_dns_send_reply(
struct mg_connection *nc,
struct mg_dns_reply *r) {
9198 size_t sent = r->io->len - r->start;
9201 uint16_t len = htons(sent);
9203 }
9204
9206 mg_send(nc, r->io->buf + r->start, r->io->len - r->start);
9207 r->io->len = r->start;
9208 }
9209}
9210
9211int mg_dns_reply_record(struct mg_dns_reply *reply,
9213 const char *
name,
int rtype,
int ttl,
const void *rdata,
9214 size_t rdata_len) {
9216 char rname[512];
9219 return -1;
9220 }
9221
9224 rname[511] = 0;
9226 }
9227
9228 *ans = *question;
9232
9234 rdata_len) == -1) {
9235 return -1;
9236 };
9237
9239 return 0;
9240}
9241
9242#endif
9243#ifdef MG_MODULE_LINES
9244#line 1 "./src/resolv.c"
9245#endif
9246
9247
9248
9249
9250
9251#ifndef MG_DISABLE_RESOLVER
9252
9253
9254
9255
9256#ifndef MG_DEFAULT_NAMESERVER
9257#define MG_DEFAULT_NAMESERVER "8.8.8.8"
9258#endif
9259
9261
9263
9272
9273
9276};
9277
9278
9279
9280
9281
9282
9284 int ret = -1;
9285
9286#ifdef _WIN32
9290 char subkey[512],
value[128],
9291 *
key =
"SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces";
9292
9293 if ((err = RegOpenKeyA(HKEY_LOCAL_MACHINE,
key, &
hKey)) != ERROR_SUCCESS) {
9294 fprintf(stderr,
"cannot open reg key %s: %d\n",
key, err);
9295 ret = -1;
9296 } else {
9297 for (ret = -1,
i = 0;
9298 RegEnumKeyA(
hKey,
i, subkey,
sizeof(subkey)) == ERROR_SUCCESS;
i++) {
9300 if (RegOpenKeyA(
hKey, subkey, &hSub) == ERROR_SUCCESS &&
9301 (RegQueryValueExA(hSub,
"NameServer", 0, &
type, (
void *)
value,
9302 &len) == ERROR_SUCCESS ||
9303 RegQueryValueExA(hSub,
"DhcpNameServer", 0, &
type, (
void *)
value,
9304 &len) == ERROR_SUCCESS)) {
9305
9306
9307
9308
9309
9310
9311
9313 if (
value[0] ==
'\0') {
9314 continue;
9315 }
9316 if (
comma != NULL) {
9318 }
9319 snprintf(
name, name_len,
"udp://%s:53",
value);
9320 ret = 0;
9321 RegCloseKey(hSub);
9322 break;
9323 }
9324 }
9326 }
9327#elif !defined(MG_DISABLE_FILESYSTEM)
9329 char line[512];
9330
9331 if ((
fp = fopen(
"/etc/resolv.conf",
"r")) == NULL) {
9332 ret = -1;
9333 } else {
9334
9335 for (ret = -1; fgets(line,
sizeof(line),
fp) != NULL;) {
9336 char buf[256];
9337 if (sscanf(line, "nameserver %255[^\n\t #]s", buf) == 1) {
9338 snprintf(
name, name_len,
"udp://%s:53", buf);
9339 ret = 0;
9340 break;
9341 }
9342 }
9344 }
9345#else
9347#endif
9348
9349 return ret;
9350}
9351
9353#ifndef MG_DISABLE_FILESYSTEM
9354
9356 char line[1024];
9357 char *p;
9358 char alias[256];
9359 unsigned int a, b,
c,
d;
9360 int len = 0;
9361
9362 if ((
fp = fopen(
"/etc/hosts",
"r")) == NULL) {
9363 return -1;
9364 }
9365
9366 for (; fgets(line,
sizeof(line),
fp) != NULL;) {
9367 if (line[0] == '#') continue;
9368
9369 if (sscanf(line,
"%u.%u.%u.%u%n", &a, &b, &
c, &
d, &len) == 0) {
9370
9371 continue;
9372 }
9373 for (p = line + len; sscanf(p, "%s%n", alias, &len) == 1; p += len) {
9374 if (strcmp(alias,
name) == 0) {
9375 usa->
sin.sin_addr.s_addr = htonl(a << 24 | b << 16 |
c << 8 |
d);
9377 return 0;
9378 }
9379 }
9380 }
9381
9383#endif
9384
9385 return -1;
9386}
9387
9389 time_t now = time(NULL);
9392
9394
9396
9397 switch (ev) {
9403 break;
9404 }
9409 }
9410 break;
9418 } else {
9420 }
9423 break;
9425
9426
9427
9428
9429 nc->
flags &= ~MG_F_CLOSE_IMMEDIATELY;
9431 break;
9435 break;
9437
9438 if (req != NULL) {
9442 }
9443 break;
9444 }
9445}
9446
9450 memset(&opts, 0, sizeof(opts));
9452}
9453
9460
9462
9463
9465 if (req == NULL) {
9466 return -1;
9467 }
9468
9469 memset(req->
name, 0,
sizeof(req->
name));
9474
9477
9478
9481 -1) {
9483 }
9484
9485 if (nameserver == NULL) {
9487 }
9488
9490 if (dns_nc == NULL) {
9491 free(req);
9492 return -1;
9493 }
9497 }
9498
9499 return 0;
9500}
9501
9502#endif
9503#ifdef MG_MODULE_LINES
9504#line 1 "./src/coap.c"
9505#endif
9506
9507
9508
9509
9510
9511
9512
9513
9514
9515
9516
9517
9518
9519
9520
9521
9522
9523
9524
9525
9526#ifdef MG_ENABLE_COAP
9527
9528void mg_coap_free_options(struct mg_coap_message *cm) {
9529 while (cm->options != NULL) {
9530 struct mg_coap_option *next = cm->options->
next;
9532 cm->options = next;
9533 }
9534}
9535
9536struct mg_coap_option *mg_coap_add_option(struct mg_coap_message *cm,
9537 uint32_t number,
char *
value,
9538 size_t len) {
9539 struct mg_coap_option *new_option =
9540 (
struct mg_coap_option *)
MG_CALLOC(1,
sizeof(*new_option));
9541
9542 new_option->number = number;
9543 new_option->value.p =
value;
9544 new_option->value.len = len;
9545
9546 if (cm->options == NULL) {
9547 cm->options = cm->optiomg_tail = new_option;
9548 } else {
9549
9550
9551
9552
9553
9554 if (cm->optiomg_tail->number <= new_option->number) {
9555
9556 cm->optiomg_tail = cm->optiomg_tail->next = new_option;
9557 } else {
9558
9559 struct mg_coap_option *current_opt = cm->options;
9560 struct mg_coap_option *prev_opt = 0;
9561
9562 while (current_opt != NULL) {
9563 if (current_opt->number > new_option->number) {
9564 break;
9565 }
9566 prev_opt = current_opt;
9567 current_opt = current_opt->next;
9568 }
9569
9570 if (prev_opt != NULL) {
9571 prev_opt->next = new_option;
9572 new_option->next = current_opt;
9573 } else {
9574
9575 new_option->next = cm->options;
9576 cm->options = new_option;
9577 }
9578 }
9579 }
9580
9581 return new_option;
9582}
9583
9584
9585
9586
9587
9588
9589static char *coap_parse_header(
char *ptr,
struct mbuf *io,
9590 struct mg_coap_message *cm) {
9591 if (io->
len <
sizeof(uint32_t)) {
9592 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9593 return NULL;
9594 }
9595
9596
9597
9598
9599
9600
9601
9602 if (((uint8_t) *ptr >> 6) != 1) {
9603 cm->flags |= MG_COAP_IGNORE;
9604 return NULL;
9605 }
9606
9607
9608
9609
9610
9611
9612 cm->msg_type = ((uint8_t) *ptr & 0x30) >> 4;
9613 cm->flags |= MG_COAP_MSG_TYPE_FIELD;
9614
9615
9616
9617
9618
9619
9620
9621 cm->token.len = *ptr & 0x0F;
9622 if (cm->token.len > 8) {
9623 cm->flags |= MG_COAP_FORMAT_ERROR;
9624 return NULL;
9625 }
9626
9627 ptr++;
9628
9629
9630
9631
9632
9633 cm->code_class = (uint8_t) *ptr >> 5;
9634 cm->code_detail = *ptr & 0x1F;
9635 cm->flags |= (MG_COAP_CODE_CLASS_FIELD | MG_COAP_CODE_DETAIL_FIELD);
9636
9637 ptr++;
9638
9639
9640 cm->msg_id = (uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1);
9641 cm->flags |= MG_COAP_MSG_ID_FIELD;
9642
9643 ptr += 2;
9644
9645 return ptr;
9646}
9647
9648
9649
9650
9651
9652
9653static char *coap_get_token(
char *ptr,
struct mbuf *io,
9654 struct mg_coap_message *cm) {
9655 if (cm->token.len != 0) {
9656 if (ptr + cm->token.len > io->
buf + io->
len) {
9657 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9658 return NULL;
9659 } else {
9660 cm->token.p = ptr;
9661 ptr += cm->token.len;
9662 cm->flags |= MG_COAP_TOKEN_FIELD;
9663 }
9664 }
9665
9666 return ptr;
9667}
9668
9669
9670
9671
9672
9673
9674static int coap_get_ext_opt(
char *ptr,
struct mbuf *io, uint16_t *opt_info) {
9675 int ret = 0;
9676
9677 if (*opt_info == 13) {
9678
9679
9680
9681
9682 if (ptr < io->buf + io->
len) {
9683 *opt_info = (uint8_t) *ptr + 13;
9684 ret = sizeof(uint8_t);
9685 } else {
9686 ret = -1;
9687 }
9688 } else if (*opt_info == 14) {
9689
9690
9691
9692
9693 if (ptr +
sizeof(uint8_t) < io->
buf + io->
len) {
9694 *opt_info = ((uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1)) + 269;
9695 ret = sizeof(uint16_t);
9696 } else {
9697 ret = -1;
9698 }
9699 }
9700
9701 return ret;
9702}
9703
9704
9705
9706
9707
9708
9709
9710
9711
9712
9713
9714
9715
9716
9717
9718
9719
9720static char *coap_get_options(
char *ptr,
struct mbuf *io,
9721 struct mg_coap_message *cm) {
9722 uint16_t prev_opt = 0;
9723
9724 if (ptr == io->
buf + io->
len) {
9725
9726 return NULL;
9727 }
9728
9729
9730 while (ptr < io->buf + io->
len && (uint8_t) *ptr != 0xFF) {
9731 uint16_t option_delta, option_lenght;
9732 int optinfo_len;
9733
9734
9735 option_delta = ((uint8_t) *ptr & 0xF0) >> 4;
9736
9737 option_lenght = *ptr & 0x0F;
9738
9739 if (option_delta == 15 || option_lenght == 15) {
9740
9741
9742
9743
9744 cm->flags |= MG_COAP_FORMAT_ERROR;
9745 break;
9746 }
9747
9748 ptr++;
9749
9750
9751 optinfo_len = coap_get_ext_opt(ptr, io, &option_delta);
9752 if (optinfo_len == -1) {
9753 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9754 break;
9755 }
9756
9757 ptr += optinfo_len;
9758
9759
9760 optinfo_len = coap_get_ext_opt(ptr, io, &option_lenght);
9761 if (optinfo_len == -1) {
9762 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9763 break;
9764 }
9765
9766 ptr += optinfo_len;
9767
9768
9769
9770
9771
9772
9773 option_delta += prev_opt;
9774
9775 mg_coap_add_option(cm, option_delta, ptr, option_lenght);
9776
9777 prev_opt = option_delta;
9778
9779 if (ptr + option_lenght > io->
buf + io->
len) {
9780 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9781 break;
9782 }
9783
9784 ptr += option_lenght;
9785 }
9786
9787 if ((cm->flags & MG_COAP_ERROR) != 0) {
9788 mg_coap_free_options(cm);
9789 return NULL;
9790 }
9791
9792 cm->flags |= MG_COAP_OPTIOMG_FIELD;
9793
9794 if (ptr == io->
buf + io->
len) {
9795
9796 return NULL;
9797 }
9798
9799 ptr++;
9800
9801 return ptr;
9802}
9803
9804uint32_t mg_coap_parse(
struct mbuf *io,
struct mg_coap_message *cm) {
9805 char *ptr;
9806
9807 memset(cm, 0, sizeof(*cm));
9808
9809 if ((ptr = coap_parse_header(io->
buf, io, cm)) == NULL) {
9810 return cm->flags;
9811 }
9812
9813 if ((ptr = coap_get_token(ptr, io, cm)) == NULL) {
9814 return cm->flags;
9815 }
9816
9817 if ((ptr = coap_get_options(ptr, io, cm)) == NULL) {
9818 return cm->flags;
9819 }
9820
9821
9822 cm->payload.len = io->
len - (ptr - io->
buf);
9823 if (cm->payload.len != 0) {
9824 cm->payload.p = ptr;
9825 cm->flags |= MG_COAP_PAYLOAD_FIELD;
9826 }
9827
9828 return cm->flags;
9829}
9830
9831
9832
9833
9834
9835
9836static size_t coap_get_ext_opt_size(uint32_t
value) {
9837 int ret = 0;
9838
9840 ret = sizeof(uint8_t);
9841 }
else if (
value > 0xFF + 13 &&
value <= 0xFFFF + 269) {
9842 ret = sizeof(uint16_t);
9843 }
9844
9845 return ret;
9846}
9847
9848
9849
9850
9851
9852
9853static int coap_split_opt(uint32_t
value, uint8_t *
base, uint16_t *ext) {
9854 int ret = 0;
9855
9858 }
else if (
value >= 13 &&
value <= 0xFF + 13) {
9861 ret = sizeof(uint8_t);
9862 }
else if (
value > 0xFF + 13 &&
value <= 0xFFFF + 269) {
9865 ret = sizeof(uint16_t);
9866 }
9867
9868 return ret;
9869}
9870
9871
9872
9873
9874
9875
9876static char *coap_add_uint16(char *ptr, uint16_t val) {
9877 *ptr = val >> 8;
9878 ptr++;
9879 *ptr = val & 0x00FF;
9880 ptr++;
9881 return ptr;
9882}
9883
9884
9885
9886
9887
9888
9889static char *coap_add_opt_info(char *ptr, uint16_t val, size_t len) {
9890 if (len == sizeof(uint8_t)) {
9891 *ptr = val;
9892 ptr++;
9893 } else if (len == sizeof(uint16_t)) {
9894 ptr = coap_add_uint16(ptr, val);
9895 }
9896
9897 return ptr;
9898}
9899
9900
9901
9902
9903
9904
9905static uint32_t coap_calculate_packet_size(struct mg_coap_message *cm,
9906 size_t *len) {
9907 struct mg_coap_option *opt;
9908 uint32_t prev_opt_number;
9909
9910 *len = 4;
9911 if (cm->msg_type > MG_COAP_MSG_MAX) {
9912 return MG_COAP_ERROR | MG_COAP_MSG_TYPE_FIELD;
9913 }
9914 if (cm->token.len > 8) {
9915 return MG_COAP_ERROR | MG_COAP_TOKEN_FIELD;
9916 }
9917 if (cm->code_class > 7) {
9918 return MG_COAP_ERROR | MG_COAP_CODE_CLASS_FIELD;
9919 }
9920 if (cm->code_detail > 31) {
9921 return MG_COAP_ERROR | MG_COAP_CODE_DETAIL_FIELD;
9922 }
9923
9924 *len += cm->token.len;
9925 if (cm->payload.len != 0) {
9926 *len += cm->payload.len + 1;
9927 }
9928
9929 opt = cm->options;
9930 prev_opt_number = 0;
9931 while (opt != NULL) {
9932 *len += 1;
9933 *len += coap_get_ext_opt_size(opt->number);
9934 *len += coap_get_ext_opt_size((uint32_t) opt->value.len);
9935
9936
9937
9938
9939
9940
9941 if ((opt->next != NULL && opt->number > opt->next->number) ||
9942 opt->value.len > 0xFFFF + 269 ||
9943 opt->number - prev_opt_number > 0xFFFF + 269) {
9944 return MG_COAP_ERROR | MG_COAP_OPTIOMG_FIELD;
9945 }
9946 *len += opt->value.len;
9947 opt = opt->next;
9948 }
9949
9950 return 0;
9951}
9952
9953uint32_t mg_coap_compose(
struct mg_coap_message *cm,
struct mbuf *io) {
9954 struct mg_coap_option *opt;
9955 uint32_t res, prev_opt_number;
9956 size_t prev_io_len, packet_size;
9957 char *ptr;
9958
9959 res = coap_calculate_packet_size(cm, &packet_size);
9960 if (res != 0) {
9961 return res;
9962 }
9963
9964
9965 prev_io_len = io->
len;
9967 ptr = io->
buf + prev_io_len;
9968
9969
9970
9971
9972
9973
9974
9975 *ptr = (1 << 6) | (cm->msg_type << 4) | (cm->token.len);
9976 ptr++;
9977
9978
9979 *ptr = (cm->code_class << 5) | (cm->code_detail);
9980 ptr++;
9981
9982 ptr = coap_add_uint16(ptr, cm->msg_id);
9983
9984 if (cm->token.len != 0) {
9985 memcpy(ptr, cm->token.p, cm->token.len);
9986 ptr += cm->token.len;
9987 }
9988
9989 opt = cm->options;
9990 prev_opt_number = 0;
9991 while (opt != NULL) {
9992 uint8_t delta_base = 0, length_base = 0;
9993 uint16_t delta_ext, length_ext;
9994
9995 size_t opt_delta_len =
9996 coap_split_opt(opt->number - prev_opt_number, &delta_base, &delta_ext);
9997 size_t opt_lenght_len =
9998 coap_split_opt((uint32_t) opt->value.len, &length_base, &length_ext);
9999
10000 *ptr = (delta_base << 4) | length_base;
10001 ptr++;
10002
10003 ptr = coap_add_opt_info(ptr, delta_ext, opt_delta_len);
10004 ptr = coap_add_opt_info(ptr, length_ext, opt_lenght_len);
10005
10006 if (opt->value.len != 0) {
10007 memcpy(ptr, opt->value.p, opt->value.len);
10008 ptr += opt->value.len;
10009 }
10010
10011 prev_opt_number = opt->number;
10012 opt = opt->next;
10013 }
10014
10015 if (cm->payload.len != 0) {
10016 *ptr = -1;
10017 ptr++;
10018 memcpy(ptr, cm->payload.p, cm->payload.len);
10019 }
10020
10021 return 0;
10022}
10023
10025 struct mg_coap_message *cm) {
10026 struct mbuf packet_out;
10027 uint32_t compose_res;
10028
10030 compose_res = mg_coap_compose(cm, &packet_out);
10031 if (compose_res != 0) {
10032 return compose_res;
10033 }
10034
10035 mg_send(nc, packet_out.buf, (
int) packet_out.len);
10037
10038 return 0;
10039}
10040
10041uint32_t mg_coap_send_ack(
struct mg_connection *nc, uint16_t msg_id) {
10042 struct mg_coap_message cm;
10043 memset(&cm, 0, sizeof(cm));
10044 cm.msg_type = MG_COAP_MSG_ACK;
10045 cm.msg_id = msg_id;
10046
10047 return mg_coap_send_message(nc, &cm);
10048}
10049
10050static void coap_handler(
struct mg_connection *nc,
int ev,
void *ev_data) {
10052 struct mg_coap_message cm;
10053 uint32_t parse_res;
10054
10055 memset(&cm, 0, sizeof(cm));
10056
10057 nc->
handler(nc, ev, ev_data);
10058
10059 switch (ev) {
10061 parse_res = mg_coap_parse(io, &cm);
10062 if ((parse_res & MG_COAP_IGNORE) == 0) {
10063 if ((cm.flags & MG_COAP_NOT_ENOUGH_DATA) != 0) {
10064
10065
10066
10067
10068 cm.flags |= MG_COAP_FORMAT_ERROR;
10069 }
10070 nc->
handler(nc, MG_COAP_EVENT_BASE + cm.msg_type, &cm);
10071 }
10072
10073 mg_coap_free_options(&cm);
10075 break;
10076 }
10077}
10078
10079
10080
10081
10082
10083
10084
10085
10086
10087
10089
10091 return -1;
10092 }
10093
10095
10096 return 0;
10097}
10098
10099#endif
10100#ifdef MG_MODULE_LINES
10101#line 1 "./src/../../common/platforms/cc3200/cc3200_libc.c"
10102#endif
10103
10104
10105
10106
10107
10108#if CS_PLATFORM == CS_P_CC3200
10109
10110#include <stdio.h>
10111#include <string.h>
10112
10113#ifndef __TI_COMPILER_VERSION__
10114#include <reent.h>
10115#include <sys/stat.h>
10116#include <sys/time.h>
10117#include <unistd.h>
10118#endif
10119
10120#include <inc/hw_types.h>
10121#include <inc/hw_memmap.h>
10122#include <driverlib/prcm.h>
10123#include <driverlib/rom.h>
10124#include <driverlib/rom_map.h>
10125#include <driverlib/uart.h>
10126#include <driverlib/utils.h>
10127
10128#define CONSOLE_UART UARTA0_BASE
10129
10130#ifndef __TI_COMPILER_VERSION__
10131int _gettimeofday_r(
struct _reent *r,
struct timeval *tp,
void *tzp) {
10132#else
10134#endif
10135 unsigned long long r1 = 0, r2;
10136
10137 do {
10138 r2 = r1;
10139 r1 = PRCMSlowClkCtrFastGet();
10140 } while (r1 != r2);
10141
10142 tp->tv_sec = (r1 >> 15);
10143
10144
10145 tp->tv_usec = (r1 & 0x7FFF) * 30;
10146 return 0;
10147}
10148
10150 return 42;
10151}
10152
10154 while (*
str !=
'\0') {
10157 }
10158}
10159
10162
10164 while (1)
10165 ;
10166}
10167
10170 fprint_str(stderr,
" is not implemented\n");
10172}
10173
10174int _kill(
int pid,
int sig) {
10175 (void) pid;
10176 (void) sig;
10178 return -1;
10179}
10180
10182 fprint_str(stderr,
"_getpid is not implemented\n");
10183 return 42;
10184}
10185
10187
10188 return fd < 2;
10189}
10190
10191#endif
10192#ifdef MG_MODULE_LINES
10193#line 1 "./src/../../common/platforms/msp432/msp432_libc.c"
10194#endif
10195
10196
10197
10198
10199
10200#if CS_PLATFORM == CS_P_MSP432
10201
10202#include <ti/sysbios/BIOS.h>
10203#include <ti/sysbios/knl/Clock.h>
10204
10206 uint32_t ticks = Clock_getTicks();
10207 tp->tv_sec = ticks / 1000;
10208 tp->tv_usec = (ticks % 1000) * 1000;
10209 return 0;
10210}
10211
10213 return 42;
10214}
10215
10216#endif
10217#ifdef MG_MODULE_LINES
10218#line 1 "./src/../../common/platforms/simplelink/sl_fs_slfs.h"
10219#endif
10220
10221
10222
10223
10224
10225#ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
10226#define CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
10227
10228#if defined(MG_FS_SLFS)
10229
10230#include <stdio.h>
10231#ifndef __TI_COMPILER_VERSION__
10232#include <unistd.h>
10233#include <sys/stat.h>
10234#endif
10235
10236#define MAX_OPEN_SLFS_FILES 8
10237
10238
10239int fs_slfs_open(const char *pathname, int flags, mode_t mode);
10240int fs_slfs_close(int fd);
10241ssize_t fs_slfs_read(
int fd,
void *buf,
size_t count);
10242ssize_t fs_slfs_write(
int fd,
const void *buf,
size_t count);
10243int fs_slfs_stat(const char *pathname, struct stat *s);
10244int fs_slfs_fstat(int fd, struct stat *s);
10245off_t fs_slfs_lseek(
int fd, off_t
offset,
int whence);
10246int fs_slfs_unlink(const char *filename);
10247int fs_slfs_rename(const char *from, const char *to);
10248
10249#endif
10250
10251#endif
10252#ifdef MG_MODULE_LINES
10253#line 1 "./src/../../common/platforms/simplelink/sl_fs_slfs.c"
10254#endif
10255
10256
10257
10258
10259
10260
10261
10262#if defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS)
10263
10264
10265
10266#include <errno.h>
10267
10268#if CS_PLATFORM == CS_P_CC3200
10269#include <inc/hw_types.h>
10270#endif
10271#include <simplelink/include/simplelink.h>
10272#include <simplelink/include/fs.h>
10273
10274
10275
10276extern int set_errno(
int e);
10277
10278
10279
10280
10281
10282#ifndef FS_SLFS_MAX_FILE_SIZE
10283#define FS_SLFS_MAX_FILE_SIZE (64 * 1024)
10284#endif
10285
10286struct sl_fd_info {
10287 _i32 fh;
10288 _off_t pos;
10289 size_t size;
10290};
10291
10292static struct sl_fd_info s_sl_fds[MAX_OPEN_SLFS_FILES];
10293
10294static int sl_fs_to_errno(_i32 r) {
10295 DBG((
"SL error: %d", (
int) r));
10296 switch (r) {
10297 case SL_FS_OK:
10298 return 0;
10299 case SL_FS_FILE_NAME_EXIST:
10300 return EEXIST;
10301 case SL_FS_WRONG_FILE_NAME:
10302 return EINVAL;
10303 case SL_FS_ERR_NO_AVAILABLE_NV_INDEX:
10304 case SL_FS_ERR_NO_AVAILABLE_BLOCKS:
10305 return ENOSPC;
10306 case SL_FS_ERR_FAILED_TO_ALLOCATE_MEM:
10307 return ENOMEM;
10308 case SL_FS_ERR_FILE_NOT_EXISTS:
10309 return ENOENT;
10310 case SL_FS_ERR_NOT_SUPPORTED:
10311 return ENOTSUP;
10312 }
10313 return ENXIO;
10314}
10315
10316int fs_slfs_open(const char *pathname, int flags, mode_t mode) {
10317 int fd;
10318 for (fd = 0; fd < MAX_OPEN_SLFS_FILES; fd++) {
10319 if (s_sl_fds[fd].fh <= 0) break;
10320 }
10321 if (fd >= MAX_OPEN_SLFS_FILES) return set_errno(ENOMEM);
10322 struct sl_fd_info *fi = &s_sl_fds[fd];
10323
10324 _u32 am = 0;
10325 fi->size = (size_t) -1;
10326 if (pathname[0] == '/') pathname++;
10327 int rw = (flags & 3);
10328 if (rw == O_RDONLY) {
10329 SlFsFileInfo_t sl_fi;
10330 _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
10331 if (r == SL_FS_OK) {
10332 fi->size = sl_fi.FileLen;
10333 }
10334 am = FS_MODE_OPEN_READ;
10335 } else {
10336 if (!(flags & O_TRUNC) || (flags & O_APPEND)) {
10337
10338
10339 return set_errno(ENOTSUP);
10340 }
10341 if (flags & O_CREAT) {
10342 am = FS_MODE_OPEN_CREATE(FS_SLFS_MAX_FILE_SIZE, 0);
10343 } else {
10344 am = FS_MODE_OPEN_WRITE;
10345 }
10346 }
10347 _i32 r = sl_FsOpen((_u8 *) pathname, am, NULL, &fi->fh);
10348 DBG((
"sl_FsOpen(%s, 0x%x) = %d, %d", pathname, (
int) am, (
int) r,
10349 (int) fi->fh));
10350 if (r == SL_FS_OK) {
10351 fi->pos = 0;
10352 r = fd;
10353 } else {
10354 fi->fh = -1;
10355 r = set_errno(sl_fs_to_errno(r));
10356 }
10357 return r;
10358}
10359
10360int fs_slfs_close(int fd) {
10361 struct sl_fd_info *fi = &s_sl_fds[fd];
10362 if (fi->fh <= 0) return set_errno(EBADF);
10363 _i32 r = sl_FsClose(fi->fh, NULL, NULL, 0);
10364 DBG((
"sl_FsClose(%d) = %d", (
int) fi->fh, (
int) r));
10365 s_sl_fds[fd].fh = -1;
10366 return set_errno(sl_fs_to_errno(r));
10367}
10368
10369ssize_t fs_slfs_read(
int fd,
void *buf,
size_t count) {
10370 struct sl_fd_info *fi = &s_sl_fds[fd];
10371 if (fi->fh <= 0) return set_errno(EBADF);
10372
10373
10374 if (fi->pos == fi->size) return 0;
10375 _i32 r = sl_FsRead(fi->fh, fi->pos, buf,
count);
10376 DBG((
"sl_FsRead(%d, %d, %d) = %d", (
int) fi->fh, (
int) fi->pos, (
int)
count,
10377 (int) r));
10378 if (r >= 0) {
10379 fi->pos += r;
10380 return r;
10381 }
10382 return set_errno(sl_fs_to_errno(r));
10383}
10384
10385ssize_t fs_slfs_write(
int fd,
const void *buf,
size_t count) {
10386 struct sl_fd_info *fi = &s_sl_fds[fd];
10387 if (fi->fh <= 0) return set_errno(EBADF);
10388 _i32 r = sl_FsWrite(fi->fh, fi->pos, (_u8 *) buf,
count);
10389 DBG((
"sl_FsWrite(%d, %d, %d) = %d", (
int) fi->fh, (
int) fi->pos, (
int)
count,
10390 (int) r));
10391 if (r >= 0) {
10392 fi->pos += r;
10393 return r;
10394 }
10395 return set_errno(sl_fs_to_errno(r));
10396}
10397
10398int fs_slfs_stat(const char *pathname, struct stat *s) {
10399 SlFsFileInfo_t sl_fi;
10400 _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
10401 if (r == SL_FS_OK) {
10402 s->st_mode = S_IFREG | 0666;
10403 s->st_nlink = 1;
10404 s->st_size = sl_fi.FileLen;
10405 return 0;
10406 }
10407 return set_errno(sl_fs_to_errno(r));
10408}
10409
10410int fs_slfs_fstat(int fd, struct stat *s) {
10411 struct sl_fd_info *fi = &s_sl_fds[fd];
10412 if (fi->fh <= 0) return set_errno(EBADF);
10413 s->st_mode = 0666;
10414 s->st_mode = S_IFREG | 0666;
10415 s->st_nlink = 1;
10416 s->st_size = fi->size;
10417 return 0;
10418}
10419
10420off_t fs_slfs_lseek(
int fd, off_t
offset,
int whence) {
10421 if (s_sl_fds[fd].fh <= 0) return set_errno(EBADF);
10422 switch (whence) {
10423 case SEEK_SET:
10424 s_sl_fds[fd].pos =
offset;
10425 break;
10426 case SEEK_CUR:
10427 s_sl_fds[fd].pos +=
offset;
10428 break;
10429 case SEEK_END:
10430 return set_errno(ENOTSUP);
10431 }
10432 return 0;
10433}
10434
10435int fs_slfs_unlink(const char *filename) {
10436 return set_errno(sl_fs_to_errno(sl_FsDel((const _u8 *) filename, 0)));
10437}
10438
10439int fs_slfs_rename(const char *from, const char *to) {
10440 return set_errno(ENOTSUP);
10441}
10442
10443#endif
10444#ifdef MG_MODULE_LINES
10445#line 1 "./src/../../common/platforms/simplelink/sl_fs.c"
10446#endif
10447
10448
10449
10450
10451
10452#if defined(MG_SOCKET_SIMPLELINK) && \
10453 (defined(MG_FS_SLFS) || defined(MG_FS_SPIFFS))
10454
10455#include <errno.h>
10456#include <stdio.h>
10457#include <stdlib.h>
10458#include <string.h>
10459#ifdef __TI_COMPILER_VERSION__
10460#include <file.h>
10461#endif
10462
10463#if CS_PLATFORM == CS_P_CC3200
10464#include <inc/hw_types.h>
10465#include <inc/hw_memmap.h>
10466#include <driverlib/rom.h>
10467#include <driverlib/rom_map.h>
10468#include <driverlib/uart.h>
10469#endif
10470
10471
10472
10473
10474#ifdef CC3200_FS_SPIFFS
10475
10476#endif
10477
10478#ifdef MG_FS_SLFS
10479
10480#endif
10481
10482#define NUM_SYS_FDS 3
10483#define SPIFFS_FD_BASE 10
10484#define SLFS_FD_BASE 100
10485
10486#define CONSOLE_UART UARTA0_BASE
10487
10488int set_errno(
int e) {
10491}
10492
10493static int is_sl_fname(const char *fname) {
10494 return strncmp(fname, "SL:", 3) == 0;
10495}
10496
10497static const char *sl_fname(const char *fname) {
10498 return fname + 3;
10499}
10500
10501static const char *drop_dir(const char *fname) {
10502 if (*fname == '.') fname++;
10503 if (*fname == '/') fname++;
10504 return fname;
10505}
10506
10507enum fd_type {
10508 FD_INVALID,
10509 FD_SYS,
10510#ifdef CC3200_FS_SPIFFS
10511 FD_SPIFFS,
10512#endif
10513#ifdef MG_FS_SLFS
10514 FD_SLFS
10515#endif
10516};
10517static int fd_type(int fd) {
10518 if (fd >= 0 && fd < NUM_SYS_FDS) return FD_SYS;
10519#ifdef CC3200_FS_SPIFFS
10520 if (fd >= SPIFFS_FD_BASE && fd < SPIFFS_FD_BASE + MAX_OPEN_SPIFFS_FILES) {
10521 return FD_SPIFFS;
10522 }
10523#endif
10524#ifdef MG_FS_SLFS
10525 if (fd >= SLFS_FD_BASE && fd < SLFS_FD_BASE + MAX_OPEN_SLFS_FILES) {
10526 return FD_SLFS;
10527 }
10528#endif
10529 return FD_INVALID;
10530}
10531
10532int _open(const char *pathname, int flags, mode_t mode) {
10533 int fd = -1;
10534 pathname = drop_dir(pathname);
10535 if (is_sl_fname(pathname)) {
10536#ifdef MG_FS_SLFS
10537 fd = fs_slfs_open(sl_fname(pathname), flags, mode);
10538 if (fd >= 0) fd += SLFS_FD_BASE;
10539#endif
10540 } else {
10541#ifdef CC3200_FS_SPIFFS
10542 fd = fs_spiffs_open(pathname, flags, mode);
10543 if (fd >= 0) fd += SPIFFS_FD_BASE;
10544#endif
10545 }
10546 DBG((
"open(%s, 0x%x) = %d", pathname, flags, fd));
10547 return fd;
10548}
10549
10550int _stat(const char *pathname, struct stat *st) {
10551 int res = -1;
10552 const char *fname = pathname;
10553 int is_sl = is_sl_fname(pathname);
10554 if (is_sl) fname = sl_fname(pathname);
10555 fname = drop_dir(fname);
10556 memset(st, 0, sizeof(*st));
10557
10558 if (strcmp(fname, "") == 0) {
10559 st->st_ino = 0;
10560 st->st_mode = S_IFDIR | 0777;
10561 st->st_nlink = 1;
10562 st->st_size = 0;
10563 return 0;
10564 }
10565 if (is_sl) {
10566#ifdef MG_FS_SLFS
10567 res = fs_slfs_stat(fname, st);
10568#endif
10569 } else {
10570#ifdef CC3200_FS_SPIFFS
10571 res = fs_spiffs_stat(fname, st);
10572#endif
10573 }
10574 DBG((
"stat(%s) = %d; fname = %s", pathname, res, fname));
10575 return res;
10576}
10577
10578int _close(int fd) {
10579 int r = -1;
10580 switch (fd_type(fd)) {
10581 case FD_INVALID:
10582 r = set_errno(EBADF);
10583 break;
10584 case FD_SYS:
10585 r = set_errno(EACCES);
10586 break;
10587#ifdef CC3200_FS_SPIFFS
10588 case FD_SPIFFS:
10589 r = fs_spiffs_close(fd - SPIFFS_FD_BASE);
10590 break;
10591#endif
10592#ifdef MG_FS_SLFS
10593 case FD_SLFS:
10594 r = fs_slfs_close(fd - SLFS_FD_BASE);
10595 break;
10596#endif
10597 }
10598 DBG((
"close(%d) = %d", fd, r));
10599 return r;
10600}
10601
10602off_t _lseek(
int fd, off_t
offset,
int whence) {
10603 int r = -1;
10604 switch (fd_type(fd)) {
10605 case FD_INVALID:
10606 r = set_errno(EBADF);
10607 break;
10608 case FD_SYS:
10609 r = set_errno(ESPIPE);
10610 break;
10611#ifdef CC3200_FS_SPIFFS
10612 case FD_SPIFFS:
10613 r = fs_spiffs_lseek(fd - SPIFFS_FD_BASE,
offset, whence);
10614 break;
10615#endif
10616#ifdef MG_FS_SLFS
10617 case FD_SLFS:
10618 r = fs_slfs_lseek(fd - SLFS_FD_BASE,
offset, whence);
10619 break;
10620#endif
10621 }
10622 DBG((
"lseek(%d, %d, %d) = %d", fd, (
int)
offset, whence, r));
10623 return r;
10624}
10625
10626int _fstat(int fd, struct stat *s) {
10627 int r = -1;
10628 memset(s, 0, sizeof(*s));
10629 switch (fd_type(fd)) {
10630 case FD_INVALID:
10631 r = set_errno(EBADF);
10632 break;
10633 case FD_SYS: {
10634
10635 memset(s, 0, sizeof(*s));
10636 s->st_ino = fd;
10637 s->st_mode = S_IFCHR | 0666;
10638 r = 0;
10639 break;
10640 }
10641#ifdef CC3200_FS_SPIFFS
10642 case FD_SPIFFS:
10643 r = fs_spiffs_fstat(fd - SPIFFS_FD_BASE, s);
10644 break;
10645#endif
10646#ifdef MG_FS_SLFS
10647 case FD_SLFS:
10648 r = fs_slfs_fstat(fd - SLFS_FD_BASE, s);
10649 break;
10650#endif
10651 }
10652 DBG((
"fstat(%d) = %d", fd, r));
10653 return r;
10654}
10655
10656ssize_t _read(
int fd,
void *buf,
size_t count) {
10657 int r = -1;
10658 switch (fd_type(fd)) {
10659 case FD_INVALID:
10660 r = set_errno(EBADF);
10661 break;
10662 case FD_SYS: {
10663 if (fd != 0) {
10664 r = set_errno(EACCES);
10665 break;
10666 }
10667
10668 r = set_errno(ENOTSUP);
10669 break;
10670 }
10671#ifdef CC3200_FS_SPIFFS
10672 case FD_SPIFFS:
10673 r = fs_spiffs_read(fd - SPIFFS_FD_BASE, buf,
count);
10674 break;
10675#endif
10676#ifdef MG_FS_SLFS
10677 case FD_SLFS:
10678 r = fs_slfs_read(fd - SLFS_FD_BASE, buf,
count);
10679 break;
10680#endif
10681 }
10682 DBG((
"read(%d, %u) = %d", fd,
count, r));
10683 return r;
10684}
10685
10686ssize_t _write(
int fd,
const void *buf,
size_t count) {
10687 int r = -1;
10689 switch (fd_type(fd)) {
10690 case FD_INVALID:
10691 r = set_errno(EBADF);
10692 break;
10693 case FD_SYS: {
10694 if (fd == 0) {
10695 r = set_errno(EACCES);
10696 break;
10697 }
10698#if CS_PLATFORM == CS_P_CC3200
10700 const char c = ((
const char *) buf)[
i];
10703 }
10704#else
10706#endif
10708 break;
10709 }
10710#ifdef CC3200_FS_SPIFFS
10711 case FD_SPIFFS:
10712 r = fs_spiffs_write(fd - SPIFFS_FD_BASE, buf,
count);
10713 break;
10714#endif
10715#ifdef MG_FS_SLFS
10716 case FD_SLFS:
10717 r = fs_slfs_write(fd - SLFS_FD_BASE, buf,
count);
10718 break;
10719#endif
10720 }
10721 return r;
10722}
10723
10724int _rename(const char *from, const char *to) {
10725 int r = -1;
10726 from = drop_dir(from);
10727 to = drop_dir(to);
10728 if (is_sl_fname(from) || is_sl_fname(to)) {
10729#ifdef MG_FS_SLFS
10730 r = fs_slfs_rename(sl_fname(from), sl_fname(to));
10731#endif
10732 } else {
10733#ifdef CC3200_FS_SPIFFS
10734 r = fs_spiffs_rename(from, to);
10735#endif
10736 }
10737 DBG((
"rename(%s, %s) = %d", from, to, r));
10738 return r;
10739}
10740
10741int _link(const char *from, const char *to) {
10742 DBG((
"link(%s, %s)", from, to));
10743 return set_errno(ENOTSUP);
10744}
10745
10746int _unlink(const char *filename) {
10747 int r = -1;
10748 filename = drop_dir(filename);
10749 if (is_sl_fname(filename)) {
10750#ifdef MG_FS_SLFS
10751 r = fs_slfs_unlink(sl_fname(filename));
10752#endif
10753 } else {
10754#ifdef CC3200_FS_SPIFFS
10755 r = fs_spiffs_unlink(filename);
10756#endif
10757 }
10758 DBG((
"unlink(%s) = %d", filename, r));
10759 return r;
10760}
10761
10762#ifdef CC3200_FS_SPIFFS
10763DIR *opendir(
const char *dir_name) {
10765 if (is_sl_fname(dir_name)) {
10766 r = NULL;
10767 set_errno(ENOTSUP);
10768 } else {
10769 r = fs_spiffs_opendir(dir_name);
10770 }
10771 DBG((
"opendir(%s) = %p", dir_name, r));
10772 return r;
10773}
10774
10775struct dirent *readdir(
DIR *dir) {
10776 struct dirent *res = fs_spiffs_readdir(dir);
10777 DBG((
"readdir(%p) = %p", dir, res));
10778 return res;
10779}
10780
10781int closedir(
DIR *dir) {
10782 int res = fs_spiffs_closedir(dir);
10783 DBG((
"closedir(%p) = %d", dir, res));
10784 return res;
10785}
10786
10787int rmdir(
const char *path) {
10788 return fs_spiffs_rmdir(path);
10789}
10790
10791int mkdir(const char *path, mode_t mode) {
10792 (void) path;
10793 (void) mode;
10794
10795 return (strlen(path) == 1 && *path == '.') ? 0 : ENOTDIR;
10796}
10797#endif
10798
10799int sl_fs_init() {
10800 int ret = 1;
10801#ifdef __TI_COMPILER_VERSION__
10802#ifdef MG_FS_SLFS
10803 ret = (add_device("SL", _MSA, fs_slfs_open, fs_slfs_close, fs_slfs_read,
10804 fs_slfs_write, fs_slfs_lseek, fs_slfs_unlink,
10805 fs_slfs_rename) == 0);
10806#endif
10807#endif
10808 return ret;
10809}
10810
10811#endif
10812
10813#ifdef MG_MODULE_LINES
10814#line 1 "./src/../../common/platforms/simplelink/sl_socket.c"
10815#endif
10816
10817
10818
10819
10820
10821#ifdef MG_SOCKET_SIMPLELINK
10822
10823#include <errno.h>
10824#include <stdio.h>
10825
10826
10827
10828#include <simplelink/include/netapp.h>
10829
10830const char *
inet_ntop(
int af,
const void *src,
char *dst, socklen_t size) {
10831 int res;
10832 struct in_addr *in = (struct in_addr *) src;
10833 if (af != AF_INET) {
10834 errno = EAFNOSUPPORT;
10835 return NULL;
10836 }
10837 res = snprintf(dst, size, "%lu.%lu.%lu.%lu", SL_IPV4_BYTE(in->s_addr, 0),
10838 SL_IPV4_BYTE(in->s_addr, 1), SL_IPV4_BYTE(in->s_addr, 2),
10839 SL_IPV4_BYTE(in->s_addr, 3));
10840 return res > 0 ? dst : NULL;
10841}
10842
10844 static char a[16];
10845 return (
char *)
inet_ntop(AF_INET, &
n, a,
sizeof(
n));
10846}
10847
10848int inet_pton(
int af,
const char *src,
void *dst) {
10849 uint32_t a0, a1, a2, a3;
10850 uint8_t *db = (uint8_t *) dst;
10851 if (af != AF_INET) {
10852 errno = EAFNOSUPPORT;
10853 return 0;
10854 }
10855 if (sscanf(src, "%lu.%lu.%lu.%lu", &a0, &a1, &a2, &a3) != 4) {
10856 return 0;
10857 }
10858 *db = a3;
10859 *(db + 1) = a2;
10860 *(db + 2) = a1;
10861 *(db + 3) = a0;
10862 return 1;
10863}
10864
10865#endif
10866#ifdef MG_MODULE_LINES
10867#line 1 "./src/../../common/platforms/simplelink/sl_mg_task.c"
10868#endif
10869#if defined(MG_SOCKET_SIMPLELINK)
10870
10871
10872
10873#include <oslib/osi.h>
10874
10877};
10882};
10884static void mg_task(
void *arg);
10885
10886bool mg_start_task(
int priority,
int stack_size, mg_init_cb mg_init) {
10887 if (osi_MsgQCreate(&
s_mg_q,
"MG",
sizeof(
struct mg_q_msg), 16) != OSI_OK) {
10888 return false;
10889 }
10890 if (osi_TaskCreate(
mg_task, (
const signed char *)
"MG", stack_size,
10891 (void *) mg_init, priority, NULL) != OSI_OK) {
10892 return false;
10893 }
10894 return true;
10895}
10896
10897static void mg_task(
void *arg) {
10899 mg_init_cb mg_init = (mg_init_cb) arg;
10901 mg_init(&mgr);
10902 while (1) {
10905 if (osi_MsgQRead(&
s_mg_q, &msg, 1) != OSI_OK)
continue;
10906 switch (msg.type) {
10908 msg.cb(&mgr, msg.arg);
10909 }
10910 }
10911 }
10912}
10913
10916 osi_MsgQWrite(&
s_mg_q, &msg, OSI_NO_WAIT);
10917}
10918
10919#endif
int mg_start_thread(mg_thread_func_t f, void *p)
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded)
int(* mg_event_handler_t)(struct mg_event *event)
time_t mg_mgr_poll(struct mg_mgr *mgr, int timeout_ms)
void mg_mqtt_ping(struct mg_connection *nc)
void mg_set_protocol_mqtt(struct mg_connection *nc)
void mg_mgr_free(struct mg_mgr *m)
const char * hexdump_file
int mg_resolve_from_hosts_file(const char *name, union socket_address *usa)
#define WEBSOCKET_DONT_FIN
#define MG_MK_STR(str_literal)
void mg_send_dns_query(struct mg_connection *nc, const char *name, int query_type)
#define WEBSOCKET_OP_PING
char * cs_md5(char buf[33],...)
struct json_token * message
void mg_mqtt_disconnect(struct mg_connection *nc)
#define MG_MQTT_CMD_PUBREC
void mg_mqtt_publish(struct mg_connection *nc, const char *topic, uint16_t message_id, int flags, const void *data, size_t len)
void mg_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa)
#define MG_MQTT_CMD_UNSUBACK
struct mg_str header_names[MG_MAX_HTTP_HEADERS]
int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap)
void mg_if_destroy_conn(struct mg_connection *nc)
#define MG_MAX_HTTP_SEND_MBUF
#define MG_MAX_DNS_ANSWERS
int mg_dns_copy_body(struct mbuf *io, struct mg_dns_message *msg)
#define MG_EV_WEBSOCKET_FRAME
int mg_stat(const char *path, cs_stat_t *st)
#define JSON_RPC_INVALID_PARAMS_ERROR
struct mg_connection * mg_connect_http(struct mg_mgr *mgr, mg_event_handler_t ev_handler, const char *url, const char *extra_headers, const char *post_data)
const char * global_auth_file
#define MG_EV_WEBSOCKET_HANDSHAKE_DONE
int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, mg_resolve_callback_t cb, void *data, struct mg_resolve_async_opts opts)
mg_event_handler_t handler
struct mg_connection * active_connections
void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code)
#define MG_MQTT_CMD_PUBACK
int mg_dns_encode_record(struct mbuf *io, struct mg_dns_resource_record *rr, const char *name, size_t nlen, const void *rdata, size_t rlen)
void mg_mqtt_pong(struct mg_connection *nc)
struct mg_connection ** dns_conn
struct json_token * message
int mg_is_big_endian(void)
#define MG_F_CLOSE_IMMEDIATELY
size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len)
size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name, size_t var_name_len, char *file_name, size_t file_name_len, const char **data, size_t *data_len)
#define MG_SOCK_STRINGIFY_PORT
void mbuf_remove(struct mbuf *mb, size_t n)
void mg_mgr_init(struct mg_mgr *m, void *user_data)
int mg_dns_insert_header(struct mbuf *io, size_t pos, struct mg_dns_message *msg)
const char * extra_headers
void mg_send_head(struct mg_connection *c, int status_code, int64_t content_length, const char *extra_headers)
void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id)
void mg_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len)
void(* proto_data_destructor)(void *proto_data)
struct mg_connection * mg_next(struct mg_mgr *s, struct mg_connection *conn)
int mg_resolve_async(struct mg_mgr *mgr, const char *name, int query, mg_resolve_callback_t cb, void *data)
void mg_if_connect_udp(struct mg_connection *nc)
void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa, size_t sa_len)
int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out)
#define WEBSOCKET_OP_CLOSE
const char * c_strnstr(const char *s, const char *find, size_t slen)
int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap)
const char * mg_set_ssl(struct mg_connection *nc, const char *cert, const char *ca_cert)
void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data, size_t len)
#define MG_DNS_AAAA_RECORD
int json_emit_unquoted_str(char *buf, int buf_len, const char *str, int len)
void mg_send_response_line(struct mg_connection *nc, int status_code, const char *extra_headers)
#define MG_MQTT_CMD_CONNACK
void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id)
#define MG_VPRINTF_BUFFER_SIZE
struct mg_str header_values[MG_MAX_HTTP_HEADERS]
void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, union socket_address *sa, size_t sa_len)
void mbuf_free(struct mbuf *mbuf)
const char * url_rewrites
#define MG_EV_WEBSOCKET_CONTROL_FRAME
void mg_serve_http(struct mg_connection *nc, struct http_message *hm, struct mg_serve_http_opts opts)
const char ** error_string
#define MG_MAX_CGI_ENVIR_VARS
#define MG_SOCK_STRINGIFY_REMOTE
void mg_if_poll(struct mg_connection *nc, time_t now)
int mg_open(const char *path, int flag, int mode)
struct json_token * method
double mg_set_timer(struct mg_connection *c, double timestamp)
struct mg_connection * mg_connect(struct mg_mgr *mgr, const char *address, mg_event_handler_t callback)
void mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len, int flags)
#define MG_MQTT_GET_QOS(flags)
struct json_token * message
struct json_token * error_message
int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req)
int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str)
#define MG_SEND_FUNC(s, b, l, f)
union mg_connection::@11 priv_1
void mbuf_resize(struct mbuf *a, size_t new_size)
void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len)
void mg_printf_html_escape(struct mg_connection *nc, const char *fmt,...)
void mg_if_sent_cb(struct mg_connection *nc, int num_sent)
#define MG_DNS_CNAME_RECORD
struct mg_connection * mg_if_accept_new_conn(struct mg_connection *lc)
#define MG_CGI_ENVIRONMENT_SIZE
const char * cgi_file_pattern
int mg_casecmp(const char *s1, const char *s2)
int mg_if_create_conn(struct mg_connection *nc)
void mg_send(struct mg_connection *nc, const void *buf, int len)
int mg_socketpair(sock_t sp[2], int sock_type)
#define MG_MQTT_CMD_PUBREL
int mg_rpc_create_error(char *buf, int len, struct mg_rpc_request *req, int code, const char *message, const char *fmt,...)
struct mg_connection * next
void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len)
#define MG_MQTT_CMD_PINGREQ
const char * cgi_interpreter
#define MG_EV_MQTT_CONNACK_SERVER_UNAVAILABLE
#define MG_ENV_EXPORT_TO_CGI
void mg_hexdump_connection(struct mg_connection *nc, const char *path, const void *buf, int num_bytes, int ev)
enum mg_dns_resource_record_kind kind
#define ARRAY_SIZE(array)
struct json_token * result
void mg_if_connect_cb(struct mg_connection *nc, int err)
int mg_http_create_digest_auth_header(char *buf, size_t buf_len, const char *method, const char *uri, const char *auth_domain, const char *user, const char *passwd)
struct mg_connection * mg_add_sock_opt(struct mg_mgr *s, sock_t sock, mg_event_handler_t callback, struct mg_add_sock_opts opts)
#define MG_EV_MQTT_CONNECT
int mg_if_listen_udp(struct mg_connection *nc, union socket_address *sa)
void mg_sock_set(struct mg_connection *nc, sock_t sock)
void mg_send_websocket_handshake2(struct mg_connection *nc, const char *path, const char *host, const char *protocol, const char *extra_headers)
void mg_if_udp_send(struct mg_connection *nc, const void *buf, size_t len)
int(* mg_rpc_handler_t)(char *buf, int len, struct mg_rpc_request *req)
int mg_if_listen_tcp(struct mg_connection *nc, union socket_address *sa)
struct mg_connection * mg_connect_opt(struct mg_mgr *mgr, const char *address, mg_event_handler_t callback, struct mg_connect_opts opts)
void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, mg_event_handler_t handler)
void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags)
#define MG_MQTT_CMD_PUBCOMP
void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id)
struct mg_str query_string
void mg_printf_websocket_frame(struct mg_connection *nc, int op, const char *fmt,...)
#define MG_MQTT_EVENT_BASE
#define MG_MQTT_CMD_PUBLISH
struct mg_dns_resource_record questions[MG_MAX_DNS_QUESTIONS]
#define JSON_RPC_SERVER_ERROR
int parse_json(const char *s, int s_len, struct json_token *arr, int arr_len)
int cs_base64_decode(const unsigned char *s, int len, char *dst)
#define MG_SOCK_STRINGIFY_IP
const char * enable_directory_listing
int mg_match_prefix(const char *pattern, int pattern_len, const char *str)
#define MG_MQTT_CMD_PINGRESP
#define MG_MQTT_CMD_CONNECT
const char * dav_auth_file
void mg_set_protocol_http_websocket(struct mg_connection *nc)
void mg_send_websocket_framev(struct mg_connection *nc, int op, const struct mg_str *strv, int strvcnt)
int mg_hexdump(const void *buf, int len, char *dst, int dst_len)
int mg_vcasecmp(const struct mg_str *str1, const char *str2)
#define MG_WEBSOCKET_PING_INTERVAL_SECONDS
int mg_base64_decode(const unsigned char *s, int len, char *dst)
struct mg_connection * mg_connect_ws(struct mg_mgr *mgr, mg_event_handler_t ev_handler, const char *url, const char *protocol, const char *extra_headers)
struct mg_connection * listener
struct mg_connection * prev
void mg_mqtt_pubrec(struct mg_connection *nc, uint16_t message_id)
void mg_set_close_on_exec(sock_t sock)
struct mg_connection * mg_connect_ws_opt(struct mg_mgr *mgr, mg_event_handler_t ev_handler, struct mg_connect_opts opts, const char *url, const char *protocol, const char *extra_headers)
#define MG_F_DELETE_CHUNK
int mg_resolve(const char *host, char *buf, size_t n)
void mg_set_protocol_dns(struct mg_connection *nc)
const char * mg_skip(const char *s, const char *end, const char *delims, struct mg_str *v)
int json_emit(char *buf, int buf_len, const char *fmt,...)
void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len, uint16_t message_id)
int json_emit_va(char *s, int s_len, const char *fmt, va_list ap)
#define MG_MAX_HTTP_REQUEST_SIZE
#define MG_MQTT_CMD_UNSUBSCRIBE
int mg_parse_dns(const char *buf, int len, struct mg_dns_message *msg)
const char * hidden_file_pattern
struct json_token * error_code
void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id)
struct mg_dns_resource_record * mg_dns_next_record(struct mg_dns_message *msg, int query, struct mg_dns_resource_record *prev)
const char * document_root
void mbuf_init(struct mbuf *mbuf, size_t initial_size)
struct mg_connection * mg_bind_opt(struct mg_mgr *mgr, const char *address, mg_event_handler_t callback, struct mg_bind_opts opts)
void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, struct mg_send_mqtt_handshake_opts opts)
#define JSON_RPC_PARSE_ERROR
size_t mbuf_append(struct mbuf *a, const void *buf, size_t len)
int json_emit_quoted_str(char *s, int s_len, const char *str, int len)
struct json_token * error_data
#define MG_F_SSL_HANDSHAKE_DONE
void mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, int flags)
const char * per_directory_auth_file
void mg_base64_encode(const unsigned char *src, int src_len, char *dst)
void mg_send_websocket_frame(struct mg_connection *nc, int op, const void *data, size_t len)
#define MG_EV_MQTT_PUBLISH
struct mg_connection * mg_bind(struct mg_mgr *srv, const char *address, mg_event_handler_t event_handler)
void(* mg_resolve_callback_t)(struct mg_dns_message *dns_message, void *user_data, enum mg_resolve_err)
#define MG_F_IS_WEBSOCKET
#define MG_RECV_FUNC(s, b, l, f)
struct json_token * find_json_token(struct json_token *toks, const char *path)
void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context)
const char ** error_string
int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf, size_t buf_size)
int mg_rpc_parse_reply(const char *buf, int len, struct json_token *toks, int max_toks, struct mg_rpc_reply *rep, struct mg_rpc_error *er)
struct mg_str mg_mk_str(const char *s)
const char ** error_string
int mg_rpc_create_request(char *buf, int len, const char *method, const char *id, const char *params_fmt,...)
void cs_base64_encode(const unsigned char *src, int src_len, char *dst)
int mg_rpc_create_std_error(char *buf, int len, struct mg_rpc_request *req, int code)
int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst, size_t dst_len)
void mg_send_websocket_handshake(struct mg_connection *nc, const char *path, const char *extra_headers)
#define JSON_RPC_METHOD_NOT_FOUND_ERROR
void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt,...)
void mg_if_connect_tcp(struct mg_connection *nc, const union socket_address *sa)
#define MG_EV_MQTT_SUBSCRIBE
const char * mg_next_comma_list_entry(const char *list, struct mg_str *val, struct mg_str *eq_val)
struct json_token * params
size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name, char *dst, int dst_len)
struct mg_connection * mg_connect_http_opt(struct mg_mgr *mgr, mg_event_handler_t ev_handler, struct mg_connect_opts opts, const char *url, const char *extra_headers, const char *post_data)
const char * nameserver_url
#define MG_MQTT_CMD_DISCONNECT
#define JSON_STRING_INVALID
FILE * mg_fopen(const char *path, const char *mode)
void mg_enable_multithreading(struct mg_connection *nc)
struct mg_str * mg_get_http_header(struct http_message *hm, const char *name)
void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data, uint32_t len)
#define MG_MQTT_CMD_SUBSCRIBE
#define MG_MQTT_CMD_SUBACK
void mg_if_recved(struct mg_connection *nc, size_t len)
int mg_vcmp(const struct mg_str *str1, const char *str2)
int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, struct mg_str *user_info, struct mg_str *host, unsigned int *port, struct mg_str *path, struct mg_str *query, struct mg_str *fragment)
int mg_check_ip_acl(const char *acl, uint32_t remote_ip)
struct mg_dns_resource_record answers[MG_MAX_DNS_ANSWERS]
void mg_if_timer(struct mg_connection *c, double now)
mg_event_handler_t proto_handler
const char * dav_document_root
void mg_close_conn(struct mg_connection *conn)
struct mg_str resp_status_msg
void cs_sha1_init(cs_sha1_ctx *context)
int mg_ncasecmp(const char *s1, const char *s2, size_t len)
int mg_dns_parse_record_data(struct mg_dns_message *msg, struct mg_dns_resource_record *rr, void *data, size_t data_len)
int mg_rpc_dispatch(const char *buf, int len, char *dst, int dst_len, const char **methods, mg_rpc_handler_t *handlers)
struct mg_connection * mg_add_sock(struct mg_mgr *s, sock_t sock, mg_event_handler_t callback)
#define MG_EV_MQTT_CONNACK_ACCEPTED
void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics, size_t topics_len, uint16_t message_id)
#define MG_EV_WEBSOCKET_HANDSHAKE_REQUEST
#define JSON_RPC_INVALID_REQUEST_ERROR
int mg_printf(struct mg_connection *conn, const char *fmt,...)
void mg_mqtt_subscribe(struct mg_connection *nc, const struct mg_mqtt_topic_expression *topics, size_t topics_len, uint16_t message_id)
int mg_rpc_create_reply(char *buf, int len, const struct mg_rpc_request *req, const char *result_fmt,...)
void mg_mqtt_pubrel(struct mg_connection *nc, uint16_t message_id)
int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, struct mg_str *topic, uint8_t *qos, int pos)
#define MG_F_SEND_AND_CLOSE
#define MG_EV_HTTP_REQUEST
@ MG_RESOLVE_EXCEEDED_RETRY_COUNT
#define message(type, str)
static const char * month_names[]
static char * addenv(struct cgi_env_block *block, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(2
bool mg_start_task(int priority, int stack_size, mg_init_cb mg_init)
char * inet_ntoa(struct in_addr n)
static void mg_task(void *arg)
const char * inet_ntop(int af, const void *src, char *dst, socklen_t size)
int inet_pton(int af, const char *src, void *dst)
static int mg_is_error(void)
void mg_run_in_task(void(*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg)
#define MG_DISABLE_HTTP_KEEP_ALIVE
int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic)
#define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src)
static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data, size_t *chunk_len)
mg_http_multipart_stream_state
@ MPS_WAITING_FOR_BOUNDARY
int _kill(int pid, int sig)
MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm)
static void mg_send_directory_listing(struct mg_connection *nc, const char *dir, struct http_message *hm, struct mg_serve_http_opts *opts)
static void do_ssi_exec(struct mg_connection *nc, char *tag)
MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm, const struct mg_serve_http_opts *opts, char **local_path, struct mg_str *remainder)
static void mg_http_free_proto_data_cgi(struct mg_http_proto_data_cgi *d)
static void mqtt_handler(struct mg_connection *nc, int ev, void *ev_data)
static void mg_recv_common(struct mg_connection *nc, void *buf, int len)
static int mg_resolve2(const char *host, struct in_addr *ina)
static void mg_handle_cgi(struct mg_connection *nc, const char *prog, const struct mg_str *path_info, const struct http_message *hm, const struct mg_serve_http_opts *opts)
static struct mg_http_proto_data * mg_http_get_proto_data(struct mg_connection *c)
static void mg_send_file_data(struct mg_connection *nc, FILE *fp)
#define MG_WS_NO_HOST_HEADER_MAGIC
MG_INTERNAL void mg_remove_conn(struct mg_connection *c)
static void mg_resolve_async_eh(struct mg_connection *nc, int ev, void *data)
void mg_ev_mgr_add_conn(struct mg_connection *nc)
static const struct @23 mg_static_builtin_mime_types[]
#define MIME_ENTRY(_ext, _type)
MG_INTERNAL struct mg_connection * mg_create_connection_base(struct mg_mgr *mgr, mg_event_handler_t callback, struct mg_add_sock_opts opts)
MG_INTERNAL struct mg_connection * mg_create_connection(struct mg_mgr *mgr, mg_event_handler_t callback, struct mg_add_sock_opts opts)
MG_INTERNAL void mg_call(struct mg_connection *nc, mg_event_handler_t ev_handler, int ev, void *ev_data)
static int mg_recvfrom(struct mg_connection *nc, union socket_address *sa, socklen_t *sa_len, char **buf)
static void mg_write_to_socket(struct mg_connection *nc)
#define _MG_CALLBACK_MODIFIABLE_FLAGS_MASK
static int mg_create_itermediate_directories(const char *path)
MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path, const struct mg_str *path_info, struct http_message *hm, struct mg_serve_http_opts *opts)
static void dns_handler(struct mg_connection *nc, int ev, void *ev_data)
static void mg_websocket_handler(struct mg_connection *nc, int ev, void *ev_data)
#define MG_UDP_RECV_BUFFER_SIZE
static int parse_net(const char *spec, uint32_t *net, uint32_t *mask)
static void mg_http_construct_etag(char *buf, size_t buf_len, const cs_stat_t *st)
MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max)
static void mg_http_conn_destructor(void *proto_data)
MG_INTERNAL char mg_dns_server[300]
void _not_implemented(const char *what)
MG_INTERNAL time_t mg_parse_date_string(const char *datetime)
static void resolve_cb(struct mg_dns_message *msg, void *data, enum mg_resolve_err e)
static sock_t mg_open_listening_socket(union socket_address *sa, int proto)
static mg_event_handler_t mg_http_get_endpoint_handler(struct mg_connection *nc, struct mg_str *uri_path)
static int mg_dns_encode_name(struct mbuf *io, const char *name, size_t len)
static int mg_is_ws_first_fragment(unsigned char flags)
static int mg_remove_directory(const struct mg_serve_http_opts *opts, const char *dir)
static int mg_http_common_url_parse(const char *url, const char *schema, const char *schema_tls, int *use_ssl, char **addr, int *port_i, const char **path)
static int mg_check_nonce(const char *nonce)
static void mg_scan_directory(struct mg_connection *nc, const char *dir, const struct mg_serve_http_opts *opts, void(*func)(struct mg_connection *, const char *, cs_stat_t *))
static void mg_do_ssi_call(struct mg_connection *nc, char *tag)
static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name, cs_stat_t *stp)
static void mg_destroy_conn(struct mg_connection *conn)
#define _MG_ALLOWED_CONNECT_FLAGS_MASK
struct mg_connection * mg_connect_http_base(struct mg_mgr *mgr, mg_event_handler_t ev_handler, struct mg_connect_opts opts, const char *schema, const char *schema_ssl, const char *url, const char **path, char **addr)
static void mg_http_send_error(struct mg_connection *nc, int code, const char *reason)
static void mg_handle_udp_read(struct mg_connection *nc)
static int left(const struct frozen *f)
static void mg_handle_put(struct mg_connection *nc, const char *path, struct http_message *hm)
static const char * mg_http_parse_headers(const char *s, const char *end, int len, struct http_message *req)
static size_t mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len)
static void mg_escape(const char *src, char *dst, size_t dst_len)
static void mg_send_ssi_file(struct mg_connection *, const char *, FILE *, int, const struct mg_serve_http_opts *)
MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st)
static int mg_get_month_index(const char *s)
static uint32_t mg_ws_random_mask(void)
static void mg_sock_get_addr(sock_t sock, int remote, union socket_address *sa)
void mg_ev_mgr_remove_conn(struct mg_connection *nc)
static const char * mg_default_dns_server
MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa, int *proto, char *host, size_t host_len)
static void mg_http_free_proto_data_file(struct mg_http_proto_data_file *d)
#define _MG_F_FD_CAN_READ
static int mg_get_ip_address_of_nameserver(char *name, size_t name_len)
static void parse_uri_component(const char **p, const char *end, char sep, struct mg_str *res)
static int mg_is_dav_request(const struct mg_str *s)
static unsigned char * mg_parse_dns_resource_record(unsigned char *data, unsigned char *end, struct mg_dns_resource_record *rr, int reply)
static void mg_mgr_handle_ctl_sock(struct mg_mgr *mgr)
#define MG_SET_PTRPTR(_ptr, _v)
static char * mg_addenv(struct mg_cgi_env_block *block, const char *fmt,...)
static int lowercase(const char *s)
static void mg_read_from_socket(struct mg_connection *conn)
static void mg_ws_mask_frame(struct mbuf *mbuf, struct ws_mask_ctx *ctx)
static void mg_prepare_cgi_environment(struct mg_connection *nc, const char *prog, const struct mg_str *path_info, const struct http_message *hm, const struct mg_serve_http_opts *opts, struct mg_cgi_env_block *blk)
void mg_ev_mgr_init(struct mg_mgr *mgr)
static void mg_handle_incoming_websocket_frame(struct mg_connection *nc, struct websocket_message *wsm)
void mg_forward(struct mg_connection *from, struct mg_connection *to)
static int mg_is_file_hidden(const char *path, const struct mg_serve_http_opts *opts, int exclude_specials)
static void mg_handle_ssi_request(struct mg_connection *nc, const char *path, const struct mg_serve_http_opts *opts)
static int mg_http_get_request_len(const char *s, int buf_len)
MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc, struct http_message *hm, char *buf, size_t blen)
int _gettimeofday_r(struct _reent *r, struct timeval *tp, void *tzp)
static void mg_addenv2(struct mg_cgi_env_block *blk, const char *name)
void mg_set_non_blocking_mode(sock_t sock)
static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len, struct ws_mask_ctx *ctx)
static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a, int64_t *b)
static void mg_print_props(struct mg_connection *nc, const char *name, cs_stat_t *stp)
static pid_t mg_start_process(const char *interp, const char *cmd, const char *env, const char *envp[], const char *dir, sock_t sock)
static void mg_accept_conn(struct mg_connection *lc)
static void mg_http_send_file2(struct mg_connection *nc, const char *path, cs_stat_t *st, struct http_message *hm, struct mg_serve_http_opts *opts)
#define MG_TCP_RECV_BUFFER_SIZE
int gettimeofday(struct timeval *tp, void *tzp)
static int mg_is_ws_fragment(unsigned char flags)
MG_INTERNAL void mg_find_index_file(const char *path, const char *list, char **index_file, cs_stat_t *stp)
static int mg_deliver_websocket_data(struct mg_connection *nc)
MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c)
static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep)
static void mg_cgi_ev_handler(struct mg_connection *cgi_nc, int ev, void *ev_data)
#define _MG_F_FD_CAN_WRITE
static void mg_http_send_digest_auth_request(struct mg_connection *c, const char *domain)
static size_t mg_get_line_len(const char *buf, size_t buf_len)
MG_INTERNAL struct mg_connection * mg_do_connect(struct mg_connection *nc, int proto, union socket_address *sa)
static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev, struct http_message *hm)
static void mg_handle_mkcol(struct mg_connection *nc, const char *path, struct http_message *hm)
static void mg_http_transfer_file_data(struct mg_connection *nc)
static void mg_mkmd5resp(const char *method, size_t method_len, const char *uri, size_t uri_len, const char *ha1, size_t ha1_len, const char *nonce, size_t nonce_len, const char *nc, size_t nc_len, const char *cnonce, size_t cnonce_len, const char *qop, size_t qop_len, char *resp)
static int mg_is_authorized(struct http_message *hm, const char *path, int is_directory, const char *domain, const char *passwords_file, int is_global_pass_file)
void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data)
static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd, uint8_t flags, size_t len)
static int mg_http_send_port_based_redirect(struct mg_connection *c, struct http_message *hm, const struct mg_serve_http_opts *opts)
static void mg_handle_delete(struct mg_connection *nc, const struct mg_serve_http_opts *opts, const char *path)
static int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, FILE *fp)
void mg_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd)
void fprint_str(FILE *fp, const char *str)
static void mg_handle_move(struct mg_connection *c, const struct mg_serve_http_opts *opts, const char *path, struct http_message *hm)
static void mg_handle_propfind(struct mg_connection *nc, const char *path, cs_stat_t *stp, struct http_message *hm, struct mg_serve_http_opts *opts)
static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t)
static void mg_http_send_options(struct mg_connection *nc)
#define MG_DEFAULT_NAMESERVER
static void mg_ws_handshake(struct mg_connection *nc, const struct mg_str *key)
static int mg_is_creation_request(const struct http_message *hm)
void mg_ev_mgr_free(struct mg_mgr *mgr)
static int mg_num_leap_years(int year)
void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now)
static struct mg_str mg_get_mime_type(const char *path, const char *dflt, const struct mg_serve_http_opts *opts)
static void mg_send_mqtt_short_command(struct mg_connection *nc, uint8_t cmd, uint16_t message_id)
struct callback_addr callback
char message[MG_CTL_MSG_MESSAGE_SIZE]
mg_event_handler_t callback
const char * vars[MG_MAX_CGI_ENVIR_VARS]
struct mg_connection * nc
char buf[MG_CGI_ENVIRONMENT_SIZE]
mg_event_handler_t handler
struct mg_http_endpoint * next
enum mg_http_multipart_stream_state state
struct mg_connection * cgi_nc
enum mg_http_proto_data_type type
struct mg_http_proto_data_chuncked chunk
struct mg_http_endpoint * endpoints
struct mg_http_proto_data_cgi cgi
mg_event_handler_t endpoint_handler
struct mg_http_proto_data_file file
void(* cb)(struct mg_mgr *mgr, void *arg)
mg_resolve_callback_t callback
bool rmdir(HNDLE hDB, HNDLE hROOT, const char *path)
static double comma(double a, double b)
static te_expr * base(state *s)
static te_expr * list(state *s)