📄 dns_client_skt.c
字号:
/* ############################################################################ (c) Copyright Virata Limited 2002## Virata Limited Confidential and Proprietary## The following software source code ("Software") is strictly confidential and# is proprietary to Virata Limited ("Virata"). It may only be read, used,# copied, adapted, modified or otherwise dealt with by you if you have# entered into a confidentiality agreement with Virata and then subject to the# terms of that confidentiality agreement and any other applicable agreement# between you and Virata. If you are in any doubt as to whether you are# entitled to access, read, use, copy, adapt, modify or otherwise deal with# the Software or whether you are entitled to disclose the Software to any# other person you should contact Virata. If you have not entered into a# confidentiality agreement with Virata granting access to this Software you# should forthwith return all media, copies and printed listings containing# the Software to Virata.## Virata reserves the right to take legal action against you should you breach# the above provisions.## If you are unsure, or to report violations, please contact# support@virata.com# ##########################################################################*//* * File: dns_client_skt.c * * Description: This file contains routines dealing with the UDP messages * that the DNS client sends and receives. The idea is to * hide some of interaction with sockets from the rest of the * code. Note that we do not set our source UDP port number. * There is no set port number that must be used by the DNS * client, and the NS must respond to whatever port we use, * (see RFC 2181 section 4.2). */#include <sys/time.h>#include <netinet/in.h>#include "dns_client.h"#include "dns_client_query.h"#include "dns_client_resource.h"#include "dns_client_statics.h"#undef DEBUG_LEVEL#define DEBUG_LEVEL (0x01) /* Only trace messages */#define SIN(ptr) ((struct sockaddr_in *)(ptr))#define SIN_PORT(p_sin) (SIN(p_sin)->sin_port)#define SIN_ADDR(p_sin) (&(SIN(p_sin)->sin_addr))#define SIN6(ptr) ((struct sockaddr_in6 *)(ptr))#define SIN6_PORT(p_sin6) (SIN6(p_sin6)->sin6_port)#define SIN6_ADDR(p_sin6) (&(SIN6(p_sin6)->sin6_addr))#define SA(ptr) ((struct sockaddr *)(ptr))#define SA_FAMILY(p_sa) (SA(p_sa)->sa_family)#define SA_PORT(p_sa) (((p_sa)->sa_family == AF_INET) ? \ SIN_PORT(p_sa) : SIN6_PORT(p_sa))#define SET_PORT(p_sa, value) if ((SA_FAMILY(p_sa) == AF_INET)) \ SIN_PORT(p_sa) = value; \ else \ SIN6_PORT(p_sa) = value #define SA_ADDR(p_sa) ((SA(p_sa)->sa_family == AF_INET) ? \ (void *)SIN_ADDR(p_sa) : \ (void *)SIN6_ADDR(p_sa))#define DNS_CLIENT_MAX_TIME ((u_long)(-1))char *dns_client_inetaddr(const struct sockaddr *addr); /* Socket for DNS client networking */static int dns_client_skt = -1;/* Timeout in milliseconds for next atmos_select() call */static u_long dns_client_posted_query_timeout = 0;/* Buffer to receive data from socket */U8 dns_client_recvbuf[BUFLEN];/* Address of the sender */static struct sockaddr_storage dns_client_msg_from;/* Length of the used part of sockaddr_storage */static socklen_t dns_client_msg_fromlen;/* dns_client_udp_send -- * Sends UDP message. The message should already have DNS message * only. DNS client socket is opened if it's necessary. * * PARAMETERS: * buffer - buffer with message to send * nbytes - number of bytes in the buffer to send * to - pointer to the target address * tolen - length of the target address * timeout - timeout for the query in milliseconds * * RETURNS: * >0 - for success - number of bytes was sent * -1 - to indicates an error condition */intdns_client_udp_send(U8 *buffer, int nbytes, const struct sockaddr *p_sa_to, socklen_t tolen, u_long timeout){ int nsent;#if defined(DNS_HAVE_IP6STACK) struct sockaddr_in6 to_sin6;#endif DNSC_DEBUG("entry\n"); /* Validate number of bytes to send */ if (nbytes <= 0 || nbytes > (int)BUFLEN) { DNSC_DEBUG("exit - number bytes to send %d invalid\n", nbytes); return -1; } /* Open socket if it is necessary */ if (dns_client_skt == -1) { DNSC_DEBUG("Try to open DGRAM socket\n");#if defined(DNS_HAVE_IP6STACK) dns_client_skt = socket(PF_INET6, SOCK_DGRAM, 0);#else dns_client_skt = socket(PF_INET, SOCK_DGRAM, 0);#endif if (dns_client_skt == -1) { DNSC_MSG("failed to open DNS client socket\n"); return -1; } DNSC_DEBUG("socket %d opened\n", dns_client_skt); } #if defined(DNS_HAVE_IP6STACK) if (p_sa_to->sa_family == AF_INET) { /* * In order to send query to IPv4 server via IPv6 socket * make IPv6 IPv4-mapped address */ MAKE_SIN6_V4MAPPED_BY_INADDR(SIN_ADDR(p_sa_to), &to_sin6); /* Substitute destination address pointer */ p_sa_to = (struct sockaddr *)&to_sin6; tolen = sizeof(to_sin6); }#endif /* Set up DNS Name Server port */ SET_PORT(p_sa_to, htons(NSPORT)); DNSC_DEBUG("Send to socket %d buffer 0x%08x len %u\n", dns_client_skt, buffer, nbytes); DNSC_DEBUG("Dst: family %s len %u addr %s\n", (p_sa_to->sa_family == AF_INET) ? "INET" : "INET6", tolen, dns_client_inetaddr(p_sa_to)); /* Transmit message to another socket */ nsent = sendto(dns_client_skt, buffer, nbytes, 0 /* no flags */, p_sa_to, tolen); DNSC_DEBUG("sendto() function returned %d\n", nsent); if (nsent == -1) { /* Change return code in order to don't fail request immediately */ nsent = 0; /* * Set timeout for the posted query to minimal possible value * in order to time out request ASAP */ dns_client_posted_query_timeout = 1; /* Error to sendto */ DNSC_DEBUG("sendto() failed\n"); } else { if (nsent != nbytes) { DNSC_TRACE("Incomplete DNS message was sent " "(%d bytes instead of %d)\n", nsent, nbytes); } /* Set timeout for the posted query (minimum) */ if ((dns_client_posted_query_timeout == 0) || (dns_client_posted_query_timeout > timeout)) { dns_client_posted_query_timeout = timeout; } DNSC_DEBUG("Set dns_client_posted_query_timeout = %d\n", timeout); } DNSC_DEBUG("exit - %d\n", nsent); return nsent;} /* dns_client_udp_send *//* dns_client_udp_receive -- * Waits for data or ATMOS messages. Receives data and processes * them. Another ATMOS messages are handled by socket handler * registered during initialization. * * PARAMETERS: * N/A * * RETURNS: * N/A */voiddns_client_udp_receive(){ int result; struct timeval current_time; struct timeval select_timeout; u_int queries_min_timeout = 0; u_int current_timeout; fd_set readfds; /* Has DNS client socket been opened? */ if (dns_client_skt == -1) { /* DNS client socket hasn't been opened */ return; } DNSC_DEBUG("entry\n"); /* Clean up set of file descriptors to read from */ FD_ZERO(&readfds); DNSC_DEBUG("dns_client_posted_query_timeout = %d\n", dns_client_posted_query_timeout); DNSC_DEBUG("queries_min_timeout = %d\n", queries_min_timeout); DNSC_DEBUG("=> current_timeout = %d\n", (dns_client_posted_query_timeout == 0) ? queries_min_timeout : (queries_min_timeout == 0) ? dns_client_posted_query_timeout : MIN(dns_client_posted_query_timeout, queries_min_timeout)); /* Do while active queries exist */ while ((current_timeout = (dns_client_posted_query_timeout == 0) ? queries_min_timeout : (queries_min_timeout == 0) ? dns_client_posted_query_timeout : MIN(dns_client_posted_query_timeout, queries_min_timeout)) > 0) { /* Set posted query timeout to zero but it may be changed */ dns_client_posted_query_timeout = 0; /* Set up DNS client socket bit */ FD_SET(dns_client_skt, &readfds); /* Prepare timeout */ select_timeout.tv_sec = 0; select_timeout.tv_usec = current_timeout * 1000; /* * Wait for ready data in opened socket and process another * messages using socket handler which was registered during * initialization */ DNSC_DEBUG("call atmos_select ...\n"); result = atmos_select(dns_client_skt + 1, &readfds, NULL /* no writefds */, NULL /* no exceptfds */, &select_timeout, NULL /* no place for ATMOS message */ ); DNSC_DEBUG("... atmos_select return code %d\n", result); if (result == -1) { /* Fatal error returned by atmos_select */ DNSC_TRACE("atmos_select() failed\n"); /* Fail here if it's debugged */ ASSERT(FALSE); break; } else if (result == 0) { /* The timeout expires before anything interesting happens */ DNSC_TRACE("Timeout\n"); } else if ((result == 1) && FD_ISSET(dns_client_skt, &readfds)) { /* Set correct length of the structure for source address */ dns_client_msg_fromlen = sizeof(dns_client_msg_from); /* Receive data from socket */ result = recvfrom(dns_client_skt, dns_client_recvbuf, BUFLEN, 0 /* no flags */, (struct sockaddr *)&dns_client_msg_from, &dns_client_msg_fromlen); if (result == -1) { /* Fatal error returned by recvfrom */ DNSC_TRACE("recvfrom failed\n"); /* Fail here if it's debugged */ ASSERT(FALSE); break; } else { DNSC_TRACE("UDP message received\n"); DNSC_DEBUG("Received from socket %d buffer 0x%08x len %u\n", dns_client_skt, dns_client_recvbuf, result); DNSC_DEBUG("Src: family %s len %u addr %s\n", (SA_FAMILY(&dns_client_msg_from) == AF_INET) ? "INET" : "INET6", dns_client_msg_fromlen, dns_client_inetaddr(SA(&dns_client_msg_from))); /* Process message */ DNSC_DEBUG("call dns_udp_message ...\n"); dns_udp_message(dns_client_recvbuf, result); DNSC_DEBUG("... dns_udp_message finished\n"); /* dns_client_posted_query_timeout might be changed */ } } else { /* Unpredictable behaviour */ DNSC_TRACE("atmos_select returned too many active " "descriptors or active not requested\n"); /* Fail here if it's debugged */ ASSERT(FALSE); break; } /* Get current time value */ if (gettimeofday(¤t_time, NULL) != 0) { /* Fatal error returned by atmos_select */ DNSC_TRACE("gettimeofday() failed\n"); /* Fail here if it's debugged */ ASSERT(FALSE); break; } /* Some time was elapsed */ DNSC_DEBUG("call dns_client_query_timeout ...\n"); queries_min_timeout = dns_client_query_timeout( ¤t_time, dns_response_timeout); DNSC_DEBUG("... dns_client_query_timeout returned %d\n", queries_min_timeout); /* dns_client_posted_query_timeout might be changed too */ DNSC_DEBUG("dns_client_posted_query_timeout = %d\n", dns_client_posted_query_timeout); } /* end while */ /* If loop was breaked by error - terminate all queries */ if (current_timeout > 0) { current_time.tv_sec = DNS_CLIENT_MAX_TIME; /* Discord all queries */ dns_client_query_timeout(¤t_time, dns_response_timeout); } /* Close socket */ close(dns_client_skt); DNSC_DEBUG("socket %d was closed\n", dns_client_skt); DNSC_TRACE("No active queries\n"); /* Mark socket ad closed */ dns_client_skt = -1; DNSC_DEBUG("exit\n");} /* dns_client_udp_receive */#ifdef DNS_DEBUG/* dns_udp_get_sourceaddr -- * Returns pointer to the source address of the UDP message. * This is useful for knowing which server responded with an * answer. Since this routine is used from debug only, we do * no error checking. * * PARAMETERS: * N/A * * RETURNS: * pointer to to the source address of the UDP message */struct sockaddr_storage *dns_client_udp_get_sourceaddr(){ return &dns_client_msg_from;} /* dns_client_udp_get_sourceaddr *//* dns_client_inetaddr -- * Converts IP (IPv4 or IPv6) address in internal representation * to human-readable form (for logging). * * PARAMETERS: * addr - IP address * * RETURNS: * pointer to address in human-readable form */char *dns_client_inetaddr(const struct sockaddr *addr){ static char addr_buf[INET6_ADDRSTRLEN]; if ((addr == NULL) || (inet_ntop(addr->sa_family, SA_ADDR(addr), addr_buf, INET6_ADDRSTRLEN) == NULL)) { addr_buf[0] = '\0'; } return addr_buf;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -