Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
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
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
esp
mongoose
Commits
9e517fde
Commit
9e517fde
authored
Nov 24, 2016
by
Alexander Alashkin
Committed by
Cesanta Bot
Nov 24, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement SNTP client
PUBLISHED_FROM=ac54bcbc81a9ee688e8b90e261172be76a9fbacd
parent
1ff61837
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
406 additions
and
0 deletions
+406
-0
Makefile
examples/sntp_client/Makefile
+3
-0
sntp_client.c
examples/sntp_client/sntp_client.c
+51
-0
mongoose.c
mongoose.c
+292
-0
mongoose.h
mongoose.h
+60
-0
No files found.
examples/sntp_client/Makefile
0 → 100644
View file @
9e517fde
PROG
=
sntp_client
MODULE_CFLAGS
=
-DMG_ENABLE_SNTP
include
../examples.mk
examples/sntp_client/sntp_client.c
0 → 100644
View file @
9e517fde
/*
* Copyright (c) 2016 Cesanta Software Limited
* All rights reserved
*/
#include "mongoose.h"
static
int
s_exit_flag
=
0
;
static
const
char
*
s_default_server
=
"pool.ntp.org"
;
static
void
ev_handler
(
struct
mg_connection
*
c
,
int
ev
,
void
*
ev_data
)
{
struct
mg_sntp_message
*
sm
=
(
struct
mg_sntp_message
*
)
ev_data
;
time_t
t
;
(
void
)
c
;
switch
(
ev
)
{
case
MG_SNTP_REPLY
:
t
=
time
(
NULL
);
fprintf
(
stdout
,
"Local time: %s"
,
ctime
(
&
t
));
t
=
(
time_t
)
sm
->
time
;
fprintf
(
stdout
,
"Time from %s: %s"
,
s_default_server
,
ctime
(
&
t
));
s_exit_flag
=
1
;
break
;
case
MG_SNTP_FAILED
:
fprintf
(
stderr
,
"Failed to get time
\n
"
);
s_exit_flag
=
1
;
break
;
}
}
int
main
()
{
struct
mg_mgr
mgr
;
struct
mg_connection
*
c
;
mg_mgr_init
(
&
mgr
,
NULL
);
c
=
mg_sntp_get_time
(
&
mgr
,
ev_handler
,
s_default_server
);
if
(
c
==
NULL
)
{
fprintf
(
stderr
,
"Failed to connect to %s
\n
"
,
s_default_server
);
return
-
1
;
}
while
(
s_exit_flag
==
0
)
{
mg_mgr_poll
(
&
mgr
,
1000
);
}
mg_mgr_free
(
&
mgr
);
return
0
;
}
mongoose.c
View file @
9e517fde
...
...
@@ -165,6 +165,16 @@ MG_INTERNAL int mg_get_errno(void);
MG_INTERNAL
void
mg_close_conn
(
struct
mg_connection
*
conn
);
MG_INTERNAL
int
mg_http_common_url_parse
(
const
char
*
url
,
const
char
*
schema
,
const
char
*
schema_tls
,
int
*
use_ssl
,
char
**
user
,
char
**
pass
,
char
**
addr
,
int
*
port_i
,
const
char
**
path
);
#if MG_ENABLE_SNTP
MG_INTERNAL
int
mg_sntp_parse_reply
(
const
char
*
buf
,
int
len
,
struct
mg_sntp_message
*
msg
);
#endif
#endif
/* CS_MONGOOSE_SRC_INTERNAL_H_ */
#ifdef MG_MODULE_LINES
#line 1 "common/cs_dbg.h"
...
...
@@ -11463,6 +11473,288 @@ void mg_tun_send_frame(struct mg_connection *ws, uint32_t stream_id,
#endif
/* MG_ENABLE_TUN */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/sntp.c"
#endif
/*
* Copyright (c) 2016 Cesanta Software Limited
* All rights reserved
*/
/* Amalgamated: #include "mongoose/src/internal.h" */
/* Amalgamated: #include "mongoose/src/sntp.h" */
/* Amalgamated: #include "mongoose/src/util.h" */
#if MG_ENABLE_SNTP
#define SNTP_TIME_OFFSET 2208988800
#ifndef SNTP_TIMEOUT
#define SNTP_TIMEOUT 10
#endif
#ifndef SNTP_ATTEMPTS
#define SNTP_ATTEMPTS 3
#endif
static
uint64_t
mg_get_sec
(
uint64_t
val
)
{
return
(
val
&
0xFFFFFFFF00000000
)
>>
32
;
}
static
uint64_t
mg_get_usec
(
uint64_t
val
)
{
uint64_t
tmp
=
(
val
&
0x00000000FFFFFFFF
);
tmp
*=
1000000
;
tmp
>>=
32
;
return
tmp
;
}
static
void
mg_ntp_to_tv
(
uint64_t
val
,
struct
timeval
*
tv
)
{
uint64_t
tmp
;
tmp
=
mg_get_sec
(
val
);
tmp
-=
SNTP_TIME_OFFSET
;
tv
->
tv_sec
=
tmp
;
tv
->
tv_usec
=
mg_get_usec
(
val
);
}
static
void
mg_get_ntp_ts
(
const
char
*
ntp
,
uint64_t
*
val
)
{
uint32_t
tmp
;
memcpy
(
&
tmp
,
ntp
,
sizeof
(
tmp
));
tmp
=
ntohl
(
tmp
);
*
val
=
(
uint64_t
)
tmp
<<
32
;
memcpy
(
&
tmp
,
ntp
+
4
,
sizeof
(
tmp
));
tmp
=
ntohl
(
tmp
);
*
val
|=
tmp
;
}
void
mg_sntp_send_request
(
struct
mg_connection
*
c
)
{
char
buf
[
48
]
=
{
0
};
/*
* header - 8 bit:
* LI (2 bit) - 3 (not in sync), VN (3 bit) - 4 (version),
* mode (3 bit) - 3 (client)
*/
buf
[
0
]
=
(
3
<<
6
)
|
(
4
<<
3
)
|
3
;
/*
* Next fields should be empty in client request
* stratum, 8 bit
* poll interval, 8 bit
* rrecision, 8 bit
* root delay, 32 bit
* root dispersion, 32 bit
* ref id, 32 bit
* ref timestamp, 64 bit
* originate Timestamp, 64 bit
* receive Timestamp, 64 bit
*/
/*
* convert time to sntp format (sntp starts from 00:00:00 01.01.1900)
* according to rfc868 it is 2208988800L sec
* this information is used to correct roundtrip delay
* but if local clock is absolutely broken (and doesn't work even
* as simple timer), it is better to disable it
*/
#ifndef MG_SNMP_NO_DELAY_CORRECTION
uint32_t
sec
;
sec
=
htonl
(
mg_time
()
+
SNTP_TIME_OFFSET
);
memcpy
(
&
buf
[
40
],
&
sec
,
sizeof
(
sec
));
#endif
mg_send
(
c
,
buf
,
sizeof
(
buf
));
}
#ifndef MG_SNMP_NO_DELAY_CORRECTION
static
uint64_t
mg_calculate_delay
(
uint64_t
t1
,
uint64_t
t2
,
uint64_t
t3
)
{
/* roundloop delay = (T4 - T1) - (T3 - T2) */
uint64_t
d1
=
((
mg_time
()
+
SNTP_TIME_OFFSET
)
*
1000000
)
-
(
mg_get_sec
(
t1
)
*
1000000
+
mg_get_usec
(
t1
));
uint64_t
d2
=
(
mg_get_sec
(
t3
)
*
1000000
+
mg_get_usec
(
t3
))
-
(
mg_get_sec
(
t2
)
*
1000000
+
mg_get_usec
(
t2
));
return
(
d1
>
d2
)
?
d1
-
d2
:
0
;
}
#endif
MG_INTERNAL
int
mg_sntp_parse_reply
(
const
char
*
buf
,
int
len
,
struct
mg_sntp_message
*
msg
)
{
uint8_t
hdr
;
uint64_t
orig_ts_T1
,
recv_ts_T2
,
trsm_ts_T3
,
delay
=
0
;
int
mode
;
struct
timeval
tv
;
(
void
)
orig_ts_T1
;
(
void
)
recv_ts_T2
;
if
(
len
<
48
)
{
return
-
1
;
}
hdr
=
buf
[
0
];
if
((
hdr
&
0x38
)
>>
3
!=
4
)
{
/* Wrong version */
return
-
1
;
}
mode
=
hdr
&
0x7
;
if
(
mode
!=
4
&&
mode
!=
5
)
{
/* Not a server reply */
return
-
1
;
}
memset
(
msg
,
0
,
sizeof
(
*
msg
));
msg
->
kiss_of_death
=
(
buf
[
1
]
==
0
);
/* Server asks to not send requests */
mg_get_ntp_ts
(
&
buf
[
40
],
&
trsm_ts_T3
);
#ifndef MG_SNMP_NO_DELAY_CORRECTION
mg_get_ntp_ts
(
&
buf
[
24
],
&
orig_ts_T1
);
mg_get_ntp_ts
(
&
buf
[
32
],
&
recv_ts_T2
);
delay
=
mg_calculate_delay
(
orig_ts_T1
,
recv_ts_T2
,
trsm_ts_T3
);
#endif
mg_ntp_to_tv
(
trsm_ts_T3
,
&
tv
);
msg
->
time
=
(
double
)
tv
.
tv_sec
+
(((
double
)
tv
.
tv_usec
+
delay
)
/
1000000
.
0
);
return
0
;
}
static
void
mg_sntp_handler
(
struct
mg_connection
*
c
,
int
ev
,
void
*
ev_data
)
{
struct
mbuf
*
io
=
&
c
->
recv_mbuf
;
struct
mg_sntp_message
msg
;
c
->
handler
(
c
,
ev
,
ev_data
);
switch
(
ev
)
{
case
MG_EV_RECV
:
{
if
(
mg_sntp_parse_reply
(
io
->
buf
,
io
->
len
,
&
msg
)
<
0
)
{
DBG
((
"Invalid SNTP packet received (%d)"
,
(
int
)
io
->
len
));
c
->
handler
(
c
,
MG_SNTP_MALFORMED_REPLY
,
NULL
);
}
else
{
c
->
handler
(
c
,
MG_SNTP_REPLY
,
(
void
*
)
&
msg
);
}
mbuf_remove
(
io
,
io
->
len
);
break
;
}
}
}
int
mg_set_protocol_sntp
(
struct
mg_connection
*
c
)
{
if
((
c
->
flags
&
MG_F_UDP
)
==
0
)
{
return
-
1
;
}
c
->
proto_handler
=
mg_sntp_handler
;
return
0
;
}
struct
mg_connection
*
mg_sntp_connect
(
struct
mg_mgr
*
mgr
,
mg_event_handler_t
event_handler
,
const
char
*
sntp_server_name
)
{
struct
mg_connection
*
c
=
NULL
;
char
url
[
100
],
*
p_url
=
url
;
const
char
*
proto
=
""
,
*
port
=
""
,
*
tmp
;
/* If port is not specified, use default (123) */
tmp
=
strchr
(
sntp_server_name
,
':'
);
if
(
tmp
!=
NULL
&&
*
(
tmp
+
1
)
==
'/'
)
{
tmp
=
strchr
(
tmp
+
1
,
':'
);
}
if
(
tmp
==
NULL
)
{
port
=
":123"
;
}
/* Add udp:// if needed */
if
(
strncmp
(
sntp_server_name
,
"udp://"
,
6
)
!=
0
)
{
proto
=
"udp://"
;
}
mg_asprintf
(
&
p_url
,
sizeof
(
url
),
"%s%s%s"
,
proto
,
sntp_server_name
,
port
);
c
=
mg_connect
(
mgr
,
p_url
,
event_handler
);
if
(
c
==
NULL
)
{
goto
cleanup
;
}
mg_set_protocol_sntp
(
c
);
cleanup:
if
(
p_url
!=
url
)
{
MG_FREE
(
p_url
);
}
return
c
;
}
struct
sntp_data
{
mg_event_handler_t
hander
;
int
count
;
};
static
void
mg_sntp_util_ev_handler
(
struct
mg_connection
*
c
,
int
ev
,
void
*
ev_data
)
{
struct
sntp_data
*
sd
=
(
struct
sntp_data
*
)
c
->
user_data
;
switch
(
ev
)
{
case
MG_EV_CONNECT
:
if
(
*
(
int
*
)
ev_data
!=
0
)
{
mg_call
(
c
,
sd
->
hander
,
MG_SNTP_FAILED
,
NULL
);
break
;
}
/* fallthrough */
case
MG_EV_TIMER
:
if
(
sd
->
count
<=
SNTP_ATTEMPTS
)
{
mg_sntp_send_request
(
c
);
mg_set_timer
(
c
,
mg_time
()
+
10
);
sd
->
count
++
;
}
else
{
mg_call
(
c
,
sd
->
hander
,
MG_SNTP_FAILED
,
NULL
);
c
->
flags
|=
MG_F_CLOSE_IMMEDIATELY
;
}
break
;
case
MG_SNTP_MALFORMED_REPLY
:
mg_call
(
c
,
sd
->
hander
,
MG_SNTP_FAILED
,
NULL
);
c
->
flags
|=
MG_F_CLOSE_IMMEDIATELY
;
break
;
case
MG_SNTP_REPLY
:
mg_call
(
c
,
sd
->
hander
,
MG_SNTP_REPLY
,
ev_data
);
c
->
flags
|=
MG_F_CLOSE_IMMEDIATELY
;
break
;
case
MG_EV_CLOSE
:
MG_FREE
(
c
->
user_data
);
c
->
user_data
=
NULL
;
break
;
}
}
struct
mg_connection
*
mg_sntp_get_time
(
struct
mg_mgr
*
mgr
,
mg_event_handler_t
event_handler
,
const
char
*
sntp_server_name
)
{
struct
mg_connection
*
c
;
struct
sntp_data
*
sd
=
(
struct
sntp_data
*
)
MG_CALLOC
(
1
,
sizeof
(
*
sd
));
if
(
sd
==
NULL
)
{
return
NULL
;
}
c
=
mg_sntp_connect
(
mgr
,
mg_sntp_util_ev_handler
,
sntp_server_name
);
if
(
c
==
NULL
)
{
MG_FREE
(
sd
);
return
NULL
;
}
sd
->
hander
=
event_handler
;
c
->
user_data
=
sd
;
return
c
;
}
#endif
/* MG_ENABLE_SNTP */
#ifdef MG_MODULE_LINES
#line 1 "common/platforms/cc3200/cc3200_libc.c"
#endif
/*
...
...
mongoose.h
View file @
9e517fde
...
...
@@ -2812,6 +2812,10 @@ struct { \
#define MG_ENABLE_TUN MG_ENABLE_HTTP_WEBSOCKET
#endif
#ifndef MG_ENABLE_SNTP
#define MG_ENABLE_SNTP 0
#endif
#endif
/* CS_MONGOOSE_SRC_FEATURES_H_ */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/net_if.h"
...
...
@@ -5591,3 +5595,59 @@ uint32_t mg_coap_compose(struct mg_coap_message *cm, struct mbuf *io);
#endif
/* MG_ENABLE_COAP */
#endif
/* CS_MONGOOSE_SRC_COAP_H_ */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/sntp.h"
#endif
/*
* Copyright (c) 2016 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_MONGOOSE_SRC_SNTP_H_
#define CS_MONGOOSE_SRC_SNTP_H_
#if MG_ENABLE_SNTP
#define MG_SNTP_EVENT_BASE 500
/*
* Received reply from time server. Event handler parameter contains
* pointer to mg_sntp_message structure
*/
#define MG_SNTP_REPLY (MG_SNTP_EVENT_BASE + 1)
/* Received malformed SNTP packet */
#define MG_SNTP_MALFORMED_REPLY (MG_SNTP_EVENT_BASE + 2)
/* Failed to get time from server (timeout etc) */
#define MG_SNTP_FAILED (MG_SNTP_EVENT_BASE + 3)
struct
mg_sntp_message
{
/* if server sends this flags, user should not send requests to it */
int
kiss_of_death
;
/* usual mg_time */
double
time
;
};
/* Establishes connection to given sntp server */
struct
mg_connection
*
mg_sntp_connect
(
struct
mg_mgr
*
mgr
,
mg_event_handler_t
event_handler
,
const
char
*
sntp_server_name
);
/* Sends time request to given connection */
void
mg_sntp_send_request
(
struct
mg_connection
*
c
);
/*
* Helper function
* Establishes connection to time server, tries to send request
* repeats sending SNTP_ATTEMPTS times every SNTP_TIMEOUT sec
* (if needed)
* See sntp_client example
*/
struct
mg_connection
*
mg_sntp_get_time
(
struct
mg_mgr
*
mgr
,
mg_event_handler_t
event_handler
,
const
char
*
sntp_server_name
);
#endif
#endif
/* CS_MONGOOSE_SRC_SNTP_H_ */
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