📄 sntp.c
字号:
// Site-Local
mreq.ipv6mr_multiaddr.s6_addr[1]=0x05;
ret = setsockopt(fd6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
CYG_ASSERT(0 == ret, "setsockopt(IPV6_JOIN_GROUP) Site-Local");
// Global
mreq.ipv6mr_multiaddr.s6_addr[1]=0x0e;
ret = setsockopt(fd6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
CYG_ASSERT(0 == ret, "setsockopt(IPV6_JOIN_GROUP) Global");
memset(&local6,0,sizeof(local6));
local6.sin6_family = AF_INET6;
local6.sin6_len = sizeof(local6);
local6.sin6_port = serv->s_port;
local6.sin6_addr = in6addr_any;
ret = bind(fd6, (struct sockaddr *)&local6,sizeof(local6));
CYG_ASSERT(0 == ret, "Bind6 failed");
n = (n > fd6 ? n : fd6);
#endif
while (1) {
FD_ZERO(&readfds);
FD_SET(fd,&readfds);
#ifdef CYGPKG_NET_INET6
FD_SET(fd6,&readfds);
#endif
#ifdef CYGPKG_NET_SNTP_UNICAST
/* By default, we will let select() wait
* for SNTP_WAITPERIOD to receive a packet. This
* allows us to periodically wake up and check
* if new servers have been configured. However,
* if we are waiting to send an update request,
* we will set ptimeout to something more
* reasonable below.
*/
timeout.tv_sec = SNTP_WAITPERIOD;
timeout.tv_usec = 0;
ptimeout = &timeout;
/* If we've already set the time, then
* check to see if it's time to try and
* update it.
*/
if (NextTimeUpdate != 0)
{
current_time = time(NULL);
if (current_time < NextTimeUpdate)
{
/* Set the select() timeout to wake us
* up when it's time to send more
* requests.
*/
timeout.tv_sec = (SNTP_WAITPERIOD > (NextTimeUpdate - current_time)?
(NextTimeUpdate - current_time):SNTP_WAITPERIOD);
} else {
/* It's already time for us to update our time */
NextTimeUpdate = 0;
}
}
/* If we need to update our time and we have
* a list of NTP servers, then send out some
* time requests.
*/
if (NextTimeUpdate == 0 && (sntp_num_servers > 0))
{
/* Send an NTP request to each NTP server
* in our server list. Use version 3
* for v3 and v4 compatibility.
*/
memset(&ntp_pkt, 0, sizeof(ntp_pkt));
ntp_pkt.Control =
NTP_LI_NOLEAP |
NTP_MODE_SET(NTP_MODE_CLIENT) |
NTP_VERSION_SET(3);
/* Send a request packet to each of our
* configured servers.
*/
cyg_mutex_lock(&sntp_mutex);
for (i = 0; i < sntp_num_servers; i++)
{
/* Send the request packet using the
* appropriate protocol.
*/
ntp_pkt.TransmitTimestamp.Seconds =
htonl(TIME_LOCAL_TO_NTP(time(NULL)));
if (sntp_servers[i].sa_family == AF_INET)
{
sendto(fd, &ntp_pkt, sizeof(ntp_pkt), 0,
&sntp_servers[i], sntp_servers[i].sa_len);
#ifdef CYGPKG_NET_INET6
} else if (sntp_servers[i].sa_family == AF_INET6) {
sendto(fd6, &ntp_pkt, sizeof(ntp_pkt), 0,
&sntp_servers[i], sntp_servers[i].sa_len);
#endif
}
}
cyg_mutex_unlock(&sntp_mutex);
/* Set the NextTimeUpdate so that we don't
* send any more requests until the next
* poll period. And we've already configured
* the select() timeout above to wait for
* replies.
*/
NextTimeUpdate = time(NULL) + SNTP_WAITPERIOD;
}
#endif /* CYGPKG_NET_SNTP_UNICAST */
ret = select(n+1, &readfds, NULL, NULL, ptimeout);
CYG_ASSERT(-1 != ret, "Select");
#ifdef CYGPKG_NET_SNTP_UNICAST
/* If we timed out, then try resending requests */
if (ret == 0)
continue;
#endif /* CYGPKG_NET_SNTP_UNICAST */
len = sizeof(new_srv.addr);
if (FD_ISSET(fd,&readfds)) {
ret=recvfrom(fd,&ntp_pkt,sizeof(ntp_pkt),0,(struct sockaddr *)&new_srv.addr,&len);
}
#ifdef CYGPKG_NET_INET6
if (FD_ISSET(fd6,&readfds)) {
ret=recvfrom(fd6,&ntp_pkt,sizeof(ntp_pkt),0,(struct sockaddr *)&new_srv.addr,&len);
}
#endif
CYG_ASSERT(0 < ret,"recvfrom");
/* We expect at least enough bytes to fill the buffer */
if (ret < NTP_PACKET_MINLEN)
continue;
new_srv.version = NTP_VERSION_GET(&ntp_pkt);
new_srv.stratum = ntp_pkt.Stratum;
new_srv.timestamp = ntohl(ntp_pkt.TransmitTimestamp.Seconds);
mode = NTP_MODE_GET(&ntp_pkt);
/* Only support protocol versions 3 or 4 */
if (new_srv.version < 3 || new_srv.version > 4) {
CYG_TRACE1(1, "Unsupported version of NTP. Version %d",new_srv.version);
continue;
}
/* Only process broadcast and server packets */
if (mode != NTP_MODE_BROADCAST && mode != NTP_MODE_SERVER)
continue;
/* Is the packet from a better server than our current one */
if (is_better(&new_srv,&best_srv)) {
best_srv = new_srv;
/* Work out the difference between server and our time.
* TODO: Implement RFC2030 recommendations for
* calculating propagation delay between the client
* and server.
*/
new_time = TIME_NTP_TO_LOCAL(best_srv.timestamp);
current_time = time(NULL);
diff = current_time - new_time;
if (diff < 0)
diff = -diff;
if (diff > 2)
cyg_libc_time_settime(new_time);
}
#ifdef CYGPKG_NET_SNTP_UNICAST
NextTimeUpdate = time(NULL) + SNTP_UPDATEPERIOD;
#endif
}
}
/* Start the SNTP server */
void cyg_sntp_start(void) {
static char sntp_stack[CYGNUM_SNTP_STACK_SIZE];
static cyg_thread sntp_thread_data;
static cyg_handle_t sntp_handle;
/* Only initialize things once */
if (sntp_initialized)
return;
sntp_initialized = 1;
#ifdef CYGPKG_NET_SNTP_UNICAST
/* Initialize the SNTP mutex */
cyg_mutex_init(&sntp_mutex);
#endif
cyg_thread_create(CYGPKG_NET_THREAD_PRIORITY+1,
sntp_fn, // entry
0, // entry parameter
"SNTP Client", // Name
&sntp_stack, // stack
sizeof(sntp_stack), // stack size
&sntp_handle, // Handle
&sntp_thread_data); // Thread data structure
cyg_thread_resume(sntp_handle);
}
#ifdef CYGPKG_NET_SNTP_UNICAST
/*
* FUNCTION cyg_sntp_set_servers
*
* DESCRIPTION
* Sets the list of SNTP/NTP servers to use
* for SNTP unicast requests. The list is
* specified as a list of sockaddr structures
* and can contain both IPv4 and IPv6
* addresses and UDP port numbers.
*
* The server_list array must be maintained
* by the caller and must not be modified after
* it is registered by this function. The
* array can be unregistered by calling this
* function again with different parameters.
*
* NOTE: If cyg_sntp_start() has not been called
* already, and this function is called with a
* list of 1 or more servers, then cyg_sntp_start()
* will be called by this function to start the client.
*
* PARAMETERS
* server_list - Array of IPv4 and/or IPv6 sockaddr's
* num_servers - Number of sockaddr's in array (0 to disable)
*
* RETURN VALUES
* None
*/
void cyg_sntp_set_servers(struct sockaddr *server_list,
cyg_uint32 num_servers)
{
/* If we haven't already started the SNTP client, then
* start it now.
*/
if (!sntp_initialized)
{
/* If we haven't started already and we don't
* have a list of servers, then don't start
* anything up.
*/
if (num_servers == 0)
return;
cyg_sntp_start();
}
/* Get the server list mutex */
cyg_mutex_lock(&sntp_mutex);
/* Record the new server list */
sntp_num_servers = num_servers;
if (num_servers == 0) {
server_list = NULL;
} else {
/* reset the waiting time to force a new update <= SNTP_WAITPERIOD*/
NextTimeUpdate = 0;
}
sntp_servers = server_list;
/* Free the mutex */
cyg_mutex_unlock(&sntp_mutex);
}
#endif /* CYGPKG_NET_SNTP_UNICAST */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -