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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      lib/getaddrinfo.c
4
//
5
//      getaddrinfo(), freeaddrinfo(), gai_strerror(), getnameinfo()
6
//
7
//==========================================================================
8
// ####ECOSPDCOPYRIGHTBEGIN####                                    
9
// -------------------------------------------                     
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
12
//
13
// Permission is granted to use, copy, modify and redistribute this
14
// file.                                                           
15
//
16
// -------------------------------------------                     
17
// ####ECOSPDCOPYRIGHTEND####                                      
18
//==========================================================================
19
//#####DESCRIPTIONBEGIN####
20
//
21
// Author(s):    gthomas
22
// Contributors: gthomas, andrew.lunn@ascom.ch
23
// Date:         2002-03-05
24
// Purpose:      
25
// Description:  
26
//              
27
//
28
//####DESCRIPTIONEND####
29
//
30
//==========================================================================
31
 
32
#include <sys/param.h>
33
#include <sys/socket.h>           // PF_xxx
34
#include <netinet/in.h>           // IPPROTO_xx
35
#include <net/netdb.h>
36
#include <netdb.h>                // DNS support routines
37
#include <errno.h>
38
#include <cyg/infra/cyg_ass.h>
39
 
40
#include <pkgconf/system.h>
41
#ifdef CYGPKG_NS_DNS
42
#include <pkgconf/ns_dns.h>
43
#ifdef CYGPKG_NS_DNS_BUILD
44
#include <cyg/ns/dns/dns.h>
45
#endif
46
#endif
47
 
48
extern int  sprintf(char *, const char *, ...);
49
extern long strtol(const char *, char **, int);
50
extern void *malloc(size_t);
51
extern void *calloc(int, size_t);
52
extern void free(void *);
53
 
54
// Allocate a new addrinfo structure and if passed an existing
55
// addrinfo copy all the port, protocol info into the new structure
56
// and then link the new onto the old.
57
 
58
struct addrinfo * alloc_addrinfo(struct addrinfo * ai) {
59
 
60
    struct addrinfo * nai;
61
    struct sockaddr * sa;
62
 
63
    nai = (struct addrinfo *)malloc(sizeof(struct addrinfo));
64
    if (!nai) {
65
        return NULL;
66
    }
67
    sa = (struct sockaddr *) malloc(sizeof(struct sockaddr));
68
    if (!sa) {
69
        free (nai);
70
        return NULL;
71
    }
72
    memset(sa,0,sizeof(*sa));
73
 
74
    if (ai) {
75
        memcpy(nai,ai,sizeof(struct addrinfo));
76
        ai->ai_next = nai;
77
    } else {
78
        memset(nai,0,sizeof(*nai));
79
    }
80
    nai->ai_addr = sa;
81
    nai->ai_addrlen = sizeof(*sa);
82
 
83
    return nai;
84
}
85
 
86
// getaddrinfo has not been passed a hostname. So it should use the
87
// loopback or the any address.
88
static int
89
no_node_addr(struct addrinfo *ai, const struct addrinfo *hints, int port) {
90
 
91
    switch (hints->ai_family) {
92
    case AF_INET: {
93
        struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
94
        if (hints->ai_flags & AI_PASSIVE) {
95
            sa->sin_addr.s_addr = htonl(INADDR_ANY);
96
        } else {
97
            sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
98
        }
99
        sa->sin_len = sizeof(*sa);
100
        sa->sin_port = htons(port);
101
        sa->sin_family = AF_INET;
102
        ai->ai_family = AF_INET;
103
        break;
104
    }
105
#ifdef CYGPKG_NET_INET6
106
    case AF_INET6: {
107
        struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
108
        if (hints->ai_flags & AI_PASSIVE) {
109
            memcpy(&sa->sin6_addr, &in6addr_any, sizeof(sa->sin6_addr));
110
        } else {
111
            memcpy(&sa->sin6_addr, &in6addr_loopback, sizeof(sa->sin6_addr));
112
        }
113
        sa->sin6_len = sizeof(*sa);
114
        sa->sin6_port = htons(port);
115
        sa->sin6_family = AF_INET6;
116
        ai->ai_family = AF_INET6;
117
        break;
118
    }
119
#endif
120
    case PF_UNSPEC: {
121
        struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
122
        if (hints->ai_flags & AI_PASSIVE) {
123
            sa->sin_addr.s_addr = htonl(INADDR_ANY);
124
        } else {
125
            sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
126
        }
127
        sa->sin_len = sizeof(*sa);
128
        sa->sin_port = htons(port);
129
        sa->sin_family = AF_INET;
130
        ai->ai_family = AF_INET;
131
#ifdef CYGPKG_NET_INET6 
132
        {
133
            struct sockaddr_in6 *sa6;
134
            ai=alloc_addrinfo(ai);
135
            if (ai == NULL) {
136
                return EAI_MEMORY;
137
            }
138
            sa6 = (struct sockaddr_in6 *) ai->ai_addr;
139
            if (hints->ai_flags & AI_PASSIVE) {
140
                memcpy(&sa6->sin6_addr, &in6addr_any, sizeof(sa6->sin6_addr));
141
            } else {
142
                memcpy(&sa6->sin6_addr, &in6addr_loopback, sizeof(sa6->sin6_addr));
143
            }
144
            sa6->sin6_len = sizeof(*sa);
145
            sa6->sin6_port = htons(port);
146
            sa6->sin6_family = AF_INET6;
147
            ai->ai_family = AF_INET6;
148
        }
149
#endif
150
        break;
151
    }
152
    }
153
   return EAI_NONE;
154
}
155
 
156
 
157
// We have been asked to convert only numeric addresses so as to not
158
// need a DNS server query.
159
static int
160
numeric_node_addr(struct addrinfo *ai, const char *node,
161
               const struct addrinfo *hints, int port) {
162
 
163
    switch (hints->ai_family) {
164
    case AF_INET: {
165
        struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
166
        if (!inet_pton(AF_INET, node, (void *)&sa->sin_addr.s_addr)) {
167
            return EAI_FAIL;
168
        }
169
        sa->sin_port = htons(port);
170
        sa->sin_family = AF_INET;
171
        sa->sin_len = sizeof(*sa);
172
        ai->ai_family = AF_INET;
173
        break;
174
    }
175
#ifdef CYGPKG_NET_INET6
176
    case AF_INET6: {
177
        struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
178
        if (!inet_pton(AF_INET6, node, (void *)&sa->sin6_addr.s6_addr)) {
179
            return EAI_FAIL;
180
        }
181
        sa->sin6_port = htons(port);
182
        sa->sin6_family = AF_INET6;
183
        sa->sin6_len = sizeof(*sa);
184
        ai->ai_family = AF_INET6;
185
        break;
186
    }
187
#endif
188
    case PF_UNSPEC: {
189
        struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
190
        sa->sin_len = sizeof(*sa);
191
        sa->sin_port = htons(port);
192
        sa->sin_family = AF_INET;
193
        ai->ai_family = AF_INET;
194
        if (inet_pton(AF_INET, node, (void *)&sa->sin_addr.s_addr)) {
195
          return EAI_NONE;
196
        }
197
#ifdef CYGPKG_NET_INET6
198
        {
199
            struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
200
            sa->sin6_len = sizeof(*sa);
201
            sa->sin6_port = htons(port);
202
            sa->sin6_family = AF_INET6;
203
            ai->ai_family = AF_INET6;
204
            if (inet_pton(AF_INET6, node, (void *)&sa->sin6_addr.s6_addr)) {
205
                return EAI_NONE;
206
            }
207
        }
208
#endif
209
        return EAI_FAIL;
210
        break;
211
    }
212
    }
213
    return EAI_NONE;
214
}
215
 
216
// We have a host name. Use the DNS client to perform a lookup. If the
217
// DNS client is not part of the configuration try using the numeric
218
// convertion.
219
static int
220
with_node_addr(struct addrinfo *ai, const char *node,
221
               const struct addrinfo *hints, int port) {
222
 
223
#ifdef CYGPKG_NS_DNS_BUILD
224
    struct sockaddr addrs[CYGNUM_NS_DNS_GETADDRINFO_ADDRESSES];
225
    int nresults;
226
    int i;
227
    char ** canon = NULL;
228
 
229
    if (hints->ai_flags & AI_CANONNAME) {
230
        canon = &ai->ai_canonname;
231
    }
232
    nresults = cyg_dns_getaddrinfo(node,
233
                                   addrs, CYGNUM_NS_DNS_GETADDRINFO_ADDRESSES,
234
                                   hints->ai_family, canon);
235
    if (nresults < 0) {
236
        return -nresults;
237
    }
238
 
239
    for (i=0; i < nresults; i++) {
240
        if (i != 0) {
241
            ai = alloc_addrinfo(ai);
242
            if (ai == NULL) {
243
                return EAI_MEMORY;
244
            }
245
        }
246
        memcpy(ai->ai_addr, &addrs[i], sizeof(addrs[i]));
247
        ai->ai_family = addrs[i].sa_family;
248
        ai->ai_addrlen = addrs[i].sa_len;
249
        switch (ai->ai_family) {
250
        case AF_INET: {
251
            struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
252
            sa->sin_port = htons(port);
253
            break;
254
        }
255
#ifdef CYGPKG_NET_INET6
256
        case AF_INET6: {
257
            struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
258
            sa->sin6_port = htons(port);
259
            break;
260
        }
261
#endif
262
        }
263
    }
264
    return EAI_NONE;
265
#else
266
    return (numeric_node_addr(ai, node, hints, port));
267
#endif
268
}
269
 
270
int
271
getaddrinfo(const char *nodename, const char *servname,
272
            const struct addrinfo *hints, struct addrinfo **res)
273
{
274
    struct addrinfo dflt_hints;
275
    struct protoent *proto = (struct protoent *)NULL;
276
    struct addrinfo *ai;
277
    char *protoname;
278
    char *endptr;
279
    int port = 0;
280
    int err;
281
 
282
    if (hints == (struct addrinfo *)NULL) {
283
        dflt_hints.ai_flags = 0;  // No special flags
284
        dflt_hints.ai_family = PF_UNSPEC;
285
        dflt_hints.ai_socktype = 0;
286
        dflt_hints.ai_protocol = 0;
287
        hints = &dflt_hints;
288
    }
289
    // Prevalidate parameters
290
    if ((nodename == (char *)NULL) && (servname == (char *)NULL)) {
291
        return EAI_NONAME;
292
    }
293
    switch (hints->ai_family) {
294
    case PF_UNSPEC:
295
    case PF_INET:
296
        break;
297
#ifdef CYGPKG_NET_INET6
298
    case PF_INET6:
299
        break;
300
#endif
301
    default:
302
        return EAI_FAMILY;
303
    }
304
    // Allocate the first/primary result
305
    *res = ai = alloc_addrinfo(NULL);
306
    if (ai == (struct addrinfo *)NULL) {
307
        return EAI_MEMORY;
308
    }
309
    // Handle request
310
    if (hints->ai_protocol != 0) {
311
        proto = getprotobynumber(hints->ai_protocol);
312
    }
313
 
314
    // Note: this does not handle the case where a given service can be
315
    // handled via multiple protocols, e.g. http/tcp & http/udp
316
    if (servname != (char *)NULL) {
317
        switch (hints->ai_socktype) {
318
        case 0:
319
        case SOCK_STREAM:
320
            protoname = "tcp";
321
            ai->ai_socktype = SOCK_STREAM;
322
            break;
323
        case SOCK_DGRAM:
324
            protoname = "udp";
325
            ai->ai_socktype = SOCK_DGRAM;
326
            break;
327
        default:
328
            freeaddrinfo(ai);
329
            return EAI_SOCKTYPE;
330
        }
331
        // See if this is just a port #
332
        if (((port = strtol(servname, &endptr, 0)) >= 0) &&
333
            (endptr > servname)) {
334
            ai->ai_socktype = hints->ai_socktype;
335
            if (hints->ai_socktype == 0) {
336
                // Need to have complete binding type/port
337
                freeaddrinfo(ai);
338
                return EAI_SERVICE;
339
            }
340
        } else {
341
            struct servent *serv = (struct servent *)NULL;
342
 
343
            serv = getservbyname(servname, protoname);
344
            if (serv == (struct servent *)NULL) {
345
                if (hints->ai_socktype == 0) {
346
                    protoname = "udp";
347
                    ai->ai_socktype = SOCK_DGRAM;
348
                    serv = getservbyname(servname, protoname);
349
                }
350
            }
351
            if (serv == (struct servent *)NULL) {
352
                freeaddrinfo(ai);
353
                return EAI_SERVICE;
354
            }
355
            port = ntohs(serv->s_port);
356
        }
357
        proto = getprotobyname(protoname);
358
        if (hints->ai_protocol && (hints->ai_protocol != proto->p_proto)) {
359
            freeaddrinfo(ai);
360
            return EAI_SOCKTYPE;
361
        }
362
        ai->ai_protocol = proto->p_proto;
363
    }
364
 
365
    if (nodename) {
366
        if (hints->ai_flags & AI_NUMERICHOST) {
367
            err = numeric_node_addr(ai, nodename, hints, port);
368
        } else {
369
            err = with_node_addr(ai, nodename, hints, port );
370
        }
371
    } else {
372
        err = no_node_addr(ai, hints, port);
373
    }
374
 
375
    if (err != EAI_NONE) {
376
        freeaddrinfo(ai);
377
        return err;
378
    }
379
 
380
    if ((hints->ai_flags & AI_CANONNAME) && !nodename) {
381
        ai->ai_canonname = malloc(strlen("localhost")+1);
382
        if (ai->ai_canonname) {
383
            strcpy(ai->ai_canonname, "localhost");
384
        } else {
385
            freeaddrinfo(ai);
386
            return EAI_MEMORY;
387
        }
388
    }
389
 
390
    /* The DNS code may have filled in the official address. If not
391
       and we have been asked for it, return an error */
392
    if ((hints->ai_flags & AI_CANONNAME) & !ai->ai_canonname) {
393
        freeaddrinfo(ai);
394
        return EAI_FAIL;
395
    }
396
    return EAI_NONE;  // No errors
397
}
398
 
399
// The canonname will probably point to the same memory in each
400
// addrinfo in the linked list. Don't free it multiple times.
401
void
402
freeaddrinfo(struct addrinfo *ai)
403
{
404
    struct addrinfo *next = ai;
405
    char * last_canonname = NULL;
406
 
407
    while ((ai = next) != (struct addrinfo *)NULL) {
408
        if ((ai->ai_canonname) &&
409
            (ai->ai_canonname != last_canonname)) {
410
            free(ai->ai_canonname);
411
            last_canonname = ai->ai_canonname;
412
        }
413
        if (ai->ai_addr) free(ai->ai_addr);
414
        next = ai->ai_next;
415
        free(ai);
416
    }
417
}
418
 
419
char
420
*gai_strerror(int err)
421
{
422
    switch (err) {
423
    case EAI_NONE:
424
        return "EAI - no error";
425
    case EAI_AGAIN:
426
        return "EAI - temporary failure in name resolution";
427
    case EAI_BADFLAGS:
428
        return "EAI - invalid flags";
429
    case EAI_FAIL:
430
        return "EAI - non-recoverable failure in name resolution";
431
    case EAI_FAMILY:
432
        return "EAI - family not supported";
433
    case EAI_MEMORY:
434
        return "EAI - memory allocation failure";
435
    case EAI_NONAME:
436
        return "EAI - hostname nor servname provided, or not known";
437
    case EAI_SERVICE:
438
        return "EAI - servname not supported for socket type";
439
    case EAI_SOCKTYPE:
440
        return "EAI - socket type not supported";
441
    case EAI_SYSTEM:
442
        return "EAI - system error";
443
    case EAI_BADHINTS:
444
        return "EAI - inconsistent hints";
445
    case EAI_PROTOCOL:
446
        return "EAI - bad protocol";
447
    default:
448
        return "EAI - unknown error";
449
    }
450
}
451
 
452
// Set of flags implemented
453
#define NI_MASK (NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM)
454
 
455
int
456
getnameinfo (const struct sockaddr *sa, socklen_t salen,
457
             char *host, socklen_t hostlen,
458
             char *serv, socklen_t servlen,
459
             unsigned int flags)
460
{
461
    int port;
462
    char *s;
463
    struct servent *se;
464
    int error;
465
    int numeric = (flags & NI_NUMERICHOST);
466
 
467
    if ((flags & ~NI_MASK) != 0) {
468
        return EAI_BADFLAGS;
469
    }
470
    switch (sa->sa_family) {
471
    case PF_INET:
472
#ifdef CYGPKG_NET_INET6
473
    case PF_INET6:
474
#endif
475
        if (host != (char *)NULL) {
476
            if ( !numeric) {
477
                error = EAI_NONAME;
478
#ifdef CYGPKG_NS_DNS_BUILD
479
                error = -cyg_dns_getnameinfo(sa, host,hostlen);
480
#endif
481
                if ((error == EAI_NONAME) && (flags & NI_NAMEREQD)) {
482
                    return EAI_NONAME;
483
                }
484
                // If lookup failed, try it as numeric address
485
                numeric = !(error == EAI_NONE);
486
            }
487
            if (numeric) {
488
                s = _inet_ntop((struct sockaddr *)sa, host, hostlen);
489
                if (!s) {
490
                    return EAI_FAIL;
491
                }
492
            }
493
            if (!numeric && flags & NI_NOFQDN) {
494
                s = index(host, '.');
495
                if (s) {
496
                    *s = '\0';
497
                }
498
            }
499
        }
500
 
501
        if (serv != (char *)NULL) {
502
            port = _inet_port((struct sockaddr *)sa);
503
            if (!port) {
504
                return EAI_FAIL;
505
            }
506
            se = (struct servent *)NULL;
507
            if ((flags & NI_NUMERICSERV) == 0) {
508
                if ((flags & NI_DGRAM) == 0) {
509
                    se = getservbyport(htons(port), "tcp");
510
                }
511
                if (se == (struct servent *)NULL) {
512
                    se = getservbyport(htons(port), "udp");
513
                }
514
            }
515
            if (se != (struct servent *)NULL) {
516
                diag_snprintf(serv,servlen, "%s/%s", se->s_name, se->s_proto);
517
            } else {
518
                diag_snprintf(serv,servlen, "%d", port);
519
            }
520
        }
521
        break;
522
    default:
523
        return EAI_FAMILY;
524
    }
525
    return EAI_NONE;
526
}

powered by: WebSVN 2.1.0

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