diff packages/redboot/current/src/net/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/redboot/current/src/net/dns.c
@@ -0,0 +1,267 @@
+//=============================================================================
+//
+//      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):   jskov
+// Contributors:jskov
+// Date:        2001-09-26
+// Description: Provides DNS lookup as per RFC 1034/1035.
+// 
+// Note:        This is a stripped down clone of dns.c from the CYGPKG_NS_DNS
+//              package which does not use malloc/free and has been tweaked to
+//              use UDP via RedBoot's network stack. Also adds commands
+//              to set the DNS server IP at runtime.
+//
+//####DESCRIPTIONEND####
+//
+//=============================================================================
+
+#include <cyg/hal/drv_api.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_trac.h>         /* Tracing support */
+
+#include <net/net.h>
+#include <redboot.h>
+/* #include <cyg/ns/dns/dns.h> - it's been moved to redboot.h */
+#include <cyg/ns/dns/dns_priv.h>
+
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+#include <flash_config.h>
+
+RedBoot_config_option("DNS server IP address",
+                      dns_ip,
+                      ALWAYS_ENABLED, true,
+                      CONFIG_IP,
+                      0
+    );
+#endif
+
+/* So we remember which ports have been used */
+static int get_port = 7700;
+
+#define DOMAIN_PORT           53
+
+/* Some magic to make dns_impl.inl compile under RedBoot */
+#define sprintf diag_sprintf
+static cyg_addrword_t _thread_data;
+static cyg_addrword_t cyg_thread_get_data(int i) { return _thread_data; }
+static void cyg_thread_set_data(int i, cyg_addrword_t data) { _thread_data = data; }
+
+struct sockaddr_in server;
+
+/* static buffers so we can make do without malloc */
+static struct hostent _hent;
+static char* _h_addr_list[2];
+static struct in_addr _h_addr_list0;
+static int _hent_alloc = 0;
+
+#define _STRING_COUNT  2
+#define _STRING_LENGTH 64
+static char _strings[_STRING_COUNT][_STRING_LENGTH];
+static int _strings_alloc = 0;
+
+/* as in dns.c proper */
+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 char*
+alloc_string(int len)
+{
+    int i;
+
+    if (len > _STRING_LENGTH)
+        return NULL;
+
+    for (i = 0; i < _STRING_COUNT; i++) {
+        if (_strings_alloc & (1 << i)) continue;
+        _strings_alloc |= (1<<i);
+        return _strings[i];
+    }
+    return NULL;
+}
+
+static void
+free_string(char* s)
+{
+    int i;
+    for (i = 0; i < _STRING_COUNT; i++) {
+        if (_strings[i] == s) {
+            _strings_alloc &= ~(1<<i);
+            break;
+        }
+    }
+}
+
+/* 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);
+    }
+    _hent_alloc = 0;
+}
+
+/* Allocate hent structure with room for one in_addr. Returns NULL on
+   failure. */
+static struct hostent*
+alloc_hent(void)
+{
+    struct hostent *hent;
+
+    if (_hent_alloc) return NULL;
+
+    hent = &_hent;
+    memset(hent, 0, sizeof(struct hostent));
+    hent->h_addr_list = _h_addr_list;
+    hent->h_addr_list[0] = (char*)&_h_addr_list0;
+    hent->h_addr_list[1] = NULL;
+    _hent_alloc = 1;
+
+    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;
+    int finished = false;
+    int read = 0;
+
+    dns_hdr = (struct dns_header *) msg;
+
+    do { 
+        int len_togo = len;
+        struct timeval timeout;
+        struct sockaddr_in local_addr, from_addr;
+
+        memset((char *)&local_addr, 0, sizeof(local_addr));
+        local_addr.sin_family = AF_INET;
+        local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+        local_addr.sin_port = htons(get_port++);
+
+        if (__udp_sendto(msg, len_togo, &server, &local_addr) < 0)
+            return -1;
+
+        memset((char *)&from_addr, 0, sizeof(from_addr));
+
+        timeout.tv_sec = CYGNUM_REDBOOT_NETWORKING_DNS_TIMEOUT;
+        timeout.tv_usec = 0;
+
+        read = __udp_recvfrom(msg, len, &from_addr, &local_addr, &timeout);
+        if (read < 0)
+            return -1;
+
+        /* Reply to an old query. Ignore it */
+        if (ntohs(dns_hdr->id) != (id-1)) {
+            continue;
+        }
+        finished = true;
+    } while (!finished);
+
+    return read;
+}
+    
+void
+set_dns(char* new_ip)
+{
+    in_addr_t dns_ip;
+
+    memset(&server.sin_addr, 0, sizeof(server.sin_addr));
+    if (!inet_aton(new_ip, &dns_ip)) {
+        diag_printf("Bad DNS server address: %s\n", new_ip);
+    } else {
+        memcpy(&server.sin_addr, &dns_ip, sizeof(dns_ip));
+        /* server config is valid */
+        s = 0;
+    }
+}
+
+void
+show_dns(void)
+{
+    diag_printf(", DNS server IP: %s", inet_ntoa((in_addr_t *)&server.sin_addr));
+    if (0 == server.sin_addr.s_addr) {
+        s = -1;
+    }
+}
+
+/* Initialise the resolver. Open a socket and bind it to the address
+   of the server.  return -1 if something goes wrong, otherwise 0 */
+int  
+redboot_dns_res_init(void)
+{
+    memset((char *)&server, 0, sizeof(server));
+    server.sin_len = sizeof(server);
+    server.sin_family = AF_INET;
+    server.sin_port = htons(DOMAIN_PORT);
+    cyg_drv_mutex_init(&dns_mutex);
+
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+    {
+        ip_addr_t dns_ip;
+
+        flash_get_config("dns_ip", &dns_ip, CONFIG_IP);
+        if (dns_ip[0] == 0 && dns_ip[1] == 0 && dns_ip[2] == 0 && dns_ip[3] == 0)
+            return -1;
+        memcpy(&server.sin_addr, &dns_ip, sizeof(dns_ip));
+        /* server config is valid */
+        s = 0;
+    }
+#else
+    // Use static configuration
+    set_dns(__Xstr(CYGPKG_REDBOOT_NETWORKING_DNS_IP));
+#endif
+
+    return 0;
+}
+
+/* Include the DNS client implementation code */
+#include <cyg/ns/dns/dns_impl.inl>