⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sntp.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:

  // 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 + -