sntp.c

来自「eCos操作系统源码」· C语言 代码 · 共 550 行 · 第 1/2 页

C
550
字号
  // 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 + =
减小字号Ctrl + -
显示快捷键?