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