Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
M
mongoose
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
mongoose
Commits
af1aff7f
Commit
af1aff7f
authored
Feb 11, 2020
by
Sergey Lyubka
Browse files
Options
Browse Files
Download
Plain Diff
mongoose.h 6.17
parents
dce60c6d
517ef216
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
240 additions
and
123 deletions
+240
-123
struct_mg_connection.md
docs/c-api/mg_net.h/struct_mg_connection.md
+12
-6
mongoose.c
mongoose.c
+0
-0
mongoose.h
mongoose.h
+0
-0
mg_common.h
src/mg_common.h
+1
-20
mg_dns.c
src/mg_dns.c
+14
-10
mg_dns.h
src/mg_dns.h
+1
-0
mg_http.c
src/mg_http.c
+79
-47
mg_http.h
src/mg_http.h
+4
-1
mg_http_ssi.c
src/mg_http_ssi.c
+11
-3
mg_license.h
src/mg_license.h
+18
-0
mg_mqtt.c
src/mg_mqtt.c
+28
-6
mg_mqtt.h
src/mg_mqtt.h
+1
-1
mg_net.c
src/mg_net.c
+1
-1
mg_net.h
src/mg_net.h
+12
-6
mg_net_if_socket.c
src/mg_net_if_socket.c
+7
-8
mg_ssl_if.h
src/mg_ssl_if.h
+1
-1
mg_ssl_if_mbedtls.c
src/mg_ssl_if_mbedtls.c
+18
-12
mg_ssl_if_openssl.c
src/mg_ssl_if_openssl.c
+1
-1
unit_test.c
test/unit_test.c
+10
-0
amalgam.py
tools/amalgam.py
+21
-0
No files found.
docs/c-api/mg_net.h/struct_mg_connection.md
View file @
af1aff7f
...
...
@@ -16,9 +16,6 @@ signature: |
struct mbuf send_mbuf; /* Data scheduled for sending */
time_t last_io_time; /* Timestamp of the last socket IO */
double ev_timer_time; /* Timestamp of the future MG_EV_TIMER */
#if MG_ENABLE_SSL
void *ssl_if_data; /* SSL library data. */
#endif
mg_event_handler_t proto_handler; /* Protocol-specific event handler */
void *proto_data; /* Protocol-specific data */
void (*proto_data_destructor)(void *proto_data);
...
...
@@ -51,16 +48,25 @@ signature: |
/* Flags that are settable by user */
#define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */
#define MG_F_CLOSE_IMMEDIATELY (1 << 11) /* Disconnect */
#define MG_F_WEBSOCKET_NO_DEFRAG (1 << 12) /* Websocket specific */
#define MG_F_DELETE_CHUNK (1 << 13) /* HTTP specific */
/* Flags for protocol handlers */
#define MG_F_PROTO_1 (1 << 12)
#define MG_F_PROTO_2 (1 << 13)
#define MG_F_ENABLE_BROADCAST (1 << 14) /* Allow broadcast address usage */
#define MG_F_USER_1 (1 << 20) /* Flags left for application */
/* Flags left for application */
#define MG_F_USER_1 (1 << 20)
#define MG_F_USER_2 (1 << 21)
#define MG_F_USER_3 (1 << 22)
#define MG_F_USER_4 (1 << 23)
#define MG_F_USER_5 (1 << 24)
#define MG_F_USER_6 (1 << 25)
#if MG_ENABLE_SSL
void *ssl_if_data; /* SSL library data. */
#else
void *unused_ssl_if_data; /* To keep the size of the structure the same. */
#endif
};
---
...
...
mongoose.c
View file @
af1aff7f
This diff is collapsed.
Click to expand it.
mongoose.h
View file @
af1aff7f
This diff is collapsed.
Click to expand it.
src/mg_common.h
View file @
af1aff7f
/*
* Copyright (c) 2004-2013 Sergey Lyubka
* Copyright (c) 2013-2015 Cesanta Software Limited
* All rights reserved
*
* This software is dual-licensed: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. For the terms of this
* license, see <http://www.gnu.org/licenses/>.
*
* You are free to use this software under the terms of the GNU General
* Public License, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* Alternatively, you can license this software under a commercial
* license, as set out in <https://www.cesanta.com/license>.
*/
#ifndef CS_MONGOOSE_SRC_COMMON_H_
#define CS_MONGOOSE_SRC_COMMON_H_
#define MG_VERSION "6.1
5
"
#define MG_VERSION "6.1
7
"
/* Local tweaks, applied before any of Mongoose's own headers. */
#ifdef MG_LOCALS
...
...
src/mg_dns.c
View file @
af1aff7f
...
...
@@ -85,35 +85,39 @@ int mg_dns_copy_questions(struct mbuf *io, struct mg_dns_message *msg) {
return
mbuf_append
(
io
,
begin
,
end
-
begin
);
}
int
mg_dns_encode_name
(
struct
mbuf
*
io
,
const
char
*
name
,
size_t
len
)
{
int
mg_dns_encode_name
_s
(
struct
mbuf
*
io
,
struct
mg_str
name
)
{
const
char
*
s
;
unsigned
char
n
;
size_t
pos
=
io
->
len
;
do
{
if
((
s
=
strchr
(
name
,
'.'
))
==
NULL
)
{
s
=
name
+
len
;
if
((
s
=
mg_
strchr
(
name
,
'.'
))
==
NULL
)
{
s
=
name
.
p
+
name
.
len
;
}
if
(
s
-
name
>
127
)
{
if
(
s
-
name
.
p
>
127
)
{
return
-
1
;
/* TODO(mkm) cover */
}
n
=
s
-
name
;
/* chunk length */
n
=
s
-
name
.
p
;
/* chunk length */
mbuf_append
(
io
,
&
n
,
1
);
/* send length */
mbuf_append
(
io
,
name
,
n
);
mbuf_append
(
io
,
name
.
p
,
n
);
if
(
*
s
==
'.'
)
{
if
(
n
<
name
.
len
&&
*
s
==
'.'
)
{
n
++
;
}
name
+=
n
;
len
-=
n
;
}
while
(
*
s
!=
'\0'
);
name
.
p
+=
n
;
name
.
len
-=
n
;
}
while
(
name
.
len
>
0
);
mbuf_append
(
io
,
"
\0
"
,
1
);
/* Mark end of host name */
return
io
->
len
-
pos
;
}
int
mg_dns_encode_name
(
struct
mbuf
*
io
,
const
char
*
name
,
size_t
len
)
{
return
mg_dns_encode_name_s
(
io
,
mg_mk_str_n
(
name
,
len
));
}
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
)
{
...
...
src/mg_dns.h
View file @
af1aff7f
...
...
@@ -124,6 +124,7 @@ int mg_dns_encode_record(struct mbuf *io, struct mg_dns_resource_record *rr,
* Encodes a DNS name.
*/
int
mg_dns_encode_name
(
struct
mbuf
*
io
,
const
char
*
name
,
size_t
len
);
int
mg_dns_encode_name_s
(
struct
mbuf
*
io
,
struct
mg_str
name
);
/* Low-level: parses a DNS response. */
int
mg_parse_dns
(
const
char
*
buf
,
int
len
,
struct
mg_dns_message
*
msg
);
...
...
src/mg_http.c
View file @
af1aff7f
...
...
@@ -328,37 +328,53 @@ static const struct {
MIME_ENTRY
(
"asf"
,
"video/x-ms-asf"
),
MIME_ENTRY
(
"avi"
,
"video/x-msvideo"
),
MIME_ENTRY
(
"bmp"
,
"image/bmp"
),
{
NULL
,
0
,
NULL
}};
{
NULL
,
0
,
NULL
},
};
static
struct
mg_str
mg_get_mime_type
(
const
char
*
path
,
const
char
*
dflt
,
const
struct
mg_serve_http_opts
*
opts
)
{
const
char
*
ext
,
*
overrides
;
size_t
i
,
path_len
;
struct
mg_str
r
,
k
,
v
;
static
struct
mg_str
mg_get_mime_types_entry
(
struct
mg_str
path
)
{
size_t
i
;
for
(
i
=
0
;
mg_static_builtin_mime_types
[
i
].
extension
!=
NULL
;
i
++
)
{
if
(
path
.
len
<
mg_static_builtin_mime_types
[
i
].
ext_len
+
1
)
continue
;
struct
mg_str
ext
=
MG_MK_STR_N
(
mg_static_builtin_mime_types
[
i
].
extension
,
mg_static_builtin_mime_types
[
i
].
ext_len
);
struct
mg_str
pext
=
MG_MK_STR_N
(
path
.
p
+
(
path
.
len
-
ext
.
len
),
ext
.
len
);
if
(
pext
.
p
[
-
1
]
==
'.'
&&
mg_strcasecmp
(
ext
,
pext
)
==
0
)
{
return
mg_mk_str
(
mg_static_builtin_mime_types
[
i
].
mime_type
);
}
}
return
mg_mk_str
(
NULL
);
}
path_len
=
strlen
(
path
);
MG_INTERNAL
int
mg_get_mime_type_encoding
(
struct
mg_str
path
,
struct
mg_str
*
type
,
struct
mg_str
*
encoding
,
const
struct
mg_serve_http_opts
*
opts
)
{
const
char
*
ext
,
*
overrides
;
struct
mg_str
k
,
v
;
overrides
=
opts
->
custom_mime_types
;
while
((
overrides
=
mg_next_comma_list_entry
(
overrides
,
&
k
,
&
v
))
!=
NULL
)
{
ext
=
path
+
(
path_len
-
k
.
len
);
if
(
path_len
>
k
.
len
&&
mg_vcasecmp
(
&
k
,
ext
)
==
0
)
{
return
v
;
ext
=
path
.
p
+
(
path
.
len
-
k
.
len
);
if
(
path
.
len
>
k
.
len
&&
mg_vcasecmp
(
&
k
,
ext
)
==
0
)
{
*
type
=
v
;
return
1
;
}
}
for
(
i
=
0
;
mg_static_builtin_mime_types
[
i
].
extension
!=
NULL
;
i
++
)
{
ext
=
path
+
(
path_len
-
mg_static_builtin_mime_types
[
i
].
ext_len
);
if
(
path_len
>
mg_static_builtin_mime_types
[
i
].
ext_len
&&
ext
[
-
1
]
==
'.'
&&
mg_casecmp
(
ext
,
mg_static_builtin_mime_types
[
i
].
extension
)
==
0
)
{
r
.
p
=
mg_static_builtin_mime_types
[
i
].
mime_type
;
r
.
len
=
strlen
(
r
.
p
);
return
r
;
*
type
=
mg_get_mime_types_entry
(
path
);
/* Check for .html.gz, .js.gz, etc. */
if
(
mg_vcmp
(
type
,
"application/x-gunzip"
)
==
0
)
{
struct
mg_str
path2
=
mg_mk_str_n
(
path
.
p
,
path
.
len
-
3
);
struct
mg_str
type2
=
mg_get_mime_types_entry
(
path2
);
LOG
(
LL_ERROR
,
(
"'%.*s' '%.*s' '%.*s'"
,
(
int
)
path
.
len
,
path
.
p
,
(
int
)
path2
.
len
,
path2
.
p
,
(
int
)
type2
.
len
,
type2
.
p
));
if
(
type2
.
len
>
0
)
{
*
type
=
type2
;
*
encoding
=
mg_mk_str
(
"gzip"
);
}
}
r
.
p
=
dflt
;
r
.
len
=
strlen
(
r
.
p
);
return
r
;
return
(
type
->
len
>
0
);
}
#endif
...
...
@@ -1458,12 +1474,15 @@ static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a,
return
result
;
}
void
mg_http_serve_file
(
struct
mg_connection
*
nc
,
struct
http_message
*
hm
,
const
char
*
path
,
const
struct
mg_str
mime_type
,
const
struct
mg_str
extra_headers
)
{
void
mg_http_serve_file_internal
(
struct
mg_connection
*
nc
,
struct
http_message
*
hm
,
const
char
*
path
,
struct
mg_str
mime_type
,
struct
mg_str
encoding
,
struct
mg_str
extra_headers
)
{
struct
mg_http_proto_data
*
pd
=
mg_http_get_proto_data
(
nc
);
cs_stat_t
st
;
LOG
(
LL_DEBUG
,
(
"%p [%s] %.*s"
,
nc
,
path
,
(
int
)
mime_type
.
len
,
mime_type
.
p
));
LOG
(
LL_DEBUG
,
(
"%p [%s] %.*s %.*s"
,
nc
,
path
,
(
int
)
mime_type
.
len
,
mime_type
.
p
,
(
int
)
encoding
.
len
,
encoding
.
p
));
if
(
mg_stat
(
path
,
&
st
)
!=
0
||
(
pd
->
file
.
fp
=
mg_fopen
(
path
,
"rb"
))
==
NULL
)
{
int
code
,
err
=
mg_get_errno
();
switch
(
err
)
{
...
...
@@ -1502,8 +1521,9 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
}
else
{
status_code
=
206
;
cl
=
r2
-
r1
+
1
;
snprintf
(
range
,
sizeof
(
range
),
"Content-Range: bytes %"
INT64_FMT
"-%"
INT64_FMT
"/%"
INT64_FMT
"
\r\n
"
,
snprintf
(
range
,
sizeof
(
range
),
"Content-Range: bytes %"
INT64_FMT
"-%"
INT64_FMT
"/%"
INT64_FMT
"
\r\n
"
,
r1
,
r1
+
cl
-
1
,
(
int64_t
)
st
.
st_size
);
#if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \
_XOPEN_SOURCE >= 600
...
...
@@ -1528,13 +1548,6 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
mg_http_construct_etag
(
etag
,
sizeof
(
etag
),
&
st
);
mg_gmt_time_string
(
current_time
,
sizeof
(
current_time
),
&
t
);
mg_gmt_time_string
(
last_modified
,
sizeof
(
last_modified
),
&
st
.
st_mtime
);
/*
* Content length casted to size_t because:
* 1) that's the maximum buffer size anyway
* 2) ESP8266 RTOS SDK newlib vprintf cannot contain a 64bit arg at non-last
* position
* TODO(mkm): fix ESP8266 RTOS SDK
*/
mg_send_response_line_s
(
nc
,
status_code
,
extra_headers
);
mg_printf
(
nc
,
"Date: %s
\r\n
"
...
...
@@ -1544,17 +1557,29 @@ void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
"Connection: %s
\r\n
"
"Content-Length: %"
SIZE_T_FMT
"
\r\n
"
"%sEtag: %s
\r\n\r\n
"
,
"%s"
"Etag: %s
\r\n
"
,
current_time
,
last_modified
,
(
int
)
mime_type
.
len
,
mime_type
.
p
,
(
pd
->
file
.
keepalive
?
"keep-alive"
:
"close"
),
(
size_t
)
cl
,
range
,
etag
);
if
(
encoding
.
len
>
0
)
{
mg_printf
(
nc
,
"Content-Encoding: %.*s
\r\n
"
,
(
int
)
encoding
.
len
,
encoding
.
p
);
}
mg_send
(
nc
,
"
\r\n
"
,
2
);
pd
->
file
.
cl
=
cl
;
pd
->
file
.
type
=
DATA_FILE
;
mg_http_transfer_file_data
(
nc
);
}
}
void
mg_http_serve_file
(
struct
mg_connection
*
nc
,
struct
http_message
*
hm
,
const
char
*
path
,
const
struct
mg_str
mime_type
,
const
struct
mg_str
extra_headers
)
{
mg_http_serve_file_internal
(
nc
,
hm
,
path
,
mime_type
,
mg_mk_str
(
NULL
),
extra_headers
);
}
static
void
mg_http_serve_file2
(
struct
mg_connection
*
nc
,
const
char
*
path
,
struct
http_message
*
hm
,
struct
mg_serve_http_opts
*
opts
)
{
...
...
@@ -1564,8 +1589,12 @@ static void mg_http_serve_file2(struct mg_connection *nc, const char *path,
return
;
}
#endif
mg_http_serve_file
(
nc
,
hm
,
path
,
mg_get_mime_type
(
path
,
"text/plain"
,
opts
),
mg_mk_str
(
opts
->
extra_headers
));
struct
mg_str
type
=
MG_NULL_STR
,
encoding
=
MG_NULL_STR
;
if
(
!
mg_get_mime_type_encoding
(
mg_mk_str
(
path
),
&
type
,
&
encoding
,
opts
))
{
type
=
mg_mk_str
(
"text/plain"
);
}
mg_http_serve_file_internal
(
nc
,
hm
,
path
,
type
,
encoding
,
mg_mk_str
(
opts
->
extra_headers
));
}
#endif
...
...
@@ -1841,7 +1870,7 @@ void cs_md5(char buf[33], ...) {
va_list
ap
;
va_start
(
ap
,
buf
);
while
((
p
=
va_arg
(
ap
,
const
unsigned
char
*
)
)
!=
NULL
)
{
while
((
p
=
va_arg
(
ap
,
const
unsigned
char
*
))
!=
NULL
)
{
msgs
[
num_msgs
]
=
p
;
msg_lens
[
num_msgs
]
=
va_arg
(
ap
,
size_t
);
num_msgs
++
;
...
...
@@ -2472,13 +2501,13 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
*
p
++
=
DIRSEP
;
/* No NULs and DIRSEPs in the component (percent-encoded). */
for
(
i
=
0
;
i
<
component
.
len
;
i
++
,
p
++
)
{
if
(
*
p
==
'\0'
||
*
p
==
DIRSEP
if
(
*
p
==
'\0'
||
*
p
==
DIRSEP
#ifdef _WIN32
/* On Windows, "/" is also accepted, so check for that too. */
||
*
p
==
'/'
||
*
p
==
'/'
#endif
)
{
)
{
ok
=
0
;
break
;
}
...
...
@@ -2691,7 +2720,9 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
mg_http_send_error
(
nc
,
501
,
NULL
);
#endif
}
else
if
(
mg_is_not_modified
(
hm
,
&
st
))
{
mg_http_send_error
(
nc
,
304
,
"Not Modified"
);
/* Note: not using mg_http_send_error in order to keep connection alive */
/* Note: passing extra headers allow users to control session cookies */
mg_send_head
(
nc
,
304
,
0
,
opts
->
extra_headers
);
}
else
{
mg_http_serve_file2
(
nc
,
index_file
?
index_file
:
path
,
hm
,
opts
);
}
...
...
@@ -2824,7 +2855,7 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
#ifdef SPIFFS_ERR_FULL
||
mg_get_errno
()
==
SPIFFS_ERR_FULL
#endif
)
{
)
{
mg_printf
(
nc
,
"HTTP/1.1 413 Payload Too Large
\r\n
"
"Content-Type: text/plain
\r\n
"
...
...
@@ -2983,8 +3014,9 @@ struct mg_connection *mg_connect_http_opt(
if
(
path
.
len
==
0
)
path
=
mg_mk_str
(
"/"
);
if
(
host
.
len
==
0
)
host
=
mg_mk_str
(
""
);
mg_printf
(
nc
,
"%s %.*s HTTP/1.1
\r\n
Host: %.*s
\r\n
Content-Length: %"
SIZE_T_FMT
"
\r\n
%.*s%s
\r\n
%s"
,
mg_printf
(
nc
,
"%s %.*s HTTP/1.1
\r\n
Host: %.*s
\r\n
Content-Length: %"
SIZE_T_FMT
"
\r\n
%.*s%s
\r\n
%s"
,
(
post_data
[
0
]
==
'\0'
?
"GET"
:
"POST"
),
(
int
)
path
.
len
,
path
.
p
,
(
int
)
(
path
.
p
-
host
.
p
),
host
.
p
,
strlen
(
post_data
),
(
int
)
auth
.
len
,
(
auth
.
buf
==
NULL
?
""
:
auth
.
buf
),
extra_headers
,
post_data
);
...
...
@@ -3093,7 +3125,7 @@ static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
#if MG_ENABLE_HTTP_STREAMING_MULTIPART
||
ev
==
MG_EV_HTTP_MULTIPART_REQUEST
#endif
)
{
)
{
struct
mg_http_endpoint
*
ep
=
mg_http_get_endpoint_handler
(
nc
->
listener
,
&
hm
->
uri
);
if
(
ep
!=
NULL
)
{
...
...
src/mg_http.h
View file @
af1aff7f
...
...
@@ -12,8 +12,8 @@
#if MG_ENABLE_HTTP
#include "mg_net.h"
#include "common/mg_str.h"
#include "mg_net.h"
#ifdef __cplusplus
extern
"C"
{
...
...
@@ -120,6 +120,9 @@ struct mg_ssi_call_ctx {
#define MG_EV_HTTP_MULTIPART_REQUEST_END 125
#endif
#define MG_F_WEBSOCKET_NO_DEFRAG MG_F_PROTO_1
#define MG_F_DELETE_CHUNK MG_F_PROTO_2
/*
* Attaches a built-in HTTP event handler to the given connection.
* The user-defined event handler will receive following extra events:
...
...
src/mg_http_ssi.c
View file @
af1aff7f
...
...
@@ -170,7 +170,7 @@ MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc,
const
char
*
path
,
const
struct
mg_serve_http_opts
*
opts
)
{
FILE
*
fp
;
struct
mg_str
mime_type
;
struct
mg_str
mime_type
=
MG_NULL_STR
,
encoding
=
MG_NULL_STR
;
DBG
((
"%p %s"
,
nc
,
path
));
if
((
fp
=
mg_fopen
(
path
,
"rb"
))
==
NULL
)
{
...
...
@@ -178,12 +178,20 @@ MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc,
}
else
{
mg_set_close_on_exec
((
sock_t
)
fileno
(
fp
));
mime_type
=
mg_get_mime_type
(
path
,
"text/plain"
,
opts
);
if
(
!
mg_get_mime_type_encoding
(
mg_mk_str
(
path
),
&
mime_type
,
&
encoding
,
opts
))
{
mime_type
=
mg_mk_str
(
"text/plain"
);
}
mg_send_response_line
(
nc
,
200
,
opts
->
extra_headers
);
mg_printf
(
nc
,
"Content-Type: %.*s
\r\n
"
"Connection: close
\r\n
\r\n
"
,
"Connection: close
\r\n
"
,
(
int
)
mime_type
.
len
,
mime_type
.
p
);
if
(
encoding
.
len
>
0
)
{
mg_printf
(
nc
,
"Content-Encoding: %.*s
\r\n
"
,
(
int
)
encoding
.
len
,
encoding
.
p
);
}
mg_send
(
nc
,
"
\r\n
"
,
2
);
mg_send_ssi_file
(
nc
,
hm
,
path
,
fp
,
0
,
opts
);
fclose
(
fp
);
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
...
...
src/mg_license.h
0 → 100644
View file @
af1aff7f
/*
* Copyright (c) 2004-2013 Sergey Lyubka
* Copyright (c) 2013-2020 Cesanta Software Limited
* All rights reserved
*
* This software is dual-licensed: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. For the terms of this
* license, see <http://www.gnu.org/licenses/>.
*
* You are free to use this software under the terms of the GNU General
* Public License, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* Alternatively, you can license this software under a commercial
* license, as set out in <https://www.cesanta.com/license>.
*/
src/mg_mqtt.c
View file @
af1aff7f
...
...
@@ -10,6 +10,8 @@
#include "mg_internal.h"
#include "mg_mqtt.h"
#define MG_F_MQTT_PING_PENDING MG_F_PROTO_1
static
uint16_t
getu16
(
const
char
*
p
)
{
const
uint8_t
*
up
=
(
const
uint8_t
*
)
p
;
return
(
up
[
0
]
<<
8
)
+
up
[
1
];
...
...
@@ -23,7 +25,7 @@ static const char *scanto(const char *p, struct mg_str *s) {
MG_INTERNAL
int
parse_mqtt
(
struct
mbuf
*
io
,
struct
mg_mqtt_message
*
mm
)
{
uint8_t
header
;
size_t
len
=
0
,
len_len
=
0
;
uint32_t
len
,
len_len
;
/* must be 32-bit, see #1055 */
const
char
*
p
,
*
end
,
*
eop
=
&
io
->
buf
[
io
->
len
];
unsigned
char
lc
=
0
;
int
cmd
;
...
...
@@ -40,7 +42,7 @@ MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) {
len
+=
(
lc
&
0x7f
)
<<
7
*
len_len
;
len_len
++
;
if
(
!
(
lc
&
0x80
))
break
;
if
(
len_len
>
4
)
return
MG_MQTT_ERROR_MALFORMED_MSG
;
if
(
len_len
>
sizeof
(
len
)
)
return
MG_MQTT_ERROR_MALFORMED_MSG
;
}
end
=
p
+
len
;
...
...
@@ -172,6 +174,10 @@ static void mqtt_handler(struct mg_connection *nc, int ev,
}
break
;
}
if
(
mm
.
cmd
==
MG_MQTT_CMD_PINGRESP
)
{
LOG
(
LL_DEBUG
,
(
"Recv PINGRESP"
));
nc
->
flags
&=
~
MG_F_MQTT_PING_PENDING
;
}
nc
->
handler
(
nc
,
MG_MQTT_EVENT_BASE
+
mm
.
cmd
,
&
mm
MG_UD_ARG
(
user_data
));
mbuf_remove
(
io
,
len
);
...
...
@@ -182,10 +188,26 @@ static void mqtt_handler(struct mg_connection *nc, int ev,
struct
mg_mqtt_proto_data
*
pd
=
(
struct
mg_mqtt_proto_data
*
)
nc
->
proto_data
;
double
now
=
mg_time
();
if
(
pd
->
keep_alive
>
0
&&
pd
->
last_control_time
>
0
&&
(
now
-
pd
->
last_control_time
)
>
pd
->
keep_alive
)
{
LOG
(
LL_DEBUG
,
(
"Send PINGREQ"
));
mg_mqtt_ping
(
nc
);
if
(
pd
->
keep_alive
>
0
&&
pd
->
last_control_time
>
0
)
{
double
diff
=
(
now
-
pd
->
last_control_time
);
if
(
diff
>
pd
->
keep_alive
)
{
if
(
diff
<
1500000000
)
{
if
(
!
(
nc
->
flags
&
MG_F_MQTT_PING_PENDING
))
{
LOG
(
LL_DEBUG
,
(
"Send PINGREQ"
));
nc
->
flags
|=
MG_F_MQTT_PING_PENDING
;
mg_mqtt_ping
(
nc
);
}
else
{
LOG
(
LL_DEBUG
,
(
"Ping timeout"
));
nc
->
flags
|=
MG_F_CLOSE_IMMEDIATELY
;
}
}
else
{
/* Wall time has just been set. Avoid immediate ping,
* more likely than not it is not needed. The standard allows for
* 1.5X interval for ping requests, so even if were just about to
* send one, we should be ok waiting 0.4X more. */
pd
->
last_control_time
=
now
-
pd
->
keep_alive
*
0
.
6
;
}
}
}
break
;
}
...
...
src/mg_mqtt.h
View file @
af1aff7f
...
...
@@ -101,10 +101,10 @@ struct mg_mqtt_proto_data {
/* Message flags */
#define MG_MQTT_RETAIN 0x1
#define MG_MQTT_DUP 0x4
#define MG_MQTT_QOS(qos) ((qos) << 1)
#define MG_MQTT_GET_QOS(flags) (((flags) &0x6) >> 1)
#define MG_MQTT_SET_QOS(flags, qos) (flags) = ((flags) & ~0x6) | ((qos) << 1)
#define MG_MQTT_DUP 0x8
/* Connection flags */
#define MG_MQTT_CLEAN_SESSION 0x02
...
...
src/mg_net.c
View file @
af1aff7f
...
...
@@ -540,7 +540,7 @@ struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) {
nc
->
iface
=
lc
->
iface
;
if
(
lc
->
flags
&
MG_F_SSL
)
nc
->
flags
|=
MG_F_SSL
;
mg_add_conn
(
nc
->
mgr
,
nc
);
LOG
(
LL_DEBUG
,
(
"%p %p %d %
d"
,
lc
,
nc
,
nc
->
sock
,
(
int
)
nc
->
flags
));
LOG
(
LL_DEBUG
,
(
"%p %p %d %
#x"
,
lc
,
nc
,
(
int
)
nc
->
sock
,
(
int
)
nc
->
flags
));
return
nc
;
}
...
...
src/mg_net.h
View file @
af1aff7f
...
...
@@ -110,9 +110,6 @@ struct mg_connection {
struct
mbuf
send_mbuf
;
/* Data scheduled for sending */
time_t
last_io_time
;
/* Timestamp of the last socket IO */
double
ev_timer_time
;
/* Timestamp of the future MG_EV_TIMER */
#if MG_ENABLE_SSL
void
*
ssl_if_data
;
/* SSL library data. */
#endif
mg_event_handler_t
proto_handler
;
/* Protocol-specific event handler */
void
*
proto_data
;
/* Protocol-specific data */
void
(
*
proto_data_destructor
)(
void
*
proto_data
);
...
...
@@ -145,16 +142,25 @@ struct mg_connection {
/* Flags that are settable by user */
#define MG_F_SEND_AND_CLOSE (1 << 10)
/* Push remaining data and close */
#define MG_F_CLOSE_IMMEDIATELY (1 << 11)
/* Disconnect */
#define MG_F_WEBSOCKET_NO_DEFRAG (1 << 12)
/* Websocket specific */
#define MG_F_DELETE_CHUNK (1 << 13)
/* HTTP specific */
/* Flags for protocol handlers */
#define MG_F_PROTO_1 (1 << 12)
#define MG_F_PROTO_2 (1 << 13)
#define MG_F_ENABLE_BROADCAST (1 << 14)
/* Allow broadcast address usage */
#define MG_F_USER_1 (1 << 20)
/* Flags left for application */
/* Flags left for application */
#define MG_F_USER_1 (1 << 20)
#define MG_F_USER_2 (1 << 21)
#define MG_F_USER_3 (1 << 22)
#define MG_F_USER_4 (1 << 23)
#define MG_F_USER_5 (1 << 24)
#define MG_F_USER_6 (1 << 25)
#if MG_ENABLE_SSL
void
*
ssl_if_data
;
/* SSL library data. */
#else
void
*
unused_ssl_if_data
;
/* To keep the size of the structure the same. */
#endif
};
/*
...
...
src/mg_net_if_socket.c
View file @
af1aff7f
...
...
@@ -47,8 +47,8 @@ void mg_socket_if_connect_tcp(struct mg_connection *nc,
#endif
rc
=
connect
(
nc
->
sock
,
&
sa
->
sa
,
sizeof
(
sa
->
sin
));
nc
->
err
=
rc
<
0
&&
mg_is_error
()
?
mg_get_errno
()
:
0
;
DBG
((
"%p sock %d rc %d errno %d err %d"
,
nc
,
nc
->
sock
,
rc
,
mg_get_errno
()
,
nc
->
err
));
DBG
((
"%p sock %d rc %d errno %d err %d"
,
nc
,
(
int
)
nc
->
sock
,
rc
,
mg_get_errno
(),
nc
->
err
));
}
void
mg_socket_if_connect_udp
(
struct
mg_connection
*
nc
)
{
...
...
@@ -218,8 +218,8 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
int
worth_logging
=
fd_flags
!=
0
||
(
nc
->
flags
&
(
MG_F_WANT_READ
|
MG_F_WANT_WRITE
));
if
(
worth_logging
)
{
DBG
((
"%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d"
,
nc
,
nc
->
sock
,
fd_flags
,
nc
->
flags
,
(
int
)
nc
->
recv_mbuf
.
len
,
DBG
((
"%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d"
,
nc
,
(
int
)
nc
->
sock
,
fd_flags
,
nc
->
flags
,
(
int
)
nc
->
recv_mbuf
.
len
,
(
int
)
nc
->
send_mbuf
.
len
));
}
...
...
@@ -271,7 +271,7 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
if
(
fd_flags
&
_MG_F_FD_CAN_WRITE
)
mg_if_can_send_cb
(
nc
);
if
(
worth_logging
)
{
DBG
((
"%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d"
,
nc
,
nc
->
sock
,
DBG
((
"%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d"
,
nc
,
(
int
)
nc
->
sock
,
nc
->
flags
,
(
int
)
nc
->
recv_mbuf
.
len
,
(
int
)
nc
->
send_mbuf
.
len
));
}
}
...
...
@@ -279,8 +279,7 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
#if MG_ENABLE_BROADCAST
static
void
mg_mgr_handle_ctl_sock
(
struct
mg_mgr
*
mgr
)
{
struct
ctl_msg
ctl_msg
;
int
len
=
(
int
)
MG_RECV_FUNC
(
mgr
->
ctl
[
1
],
(
char
*
)
&
ctl_msg
,
sizeof
(
ctl_msg
),
0
);
int
len
=
(
int
)
MG_RECV_FUNC
(
mgr
->
ctl
[
1
],
(
char
*
)
&
ctl_msg
,
sizeof
(
ctl_msg
),
0
);
size_t
dummy
=
MG_SEND_FUNC
(
mgr
->
ctl
[
1
],
ctl_msg
.
message
,
1
,
0
);
DBG
((
"read %d from ctl socket"
,
len
));
(
void
)
dummy
;
/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 */
...
...
@@ -299,7 +298,7 @@ void mg_socket_if_sock_set(struct mg_connection *nc, sock_t sock) {
mg_set_non_blocking_mode
(
sock
);
mg_set_close_on_exec
(
sock
);
nc
->
sock
=
sock
;
DBG
((
"%p %d"
,
nc
,
sock
));
DBG
((
"%p %d"
,
nc
,
(
int
)
sock
));
}
void
mg_socket_if_init
(
struct
mg_iface
*
iface
)
{
...
...
src/mg_ssl_if.h
View file @
af1aff7f
...
...
@@ -15,7 +15,7 @@ extern "C" {
struct
mg_ssl_if_ctx
;
struct
mg_connection
;
void
mg_ssl_if_init
();
void
mg_ssl_if_init
(
void
);
enum
mg_ssl_if_result
{
MG_SSL_OK
=
0
,
...
...
src/mg_ssl_if_mbedtls.c
View file @
af1aff7f
...
...
@@ -44,7 +44,11 @@ struct mg_ssl_if_ctx {
mbedtls_ssl_context
*
ssl
;
mbedtls_x509_crt
*
cert
;
mbedtls_pk_context
*
key
;
#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
char
*
ca_chain_file
;
#else
mbedtls_x509_crt
*
ca_cert
;
#endif
struct
mbuf
cipher_suites
;
size_t
saved_len
;
};
...
...
@@ -52,7 +56,7 @@ struct mg_ssl_if_ctx {
/* Must be provided by the platform. ctx is struct mg_connection. */
extern
int
mg_ssl_if_mbed_random
(
void
*
ctx
,
unsigned
char
*
buf
,
size_t
len
);
void
mg_ssl_if_init
()
{
void
mg_ssl_if_init
(
void
)
{
LOG
(
LL_INFO
,
(
"%s"
,
MBEDTLS_VERSION_STRING_FULL
));
}
...
...
@@ -220,18 +224,17 @@ static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) {
MG_FREE
(
ctx
->
key
);
ctx
->
key
=
NULL
;
}
#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
MG_FREE
(
ctx
->
ca_chain_file
);
ctx
->
ca_chain_file
=
NULL
;
#else
if
(
ctx
->
ca_cert
!=
NULL
)
{
mbedtls_ssl_conf_ca_chain
(
ctx
->
conf
,
NULL
,
NULL
);
#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
if
(
ctx
->
conf
->
ca_chain_file
!=
NULL
)
{
MG_FREE
((
void
*
)
ctx
->
conf
->
ca_chain_file
);
ctx
->
conf
->
ca_chain_file
=
NULL
;
}
#endif
mbedtls_x509_crt_free
(
ctx
->
ca_cert
);
MG_FREE
(
ctx
->
ca_cert
);
ctx
->
ca_cert
=
NULL
;
}
#endif
}
enum
mg_ssl_if_result
mg_ssl_if_handshake
(
struct
mg_connection
*
nc
)
{
...
...
@@ -312,11 +315,11 @@ void mg_ssl_if_conn_free(struct mg_connection *nc) {
mbedtls_ssl_free
(
ctx
->
ssl
);
MG_FREE
(
ctx
->
ssl
);
}
mg_ssl_if_mbed_free_certs_and_keys
(
ctx
);
if
(
ctx
->
conf
!=
NULL
)
{
mbedtls_ssl_config_free
(
ctx
->
conf
);
MG_FREE
(
ctx
->
conf
);
}
mg_ssl_if_mbed_free_certs_and_keys
(
ctx
);
mbuf_free
(
&
ctx
->
cipher_suites
);
memset
(
ctx
,
0
,
sizeof
(
*
ctx
));
MG_FREE
(
ctx
);
...
...
@@ -328,12 +331,15 @@ static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
mbedtls_ssl_conf_authmode
(
ctx
->
conf
,
MBEDTLS_SSL_VERIFY_NONE
);
return
MG_SSL_OK
;
}
ctx
->
ca_cert
=
(
mbedtls_x509_crt
*
)
MG_CALLOC
(
1
,
sizeof
(
*
ctx
->
ca_cert
));
mbedtls_x509_crt_init
(
ctx
->
ca_cert
);
#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
ca_cert
=
strdup
(
ca_cert
);
mbedtls_ssl_conf_ca_chain_file
(
ctx
->
conf
,
ca_cert
,
NULL
);
ctx
->
ca_chain_file
=
strdup
(
ca_cert
);
if
(
ctx
->
ca_chain_file
==
NULL
)
return
MG_SSL_ERROR
;
if
(
mbedtls_ssl_conf_ca_chain_file
(
ctx
->
conf
,
ctx
->
ca_chain_file
,
NULL
)
!=
0
)
{
return
MG_SSL_ERROR
;
}
#else
ctx
->
ca_cert
=
(
mbedtls_x509_crt
*
)
MG_CALLOC
(
1
,
sizeof
(
*
ctx
->
ca_cert
));
mbedtls_x509_crt_init
(
ctx
->
ca_cert
);
if
(
mbedtls_x509_crt_parse_file
(
ctx
->
ca_cert
,
ca_cert
)
!=
0
)
{
return
MG_SSL_ERROR
;
}
...
...
src/mg_ssl_if_openssl.c
View file @
af1aff7f
...
...
@@ -21,7 +21,7 @@ struct mg_ssl_if_ctx {
size_t
identity_len
;
};
void
mg_ssl_if_init
()
{
void
mg_ssl_if_init
(
void
)
{
SSL_library_init
();
}
...
...
test/unit_test.c
View file @
af1aff7f
...
...
@@ -4590,6 +4590,15 @@ static const char *test_dns_encode(void) {
return
NULL
;
}
static
const
char
*
test_dns_encode_name
(
void
)
{
struct
mbuf
mb
;
mbuf_init
(
&
mb
,
0
);
ASSERT_EQ
(
mg_dns_encode_name
(
&
mb
,
"www.cesanta.com.net.org"
,
15
),
17
);
ASSERT_STREQ_NZ
(
mb
.
buf
,
"
\x03
"
"www"
"
\x07
"
"cesanta"
"
\x03
"
"com"
);
mbuf_free
(
&
mb
);
return
NULL
;
}
static
const
char
*
test_dns_uncompress
(
void
)
{
/*
* Order or string constants is important. Names being uncompressed
...
...
@@ -5781,6 +5790,7 @@ const char *tests_run(const char *filter) {
RUN_TEST
(
test_mqtt_broker
);
#endif
RUN_TEST
(
test_dns_encode
);
RUN_TEST
(
test_dns_encode_name
);
RUN_TEST
(
test_dns_uncompress
);
RUN_TEST
(
test_dns_decode
);
RUN_TEST
(
test_dns_decode_truncated
);
...
...
tools/amalgam.py
View file @
af1aff7f
...
...
@@ -59,6 +59,7 @@ parser.add_argument('--exportable-headers', dest="export", action='store_true',
help
=
'allow exporting internal headers'
)
parser
.
add_argument
(
'-I'
,
default
=
[
'.'
],
dest
=
'include_path'
,
help
=
'include path'
,
action
=
'append'
)
parser
.
add_argument
(
'sources'
,
nargs
=
'*'
,
help
=
'sources'
)
parser
.
add_argument
(
'--license'
,
dest
=
"license"
,
help
=
'License file'
)
class
File
(
object
):
def
__init__
(
self
,
name
,
parent_name
):
...
...
@@ -121,7 +122,22 @@ def emit_body(out, name, parent_name):
return
with
open
(
resolved_name
)
as
f
:
in_comment
=
False
comment
=
''
for
l
in
f
:
if
in_comment
:
comment
+=
l
if
re
.
match
(
'
\
s*
\
*/$'
,
l
):
in_comment
=
False
if
not
re
.
match
(
'.*Copyright.*Cesanta'
,
comment
,
re
.
M
|
re
.
S
):
print
>>
out
,
comment
,
continue
if
re
.
match
(
'/
\
*$'
,
l
):
in_comment
=
True
comment
=
l
continue
match
=
re
.
match
(
'( *#include "(.*)")'
,
l
)
if
match
:
all
,
path_to_include
=
match
.
groups
()
...
...
@@ -155,6 +171,11 @@ if sys.platform == "win32":
import
os
,
msvcrt
msvcrt
.
setmode
(
sys
.
stdout
.
fileno
(),
os
.
O_BINARY
)
if
args
.
license
:
with
open
(
args
.
license
)
as
f
:
print
f
.
read
()
if
args
.
public
:
print
'#include "
%
s"'
%
(
args
.
public
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment