/** UDP receive callback for the sntp pcb */ static void sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { u8_t mode; u8_t stratum; u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE]; err_t err; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(pcb); /* packet received: stop retry timeout */ sys_untimeout(sntp_try_next_server, NULL); sys_untimeout(sntp_request, NULL); err = ERR_ARG; #if SNTP_CHECK_RESPONSE >= 1 /* Check server address and port */ if (ip_addr_cmp(addr, &sntp_last_server_address) && (port == SNTP_PORT)) #else /* SNTP_CHECK_RESPONSE >= 1 */ LWIP_UNUSED_ARG(addr); LWIP_UNUSED_ARG(port); #endif /* SNTP_CHECK_RESPONSE >= 1 */ { /* Process the response */ if (p->tot_len == SNTP_MSG_LEN) { pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE); mode &= SNTP_MODE_MASK; /* If this is a SNTP response... */ if ((mode == SNTP_MODE_SERVER) || (mode == SNTP_MODE_BROADCAST)) { pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM); if (stratum == SNTP_STRATUM_KOD) { /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ err = SNTP_ERR_KOD; LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n")); } else { #if SNTP_CHECK_RESPONSE >= 2 /* check originate_timetamp against sntp_last_timestamp_sent */ u32_t originate_timestamp[2]; pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME); if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) || (originate_timestamp[1] != sntp_last_timestamp_sent[1])) { LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n")); } else #endif /* SNTP_CHECK_RESPONSE >= 2 */ /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */ { /* Correct answer */ err = ERR_OK; pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_RECEIVE_TIME); } } } else { LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode)); } } else { LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len)); } } pbuf_free(p); if (err == ERR_OK) { /* Correct response, reset retry timeout */ SNTP_RESET_RETRY_TIMEOUT(); sntp_process(receive_timestamp); /* Set up timeout for next request */ sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL); LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n", (u32_t)SNTP_UPDATE_DELAY)); } else if (err == SNTP_ERR_KOD) { /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ sntp_try_next_server(NULL); } else { /* Another error, try the same server again */ sntp_retry(NULL); } }
/** * SNTP request */ static void sntp_request() { int sock; struct sockaddr_in local; struct sockaddr_in to; int tolen; int size; int timeout; u8_t sntp_request [SNTP_MAX_DATA_LEN]; u8_t sntp_response[SNTP_MAX_DATA_LEN]; u32_t sntp_server_address; u32_t timestamp; time_t t; /* initialize SNTP server address */ sntp_server_address = SNTP_SERVER_ADDRESS; /* if we got a valid SNTP server address... */ if (sntp_server_address!=0) { /* create new socket */ sock = socket( AF_INET, SOCK_DGRAM, 0); if (sock>=0) { /* prepare local address */ memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_port = htons(INADDR_ANY); local.sin_addr.s_addr = htonl(INADDR_ANY); /* bind to local address */ if (bind( sock, (struct sockaddr *)&local, sizeof(local))==0) { /* set recv timeout */ timeout = SNTP_RECV_TIMEOUT; setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); /* prepare SNTP request */ memset( sntp_request, 0, sizeof(sntp_request)); sntp_request[0] = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT; /* prepare SNTP server address */ memset(&to, 0, sizeof(to)); to.sin_family = AF_INET; to.sin_port = htons(SNTP_PORT); to.sin_addr.s_addr = sntp_server_address; /* send SNTP request to server */ if (sendto( sock, sntp_request, sizeof(sntp_request), 0, (struct sockaddr *)&to, sizeof(to))>=0) { /* receive SNTP server response */ tolen = sizeof(to); size = recvfrom( sock, sntp_response, sizeof(sntp_response), 0, (struct sockaddr *)&to, (socklen_t *)&tolen); /* if the response size is good */ if (size == SNTP_MAX_DATA_LEN) { /* if this is a SNTP response... */ if (((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_SERVER) || ((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_BROADCAST)) { /* extract GMT time from response */ SMEMCPY( ×tamp, (sntp_response+SNTP_RCV_TIME_OFS), sizeof(timestamp)); t = (ntohl(timestamp) - DIFF_SEC_1900_1970); /* do time processing */ sntp_process(t); } else { LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not response frame code\n")); } } else { LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not recvfrom==%i\n", errno)); } } else { LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not sendto==%i\n", errno)); } } /* close the socket */ closesocket(sock); } } }
/** * Send an SNTP request via sockets. * This is a very minimal implementation that does not fully conform * to the SNTPv4 RFC, especially regarding server load and error procesing. */ void sntp_request(void *arg) { int sock; struct sockaddr_in local; struct sockaddr_in to; int tolen; int size; int timeout; struct sntp_msg sntpmsg; ip_addr_t sntp_server_address; LWIP_UNUSED_ARG(arg); /* if we got a valid SNTP server address... */ if (ipaddr_aton(SNTP_SERVER_ADDRESS, &sntp_server_address)) { /* create new socket */ sock = lwip_socket(AF_INET, SOCK_DGRAM, 0); if (sock >= 0) { /* prepare local address */ memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_port = PP_HTONS(INADDR_ANY); local.sin_addr.s_addr = PP_HTONL(INADDR_ANY); /* bind to local address */ if (lwip_bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) { /* set recv timeout */ timeout = SNTP_RECV_TIMEOUT; lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); /* prepare SNTP request */ sntp_initialize_request(&sntpmsg); /* prepare SNTP server address */ memset(&to, 0, sizeof(to)); to.sin_family = AF_INET; to.sin_port = PP_HTONS(SNTP_PORT); inet_addr_from_ipaddr(&to.sin_addr, &sntp_server_address); /* send SNTP request to server */ if (lwip_sendto(sock, &sntpmsg, SNTP_MSG_LEN, 0, (struct sockaddr *)&to, sizeof(to)) >= 0) { /* receive SNTP server response */ tolen = sizeof(to); size = lwip_recvfrom(sock, &sntpmsg, SNTP_MSG_LEN, 0, (struct sockaddr *)&to, (socklen_t *)&tolen); /* if the response size is good */ if (size == SNTP_MSG_LEN) { /* if this is a SNTP response... */ if (((sntpmsg.li_vn_mode & SNTP_MODE_MASK) == SNTP_MODE_SERVER) || ((sntpmsg.li_vn_mode & SNTP_MODE_MASK) == SNTP_MODE_BROADCAST)) { /* do time processing */ sntp_process(sntpmsg.receive_timestamp); } else { LWIP_DEBUGF( SNTP_DEBUG_WARN, ("sntp_request: not response frame code\n")); } } } else { LWIP_DEBUGF( SNTP_DEBUG_WARN, ("sntp_request: not sendto==%i\n", errno)); } } /* close the socket */ closesocket(sock); } } }