xref: /FreeRTOS-Plus-TCP-v3.1.0/source/FreeRTOS_DNS_Callback.c (revision 37bdfe577f3b728058de714e2e747d3c78803f26)
1 /*
2  * FreeRTOS+TCP V3.1.0
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 FreeRTOS_DNS_Callback.c
30  * @brief File that handles the DNS Callback option
31  */
32 
33 #include "FreeRTOS_DNS_Callback.h"
34 
35 #include "FreeRTOS_IP.h"
36 #include "FreeRTOS_IP_Private.h"
37 #include "FreeRTOS_DNS_Globals.h"
38 #include "FreeRTOS_IP_Timers.h"
39 
40 #if ( ( ipconfigDNS_USE_CALLBACKS == 1 ) && ( ipconfigUSE_DNS != 0 ) )
41 
42 /**
43  * @brief list of callbacks to send
44  */
45     static List_t xCallbackList;
46 
47 /**
48  * @brief A DNS reply was received, see if there is any matching entry and
49  *        call the handler.
50  *
51  * @param[in] uxIdentifier: Identifier associated with the callback function.
52  * @param[in] pcName: The name associated with the callback function.
53  * @param[in] ulIPAddress: IP-address obtained from the DNS server.
54  *
55  * @return Returns pdTRUE if uxIdentifier was recognized.
56  */
xDNSDoCallback(TickType_t uxIdentifier,const char * pcName,uint32_t ulIPAddress)57     BaseType_t xDNSDoCallback( TickType_t uxIdentifier,
58                                const char * pcName,
59                                uint32_t ulIPAddress )
60     {
61         BaseType_t xResult = pdFALSE;
62         const ListItem_t * pxIterator;
63         const ListItem_t * xEnd = listGET_END_MARKER( &xCallbackList );
64 
65         vTaskSuspendAll();
66         {
67             for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
68                  pxIterator != ( const ListItem_t * ) xEnd;
69                  pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
70             {
71                 if( listGET_LIST_ITEM_VALUE( pxIterator ) == uxIdentifier )
72                 {
73                     DNSCallback_t * pxCallback = ( ( DNSCallback_t * )
74                                                    listGET_LIST_ITEM_OWNER( pxIterator ) );
75 
76                     pxCallback->pCallbackFunction( pcName, pxCallback->pvSearchID,
77                                                    ulIPAddress );
78                     ( void ) uxListRemove( &pxCallback->xListItem );
79                     vPortFree( pxCallback );
80 
81                     if( listLIST_IS_EMPTY( &xCallbackList ) != pdFALSE )
82                     {
83                         /* The list of outstanding requests is empty. No need for periodic polling. */
84                         vIPSetDNSTimerEnableState( pdFALSE );
85                     }
86 
87                     xResult = pdTRUE;
88                     break;
89                 }
90             }
91         }
92         ( void ) xTaskResumeAll();
93         return xResult;
94     }
95 
96 /**
97  * @brief FreeRTOS_gethostbyname_a() was called along with callback parameters.
98  *        Store them in a list for later reference.
99  *
100  * @param[in] pcHostName: The hostname whose IP address is being searched for.
101  * @param[in] pvSearchID: The search ID of the DNS callback function to set.
102  * @param[in] pCallbackFunction: The callback function pointer.
103  * @param[in] uxTimeout: Timeout of the callback function.
104  * @param[in] uxIdentifier: Random number used as ID in the DNS message.
105  */
vDNSSetCallBack(const char * pcHostName,void * pvSearchID,FOnDNSEvent pCallbackFunction,TickType_t uxTimeout,TickType_t uxIdentifier)106     void vDNSSetCallBack( const char * pcHostName,
107                           void * pvSearchID,
108                           FOnDNSEvent pCallbackFunction,
109                           TickType_t uxTimeout,
110                           TickType_t uxIdentifier )
111     {
112         size_t lLength = strlen( pcHostName );
113         DNSCallback_t * pxCallback = ( ( DNSCallback_t * ) pvPortMalloc( sizeof( *pxCallback ) + lLength ) );
114 
115         /* Translate from ms to number of clock ticks. */
116         uxTimeout /= portTICK_PERIOD_MS;
117 
118         if( pxCallback != NULL )
119         {
120             if( listLIST_IS_EMPTY( &xCallbackList ) != pdFALSE )
121             {
122                 /* This is the first one, start the DNS timer to check for timeouts */
123                 vDNSTimerReload( FreeRTOS_min_uint32( 1000U, uxTimeout ) );
124             }
125 
126             ( void ) strcpy( pxCallback->pcName, pcHostName );
127             pxCallback->pCallbackFunction = pCallbackFunction;
128             pxCallback->pvSearchID = pvSearchID;
129             pxCallback->uxRemainingTime = uxTimeout;
130             vTaskSetTimeOutState( &pxCallback->uxTimeoutState );
131             listSET_LIST_ITEM_OWNER( &( pxCallback->xListItem ), ( void * ) pxCallback );
132             listSET_LIST_ITEM_VALUE( &( pxCallback->xListItem ), uxIdentifier );
133             vTaskSuspendAll();
134             {
135                 vListInsertEnd( &xCallbackList, &pxCallback->xListItem );
136             }
137             ( void ) xTaskResumeAll();
138         }
139         else
140         {
141             FreeRTOS_debug_printf( ( " vDNSSetCallBack : Could not allocate memory: %u bytes",
142                                      ( unsigned ) ( sizeof( *pxCallback ) + lLength ) ) );
143         }
144     }
145 
146 /**
147  * @brief Iterate through the list of call-back structures and remove
148  *        old entries which have reached a timeout.
149  *        As soon as the list has become empty, the DNS timer will be stopped.
150  *        In case pvSearchID is supplied, the user wants to cancel a DNS request.
151  *
152  * @param[in] pvSearchID: The search ID of callback function whose associated
153  *                 DNS request is being cancelled. If non-ID specific checking of
154  *                 all requests is required, then this field should be kept as NULL.
155  */
vDNSCheckCallBack(void * pvSearchID)156     void vDNSCheckCallBack( void * pvSearchID )
157     {
158         const ListItem_t * pxIterator;
159         const ListItem_t * xEnd = listGET_END_MARKER( &xCallbackList );
160 
161         vTaskSuspendAll();
162         {
163             for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
164                  pxIterator != xEnd; )
165             {
166                 DNSCallback_t * pxCallback = ( ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
167                 /* Move to the next item because we might remove this item */
168                 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
169 
170                 if( ( pvSearchID != NULL ) && ( pvSearchID == pxCallback->pvSearchID ) )
171                 {
172                     ( void ) uxListRemove( &( pxCallback->xListItem ) );
173                     vPortFree( pxCallback );
174                 }
175                 else if( xTaskCheckForTimeOut( &pxCallback->uxTimeoutState, &pxCallback->uxRemainingTime ) != pdFALSE )
176                 {
177                     pxCallback->pCallbackFunction( pxCallback->pcName, pxCallback->pvSearchID, 0 );
178                     ( void ) uxListRemove( &( pxCallback->xListItem ) );
179                     vPortFree( pxCallback );
180                 }
181                 else
182                 {
183                     /* This call-back is still waiting for a reply or a time-out. */
184                 }
185             }
186         }
187         ( void ) xTaskResumeAll();
188 
189         if( listLIST_IS_EMPTY( &xCallbackList ) != pdFALSE )
190         {
191             vIPSetDNSTimerEnableState( pdFALSE );
192         }
193     }
194 
195 /**
196  * @brief initialize the cache
197  * @post will modify global list xCallbackList
198  */
vDNSCallbackInitialise()199     void vDNSCallbackInitialise()
200     {
201         vListInitialise( &xCallbackList );
202     }
203 #endif /* if ( ipconfigDNS_USE_CALLBACKS == 1 ) */
204