text: #include <stdlib.h>
  #include <netdb.h>
  #include <time.h>
  #include <unistd.h>
  #include <arpa/inet.h>
  #include <sys/socket.h>
  #include <poll.h>
  #include <string.h>
  #include <assert.h>
  #include "core_sntp_client.h"
  
  /* @[code_example_sntpdnsresolve] */
  /* Example POSIX implementation of SntpDnsReolve_t interface. */
  static bool resolveDns( const SntpServerInfo_t * pServerAddr,
                          uint32_t * pIpV4Addr )
  {
      bool status = false;
      int32_t dnsStatus = -1;
      struct addrinfo hints;
      struct addrinfo * pListHead = NULL;
  
      hints.ai_family = AF_UNSPEC;
  
      hints.ai_socktype = ( int32_t ) SOCK_STREAM;
      hints.ai_protocol = IPPROTO_TCP;
  
      dnsStatus = getaddrinfo( pServerAddr->pServerName, NULL, &hints, &pListHead );
  
      if( dnsStatus == 0 )
      {
          struct sockaddr_in * pAddrInfo = ( struct sockaddr_in * ) pListHead->ai_addr;
          inet_ntop( pAddrInfo->sin_family,
                     &pAddrInfo->sin_addr,
                     ( int8_t * ) pIpV4Addr,
                     INET_ADDRSTRLEN );
  
          status = true;
      }
  
      freeaddrinfo( pListHead );
  
      return status;
  }
  /* @[code_example_sntpdnsresolve] */
  
  /* @[code_example_networkcontext] */
  /* Example definition of NetworkContext_t for UDP socket operations. */
  struct NetworkContext
  {
      int udpSocket;
  };
  /* @[code_example_networkcontext] */
  
  /* @[code_example_udptransport_sendto] */
  /* Example POSIX implementation of the UdpTransportSendTo_t function of UDP transport interface. */
  static int32_t UdpTransport_Send( NetworkContext_t * pNetworkContext,
                                    uint32_t serverAddr,
                                    uint16_t serverPort,
                                    const void * pBuffer,
                                    uint16_t bytesToSend )
  {
      int32_t bytesSent = -1, pollStatus = 1;
      struct pollfd pollFds;
  
      pollFds.events = POLLOUT | POLLPRI;
      pollFds.revents = 0;
      pollFds.fd = pNetworkContext->udpSocket;
  
      /* Check if there is data to read from the socket. */
      pollStatus = poll( &pollFds, 1, 0 );
  
      if( pollStatus > 0 )
      {
          struct sockaddr_in addrInfo;
          addrInfo.sin_family = AF_INET;
          addrInfo.sin_port = htons( serverPort );
          addrInfo.sin_addr.s_addr = htonl( serverAddr );
  
          bytesSent = sendto( pNetworkContext->udpSocket,
                              pBuffer,
                              bytesToSend, 0,
                              ( const struct sockaddr * ) &addrInfo,
                              sizeof( addrInfo ) );
      }
      else if( pollStatus == 0 )
      {
          bytesSent = 0;
      }
  
      return bytesSent;
  }
  /* @[code_example_udptransport_sendto] */
  
  /* @[code_example_udptransport_recvfrom] */
  /* Example POSIX implementation of the UdpTransportRecvFrom_t function of UDP transport interface. */
  static int32_t UdpTransport_Recv( NetworkContext_t * pNetworkContext,
                                    uint32_t serverAddr,
                                    uint16_t serverPort,
                                    void * pBuffer,
                                    uint16_t bytesToRecv )
  {
      int32_t bytesReceived = -1, pollStatus = 1;
      struct pollfd pollFds;
  
      pollFds.events = POLLIN | POLLPRI;
      pollFds.revents = 0;
      pollFds.fd = pNetworkContext->udpSocket;
  
      /* Check if there is data to read from the socket. */
      pollStatus = poll( &pollFds, 1, 0 );
  
      if( pollStatus > 0 )
      {
          struct sockaddr_in addrInfo;
          addrInfo.sin_family = AF_INET;
          addrInfo.sin_port = htons( serverPort );
          addrInfo.sin_addr.s_addr = htonl( serverAddr );
          socklen_t addrLen = sizeof( addrInfo );
  
          bytesReceived = recvfrom( pNetworkContext->udpSocket, pBuffer,
                                    bytesToRecv, 0,
                                    ( struct sockaddr * ) &addrInfo,
                                    &addrLen );
      }
      else if( pollStatus == 0 )
      {
          bytesReceived = 0;
      }
  
      return bytesReceived;
  }
  /* @[code_example_udptransport_recvfrom] */
  
  /* @[code_example_sntpsettime] */
  /* Example implementation of the SntpSetTime_t interface for POSIX platforms. */
  static void sntpClient_SetTime( const SntpServerInfo_t * pTimeServer,
                                  const SntpTimestamp_t * pServerTime,
                                  int64_t clockOffsetMs,
                                  SntpLeapSecondInfo_t leapSecondInfo )
  {
      /* @[code_example_sntp_converttounixtime] */
      uint32_t unixSecs;
      uint32_t unixMs;
      SntpStatus_t status = Sntp_ConvertToUnixTime( pServerTime, &unixSecs, &unixMs );
  
      /* @[code_example_sntp_converttounixtime] */
      assert( status == SntpSuccess );
  
      struct timespec serverTime =
      {
          .tv_sec  = unixSecs,
          .tv_nsec = unixMs * 1000
      };
  
      clock_settime( CLOCK_REALTIME, &serverTime );
  }
  /* @[code_example_sntpsettime] */
  
  /* @[code_example_sntpgettime] */
  /* Example implementation of the SntpGetTime_t interface for POSIX platforms. */
  static void sntpClient_GetTime( SntpTimestamp_t * pCurrentTime )
  {
      struct timespec currTime;
  
      ( void ) clock_gettime( CLOCK_REALTIME, &currTime );
  
      pCurrentTime->seconds = currTime.tv_sec;
      pCurrentTime->fractions = ( currTime.tv_sec / 1000 ) * SNTP_FRACTION_VALUE_PER_MICROSECOND;
  }
  /* @[code_example_sntpgettime] */
  
  /* Configuration constants for the example SNTP client. */
  
  /* Following Time Servers are used for illustrating the usage of library API.
   * The library can be configured to use ANY time server, whether publicly available
   * time service like NTP Pool or a privately owned NTP server. */
  #define TEST_TIME_SERVER_1                      "0.pool.ntp.org"
  #define TEST_TIME_SERVER_2                      "1.pool.ntp.org"
  
  #define SERVER_RESPONSE_TIMEOUT_MS              3000
  #define TIME_REQUEST_SEND_WAIT_TIME_MS          2000
  #define TIME_REQUEST_RECEIVE_WAIT_TIME_MS       1000
  
  #define SYSTEM_CLOCK_FREQUENCY_TOLERANCE_PPM    500
  #define SYSTEM_CLOCK_DESIRED_ACCURACY_MS        300
  
  int main( void )
  {
      /* @[code_example_sntp_init] */
      /* Memory for network buffer. */
      uint8_t networkBuffer[ SNTP_PACKET_BASE_SIZE ];
  
      /* Create UDP socket. */
      NetworkContext_t udpContext;
  
      udpContext.udpSocket = socket( AF_INET, SOCK_DGRAM, 0 );
  
      /* Setup list of time servers. */
      SntpServerInfo_t pTimeServers[] =
      {
          {
              .port = SNTP_DEFAULT_SERVER_PORT,
              .pServerName = TEST_TIME_SERVER_1,
              .serverNameLen = strlen( TEST_TIME_SERVER_1 )
          },
          {
              .port = SNTP_DEFAULT_SERVER_PORT,
              .pServerName = TEST_TIME_SERVER_2,
              .serverNameLen = strlen( TEST_TIME_SERVER_2 )
          }
      };
  
      /* Set the UDP transport interface object. */
      UdpTransportInterface_t udpTransportIntf;
  
      udpTransportIntf.pUserContext = &udpContext;
      udpTransportIntf.sendTo = UdpTransport_Send;
      udpTransportIntf.recvFrom = UdpTransport_Recv;
  
      /* Context variable. */
      SntpContext_t context;
  
      /* Initialize context. */
      SntpStatus_t status = Sntp_Init( &context,
                                       pTimeServers,
                                       sizeof( pTimeServers ) / sizeof( SntpServerInfo_t ),
                                       SERVER_RESPONSE_TIMEOUT_MS,
                                       networkBuffer,
                                       SNTP_PACKET_BASE_SIZE,
                                       resolveDns,
                                       sntpClient_GetTime,
                                       sntpClient_SetTime,
                                       &udpTransportIntf,
                                       NULL );
  
      assert( status == SntpSuccess );
      /* @[code_example_sntp_init] */
  
      /* Calculate the polling interval period for the SNTP client. */
      /* @[code_example_sntp_calculatepollinterval] */
      uint32_t pollingIntervalPeriod;
  
      status = Sntp_CalculatePollInterval( SYSTEM_CLOCK_FREQUENCY_TOLERANCE_PPM,
                                           SYSTEM_CLOCK_DESIRED_ACCURACY_MS,
                                           &pollingIntervalPeriod );
      /* @[code_example_sntp_calculatepollinterval] */
      assert( status == SntpSuccess );
  
      /* Loop of SNTP client for period time synchronization. */
      /* @[code_example_sntp_send_receive] */
      while( 1 )
      {
          status = Sntp_SendTimeRequest( &context,
                                         rand() % UINT32_MAX,
                                         TIME_REQUEST_SEND_WAIT_TIME_MS );
          assert( status == SntpSuccess );
  
          do
          {
              status = Sntp_ReceiveTimeResponse( &context, TIME_REQUEST_RECEIVE_WAIT_TIME_MS );
          } while( status == SntpNoResponseReceived );
  
          assert( status == SntpSuccess );
  
          /* Delay of poll interval period before next time synchronization. */
          sleep( pollingIntervalPeriod );
      }
  
      /* @[code_example_sntp_send_receive] */
  
      return EXIT_SUCCESS;
  }
  