1 /*
2  * FreeRTOS V202212.00
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * https://www.FreeRTOS.org
23  * https://github.com/FreeRTOS
24  *
25  */
26 
27 /*
28  * NTPDemo.c
29  *
30  * An example of how to lookup a domain using DNS
31  * And also how to send and receive UDP messages to get the NTP time
32  *
33  */
34 
35 /* Standard includes. */
36 #include <stdint.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <time.h>
40 
41 /* FreeRTOS includes. */
42 #include "FreeRTOS.h"
43 #include "task.h"
44 #include "semphr.h"
45 
46 /* FreeRTOS+TCP includes. */
47 #include "FreeRTOS_IP.h"
48 #include "FreeRTOS_Sockets.h"
49 #include "FreeRTOS_DNS.h"
50 #include "FreeRTOS_Stream_Buffer.h"
51 
52 /* Use the date & time functions from +FAT. */
53 #if ( USE_PLUS_FAT != 0 )
54     #include "ff_time.h"
55 #endif /* ( USE_PLUS_FAT != 0 ) */
56 
57 #include "NTPDemo.h"
58 #include "ntpClient.h"
59 
60 #include "date_and_time.h"
61 
62 #if ( ipconfigDNS_USE_CALLBACKS == 0 )
63     #error ipconfigDNS_USE_CALLBACKS must be 1
64 #endif
65 
66 #if ( ipconfigMULTI_INTERFACE == 0 )
67     #ifndef ipSIZE_OF_IPv4_ADDRESS
68         #define ipSIZE_OF_IPv4_ADDRESS    4
69     #endif
70     #define FREERTOS_AF_INET4             FREERTOS_AF_INET
71 #endif
72 
73 /* Set time: sets the current time in seconds-after-1/1/1970
74  * This function must be provided by the application. */
75 
76 time_t get_time( time_t * puxTime );
77 int set_time( const time_t * t );
78 
79 enum EStatus
80 {
81     EStatusLookup,
82     EStatusAsking,
83     EStatusPause,
84     EStatusFailed,
85 };
86 
87 static struct SNtpPacket xNTPPacket;
88 
89 BaseType_t xNTPHasTime;
90 uint32_t ulNTPTime;
91 
92 #if ( ipconfigUSE_CALLBACKS == 0 )
93     static char cRecvBuffer[ sizeof( struct SNtpPacket ) + 64 ];
94 #endif
95 
96 static enum EStatus xStatus = EStatusLookup;
97 
98 static const char * pcTimeServers[] =
99 {
100     "0.asia.pool.ntp.org",
101     "0.europe.pool.ntp.org",
102     "0.id.pool.ntp.org",
103     "0.south-america.pool.ntp.org",
104     "0.oceania.pool.ntp.org",
105     "0.north-america.pool.ntp.org"
106 };
107 
108 static SemaphoreHandle_t xNTPWakeupSem = NULL;
109 static uint32_t ulIPAddressFound;
110 
111 #if ( ipconfigUSE_IPv6 != 0 )
112     static struct freertos_sockaddr xIPAddressFound;
113 #endif
114 static BaseType_t xHasIPAddress = pdFALSE;
115 
116 static Socket_t xUDPSocket = NULL;
117 static TaskHandle_t xNTPTaskhandle = NULL;
118 static TickType_t uxSendTime;
119 static BaseType_t xPreferredHostType = FREERTOS_AF_INET4;
120 static BaseType_t xDNSAsynchronous = pdTRUE;
121 static BaseType_t xDNSLogging = pdFALSE;
122 
123 static void prvNTPTask( void * pvParameters );
124 
vSignalTask(void)125 static void vSignalTask( void )
126 {
127     #if ( ipconfigUSE_CALLBACKS == 0 )
128         if( xUDPSocket != NULL )
129         {
130             /* Send a signal to the socket so that the
131              *  FreeRTOS_recvfrom will get interrupted. */
132             FreeRTOS_SignalSocket( xUDPSocket );
133         }
134         else
135     #endif
136 
137     if( xNTPWakeupSem != NULL )
138     {
139         xSemaphoreGive( xNTPWakeupSem );
140     }
141 }
142 
vNTPClearCache(void)143 void vNTPClearCache( void )
144 {
145     ulIPAddressFound = 0U;
146     #if ( ipconfigUSE_IPv6 != 0 )
147     {
148         memset( &( xIPAddressFound ), 0, sizeof xIPAddressFound );
149     }
150     #endif
151     xHasIPAddress = pdFALSE;
152 }
153 
vNTPSetNTPType(BaseType_t aIPType,BaseType_t xAsynchronous,BaseType_t xLogging)154 void vNTPSetNTPType( BaseType_t aIPType,
155                      BaseType_t xAsynchronous,
156                      BaseType_t xLogging )
157 {
158     switch( aIPType )
159     {
160         case 4:
161             xPreferredHostType = FREERTOS_AF_INET4;
162             break;
163 
164             #if ( ipconfigUSE_IPv6 != 0 )
165                 case 6:
166                     xPreferredHostType = FREERTOS_AF_INET6;
167                     break;
168             #endif
169         default:
170             break;
171     }
172 
173     xDNSAsynchronous = xAsynchronous;
174     xDNSLogging = xLogging;
175 }
176 
vStartNTPTask(uint16_t usTaskStackSize,UBaseType_t uxTaskPriority)177 void vStartNTPTask( uint16_t usTaskStackSize,
178                     UBaseType_t uxTaskPriority )
179 {
180     /* The only public function in this module: start a task to contact
181      * some NTP server. */
182 
183     if( xNTPTaskhandle != NULL )
184     {
185         switch( xStatus )
186         {
187             case EStatusPause:
188                 xStatus = EStatusAsking;
189                 vSignalTask();
190                 break;
191 
192             case EStatusLookup:
193                 FreeRTOS_printf( ( "NTP looking up server\n" ) );
194                 break;
195 
196             case EStatusAsking:
197                 FreeRTOS_printf( ( "NTP still asking\n" ) );
198                 break;
199 
200             case EStatusFailed:
201                 FreeRTOS_printf( ( "NTP failed somehow\n" ) );
202                 ulIPAddressFound = 0ul;
203                 xStatus = EStatusLookup;
204                 vSignalTask();
205                 break;
206         }
207     }
208     else
209     {
210         xUDPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
211 
212         if( xUDPSocket != NULL )
213         {
214             struct freertos_sockaddr xAddress;
215             #if ( ipconfigUSE_CALLBACKS != 0 )
216                 BaseType_t xReceiveTimeOut = pdMS_TO_TICKS( 0 );
217             #else
218                 BaseType_t xReceiveTimeOut = pdMS_TO_TICKS( 5000 );
219             #endif
220 
221             xAddress.sin_address.ulIP_IPv4 = 0ul;
222             xAddress.sin_port = FreeRTOS_htons( NTP_PORT );
223             xAddress.sin_family = FREERTOS_AF_INET;
224 
225             FreeRTOS_bind( xUDPSocket, &xAddress, sizeof( xAddress ) );
226             FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
227             xTaskCreate( prvNTPTask,                    /* The function that implements the task. */
228                          ( const char * ) "NTP client", /* Just a text name for the task to aid debugging. */
229                          usTaskStackSize,               /* The stack size is defined in FreeRTOSIPConfig.h. */
230                          NULL,                          /* The task parameter, not used in this case. */
231                          uxTaskPriority,                /* The priority assigned to the task is defined in FreeRTOSConfig.h. */
232                          &xNTPTaskhandle );             /* The task handle. */
233         }
234         else
235         {
236             FreeRTOS_printf( ( "Creating socket failed\n" ) );
237         }
238     }
239 }
240 /*-----------------------------------------------------------*/
241 
242 #if ( ipconfigUSE_IPv6 != 0 )
vDNS_callback(const char * pcName,void * pvSearchID,struct freertos_addrinfo * pxAddress)243     static void vDNS_callback( const char * pcName,
244                                void * pvSearchID,
245                                struct freertos_addrinfo * pxAddress )
246     {
247         xStatus = EStatusAsking;
248 
249         ( void ) pvSearchID;
250         ( void ) pcName;
251 
252         if( pxAddress == NULL )
253         {
254             FreeRTOS_printf( ( "DNS lookup timed out\n" ) );
255         }
256         else
257         {
258             if( pxAddress->ai_family == FREERTOS_AF_INET4 )
259             {
260                 char pcBuf[ 16 ];
261                 uint32_t ulIPAddress;
262 
263                 /* The DNS lookup has a result, or it has reached the time-out. */
264                 ulIPAddress = pxAddress->ai_addr->sin_address.ulIP_IPv4;
265                 FreeRTOS_inet_ntoa( ulIPAddress, pcBuf );
266                 FreeRTOS_printf( ( "vDNS_callback: IP address of %s found: %s\n", pcName, pcBuf ) );
267 
268                 /*			if( ulIPAddressFound == 0U ) */
269                 /*			{ */
270                 /*				ulIPAddressFound = FreeRTOS_inet_addr_quick( 162, 159, 200, 1 ); */
271                 /*			} */
272                 if( ulIPAddressFound != 0U )
273                 {
274                     memset( xIPAddressFound.sin_address.xIP_IPv6.ucBytes, 0, ipSIZE_OF_IPv6_ADDRESS );
275                     xHasIPAddress = pdTRUE;
276                 }
277             }
278             else if( pxAddress->ai_family == FREERTOS_AF_INET6 )
279             {
280                 /*  struct freertos_sockaddr * ai_addr */
281                 struct freertos_sockaddr * sockaddr6 = ( struct freertos_sockaddr * ) pxAddress->ai_addr;
282 
283                 xIPAddressFound.sin_len = sizeof( xIPAddressFound ); /* Ignored, still present for backward compatibility. */
284                 xIPAddressFound.sin_family = FREERTOS_AF_INET6;      /* Set to FREERTOS_AF_INET6. */
285                 xIPAddressFound.sin_port = FreeRTOS_htons( NTP_PORT );
286                 xIPAddressFound.sin_flowinfo = 0;                    /* IPv6 flow information. */
287                 memcpy( xIPAddressFound.sin_address.xIP_IPv6.ucBytes, sockaddr6->sin_address.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
288 
289                 FreeRTOS_printf( ( "vDNS_callback: using address %pip\n", xIPAddressFound.sin_address.xIP_IPv6.ucBytes ) );
290                 ulIPAddressFound = 0U;
291                 xHasIPAddress = pdTRUE;
292             }
293         }
294 
295         vSignalTask();
296     }
297 #else /* if ( ipconfigUSE_IPv6 != 0 ) */
vDNS_callback(const char * pcName,void * pvSearchID,uint32_t ulIPAddress)298     static void vDNS_callback( const char * pcName,
299                                void * pvSearchID,
300                                uint32_t ulIPAddress )
301     {
302         char pcBuf[ 16 ];
303 
304         /* The DNS lookup has a result, or it has reached the time-out. */
305         FreeRTOS_inet_ntoa( ulIPAddress, pcBuf );
306         FreeRTOS_printf( ( "IP address of %s found: %s\n", pcName, pcBuf ) );
307 
308         if( ulIPAddressFound == 0U )
309         {
310             ulIPAddressFound = ulIPAddress;
311         }
312 
313         /* For testing: in case DNS doesn't respond, still try some NTP server
314          * with a known IP-address. */
315 /*		if( ulIPAddressFound == 0U ) */
316 /*		{ */
317 /*			ulIPAddressFound = FreeRTOS_inet_addr_quick( 184, 105, 182, 7 ); */
318 /*			/ *		ulIPAddressFound = FreeRTOS_inet_addr_quick( 103, 242,  70, 4 );	* / */
319 /*		} */
320         if( ulIPAddressFound != 0U )
321         {
322             xHasIPAddress = pdTRUE;
323             xStatus = EStatusAsking;
324         }
325 
326         vSignalTask();
327     }
328 #endif /* if ( ipconfigUSE_IPv6 != 0 ) */
329 /*-----------------------------------------------------------*/
330 
prvSwapFields(struct SNtpPacket * pxPacket)331 static void prvSwapFields( struct SNtpPacket * pxPacket )
332 {
333     /* NTP messages are big-endian */
334     pxPacket->rootDelay = FreeRTOS_htonl( pxPacket->rootDelay );
335     pxPacket->rootDispersion = FreeRTOS_htonl( pxPacket->rootDispersion );
336 
337     pxPacket->referenceTimestamp.seconds = FreeRTOS_htonl( pxPacket->referenceTimestamp.seconds );
338     pxPacket->referenceTimestamp.fraction = FreeRTOS_htonl( pxPacket->referenceTimestamp.fraction );
339 
340     pxPacket->originateTimestamp.seconds = FreeRTOS_htonl( pxPacket->originateTimestamp.seconds );
341     pxPacket->originateTimestamp.fraction = FreeRTOS_htonl( pxPacket->originateTimestamp.fraction );
342 
343     pxPacket->receiveTimestamp.seconds = FreeRTOS_htonl( pxPacket->receiveTimestamp.seconds );
344     pxPacket->receiveTimestamp.fraction = FreeRTOS_htonl( pxPacket->receiveTimestamp.fraction );
345 
346     pxPacket->transmitTimestamp.seconds = FreeRTOS_htonl( pxPacket->transmitTimestamp.seconds );
347     pxPacket->transmitTimestamp.fraction = FreeRTOS_htonl( pxPacket->transmitTimestamp.fraction );
348 }
349 /*-----------------------------------------------------------*/
350 
prvNTPPacketInit()351 static void prvNTPPacketInit()
352 {
353     memset( &xNTPPacket, '\0', sizeof( xNTPPacket ) );
354 
355     xNTPPacket.flags = 0xDB;                /* value 0xDB : mode 3 (client), version 3, leap indicator unknown 3 */
356     xNTPPacket.poll = 10;                   /* 10 means 1 << 10 = 1024 seconds */
357     xNTPPacket.precision = 0xFA;            /* = 250 = 0.015625 seconds */
358     xNTPPacket.rootDelay = 0x5D2E;          /* 0x5D2E = 23854 or (23854/65535)= 0.3640 sec */
359     xNTPPacket.rootDispersion = 0x0008CAC8; /* 0x0008CAC8 = 8.7912  seconds */
360 
361     /* use the recorded NTP time */
362     time_t uxSecs = get_time( NULL );               /* apTime may be NULL, returns seconds */
363 
364     xNTPPacket.referenceTimestamp.seconds = uxSecs; /* Current time */
365     xNTPPacket.transmitTimestamp.seconds = uxSecs + 3;
366 
367     /* Transform the contents of the fields from native to big endian. */
368     prvSwapFields( &xNTPPacket );
369 }
370 /*-----------------------------------------------------------*/
371 
prvReadTime(struct SNtpPacket * pxPacket)372 static void prvReadTime( struct SNtpPacket * pxPacket )
373 {
374     #if ( USE_PLUS_FAT != 0 )
375         FF_TimeStruct_t xTimeStruct;
376     #else
377         struct tm xTimeStruct;
378     #endif
379 
380     time_t uxPreviousSeconds;
381     time_t uxPreviousMS;
382 
383     time_t uxCurrentSeconds;
384     time_t uxCurrentMS;
385 
386     const char * pcTimeUnit;
387     int32_t ilDiff;
388     TickType_t uxTravelTime;
389 
390     uxTravelTime = xTaskGetTickCount() - uxSendTime;
391 
392     /* Transform the contents of the fields from big to native endian. */
393     prvSwapFields( pxPacket );
394 
395     uxCurrentSeconds = pxPacket->receiveTimestamp.seconds - TIME1970;
396     uxCurrentMS = pxPacket->receiveTimestamp.fraction / 4294967;
397     uxCurrentSeconds += uxCurrentMS / 1000;
398     uxCurrentMS = uxCurrentMS % 1000;
399 
400     /* Get the last time recorded */
401     uxPreviousSeconds = FreeRTOS_get_secs_msec( &uxPreviousMS );
402 
403     /* Set the new time with precision in msec. * / */
404     FreeRTOS_set_secs_msec( &uxCurrentSeconds, &uxCurrentMS );
405 
406     if( uxCurrentSeconds >= uxPreviousSeconds )
407     {
408         ilDiff = ( int32_t ) ( uxCurrentSeconds - uxPreviousSeconds );
409     }
410     else
411     {
412         ilDiff = 0 - ( int32_t ) ( uxPreviousSeconds - uxCurrentSeconds );
413     }
414 
415     if( ( ilDiff < -5 ) || ( ilDiff > 5 ) )
416     {
417         /* More than 5 seconds difference. */
418         pcTimeUnit = "sec";
419     }
420     else
421     {
422         /* Less than or equal to 5 second difference. */
423         pcTimeUnit = "ms";
424         uint32_t ulLowest = ( uxCurrentSeconds <= uxPreviousSeconds ) ? uxCurrentSeconds : uxPreviousSeconds;
425         int32_t iCurMS = 1000 * ( uxCurrentSeconds - ulLowest ) + uxCurrentMS;
426         int32_t iPrevMS = 1000 * ( uxPreviousSeconds - ulLowest ) + uxPreviousMS;
427         ilDiff = iCurMS - iPrevMS;
428     }
429 
430     /*uxCurrentSeconds -= iTimeZone; */
431 
432     #if ( USE_PLUS_FAT != 0 )
433         FreeRTOS_gmtime_r( &uxCurrentSeconds, &xTimeStruct );
434     #else
435         extern struct tm * gmtime_r( const time_t * pxTime,
436                                      struct tm * tmStruct );
437         gmtime_r( &uxCurrentSeconds, &xTimeStruct );
438     #endif /* ( USE_PLUS_FAT != 0 ) */
439 
440     /*
441      *  378.067 [NTP client] NTP time: 9/11/2015 16:11:19.559 Diff -20 ms (289 ms)
442      *  379.441 [NTP client] NTP time: 9/11/2015 16:11:20.933 Diff 0 ms (263 ms)
443      */
444     /* NTP time: -858993460/-858993459/-858991560 -858993460:-858993460:-858993460.158 Diff 1607503255 sec (60 ms) */
445     FreeRTOS_printf( ( "NTP time: %u/%u/%02u %2u:%02u:%02u.%03u Diff %d %s (%lu ms)\n",
446                        ( unsigned ) xTimeStruct.tm_mday,
447                        ( unsigned ) xTimeStruct.tm_mon + 1,
448                        ( unsigned ) xTimeStruct.tm_year + 1900,
449                        ( unsigned ) xTimeStruct.tm_hour,
450                        ( unsigned ) xTimeStruct.tm_min,
451                        ( unsigned ) xTimeStruct.tm_sec,
452                        ( unsigned ) uxCurrentMS,
453                        ( signed ) ilDiff,
454                        pcTimeUnit,
455                        uxTravelTime ) );
456 
457     xNTPHasTime = pdTRUE;
458     ulNTPTime = uxCurrentSeconds;
459     set_time( &uxCurrentSeconds );
460 
461     /* Remove compiler warnings in case FreeRTOS_printf() is not used. */
462     ( void ) pcTimeUnit;
463     ( void ) uxTravelTime;
464 }
465 /*-----------------------------------------------------------*/
466 
467 #if ( ipconfigUSE_CALLBACKS != 0 )
468 
xOnUDPReceive(Socket_t xSocket,void * pvData,size_t xLength,const struct freertos_sockaddr * pxFrom,const struct freertos_sockaddr * pxDest)469     static BaseType_t xOnUDPReceive( Socket_t xSocket,
470                                      void * pvData,
471                                      size_t xLength,
472                                      const struct freertos_sockaddr * pxFrom,
473                                      const struct freertos_sockaddr * pxDest )
474     {
475         ( void ) xSocket;
476         ( void ) pxFrom;
477         ( void ) pxDest;
478 
479         if( xLength >= sizeof( xNTPPacket ) )
480         {
481             prvReadTime( ( struct SNtpPacket * ) pvData );
482 
483             if( xStatus != EStatusPause )
484             {
485                 xStatus = EStatusPause;
486             }
487         }
488 
489         vSignalTask();
490         /* Tell the driver not to store the RX data */
491         return 1;
492     }
493     /*-----------------------------------------------------------*/
494 
495 #endif /* ipconfigUSE_CALLBACKS != 0 */
496 
prvNTPTask(void * pvParameters)497 static void prvNTPTask( void * pvParameters )
498 {
499     BaseType_t xServerIndex = 3;
500     struct freertos_sockaddr xAddress;
501 
502     #if ( ipconfigUSE_CALLBACKS != 0 )
503         F_TCP_UDP_Handler_t xHandler;
504     #endif /* ipconfigUSE_CALLBACKS != 0 */
505 
506     ( void ) pvParameters;
507 
508     xStatus = EStatusLookup;
509     #if ( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) || ( ipconfigUSE_CALLBACKS != 0 )
510     {
511         xNTPWakeupSem = xSemaphoreCreateBinary();
512     }
513     #endif
514 
515     #if ( ipconfigUSE_CALLBACKS != 0 )
516     {
517         memset( &xHandler, '\0', sizeof( xHandler ) );
518         xHandler.pxOnUDPReceive = xOnUDPReceive;
519         FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_UDP_RECV_HANDLER, ( void * ) &xHandler, sizeof( xHandler ) );
520     }
521     #endif
522     #if ( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 )
523     {
524         FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_SET_SEMAPHORE, ( void * ) &xNTPWakeupSem, sizeof( xNTPWakeupSem ) );
525     }
526     #endif
527 
528     for( ; ; )
529     {
530         switch( xStatus )
531         {
532             case EStatusLookup:
533 
534                 if( xHasIPAddress == 0 )
535                 {
536                     char pcServerName[ 64 ];
537 
538                     if( ++xServerIndex == sizeof( pcTimeServers ) / sizeof( pcTimeServers[ 0 ] ) )
539                     {
540                         xServerIndex = 0;
541                     }
542 
543                     snprintf( pcServerName, sizeof pcServerName, "%s", pcTimeServers[ xServerIndex ] );
544 
545                     if( ( pcServerName[ 0 ] == '0' ) && ( xPreferredHostType == FREERTOS_AF_INET6 ) )
546                     {
547                         pcServerName[ 0 ] = '2';
548                     }
549 
550                     FreeRTOS_printf( ( "Looking up server '%s' IPv%c\n",
551                                        pcServerName,
552                                        ( xPreferredHostType == FREERTOS_AF_INET4 ) ? '4' : '6' ) );
553                     #if ( ipconfigMULTI_INTERFACE != 0 )
554                         struct freertos_addrinfo xHints;
555                         struct freertos_addrinfo * pxResults = NULL;
556 
557                         memset( &( xHints ), 0, sizeof xHints );
558                         xHints.ai_family = xPreferredHostType;
559 
560                         if( xDNSAsynchronous != 0 )
561                         {
562                             FreeRTOS_getaddrinfo_a( pcServerName,    /* The name of the node or device */
563                                                     NULL,            /* Ignored for now. */
564                                                     &( xHints ),     /* If not NULL: preferences. */
565                                                     &( pxResults ),  /* An allocated struct, containing the results. */
566                                                     vDNS_callback,
567                                                     ( void * ) NULL, /* An object or a reference. */
568                                                     pdMS_TO_TICKS( 2500U ) );
569                         }
570                         else
571                         {
572                             FreeRTOS_getaddrinfo( pcServerName,     /* The name of the node or device */
573                                                   NULL,             /* Ignored for now. */
574                                                   &( xHints ),      /* If not NULL: preferences. */
575                                                   &( pxResults ) ); /* An allocated struct, containing the results. */
576 
577                             if( pxResults != NULL )
578                             {
579                                 vDNS_callback( pcServerName, NULL, pxResults );
580                             }
581                         }
582                     #else /* if ( ipconfigMULTI_INTERFACE != 0 ) */
583                         FreeRTOS_gethostbyname_a( pcServerName, vDNS_callback, ( void * ) NULL, 1200 );
584                     #endif /* if ( ipconfigMULTI_INTERFACE != 0 ) */
585                 }
586                 else
587                 {
588                     xStatus = EStatusAsking;
589                 }
590 
591                 break;
592 
593             case EStatusAsking:
594                 prvNTPPacketInit();
595                 uxSendTime = xTaskGetTickCount();
596                 #if ( ipconfigUSE_IPv6 != 0 )
597                     if( memcmp( xIPAddressFound.sin_address.xIP_IPv6.ucBytes, FreeRTOS_in6addr_any.ucBytes, ipSIZE_OF_IPv6_ADDRESS ) != 0 )
598                     {
599                         FreeRTOS_printf( ( "Sending UDP message to %pip:%u\n",
600                                            xIPAddressFound.sin_address.xIP_IPv6.ucBytes,
601                                            FreeRTOS_ntohs( xIPAddressFound.sin_port ) ) );
602 
603                         FreeRTOS_sendto( xUDPSocket,
604                                          ( void * ) &xNTPPacket, sizeof( xNTPPacket ),
605                                          0,
606                                          ( const struct freertos_sockaddr * ) &( xIPAddressFound ),
607                                          sizeof( xIPAddressFound ) );
608                     }
609                     else
610                 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
611                 {
612                     xAddress.sin_address.ulIP_IPv4 = ulIPAddressFound;
613                     xAddress.sin_port = FreeRTOS_htons( NTP_PORT );
614                     xAddress.sin_family = FREERTOS_AF_INET;
615 
616                     FreeRTOS_printf( ( "Sending UDP message to %lxip:%u\n",
617                                        FreeRTOS_ntohl( ulIPAddressFound ),
618                                        FreeRTOS_ntohs( xAddress.sin_port ) ) );
619 
620                     FreeRTOS_sendto( xUDPSocket,
621                                      ( void * ) &xNTPPacket,
622                                      sizeof( xNTPPacket ),
623                                      0, &( xAddress ),
624                                      sizeof( xAddress ) );
625                 }
626 
627                 break;
628 
629             case EStatusPause:
630                 break;
631 
632             case EStatusFailed:
633                 break;
634         }
635 
636         #if ( ipconfigUSE_CALLBACKS != 0 )
637         {
638             xSemaphoreTake( xNTPWakeupSem, 5000 );
639         }
640         #else
641         {
642             uint32_t xAddressSize;
643             BaseType_t xReturned;
644 
645             xAddressSize = sizeof( xAddress );
646             xReturned = FreeRTOS_recvfrom( xUDPSocket, ( void * ) cRecvBuffer, sizeof( cRecvBuffer ), 0, &xAddress, &xAddressSize );
647 
648             switch( xReturned )
649             {
650                 case 0:
651                 case -pdFREERTOS_ERRNO_EAGAIN:
652                 case -pdFREERTOS_ERRNO_EINTR:
653                     break;
654 
655                 default:
656 
657                     if( xReturned < sizeof( xNTPPacket ) )
658                     {
659                         FreeRTOS_printf( ( "FreeRTOS_recvfrom: returns %ld\n", xReturned ) );
660                     }
661                     else
662                     {
663                         prvReadTime( ( struct SNtpPacket * ) cRecvBuffer );
664 
665                         if( xStatus != EStatusPause )
666                         {
667                             xStatus = EStatusPause;
668                         }
669                     }
670 
671                     break;
672             }
673         }
674         #endif /* if ( ipconfigUSE_CALLBACKS != 0 ) */
675     }
676 }
677 /*-----------------------------------------------------------*/
678