mirror of
				https://github.com/espressif/esp-protocols.git
				synced 2025-10-30 22:21:39 +01:00 
			
		
		
		
	
		
			
	
	
		
			189 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			189 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD | ||
|  |  * | ||
|  |  * SPDX-License-Identifier: Apache-2.0 | ||
|  |  */ | ||
|  | #include "esp_transport.h"
 | ||
|  | #include "esp_transport_tcp.h"
 | ||
|  | #include "esp_dns_priv.h"
 | ||
|  | #include "esp_dns.h"
 | ||
|  | 
 | ||
|  | #define TAG "ESP_DNS_TCP"
 | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * @brief Initializes the TCP DNS module | ||
|  |  * | ||
|  |  * Sets up the TCP DNS service using the provided configuration. Validates the parameters, | ||
|  |  * sets the protocol, and initializes the DNS module. | ||
|  |  * | ||
|  |  * @param config Pointer to the DNS configuration structure | ||
|  |  * | ||
|  |  * @return Handle to the initialized TCP module on success, NULL on failure | ||
|  |  */ | ||
|  | esp_dns_handle_t esp_dns_init_tcp(esp_dns_config_t *config) | ||
|  | { | ||
|  |     ESP_LOGD(TAG, "Initializing TCP DNS"); | ||
|  | 
 | ||
|  |     /* Validate parameters */ | ||
|  |     if (config == NULL) { | ||
|  |         ESP_LOGE(TAG, "Invalid configuration (NULL)"); | ||
|  |         return NULL; | ||
|  |     } | ||
|  | 
 | ||
|  |     config->protocol = ESP_DNS_PROTOCOL_TCP; | ||
|  | 
 | ||
|  |     esp_dns_handle_t handle = esp_dns_init(config); | ||
|  |     if (handle == NULL) { | ||
|  |         ESP_LOGE(TAG, "Failed to initialize DNS"); | ||
|  |         return NULL; | ||
|  |     } | ||
|  | 
 | ||
|  |     ESP_LOGD(TAG, "DNS module initialized successfully with protocol DNS Over TCP(%d)", config->protocol); | ||
|  |     return handle; | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * @brief Cleans up the TCP DNS module | ||
|  |  * | ||
|  |  * Releases resources allocated for the TCP DNS service. Validates the parameters, | ||
|  |  * checks the protocol, and cleans up the DNS module. | ||
|  |  * | ||
|  |  * @param handle Pointer to the DNS handle to be cleaned up | ||
|  |  * | ||
|  |  * @return 0 on success, -1 on failure | ||
|  |  */ | ||
|  | int esp_dns_cleanup_tcp(esp_dns_handle_t handle) | ||
|  | { | ||
|  |     ESP_LOGD(TAG, "Cleaning up TCP DNS"); | ||
|  | 
 | ||
|  |     /* Validate parameters */ | ||
|  |     if (handle == NULL) { | ||
|  |         ESP_LOGE(TAG, "Invalid handle (NULL)"); | ||
|  |         return -1; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (handle->config.protocol != ESP_DNS_PROTOCOL_TCP) { | ||
|  |         ESP_LOGW(TAG, "Unknown protocol during cleanup: %d", handle->config.protocol); | ||
|  |         return -1; | ||
|  |     } | ||
|  | 
 | ||
|  |     int ret = esp_dns_cleanup(handle); | ||
|  |     if (ret != 0) { | ||
|  |         ESP_LOGE(TAG, "Failed to cleanup DNS"); | ||
|  |         return ret; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* Empty the handle */ | ||
|  |     memset(handle, 0, sizeof(*handle)); | ||
|  | 
 | ||
|  |     ESP_LOGD(TAG, "DNS module cleaned up DNS Over TCP successfully"); | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * @brief Resolves a hostname using TCP DNS | ||
|  |  * | ||
|  |  * Performs DNS resolution over TCP for the given hostname. Creates a TCP connection, | ||
|  |  * sends the DNS query, and processes the response. | ||
|  |  * | ||
|  |  * @param handle DNS handle | ||
|  |  * @param name Hostname to resolve | ||
|  |  * @param addr Pointer to store the resolved IP address | ||
|  |  * @param rrtype DNS record type | ||
|  |  * | ||
|  |  * @return ERR_OK on success, error code on failure | ||
|  |  */ | ||
|  | err_t dns_resolve_tcp(const esp_dns_handle_t handle, const char *name, ip_addr_t *addr, u8_t rrtype) | ||
|  | { | ||
|  |     int err = ERR_OK; | ||
|  |     esp_transport_handle_t transport = NULL; | ||
|  |     int len = 0; | ||
|  |     char tcp_buffer[ESP_DNS_BUFFER_SIZE]; | ||
|  |     size_t query_size; | ||
|  |     int timeout_ms; | ||
|  |     int tcp_port; | ||
|  | 
 | ||
|  |     if (addr == NULL) { | ||
|  |         return ERR_ARG; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* Set timeout and port values, using defaults if not specified in config */ | ||
|  |     timeout_ms = handle->config.timeout_ms ? : ESP_DNS_DEFAULT_TIMEOUT_MS; | ||
|  |     tcp_port = handle->config.port ? : ESP_DNS_DEFAULT_TCP_PORT; | ||
|  | 
 | ||
|  |     /* Clear the response buffer to ensure no residual data remains */ | ||
|  |     memset(&handle->response_buffer, 0, sizeof(response_buffer_t)); | ||
|  | 
 | ||
|  |     /* Create DNS query in wire format, leaving 2 bytes at start for length prefix as required by RFC 7858 */ | ||
|  |     memset(tcp_buffer, 0, ESP_DNS_BUFFER_SIZE); | ||
|  |     query_size = esp_dns_create_query((uint8_t *)(tcp_buffer + 2), sizeof(tcp_buffer) - 2, | ||
|  |                                       name, rrtype, &handle->response_buffer.dns_response.id); | ||
|  |     if (query_size == -1) { | ||
|  |         ESP_LOGE(TAG, "Error: Hostname too big"); | ||
|  |         return ERR_MEM; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* Prepends the 2-byte length field to DNS messages as required by RFC 7858 */ | ||
|  |     tcp_buffer[0] = (query_size >> 8) & 0xFF; | ||
|  |     tcp_buffer[1] = query_size & 0xFF; | ||
|  | 
 | ||
|  |     transport = esp_transport_tcp_init(); | ||
|  |     if (!transport) { | ||
|  |         ESP_LOGE(TAG, "Failed to initialize transport"); | ||
|  |         return ERR_MEM; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (esp_transport_connect(transport, handle->config.dns_server, tcp_port, timeout_ms) < 0) { | ||
|  |         ESP_LOGE(TAG, "TCP connection failed"); | ||
|  |         err = ERR_CONN; | ||
|  |         goto cleanup; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* Send DNS query */ | ||
|  |     len = esp_transport_write(transport, | ||
|  |                               tcp_buffer, | ||
|  |                               query_size + 2, | ||
|  |                               timeout_ms); | ||
|  |     if (len < 0) { | ||
|  |         ESP_LOGE(TAG, "Failed to send DNS query"); | ||
|  |         err = ERR_ABRT; | ||
|  |         goto cleanup; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* Read response */ | ||
|  |     memset(tcp_buffer, 0, ESP_DNS_BUFFER_SIZE); | ||
|  |     len = esp_transport_read(transport, | ||
|  |                              tcp_buffer, | ||
|  |                              sizeof(tcp_buffer), | ||
|  |                              timeout_ms); | ||
|  |     if (len > 0) { | ||
|  |         /* Skip the 2-byte length field that prepends DNS messages as required by RFC 7858 */ | ||
|  |         handle->response_buffer.buffer = tcp_buffer + 2; | ||
|  |         handle->response_buffer.length = len - 2; | ||
|  | 
 | ||
|  |         /* Parse the DNS response */ | ||
|  |         esp_dns_parse_response((uint8_t *)handle->response_buffer.buffer, | ||
|  |                                handle->response_buffer.length, | ||
|  |                                &handle->response_buffer.dns_response); | ||
|  | 
 | ||
|  |         /* Extract IP addresses from DNS response */ | ||
|  |         err = esp_dns_extract_ip_addresses_from_response(&handle->response_buffer.dns_response, addr); | ||
|  |         if (err != ERR_OK) { | ||
|  |             ESP_LOGE(TAG, "Failed to extract IP address from DNS response"); | ||
|  |             goto cleanup; | ||
|  |         } | ||
|  |     } else { | ||
|  |         ESP_LOGE(TAG, "Failed to receive response"); | ||
|  |         err = ERR_ABRT; | ||
|  |         goto cleanup; | ||
|  |     } | ||
|  | 
 | ||
|  | cleanup: | ||
|  |     if (transport) { | ||
|  |         esp_transport_close(transport); | ||
|  |         esp_transport_destroy(transport); | ||
|  |     } | ||
|  | 
 | ||
|  |     return err; | ||
|  | } |