diff packages/net/ns/dns/current/src/dns.c @ 208:e0c0827131d1 ecos

Merge from eCos master repository on 2002-05-20-20:11:54-BST
author jlarmour
date Mon, 20 May 2002 22:19:26 +0000
parents
children d2c90368aeef
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/net/ns/dns/current/src/dns.c
@@ -0,0 +1,276 @@
+//=============================================================================
+//
+//      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 <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);
+    }
+}
+
+/* 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;
+}
+
+/* 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;
+}