OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [ns/] [dns/] [current/] [src/] [dns.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//=============================================================================
2
//
3
//      dns.c
4
//
5
//      DNS client code
6
//
7
//=============================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//=============================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):   andrew.lunn
43
// Contributors:andrew.lunn, jskov
44
// Date:        2001-09-18
45
// Description: Provides DNS lookup as per RFC 1034/1035.
46
// 
47
// Note:        Does only support A and PTR lookups. Maybe add for other
48
//              types as well?
49
//
50
//              parse_answer() only returns the first found record.
51
//
52
//              Add tracing and assertions.
53
//
54
//####DESCRIPTIONEND####
55
//
56
//=============================================================================
57
 
58
#include <pkgconf/system.h>
59
#ifdef CYGPKG_KERNEL
60
# include <pkgconf/kernel.h>
61
# include <cyg/kernel/kapi.h>
62
#endif
63
#include <cyg/hal/drv_api.h>
64
#include <cyg/infra/cyg_type.h>
65
#include <cyg/infra/cyg_trac.h>         /* Tracing support */
66
 
67
#include <netdb.h>
68
 
69
#include <sys/time.h>
70
#include <sys/types.h>
71
#include <sys/socket.h>
72
#include <arpa/inet.h>
73
 
74
#include <ctype.h>
75
#include <unistd.h>
76
#include <stdio.h>
77
#include <string.h>
78
#include <stdlib.h>
79
 
80
#include <cyg/ns/dns/dns_priv.h>
81
 
82
static cyg_uint16 id = 0;         /* ID of the last query */
83
static int s = -1;                /* Socket to the DNS server */
84
static cyg_drv_mutex_t dns_mutex; /* Mutex to stop multiple queries as once */
85
static cyg_ucount32 ptdindex;     /* Index for the per thread data */
86
static char * domainname=NULL;    /* Domain name used for queries */
87
 
88
/* Allocate space for string of length len. Return NULL on failure. */
89
static inline char*
90
alloc_string(int len)
91
{
92
    return malloc(len);
93
}
94
 
95
static inline void
96
free_string(char* s)
97
{
98
    free(s);
99
}
100
 
101
/* Deallocate the memory taken to hold a hent structure */
102
static void
103
free_hent(struct hostent * hent)
104
{
105
    if (hent->h_name) {
106
        free_string(hent->h_name);
107
    }
108
 
109
    if (hent->h_addr_list) {
110
        int i = 0;
111
        while (hent->h_addr_list[i]) {
112
            free(hent->h_addr_list[i]);
113
            i++;
114
        }
115
        free(hent->h_addr_list);
116
    }
117
    free(hent);
118
}
119
 
120
/* Allocate hent structure with room for one in_addr. Returns NULL on
121
   failure. */
122
static struct hostent*
123
alloc_hent(void)
124
{
125
    struct hostent *hent;
126
 
127
    hent = malloc(sizeof(struct hostent));
128
    if (hent) {
129
        memset(hent, 0, sizeof(struct hostent));
130
        hent->h_addr_list = malloc(sizeof(char *)*2);
131
        if (!hent->h_addr_list) {
132
            free_hent(hent);
133
            return NULL;
134
        }
135
        hent->h_addr_list[0] = malloc(sizeof(struct in_addr));
136
        if (!hent->h_addr_list[0]) {
137
            free_hent(hent);
138
            return NULL;
139
        }
140
        hent->h_addr_list[1] = NULL;
141
    }
142
 
143
    return hent;
144
}
145
 
146
/* Thread destructor used to free stuff stored in per-thread data slot. */
147
static void
148
thread_destructor(CYG_ADDRWORD data)
149
{
150
    struct hostent *hent;
151
    hent = (struct hostent *)cyg_thread_get_data(ptdindex);
152
    if (hent)
153
        free_hent(hent);
154
    return;
155
    data=data;
156
}
157
 
158
/* Store the hent away in the per-thread data. */
159
static void
160
store_hent(struct hostent *hent)
161
{
162
    // Prevent memory leaks by setting a destructor to be
163
    // called on thread exit to free per-thread data.
164
    cyg_thread_add_destructor( &thread_destructor, 0 );
165
    cyg_thread_set_data(ptdindex, (CYG_ADDRWORD)hent);
166
}
167
 
168
/* If there is an answer to an old query, free the memory it uses. */
169
static void
170
free_stored_hent(void)
171
{
172
    struct hostent *hent;
173
    hent = (struct hostent *)cyg_thread_get_data(ptdindex);
174
    if (hent) {
175
        free_hent(hent);
176
        cyg_thread_set_data(ptdindex, (CYG_ADDRWORD)NULL);
177
        cyg_thread_rem_destructor( &thread_destructor, 0 );
178
    }
179
}
180
 
181
/* Send the query to the server and read the response back. Return -1
182
   if it fails, otherwise put the response back in msg and return the
183
   length of the response. */
184
static int
185
send_recv(unsigned char * msg, int len, int msglen)
186
{
187
    struct dns_header *dns_hdr;
188
    struct timeval timeout;
189
    int finished = false;
190
    int backoff = 1;
191
    fd_set readfds;
192
    int written;
193
    int ret;
194
 
195
    CYG_REPORT_FUNCNAMETYPE( "send_recv", "returning %d" );
196
    CYG_REPORT_FUNCARG3( "msg=%08x, len=%d, msglen", msg, len, msglen );
197
 
198
    CYG_CHECK_DATA_PTR( msg, "msg is not a valid pointer!" );
199
 
200
    dns_hdr = (struct dns_header *) msg;
201
 
202
    do {
203
        written = write(s, msg, len);
204
        if (written < 0) {
205
            ret = -1;
206
            break;
207
        }
208
 
209
        FD_ZERO(&readfds);
210
        FD_SET(s, &readfds);
211
 
212
        timeout.tv_sec = backoff;
213
        timeout.tv_usec = 0;
214
        backoff = backoff << 1;
215
 
216
        ret = select(s+1, &readfds, NULL, NULL, &timeout);
217
        if (ret < 0) {
218
            ret = -1;
219
            break;
220
        }
221
        /* Timeout */
222
        if (ret == 0) {
223
            if (backoff > 16) {
224
                h_errno = TRY_AGAIN;
225
                ret = -1;
226
                break;
227
            }
228
        }
229
        if (ret == 1) {
230
            ret = read(s, msg, msglen);
231
            if (ret < 0) {
232
                ret = -1;
233
                break;
234
            }
235
 
236
            /* Reply to an old query. Ignore it */
237
            if (ntohs(dns_hdr->id) != (id-1)) {
238
                continue;
239
            }
240
            finished = true;
241
        }
242
    } while (!finished);
243
 
244
    CYG_REPORT_RETVAL( ret );
245
 
246
    return ret;
247
}
248
 
249
/* Include the DNS client implementation code */
250
#include <cyg/ns/dns/dns_impl.inl>
251
 
252
/* (re)Start the DNS client. This opens a socket to the DNS server
253
   who's address is passed in. This address can be either an IPv4 or
254
   IPv6 address. This function can be called multiple times.  If we
255
   are being called a second time we have to be careful to allow any
256
   ongoing lookups to finish before we close the socket and connect to
257
   a different DNS server. The danger here is that we may have to wait
258
   for up to 32 seconds if the DNS server is down.
259
   Each invocation will close any previous connection and make a new
260
   connection to the new server. Note the address of the server must
261
   be in numeric form since its not possible to do a DNS lookup! */
262
 
263
int cyg_dns_res_start(char * dns_server) {
264
 
265
    static int init =0;
266
    struct addrinfo * res;
267
    int err;
268
 
269
    CYG_REPORT_FUNCNAMETYPE( "cyg_dns_res_start", "returning %d" );
270
    CYG_REPORT_FUNCARG1( "dns_server=%s", dns_server );
271
 
272
    CYG_CHECK_DATA_PTR( dns_server, "dns_server is not a valid pointer!" );
273
 
274
    if (init) {
275
      cyg_drv_mutex_lock(&dns_mutex);
276
      cyg_thread_free_data_index(ptdindex);
277
      if (s >= 0) {
278
        close(s);
279
      }
280
    } else {
281
      init = 1;
282
      cyg_drv_mutex_init(&dns_mutex);
283
      cyg_drv_mutex_lock(&dns_mutex);
284
    }
285
 
286
    err = getaddrinfo(dns_server,"domain", NULL, &res);
287
    if (err != 0) {
288
        cyg_drv_mutex_unlock(&dns_mutex);
289
        CYG_REPORT_RETVAL( -1 );
290
        return -1;
291
    }
292
 
293
    s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
294
    if (s == -1) {
295
        cyg_drv_mutex_unlock(&dns_mutex);
296
        freeaddrinfo(res);
297
        CYG_REPORT_RETVAL( -1 );
298
        return -1;
299
    }
300
 
301
    if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
302
        s = -1;
303
        cyg_drv_mutex_unlock(&dns_mutex);
304
        freeaddrinfo(res);
305
        CYG_REPORT_RETVAL( -1 );
306
        return -1;
307
    }
308
    ptdindex = cyg_thread_new_data_index();
309
 
310
    cyg_drv_mutex_unlock(&dns_mutex);
311
    freeaddrinfo(res);
312
    CYG_REPORT_RETVAL( 0 );
313
    return 0;
314
}
315
 
316
/* This is the old interface to start the resolver. It is only IPv4
317
   capable and so is now deprecated in favor of cyg_dns_res_start().
318
   Initialise the resolver. Open a socket and bind it to the
319
   address of the server.  return -1 if something goes wrong,
320
   otherwise 0. If we are being called a second time we have to be
321
   careful to allow any ongoing lookups to finish before we close the
322
   socket and connect to a different DNS server. The danger here is
323
   that we may have to wait for up to 32 seconds if the DNS server is
324
   down.  */
325
int
326
cyg_dns_res_init(struct in_addr *dns_server)
327
{
328
  char name[20];
329
  unsigned char *bytes = (unsigned char *)dns_server;
330
  int ret;
331
 
332
  CYG_REPORT_FUNCNAMETYPE( "cyg_dns_res_init", "returning %d" );
333
  CYG_REPORT_FUNCARG1( "dns_server=%08x", dns_server );
334
 
335
  diag_sprintf(name, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
336
 
337
  ret = cyg_dns_res_start(name);
338
 
339
  CYG_REPORT_RETVAL( ret );
340
  return ret;
341
}
342
 
343
/* add_answer checks to see if we already have this answer and if not,
344
   adds it to the answers. */
345
static int
346
add_answer(char *rdata, short rr_type, int family,
347
           struct sockaddr addrs[], int num, int used) {
348
    int i;
349
    int found = 0;
350
 
351
    for (i = 0; i < used ; i++) {
352
        if ((addrs[i].sa_family == family) &&
353
            !memcmp(addrs[i].sa_data, rdata, addrs[i].sa_len)) {
354
            found = 1;
355
            break;
356
        }
357
    }
358
    if (!found) {
359
        memset(&addrs[used],0,sizeof(addrs[used]));
360
        addrs[used].sa_family = family;
361
 
362
        switch(family) {
363
        case AF_INET: {
364
            struct sockaddr_in * addr = (struct sockaddr_in *) &addrs[used];
365
            addr->sin_len = sizeof(*addr);
366
            memcpy(&addr->sin_addr, rdata, sizeof(struct in_addr));
367
            used++;
368
            break;
369
        }
370
#ifdef CYGPKG_NET_INET6
371
        case AF_INET6: {
372
            struct sockaddr_in6 * addr = (struct sockaddr_in6 *) &addrs[used];
373
            addr->sin6_len = sizeof(*addr);
374
            memcpy(&addr->sin6_addr, rdata, sizeof(struct in6_addr));
375
            used++;
376
            break;
377
        }
378
#endif
379
        default:
380
            used = -EAI_FAMILY;
381
        }
382
    }
383
    return used;
384
}
385
 
386
/* This decodes the answer and puts the results into the addrs
387
   array. This function can deal with IPv6 AAAA records as well as A
388
   records. Thus its more complex than the parse_answer function in
389
   the inline code. This complexity is only needed by getaddrinfo, so
390
   i decided to leave parse_anser alone. */
391
 
392
static int
393
decode(unsigned char *msg, short rr_type, int family,
394
       struct sockaddr addrs[], int num, int used, char **canon) {
395
 
396
    struct dns_header *dns_hdr;
397
    struct resource_record rr, *rr_p = NULL;
398
    unsigned char *qname = NULL;
399
    unsigned char *ptr;
400
 
401
    dns_hdr = (struct dns_header *)msg;
402
 
403
    if (DNS_REPLY_NAME_ERROR == dns_hdr->rcode) {
404
        h_errno = HOST_NOT_FOUND;
405
        return -EAI_NONAME;
406
    }
407
 
408
    if ((dns_hdr->qr != 1) ||
409
        (dns_hdr->opcode != DNS_QUERY)) {
410
      return -EAI_FAIL;
411
    }
412
 
413
    if (dns_hdr->rcode != DNS_REPLY_NOERR) {
414
      return -EAI_NONAME;
415
    }
416
 
417
    dns_hdr->ancount = ntohs(dns_hdr->ancount);
418
    dns_hdr->qdcount = ntohs(dns_hdr->qdcount);
419
    ptr = (unsigned char *)&dns_hdr[1];
420
 
421
    /* Skip over the query section */
422
    if (dns_hdr->qdcount > 0) {
423
        while (dns_hdr->qdcount) {
424
            ptr += qname_len(ptr);
425
            ptr += 4;                   /* skip type & class */
426
            dns_hdr->qdcount--;
427
        }
428
    }
429
 
430
    /* Read the answers resource records to find an answer of the
431
       correct type. */
432
    while (dns_hdr->ancount && (used >= 0) && (used < num)) {
433
        qname = ptr;
434
        ptr += qname_len(ptr);
435
        rr_p = (struct resource_record *)ptr;
436
        memcpy(&rr, ptr, sizeof(rr));
437
        if ((rr.rr_type == htons(rr_type)) &&
438
            (rr.class == htons(DNS_CLASS_IN))) {
439
            used = add_answer(rr_p->rdata, rr_type, family, addrs, num, used);
440
            if (canon && !*canon) {
441
                *canon = real_name(msg,qname);
442
            }
443
        }
444
        ptr += sizeof(struct resource_record) -
445
            sizeof(rr.rdata) + ntohs(rr.rdlength);
446
        dns_hdr->ancount--;
447
    }
448
    if (used == 0) {
449
        return -EAI_NONAME;
450
    }
451
    return used;
452
}
453
 
454
/* Do a lookup for a particular type of resource record. */
455
static int
456
do_lookup (const char * hostname,
457
           struct sockaddr addrs[], int num, int used,
458
           short rr_type, int family, char **canon) {
459
 
460
    unsigned char msg[MAXDNSMSGSIZE];
461
    int error;
462
    int len;
463
 
464
    /* First try the name as passed in */
465
    memset(msg, 0, sizeof(msg));
466
    len = build_query(msg, hostname, rr_type);
467
    if (len < 0) {
468
        return -EAI_FAIL;
469
    }
470
 
471
    /* Send the query and wait for an answer */
472
    len = send_recv(msg, len, sizeof(msg));
473
    if (len < 0) {
474
        return -EAI_FAIL;
475
    }
476
 
477
    /* Decode the answer */
478
    error = decode(msg, rr_type, family, addrs, num, used, canon);
479
    return error;
480
}
481
 
482
static int do_lookups(const char * hostname,
483
                      struct sockaddr addrs[], int num,
484
                      int family, char ** canon) {
485
    int error;
486
#ifdef CYGPKG_NET_INET6
487
    int error6;
488
#endif
489
 
490
    switch (family) {
491
    case AF_INET:
492
        error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_A, AF_INET, canon);
493
        break;
494
#ifdef CYGPKG_NET_INET6
495
    case AF_INET6:
496
        error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_AAAA, AF_INET6, canon);
497
        break;
498
#endif
499
    case PF_UNSPEC:
500
#ifndef CYGPKG_NET_INET6
501
        error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_A, AF_INET, canon);
502
#else 
503
#ifdef CYGOPT_NS_DNS_FIRST_FAMILTY_AF_INET
504
        error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_A, AF_INET, canon);
505
        if (error > 0 ) {
506
            error6 = do_lookup(hostname, addrs, num, error, DNS_TYPE_AAAA,
507
                               AF_INET6, canon);
508
        } else {
509
            error6 = do_lookup(hostname, addrs, num, 0, DNS_TYPE_AAAA,
510
                               AF_INET6, canon);
511
        }
512
        if (error6 > 0) {
513
            error = error6;
514
        }
515
#else // CYGOPT_NS_DNS_FIRST_FAMILY_AF_INET
516
        error6 = do_lookup(hostname, addrs, num, 0, DNS_TYPE_AAAA,
517
                           AF_INET6, canon);
518
        if (error6> 0 ) {
519
            error = do_lookup(hostname, addrs, num, error6, DNS_TYPE_A,
520
                               AF_INET, canon);
521
        } else {
522
            error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_A,
523
                               AF_INET, canon);
524
        }
525
#endif // CYGOPT_NS_DNS_FIRST_FAMILY_AF_INET
526
#endif // CYGPKG_NET_INET6
527
        break;
528
    default:
529
        error = -EAI_FAMILY;
530
    }
531
    return error;
532
}
533
 
534
/* This implements the interface between getaddrinfo and the dns
535
   client. hostent is not used here since that only works with IPv4
536
   addresses, where as this function needs to be protocol
537
   independent. */
538
int
539
cyg_dns_getaddrinfo(const char * hostname,
540
                    struct sockaddr addrs[], int num,
541
                    int family,
542
                    char ** canon)
543
{
544
    int error;
545
    char name[256];
546
    char * dot;
547
 
548
    CYG_REPORT_FUNCNAMETYPE( "cyg_dns_getaddrinfo", "returning %08x" );
549
    CYG_REPORT_FUNCARG3( "hostname=%08x, addrs=%08x, num=%2d",
550
                         hostname, addrs, num );
551
 
552
    if ( !hostname || !addrs || !num ) {
553
        CYG_REPORT_RETVAL( NULL );
554
        return -EAI_FAIL;
555
    }
556
 
557
    CYG_CHECK_DATA_PTR( hostname, "hostname is not a valid pointer!" );
558
    CYG_CHECK_DATA_PTR( addrs, "addrs is not a valid pointer!");
559
    CYG_ASSERT( num > 0, "Invalid number of sockaddr stuctures");
560
 
561
    if (!valid_hostname(hostname)) {
562
        /* it could be a dot address */
563
        struct sockaddr_in * sa4 = (struct sockaddr_in *)&addrs[0];
564
        memset(&addrs[0],0,sizeof(struct sockaddr));
565
        if (inet_pton(AF_INET, hostname, (char *)&sa4->sin_addr.s_addr)) {
566
            sa4->sin_family = AF_INET;
567
            sa4->sin_len = sizeof(*sa4);
568
            CYG_REPORT_RETVAL (1);
569
            return 1;
570
        }
571
#ifdef CYGPKG_NET_INET6
572
        {
573
            /* it could be a colon address */
574
            struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *)&addrs[0];
575
            memset(&addrs[0],0,sizeof(struct sockaddr));
576
            if (inet_pton(AF_INET6, hostname, (char *)&sa6->sin6_addr.s6_addr)) {
577
                sa6->sin6_family = AF_INET6;
578
                sa6->sin6_len = sizeof(*sa6);
579
                CYG_REPORT_RETVAL (1);
580
                return 1;
581
            }
582
        }
583
#endif
584
        CYG_REPORT_RETVAL (-EAI_NONAME);
585
        return -EAI_NONAME;
586
    }
587
 
588
    /* Has the socket to the DNS server been opened? */
589
    if (s < 0) {
590
        CYG_REPORT_RETVAL( -EAI_FAIL );
591
        return -EAI_FAIL;
592
    }
593
 
594
    if (domainname) {
595
        if ((strlen(hostname) + strlen(domainname)) > 254) {
596
            CYG_REPORT_RETVAL( -EAI_FAIL );
597
            return -EAI_FAIL;
598
        }
599
        strcpy(name, hostname);
600
        strcat(name, ".");
601
        strcat(name, domainname);
602
    }
603
    cyg_drv_mutex_lock(&dns_mutex);
604
 
605
    /* If the hostname ends with . it a FQDN. Don't bother adding the
606
    domainname. If it does not contain a . , try appending with the
607
    domainname first. If it does have a . , try without a domain name
608
    first. */
609
 
610
    dot = rindex(hostname,'.');
611
    if (dot) {
612
        if (*(dot+1) == '\0') {
613
            /* FQDN */
614
            error = do_lookups(hostname, addrs, num, family, canon);
615
        } else {
616
          /* Dot somewhere */
617
          error = do_lookups(hostname, addrs, num, family, canon);
618
          if (domainname && (error == -EAI_NONAME)) {
619
            error = do_lookups(name, addrs, num, family, canon);
620
          }
621
        }
622
    } else {
623
    /* No Dot. Try adding domainname first */
624
        error = -EAI_NONAME;
625
        if (domainname) {
626
            error = do_lookups(name, addrs, num, family, canon);
627
        }
628
        if (error == -EAI_NONAME) {
629
            error = do_lookups(hostname, addrs, num, family, canon);
630
        }
631
    }
632
    cyg_drv_mutex_unlock(&dns_mutex);
633
    CYG_REPORT_RETVAL( error );
634
    return error;
635
}
636
 
637
/* This implements the interface between getnameinfo and the dns
638
   client. */
639
externC int
640
cyg_dns_getnameinfo(const struct sockaddr * sa, char * host, size_t hostlen)
641
{
642
    char hostname[80];
643
    unsigned char msg[MAXDNSMSGSIZE];
644
    struct hostent * hent;
645
    int len;
646
 
647
    CYG_REPORT_FUNCNAMETYPE( "cyg_dns_getnameinfo", "returning %08x" );
648
    CYG_REPORT_FUNCARG3( "sa=%08x, host=%08x, hostlen=%3d",
649
                         sa, host, hostlen );
650
 
651
    CYG_CHECK_DATA_PTR( sa, "sa is not a valid pointer");
652
    CYG_CHECK_DATA_PTR( host, "host is not a valid data pointer");
653
    CYG_ASSERT(hostlen >0, "Invalid host length");
654
 
655
    /* Has the socket to the DNS server been opened? */
656
    if (s < 0) {
657
        CYG_REPORT_RETVAL( -EAI_FAIL );
658
        return -EAI_FAIL;
659
    }
660
 
661
    cyg_drv_mutex_lock(&dns_mutex);
662
 
663
    switch (sa->sa_family) {
664
    case AF_INET: {
665
        struct sockaddr_in * sa4 = (struct sockaddr_in *)sa;
666
        unsigned char * addr = (unsigned char *)&sa4->sin_addr.s_addr;
667
        sprintf(hostname, "%d.%d.%d.%d.IN-ADDR.ARPA.",
668
                addr[3],addr[2],addr[1],addr[0]);
669
        break;
670
    }
671
#ifdef CYGPKG_NET_INET6
672
    case AF_INET6: {
673
        struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *)sa;
674
        int i;
675
 
676
        for (i=15; i >= 0; i--) {
677
            sprintf(&hostname[(15*2*2) - (i*2*2)], "%x.%x.",
678
                    sa6->sin6_addr.s6_addr[i] & 0x0f,
679
                    (sa6->sin6_addr.s6_addr[i] & 0xf0) >> 4);
680
        }
681
        sprintf(&hostname[16*2*2],"IP6.INT");
682
        break;
683
    }
684
#endif
685
    default:
686
        cyg_drv_mutex_lock(&dns_mutex);
687
        CYG_REPORT_RETVAL( -EAI_FAMILY);
688
        return -EAI_FAMILY;
689
    }
690
 
691
    memset(msg, 0, sizeof(msg));
692
 
693
    /* Build a PTR type request using the hostname */
694
    len = build_query(msg, hostname, DNS_TYPE_PTR);
695
    if (len < 0) {
696
        cyg_drv_mutex_unlock(&dns_mutex);
697
        CYG_REPORT_RETVAL( -EAI_FAIL );
698
        return -EAI_FAIL;
699
    }
700
 
701
    /* Send the request and wait for an answer */
702
    len = send_recv(msg, len, sizeof(msg));
703
    if (len < 0) {
704
        cyg_drv_mutex_unlock(&dns_mutex);
705
        CYG_REPORT_RETVAL( -EAI_FAIL );
706
        return -EAI_FAIL;
707
    }
708
 
709
    /* Parse the answer for the host name */
710
    hent = parse_answer(msg, DNS_TYPE_PTR);
711
 
712
    /* If no name is known return an error */
713
    if (!hent) {
714
        cyg_drv_mutex_unlock(&dns_mutex);
715
        CYG_REPORT_RETVAL( -EAI_NONAME );
716
        return -EAI_NONAME;
717
    }
718
 
719
    /* Otherwise copy it into our results buffer and tidy up */
720
    strncpy(host, hent->h_name,hostlen);
721
    free_hent(hent);
722
 
723
    cyg_drv_mutex_unlock(&dns_mutex);
724
    CYG_REPORT_RETVAL( -EAI_NONE );
725
    return -EAI_NONE;
726
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.