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