URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k/trunk/ecos-2.0/packages/net/ns/dns/v2_0/src
- from Rev 1254 to Rev 1765
- ↔ Reverse comparison
Rev 1254 → Rev 1765
/dns.c
0,0 → 1,317
//============================================================================= |
// |
// dns.c |
// |
// DNS client code |
// |
//============================================================================= |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//============================================================================= |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): andrew.lunn |
// Contributors:andrew.lunn, jskov |
// Date: 2001-09-18 |
// Description: Provides DNS lookup as per RFC 1034/1035. |
// |
// Note: Does only support A and PTR lookups. Maybe add for other |
// types as well? |
// |
// parse_answer() only returns the first found record. |
// |
// Add tracing and assertions. |
// |
//####DESCRIPTIONEND#### |
// |
//============================================================================= |
|
#include <pkgconf/system.h> |
#ifdef CYGPKG_KERNEL |
# include <pkgconf/kernel.h> |
# include <cyg/kernel/kapi.h> |
#endif |
#include <cyg/hal/drv_api.h> |
#include <cyg/infra/cyg_type.h> |
#include <cyg/infra/cyg_trac.h> /* Tracing support */ |
|
#include <netdb.h> |
|
#include <sys/time.h> |
#include <sys/types.h> |
#include <sys/socket.h> |
#include <arpa/inet.h> |
|
#include <ctype.h> |
#include <unistd.h> |
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
|
#include <cyg/ns/dns/dns_priv.h> |
|
static short id = 0; /* ID of the last query */ |
static int s = -1; /* Socket to the DNS server */ |
static cyg_drv_mutex_t dns_mutex; /* Mutex to stop multiple queries as once */ |
static cyg_ucount32 ptdindex; /* Index for the per thread data */ |
static char * domainname=NULL; /* Domain name used for queries */ |
|
/* Allocate space for string of length len. Return NULL on failure. */ |
static inline char* |
alloc_string(int len) |
{ |
return malloc(len); |
} |
|
static inline void |
free_string(char* s) |
{ |
free(s); |
} |
|
/* Deallocate the memory taken to hold a hent structure */ |
static void |
free_hent(struct hostent * hent) |
{ |
if (hent->h_name) { |
free_string(hent->h_name); |
} |
|
if (hent->h_addr_list) { |
int i = 0; |
while (hent->h_addr_list[i]) { |
free(hent->h_addr_list[i]); |
i++; |
} |
free(hent->h_addr_list); |
} |
free(hent); |
} |
|
/* Allocate hent structure with room for one in_addr. Returns NULL on |
failure. */ |
static struct hostent* |
alloc_hent(void) |
{ |
struct hostent *hent; |
|
hent = malloc(sizeof(struct hostent)); |
if (hent) { |
memset(hent, 0, sizeof(struct hostent)); |
hent->h_addr_list = malloc(sizeof(char *)*2); |
if (!hent->h_addr_list) { |
free_hent(hent); |
return NULL; |
} |
hent->h_addr_list[0] = malloc(sizeof(struct in_addr)); |
if (!hent->h_addr_list[0]) { |
free_hent(hent); |
return NULL; |
} |
hent->h_addr_list[1] = NULL; |
} |
|
return hent; |
} |
|
/* Thread destructor used to free stuff stored in per-thread data slot. */ |
static void |
thread_destructor(CYG_ADDRWORD data) |
{ |
struct hostent *hent; |
hent = (struct hostent *)cyg_thread_get_data(ptdindex); |
if (hent) |
free_hent(hent); |
return; |
data=data; |
} |
|
/* Store the hent away in the per-thread data. */ |
static void |
store_hent(struct hostent *hent) |
{ |
// Prevent memory leaks by setting a destructor to be |
// called on thread exit to free per-thread data. |
cyg_thread_add_destructor( &thread_destructor, 0 ); |
cyg_thread_set_data(ptdindex, (CYG_ADDRWORD)hent); |
} |
|
/* If there is an answer to an old query, free the memory it uses. */ |
static void |
free_stored_hent(void) |
{ |
struct hostent *hent; |
hent = (struct hostent *)cyg_thread_get_data(ptdindex); |
if (hent) { |
free_hent(hent); |
cyg_thread_set_data(ptdindex, (CYG_ADDRWORD)NULL); |
cyg_thread_rem_destructor( &thread_destructor, 0 ); |
} |
} |
|
/* Send the query to the server and read the response back. Return -1 |
if it fails, otherwise put the response back in msg and return the |
length of the response. */ |
static int |
send_recv(char * msg, int len, int msglen) |
{ |
struct dns_header *dns_hdr; |
struct timeval timeout; |
int finished = false; |
int backoff = 1; |
fd_set readfds; |
int written; |
int ret; |
|
CYG_REPORT_FUNCNAMETYPE( "send_recv", "returning %d" ); |
CYG_REPORT_FUNCARG3( "msg=%08x, len=%d, msglen", msg, len, msglen ); |
|
CYG_CHECK_DATA_PTR( msg, "msg is not a valid pointer!" ); |
|
dns_hdr = (struct dns_header *) msg; |
|
do { |
written = write(s, msg, len); |
if (written < 0) { |
ret = -1; |
break; |
} |
|
FD_ZERO(&readfds); |
FD_SET(s, &readfds); |
|
timeout.tv_sec = backoff; |
timeout.tv_usec = 0; |
backoff = backoff << 1; |
|
ret = select(s+1, &readfds, NULL, NULL, &timeout); |
if (ret < 0) { |
ret = -1; |
break; |
} |
/* Timeout */ |
if (ret == 0) { |
if (backoff > 16) { |
h_errno = TRY_AGAIN; |
ret = -1; |
break; |
} |
} |
if (ret == 1) { |
ret = read(s, msg, msglen); |
if (ret < 0) { |
ret = -1; |
break; |
} |
|
/* Reply to an old query. Ignore it */ |
if (ntohs(dns_hdr->id) != (id-1)) { |
continue; |
} |
finished = true; |
} |
} while (!finished); |
|
CYG_REPORT_RETVAL( ret ); |
|
return ret; |
} |
|
/* Include the DNS client implementation code */ |
#include <cyg/ns/dns/dns_impl.inl> |
|
/* Initialise the resolver. Open a socket and bind it to the address |
of the server. return -1 if something goes wrong, otherwise 0. If |
we are being called a second time we have to be careful to allow |
any ongoing lookups to finish before we close the socket and |
connect to a different DNS server. The danger here is that we may |
have to wait for upto 32 seconds if the DNS server is down. |
*/ |
int |
cyg_dns_res_init(struct in_addr *dns_server) |
{ |
struct sockaddr_in server; |
struct servent *sent; |
static int init =0; |
|
CYG_REPORT_FUNCNAMETYPE( "cyg_dns_res_init", "returning %d" ); |
CYG_REPORT_FUNCARG1( "dns_server=%08x", dns_server ); |
|
CYG_CHECK_DATA_PTR( dns_server, "dns_server is not a valid pointer!" ); |
|
if (init) { |
cyg_drv_mutex_lock(&dns_mutex); |
cyg_thread_free_data_index(ptdindex); |
if (s >= 0) { |
close(s); |
} |
} else { |
init = 1; |
cyg_drv_mutex_init(&dns_mutex); |
cyg_drv_mutex_lock(&dns_mutex); |
} |
|
|
s = socket(PF_INET, SOCK_DGRAM, 0); |
if (s < 0) { |
cyg_drv_mutex_unlock(&dns_mutex); |
CYG_REPORT_RETVAL( -1 ); |
return -1; |
} |
|
sent = getservbyname("domain", "udp"); |
if (sent == (struct servent *)0) { |
s = -1; |
cyg_drv_mutex_unlock(&dns_mutex); |
CYG_REPORT_RETVAL( -1 ); |
return -1; |
} |
|
memcpy((char *)&server.sin_addr, dns_server, sizeof(server.sin_addr)); |
server.sin_port = sent->s_port; |
server.sin_family = AF_INET; |
server.sin_len = sizeof(server); |
|
if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0) { |
s = -1; |
cyg_drv_mutex_unlock(&dns_mutex); |
CYG_REPORT_RETVAL( -1 ); |
return -1; |
} |
ptdindex = cyg_thread_new_data_index(); |
|
cyg_drv_mutex_unlock(&dns_mutex); |
|
CYG_REPORT_RETVAL( 0 ); |
return 0; |
} |