Webserver+3d print

Dependents:   Nucleo

Revision:
0:8918a71cdbe9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyclone_tcp/sntp/sntp_client.c	Sat Feb 04 18:15:49 2017 +0000
@@ -0,0 +1,354 @@
+/**
+ * @file sntp_client.c
+ * @brief SNTP client (Simple Network Time Protocol)
+ *
+ * @section License
+ *
+ * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
+ *
+ * This file is part of CycloneTCP Open.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * @section Description
+ *
+ * The Simple Network Time Protocol is used to synchronize computer clocks
+ * in the Internet. Refer to RFC 4330 for more details
+ *
+ * @author Oryx Embedded SARL (www.oryx-embedded.com)
+ * @version 1.7.6
+ **/
+
+//Switch to the appropriate trace level
+#define TRACE_LEVEL SNTP_TRACE_LEVEL
+
+//Dependencies
+#include "core/net.h"
+#include "sntp/sntp_client.h"
+#include "error.h"
+#include "debug.h"
+
+//Check TCP/IP stack configuration
+#if (SNTP_CLIENT_SUPPORT == ENABLED)
+
+
+/**
+ * @brief Retrieve current time from NTP server using SNTP protocol
+ * @param[in] interface Underlying network interface (optional parameter)
+ * @param[in] serverIpAddr IP address of the NTP server
+ * @param[out] timestamp Current time
+ * @return Error code
+ **/
+
+ error_t sntpClientGetTimestamp(NetInterface *interface,
+   const IpAddr *serverIpAddr, NtpTimestamp *timestamp)
+{
+   error_t error;
+   uint_t i;
+   systime_t timeout;
+   SntpClientContext context;
+
+   //Check parameters
+   if(serverIpAddr == NULL || timestamp == NULL)
+      return ERROR_INVALID_PARAMETER;
+
+   //Use default network interface?
+   if(interface == NULL)
+      interface = netGetDefaultInterface();
+
+   //Open a UDP socket
+   context.socket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP);
+   //Failed to open socket?
+   if(!context.socket)
+      return ERROR_OPEN_FAILED;
+
+   //Associate the socket with the relevant interface
+   error = socketBindToInterface(context.socket, interface);
+   //Any error to report?
+   if(error)
+   {
+      //Close socket
+      socketClose(context.socket);
+      //Return status code
+      return error;
+   }
+
+   //Only accept datagrams from the specified NTP server
+   error = socketConnect(context.socket, serverIpAddr, NTP_PORT);
+   //Any error to report?
+   if(error)
+   {
+      //Close socket
+      socketClose(context.socket);
+      //Return status code
+      return error;
+   }
+
+   //Initial timeout value
+   timeout = SNTP_CLIENT_INIT_TIMEOUT;
+
+   //Retransmission loop
+   for(i = 0; i < SNTP_CLIENT_MAX_RETRIES; i++)
+   {
+      //Send NTP request message
+      error = sntpSendRequest(&context);
+      //Failed to send message ?
+      if(error)
+         break;
+
+      //Wait for a valid NTP response message
+      error = sntpWaitForResponse(&context, timeout);
+      //Valid NTP response received?
+      if(!error)
+         break;
+
+      //The timeout value is doubled for each subsequent retransmission
+      timeout = MIN(timeout * 2, SNTP_CLIENT_MAX_TIMEOUT);
+   }
+
+   //Successful processing?
+   if(!error)
+   {
+      //Save server timestamp
+      timestamp->seconds = ntohl(context.message.transmitTimestamp.seconds);
+      timestamp->fraction = ntohl(context.message.transmitTimestamp.fraction);
+   }
+
+   //Close socket
+   socketClose(context.socket);
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Send NTP request using SNTP protocol
+ * @param[in] context SNTP client context
+ * @return Error code
+ **/
+
+error_t sntpSendRequest(SntpClientContext *context)
+{
+   size_t length;
+   NtpHeader *message;
+
+   //Point to the buffer where to format the NTP message
+   message = &context->message;
+
+   //Clear NTP message
+   memset(message, 0, sizeof(NtpHeader));
+
+   //Format NTP request
+   message->vn = NTP_VERSION_3;
+   message->mode = NTP_MODE_CLIENT;
+
+   //Time at which the NTP request was sent
+   context->t1 = osGetSystemTime();
+
+   //The Transmit Timestamp allows a simple calculation to determine the
+   //propagation delay between the server and client and to align the system
+   //clock generally within a few tens of milliseconds relative to the server
+   message->transmitTimestamp.seconds = 0;
+   message->transmitTimestamp.fraction = htonl(context->t1);
+
+   //Length of the NTP request
+   length = sizeof(NtpHeader);
+
+   //Debug message
+   TRACE_INFO("Sending NTP request message (%" PRIuSIZE " bytes)...\r\n", sizeof(NtpHeader));
+   //Dump NTP message
+   sntpDumpMessage(message, length);
+
+   //Send NTP request
+   return socketSend(context->socket, message, length, NULL, 0);
+}
+
+
+/**
+ * @brief Wait for a valid response from the NTP server
+ * @param[in] context Pointer to the SNTP client context
+ * @param[in] timeout Maximum time period to wait
+ * @return Error code
+ **/
+
+error_t sntpWaitForResponse(SntpClientContext *context, systime_t timeout)
+{
+   error_t error;
+   size_t length;
+   systime_t elapsedTime;
+
+   //Time elapsed since the NTP request was sent
+   elapsedTime = 0;
+
+   //Keep listening as long as the retransmission timeout has not been reached
+   while(elapsedTime < timeout)
+   {
+      //Adjust receive timeout
+      error = socketSetTimeout(context->socket, timeout - elapsedTime);
+      //Any error to report?
+      if(error)
+         break;
+
+      //Wait for a response from the NTP server
+      error = socketReceive(context->socket, &context->message,
+         sizeof(NtpHeader), &length, 0);
+
+      //Any datagram received?
+      if(!error)
+      {
+         //Time at which the response was received
+         context->t4 = osGetSystemTime();
+
+         //Parse incoming datagram
+         error = sntpParseResponse(context, &context->message, length);
+         //Valid NTP response message?
+         if(!error)
+            return NO_ERROR;
+      }
+
+      //Compute the time elapsed since the NTP request was sent
+      elapsedTime = osGetSystemTime() - context->t1;
+   }
+
+   //The timeout period elapsed
+   return ERROR_TIMEOUT;
+}
+
+
+/**
+ * @brief Parse NTP server response
+ * @param[in] context Pointer to the SNTP client context
+ * @param[in] message NTP response message to parse
+ * @param[in] length Length of the incoming NTP message
+ * @return Error code
+ **/
+
+error_t sntpParseResponse(SntpClientContext *context,
+   const NtpHeader *message, size_t length)
+{
+   //Ensure the NTP message is valid
+   if(length < sizeof(NtpHeader))
+      return ERROR_INVALID_MESSAGE;
+
+   //Debug message
+   TRACE_INFO("NTP response message received (%" PRIuSIZE " bytes)...\r\n", length);
+   //Dump NTP message
+   sntpDumpMessage(message, length);
+
+   //The server reply should be discarded if any of the VN, Stratum,
+   //or Transmit Timestamp fields is 0
+   if(!message->vn || !message->stratum)
+      return ERROR_INVALID_MESSAGE;
+   if(!message->transmitTimestamp.seconds || !message->transmitTimestamp.fraction)
+      return ERROR_INVALID_MESSAGE;
+
+   //The server reply should be discarded if the Mode field is
+   //not 4 (unicast) or 5 (broadcast)
+   if(message->mode != NTP_MODE_SERVER && message->mode != NTP_MODE_BROADCAST)
+      return ERROR_INVALID_MESSAGE;
+
+   //The Originate Timestamp in the server reply should match the
+   //Transmit Timestamp used in the client request
+   if(message->originateTimestamp.seconds != 0)
+      return ERROR_INVALID_TIMESTAMP;
+   if(message->originateTimestamp.fraction != htonl(context->t1))
+      return ERROR_INVALID_TIMESTAMP;
+
+   //The NTP response message is acceptable
+   return NO_ERROR;
+}
+
+
+/**
+ * @brief Dump NTP message for debugging purpose
+ * @param[in] message Pointer to the NTP message
+ * @param[in] length Length of the NTP message
+ **/
+
+void sntpDumpMessage(const NtpHeader *message, size_t length)
+{
+#if (SNTP_TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
+   uint8_t *p;
+   NtpAuthData* authData;
+
+   //Point to the beginning of the message
+   p = (uint8_t *) message;
+
+   //Check message length
+   if(length >= sizeof(NtpHeader))
+   {
+      //Dump NTP message
+      TRACE_DEBUG("  Mode = %" PRIu8 "\r\n", message->mode);
+      TRACE_DEBUG("  Version = %" PRIu8 "\r\n", message->vn);
+      TRACE_DEBUG("  Leap indicator = %" PRIu8 "\r\n", message->li);
+      TRACE_DEBUG("  Stratum = %" PRIu8 "\r\n", message->stratum);
+      TRACE_DEBUG("  Poll = %" PRIu8 "\r\n", message->poll);
+      TRACE_DEBUG("  Precision = %" PRId8 "\r\n", message->precision);
+      TRACE_DEBUG("  Root Delay = %" PRIu32 "\r\n", ntohl(message->rootDelay));
+      TRACE_DEBUG("  Root Dispersion = %" PRIu32 "\r\n", ntohl(message->rootDispersion));
+      TRACE_DEBUG("  Reference Identifier = %" PRIu32 "\r\n", ntohl(message->referenceIdentifier));
+
+      //Dump reference timestamp
+      TRACE_DEBUG("  ReferenceTimestamp\r\n");
+      sntpDumpTimestamp(&message->referenceTimestamp);
+
+      //Dump originate timestamp
+      TRACE_DEBUG("  Originate Timestamp\r\n");
+      sntpDumpTimestamp(&message->originateTimestamp);
+
+      //Dump receive timestamp
+      TRACE_DEBUG("  Receive Timestamp\r\n");
+      sntpDumpTimestamp(&message->receiveTimestamp);
+
+      //Dump transmit timestamp
+      TRACE_DEBUG("  Transmit Timestamp\r\n");
+      sntpDumpTimestamp(&message->transmitTimestamp);
+
+      //Advance data pointer
+      p += sizeof(NtpHeader);
+      length -= sizeof(NtpHeader);
+
+      //Any authentication data?
+      if(length >= sizeof(NtpAuthData))
+      {
+         //Point to the beginning of the authentication data
+         authData = (NtpAuthData *) p;
+
+         //Dump transmit timestamp
+         TRACE_DEBUG("  Key Identifier = %" PRIu32 "\r\n", ntohl(authData->keyIdentifier));
+         //Dump message digest
+         TRACE_DEBUG("  Message Digest\r\n");
+         TRACE_DEBUG_ARRAY("    ", authData->messageDigest, 16);
+      }
+   }
+#endif
+}
+
+
+/**
+ * @brief Dump NTP timestamp
+ * @param[in] timestamp Pointer to the NTP timestamp
+ **/
+
+void sntpDumpTimestamp(const NtpTimestamp *timestamp)
+{
+   //Dump seconds
+   TRACE_DEBUG("    Seconds = %" PRIu32 "\r\n", ntohl(timestamp->seconds));
+   //Dump fraction field
+   TRACE_DEBUG("    Fraction = %" PRIu32 "\r\n", ntohl(timestamp->fraction));
+}
+
+#endif
+