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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libc/] [inet/] [getaddrinfo.c] - Blame information for rev 1766

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/* $USAGI: getaddrinfo.c,v 1.16 2001/10/04 09:52:03 sekiya Exp $ */
2
 
3
/* The Inner Net License, Version 2.00
4
 
5
  The author(s) grant permission for redistribution and use in source and
6
binary forms, with or without modification, of the software and documentation
7
provided that the following conditions are met:
8
 
9
0. If you receive a version of the software that is specifically labelled
10
   as not being for redistribution (check the version message and/or README),
11
   you are not permitted to redistribute that version of the software in any
12
   way or form.
13
1. All terms of the all other applicable copyrights and licenses must be
14
   followed.
15
2. Redistributions of source code must retain the authors' copyright
16
   notice(s), this list of conditions, and the following disclaimer.
17
3. Redistributions in binary form must reproduce the authors' copyright
18
   notice(s), this list of conditions, and the following disclaimer in the
19
   documentation and/or other materials provided with the distribution.
20
4. All advertising materials mentioning features or use of this software
21
   must display the following acknowledgement with the name(s) of the
22
   authors as specified in the copyright notice(s) substituted where
23
   indicated:
24
 
25
        This product includes software developed by <name(s)>, The Inner
26
        Net, and other contributors.
27
 
28
5. Neither the name(s) of the author(s) nor the names of its contributors
29
   may be used to endorse or promote products derived from this software
30
   without specific prior written permission.
31
 
32
THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
33
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
36
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
39
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
 
43
  If these license terms cause you a real problem, contact the author.  */
44
 
45
/* This software is Copyright 1996 by Craig Metz, All Rights Reserved.  */
46
 
47
#define _GNU_SOURCE
48
#define __FORCE_GLIBC
49
#include <features.h>
50
#include <assert.h>
51
#include <errno.h>
52
#include <netdb.h>
53
#include <resolv.h>
54
#include <stdio.h>
55
#include <stdlib.h>
56
#include <string.h>
57
#include <unistd.h>
58
#include <arpa/inet.h>
59
#include <sys/socket.h>
60
#include <netinet/in.h>
61
#include <sys/types.h>
62
#include <sys/un.h>
63
#include <sys/utsname.h>
64
#include <net/if.h>
65
 
66
/* The following declarations and definitions have been removed from
67
 *    the public header since we don't want people to use them.  */
68
#define AI_V4MAPPED     0x0008  /* IPv4-mapped addresses are acceptable.  */
69
#define AI_ALL          0x0010  /* Return both IPv4 and IPv6 addresses.  */
70
#define AI_ADDRCONFIG   0x0020  /* Use configuration of this host to choose 
71
                                    returned address type.  */
72
#define AI_DEFAULT    (AI_V4MAPPED | AI_ADDRCONFIG)
73
 
74
 
75
#define GAIH_OKIFUNSPEC 0x0100
76
#define GAIH_EAI        ~(GAIH_OKIFUNSPEC)
77
 
78
#ifndef UNIX_PATH_MAX
79
#define UNIX_PATH_MAX  108
80
#endif
81
 
82
struct gaih_service
83
{
84
    const char *name;
85
    int num;
86
};
87
 
88
struct gaih_servtuple
89
{
90
    struct gaih_servtuple *next;
91
    int socktype;
92
    int protocol;
93
    int port;
94
};
95
 
96
static const struct gaih_servtuple nullserv;
97
 
98
struct gaih_addrtuple
99
{
100
    struct gaih_addrtuple *next;
101
    int family;
102
    char addr[16];
103
    uint32_t scopeid;
104
};
105
 
106
struct gaih_typeproto
107
{
108
    int socktype;
109
    int protocol;
110
    char name[4];
111
    int protoflag;
112
};
113
 
114
/* Values for `protoflag'.  */
115
#define GAI_PROTO_NOSERVICE     1
116
#define GAI_PROTO_PROTOANY      2
117
 
118
static const struct gaih_typeproto gaih_inet_typeproto[] =
119
{
120
    { 0, 0, "", 0 },
121
    { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
122
    { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
123
    { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
124
    { 0, 0, "", 0 }
125
};
126
 
127
struct gaih
128
{
129
    int family;
130
    int (*gaih)(const char *name, const struct gaih_service *service,
131
                const struct addrinfo *req, struct addrinfo **pai);
132
};
133
 
134
#if PF_UNSPEC == 0
135
static const struct addrinfo default_hints;
136
#else
137
static const struct addrinfo default_hints =
138
{ 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
139
#endif
140
 
141
 
142
static int addrconfig (sa_family_t af)
143
{
144
    int s;
145
    int ret;
146
    int saved_errno = errno;
147
    s = socket(af, SOCK_DGRAM, 0);
148
    if (s < 0)
149
        ret = (errno == EMFILE) ? 1 : 0;
150
    else
151
    {
152
        close(s);
153
        ret = 1;
154
    }
155
    __set_errno (saved_errno);
156
    return ret;
157
}
158
 
159
#if 0
160
/* Using Unix sockets this way is a security risk.  */
161
static int
162
gaih_local (const char *name, const struct gaih_service *service,
163
            const struct addrinfo *req, struct addrinfo **pai)
164
{
165
    struct utsname utsname;
166
 
167
    if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
168
        return GAIH_OKIFUNSPEC | -EAI_NONAME;
169
 
170
    if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
171
        if (uname (&utsname) < 0)
172
            return -EAI_SYSTEM;
173
 
174
    if (name != NULL)
175
    {
176
        if (strcmp(name, "localhost") &&
177
            strcmp(name, "local") &&
178
            strcmp(name, "unix") &&
179
            strcmp(name, utsname.nodename))
180
            return GAIH_OKIFUNSPEC | -EAI_NONAME;
181
    }
182
 
183
    if (req->ai_protocol || req->ai_socktype)
184
    {
185
        const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
186
 
187
        while (tp->name[0]
188
               && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
189
                   || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
190
                   || (req->ai_protocol != 0
191
                       && !(tp->protoflag & GAI_PROTO_PROTOANY)
192
                       && req->ai_protocol != tp->protocol)))
193
            ++tp;
194
 
195
        if (! tp->name[0])
196
        {
197
            if (req->ai_socktype)
198
                return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
199
            else
200
                return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
201
        }
202
    }
203
 
204
    *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
205
                   + ((req->ai_flags & AI_CANONNAME)
206
                      ? (strlen(utsname.nodename) + 1): 0));
207
    if (*pai == NULL)
208
        return -EAI_MEMORY;
209
 
210
    (*pai)->ai_next = NULL;
211
    (*pai)->ai_flags = req->ai_flags;
212
    (*pai)->ai_family = AF_LOCAL;
213
    (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
214
    (*pai)->ai_protocol = req->ai_protocol;
215
    (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
216
    (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
217
 
218
#if SALEN
219
    ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
220
        sizeof (struct sockaddr_un);
221
#endif /* SALEN */
222
 
223
    ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
224
    memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
225
 
226
    if (service)
227
    {
228
        struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
229
 
230
        if (strchr (service->name, '/') != NULL)
231
        {
232
            if (strlen (service->name) >= sizeof (sunp->sun_path))
233
                return GAIH_OKIFUNSPEC | -EAI_SERVICE;
234
 
235
            strcpy (sunp->sun_path, service->name);
236
        }
237
        else
238
        {
239
            if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
240
                sizeof (sunp->sun_path))
241
                return GAIH_OKIFUNSPEC | -EAI_SERVICE;
242
 
243
            __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
244
        }
245
    }
246
    else
247
    {
248
        /* This is a dangerous use of the interface since there is a time
249
           window between the test for the file and the actual creation
250
           (done by the caller) in which a file with the same name could
251
           be created.  */
252
        char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
253
 
254
        if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
255
                              0) != 0
256
            || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
257
            return -EAI_SYSTEM;
258
    }
259
 
260
    if (req->ai_flags & AI_CANONNAME)
261
        (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
262
                                       + sizeof (struct sockaddr_un),
263
                                       utsname.nodename);
264
    else
265
        (*pai)->ai_canonname = NULL;
266
    return 0;
267
}
268
#endif  /* 0 */
269
 
270
static int
271
gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
272
                const struct addrinfo *req, struct gaih_servtuple *st)
273
{
274
    struct servent *s;
275
    size_t tmpbuflen = 1024;
276
    struct servent ts;
277
    char *tmpbuf;
278
    int r;
279
 
280
    do
281
    {
282
        tmpbuf = alloca (tmpbuflen);
283
 
284
        r = getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
285
                             &s);
286
        if (r != 0 || s == NULL)
287
        {
288
            if (r == ERANGE)
289
                tmpbuflen *= 2;
290
            else
291
                return GAIH_OKIFUNSPEC | -EAI_SERVICE;
292
        }
293
    }
294
    while (r);
295
 
296
    st->next = NULL;
297
    st->socktype = tp->socktype;
298
    st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
299
                    ? req->ai_protocol : tp->protocol);
300
    st->port = s->s_port;
301
 
302
    return 0;
303
}
304
 
305
#define gethosts(_family, _type)                                        \
306
{                                                                       \
307
    int i, herrno;                                                      \
308
    size_t tmpbuflen;                                                   \
309
    struct hostent th;                                                  \
310
    char *tmpbuf;                                                       \
311
    tmpbuflen = 512;                                                    \
312
    no_data = 0;                                                 \
313
    do {                                                                \
314
        tmpbuflen *= 2;                                                 \
315
        tmpbuf = alloca (tmpbuflen);                                    \
316
        rc = gethostbyname2_r (name, _family, &th, tmpbuf,              \
317
                               tmpbuflen, &h, &herrno);                 \
318
    } while (rc == ERANGE && herrno == NETDB_INTERNAL);                 \
319
    if (rc != 0)                                                 \
320
    {                                                                   \
321
        if (herrno == NETDB_INTERNAL)                                   \
322
        {                                                               \
323
            __set_h_errno (herrno);                                     \
324
                return -EAI_SYSTEM;                                     \
325
        }                                                               \
326
        if (herrno == TRY_AGAIN)                                        \
327
            no_data = EAI_AGAIN;                                        \
328
        else                                                            \
329
            no_data = herrno == NO_DATA;                                \
330
    }                                                                   \
331
    else if (h != NULL)                                                 \
332
    {                                                                   \
333
        for (i = 0; h->h_addr_list[i]; i++)                              \
334
        {                                                               \
335
            if (*pat == NULL) {                                         \
336
                *pat = alloca (sizeof(struct gaih_addrtuple));          \
337
                    (*pat)->scopeid = 0;                         \
338
            }                                                           \
339
            (*pat)->next = NULL;                                        \
340
                (*pat)->family = _family;                               \
341
                memcpy ((*pat)->addr, h->h_addr_list[i],                \
342
                        sizeof(_type));                                 \
343
                pat = &((*pat)->next);                                  \
344
        }                                                               \
345
    }                                                                   \
346
}
347
 
348
static int
349
gaih_inet (const char *name, const struct gaih_service *service,
350
           const struct addrinfo *req, struct addrinfo **pai)
351
{
352
    const struct gaih_typeproto *tp = gaih_inet_typeproto;
353
    struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
354
    struct gaih_addrtuple *at = NULL;
355
    int rc;
356
    int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6) &&
357
        (req->ai_flags & AI_V4MAPPED);
358
 
359
    if (req->ai_protocol || req->ai_socktype)
360
    {
361
        ++tp;
362
 
363
        while (tp->name[0]
364
               && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
365
                   || (req->ai_protocol != 0
366
                       && !(tp->protoflag & GAI_PROTO_PROTOANY)
367
                       && req->ai_protocol != tp->protocol)))
368
            ++tp;
369
 
370
        if (! tp->name[0])
371
        {
372
            if (req->ai_socktype)
373
                return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
374
            else
375
                return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
376
        }
377
    }
378
 
379
    if (service != NULL)
380
    {
381
        if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
382
            return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
383
 
384
        if (service->num < 0)
385
        {
386
            if (tp->name[0])
387
            {
388
                st = (struct gaih_servtuple *)
389
                    alloca (sizeof (struct gaih_servtuple));
390
 
391
                if ((rc = gaih_inet_serv (service->name, tp, req, st)))
392
                    return rc;
393
            }
394
            else
395
            {
396
                struct gaih_servtuple **pst = &st;
397
                for (tp++; tp->name[0]; tp++)
398
                {
399
                    struct gaih_servtuple *newp;
400
 
401
                    if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
402
                        continue;
403
 
404
                    if (req->ai_socktype != 0
405
                        && req->ai_socktype != tp->socktype)
406
                        continue;
407
                    if (req->ai_protocol != 0
408
                        && !(tp->protoflag & GAI_PROTO_PROTOANY)
409
                        && req->ai_protocol != tp->protocol)
410
                        continue;
411
 
412
                    newp = (struct gaih_servtuple *)
413
                        alloca (sizeof (struct gaih_servtuple));
414
 
415
                    if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
416
                    {
417
                        if (rc & GAIH_OKIFUNSPEC)
418
                            continue;
419
                        return rc;
420
                    }
421
 
422
                    *pst = newp;
423
                    pst = &(newp->next);
424
                }
425
                if (st == (struct gaih_servtuple *) &nullserv)
426
                    return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
427
            }
428
        }
429
        else
430
        {
431
            st = alloca (sizeof (struct gaih_servtuple));
432
            st->next = NULL;
433
            st->socktype = tp->socktype;
434
            st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
435
                            ? req->ai_protocol : tp->protocol);
436
            st->port = htons (service->num);
437
        }
438
    }
439
    else if (req->ai_socktype || req->ai_protocol)
440
    {
441
        st = alloca (sizeof (struct gaih_servtuple));
442
        st->next = NULL;
443
        st->socktype = tp->socktype;
444
        st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
445
                        ? req->ai_protocol : tp->protocol);
446
        st->port = 0;
447
    }
448
    else
449
    {
450
        /*
451
         * Neither socket type nor protocol is set.  Return all socket types
452
         * we know about.
453
         */
454
        struct gaih_servtuple **lastp = &st;
455
        for (++tp; tp->name[0]; ++tp)
456
        {
457
            struct gaih_servtuple *newp;
458
 
459
            newp = alloca (sizeof (struct gaih_servtuple));
460
            newp->next = NULL;
461
            newp->socktype = tp->socktype;
462
            newp->protocol = tp->protocol;
463
            newp->port = 0;
464
 
465
            *lastp = newp;
466
            lastp = &newp->next;
467
        }
468
    }
469
 
470
    if (name != NULL)
471
    {
472
        at = alloca (sizeof (struct gaih_addrtuple));
473
 
474
        at->family = AF_UNSPEC;
475
        at->scopeid = 0;
476
        at->next = NULL;
477
 
478
        if (inet_pton (AF_INET, name, at->addr) > 0)
479
        {
480
            if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
481
                at->family = AF_INET;
482
            else
483
                return -EAI_FAMILY;
484
        }
485
 
486
#if __UCLIBC_HAS_IPV6__
487
        if (at->family == AF_UNSPEC)
488
        {
489
            char *namebuf = strdupa (name);
490
            char *scope_delim;
491
 
492
            scope_delim = strchr (namebuf, SCOPE_DELIMITER);
493
            if (scope_delim != NULL)
494
                *scope_delim = '\0';
495
 
496
            if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
497
            {
498
                if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
499
                    at->family = AF_INET6;
500
                else
501
                    return -EAI_FAMILY;
502
 
503
                if (scope_delim != NULL)
504
                {
505
                    int try_numericscope = 0;
506
                    if (IN6_IS_ADDR_LINKLOCAL (at->addr)
507
                        || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
508
                    {
509
                        at->scopeid = if_nametoindex (scope_delim + 1);
510
                        if (at->scopeid == 0)
511
                            try_numericscope = 1;
512
                    }
513
                    else
514
                        try_numericscope = 1;
515
 
516
                    if (try_numericscope != 0)
517
                    {
518
                        char *end;
519
                        assert (sizeof (uint32_t) <= sizeof (unsigned long));
520
                        at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
521
                                                          10);
522
                        if (*end != '\0')
523
                            return GAIH_OKIFUNSPEC | -EAI_NONAME;
524
                    }
525
                }
526
            }
527
        }
528
#endif
529
 
530
        if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
531
        {
532
            struct hostent *h;
533
            struct gaih_addrtuple **pat = &at;
534
            int no_data = 0;
535
            int no_inet6_data;
536
 
537
            /*
538
             * If we are looking for both IPv4 and IPv6 address we don't want
539
             * the lookup functions to automatically promote IPv4 addresses to
540
             * IPv6 addresses.
541
             */
542
 
543
#if __UCLIBC_HAS_IPV6__
544
            if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
545
                gethosts (AF_INET6, struct in6_addr);
546
#endif
547
            no_inet6_data = no_data;
548
 
549
            if (req->ai_family == AF_INET ||
550
                (!v4mapped && req->ai_family == AF_UNSPEC) ||
551
                (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL))))
552
                gethosts (AF_INET, struct in_addr);
553
 
554
            if (no_data != 0 && no_inet6_data != 0)
555
            {
556
                /* If both requests timed out report this. */
557
                if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
558
                    return -EAI_AGAIN;
559
 
560
                /*
561
                 * We made requests but they turned out no data.
562
                 * The name is known, though.
563
                 */
564
                return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
565
            }
566
        }
567
 
568
        if (at->family == AF_UNSPEC)
569
            return (GAIH_OKIFUNSPEC | -EAI_NONAME);
570
    }
571
    else
572
    {
573
        struct gaih_addrtuple *atr;
574
        atr = at = alloca (sizeof (struct gaih_addrtuple));
575
        memset (at, '\0', sizeof (struct gaih_addrtuple));
576
 
577
        if (req->ai_family == 0)
578
        {
579
            at->next = alloca (sizeof (struct gaih_addrtuple));
580
            memset (at->next, '\0', sizeof (struct gaih_addrtuple));
581
        }
582
 
583
#if __UCLIBC_HAS_IPV6__
584
        if (req->ai_family == 0 || req->ai_family == AF_INET6)
585
        {
586
            extern const struct in6_addr __in6addr_loopback;
587
            at->family = AF_INET6;
588
            if ((req->ai_flags & AI_PASSIVE) == 0)
589
                memcpy (at->addr, &__in6addr_loopback, sizeof (struct in6_addr));
590
            atr = at->next;
591
        }
592
#endif
593
 
594
        if (req->ai_family == 0 || req->ai_family == AF_INET)
595
        {
596
            atr->family = AF_INET;
597
            if ((req->ai_flags & AI_PASSIVE) == 0)
598
                *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
599
        }
600
    }
601
 
602
    if (pai == NULL)
603
        return 0;
604
 
605
    {
606
        const char *c = NULL;
607
        struct gaih_servtuple *st2;
608
        struct gaih_addrtuple *at2 = at;
609
        size_t socklen, namelen;
610
        sa_family_t family;
611
 
612
        /*
613
         * buffer is the size of an unformatted IPv6 address in
614
         * printable format.
615
         */
616
        char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
617
 
618
        while (at2 != NULL)
619
        {
620
            if (req->ai_flags & AI_CANONNAME)
621
            {
622
                struct hostent *h = NULL;
623
 
624
                int herrno;
625
                struct hostent th;
626
                size_t tmpbuflen = 512;
627
                char *tmpbuf;
628
 
629
                do
630
                {
631
                    tmpbuflen *= 2;
632
                    tmpbuf = alloca (tmpbuflen);
633
 
634
                    if (tmpbuf == NULL)
635
                        return -EAI_MEMORY;
636
 
637
                    rc = gethostbyaddr_r (at2->addr,
638
                                          ((at2->family == AF_INET6)
639
                                           ? sizeof(struct in6_addr)
640
                                           : sizeof(struct in_addr)),
641
                                          at2->family, &th, tmpbuf, tmpbuflen,
642
                                          &h, &herrno);
643
 
644
                }
645
                while (rc == errno && herrno == NETDB_INTERNAL);
646
 
647
                if (rc != 0 && herrno == NETDB_INTERNAL)
648
                {
649
                    __set_h_errno (herrno);
650
                    return -EAI_SYSTEM;
651
                }
652
 
653
                if (h == NULL)
654
                    c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
655
                else
656
                    c = h->h_name;
657
 
658
                if (c == NULL)
659
                    return GAIH_OKIFUNSPEC | -EAI_NONAME;
660
 
661
                namelen = strlen (c) + 1;
662
            }
663
            else
664
                namelen = 0;
665
 
666
#if __UCLIBC_HAS_IPV6__
667
            if (at2->family == AF_INET6 || v4mapped)
668
            {
669
                family = AF_INET6;
670
                socklen = sizeof (struct sockaddr_in6);
671
            }
672
            else
673
#endif
674
            {
675
                family = AF_INET;
676
                socklen = sizeof (struct sockaddr_in);
677
            }
678
 
679
            for (st2 = st; st2 != NULL; st2 = st2->next)
680
            {
681
                *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
682
                if (*pai == NULL)
683
                    return -EAI_MEMORY;
684
 
685
                (*pai)->ai_flags = req->ai_flags;
686
                (*pai)->ai_family = family;
687
                (*pai)->ai_socktype = st2->socktype;
688
                (*pai)->ai_protocol = st2->protocol;
689
                (*pai)->ai_addrlen = socklen;
690
                (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
691
#if SALEN
692
                (*pai)->ai_addr->sa_len = socklen;
693
#endif /* SALEN */
694
                (*pai)->ai_addr->sa_family = family;
695
 
696
#if __UCLIBC_HAS_IPV6__
697
                if (family == AF_INET6)
698
                {
699
                    struct sockaddr_in6 *sin6p =
700
                        (struct sockaddr_in6 *) (*pai)->ai_addr;
701
 
702
                    sin6p->sin6_flowinfo = 0;
703
                    if (at2->family == AF_INET6)
704
                    {
705
                        memcpy (&sin6p->sin6_addr,
706
                                at2->addr, sizeof (struct in6_addr));
707
                    }
708
                    else
709
                    {
710
                        sin6p->sin6_addr.s6_addr32[0] = 0;
711
                        sin6p->sin6_addr.s6_addr32[1] = 0;
712
                        sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
713
                        memcpy(&sin6p->sin6_addr.s6_addr32[3],
714
                               at2->addr, sizeof (sin6p->sin6_addr.s6_addr32[3]));
715
                    }
716
                    sin6p->sin6_port = st2->port;
717
                    sin6p->sin6_scope_id = at2->scopeid;
718
                }
719
                else
720
#endif
721
                {
722
                    struct sockaddr_in *sinp =
723
                        (struct sockaddr_in *) (*pai)->ai_addr;
724
 
725
                    memcpy (&sinp->sin_addr,
726
                            at2->addr, sizeof (struct in_addr));
727
                    sinp->sin_port = st2->port;
728
                    memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
729
                }
730
 
731
                if (c)
732
                {
733
                    (*pai)->ai_canonname = ((void *) (*pai) +
734
                                            sizeof (struct addrinfo) + socklen);
735
                    strcpy ((*pai)->ai_canonname, c);
736
                }
737
                else
738
                    (*pai)->ai_canonname = NULL;
739
 
740
                (*pai)->ai_next = NULL;
741
                pai = &((*pai)->ai_next);
742
            }
743
 
744
            at2 = at2->next;
745
        }
746
    }
747
    return 0;
748
}
749
 
750
static struct gaih gaih[] =
751
{
752
#if __UCLIBC_HAS_IPV6__
753
    { PF_INET6, gaih_inet },
754
#endif
755
    { PF_INET, gaih_inet },
756
#if 0
757
    { PF_LOCAL, gaih_local },
758
#endif
759
    { PF_UNSPEC, NULL }
760
};
761
 
762
int
763
getaddrinfo (const char *name, const char *service,
764
             const struct addrinfo *hints, struct addrinfo **pai)
765
{
766
    int i = 0, j = 0, last_i = 0;
767
    struct addrinfo *p = NULL, **end;
768
    struct gaih *g = gaih, *pg = NULL;
769
    struct gaih_service gaih_service, *pservice;
770
 
771
    if (name != NULL && name[0] == '*' && name[1] == 0)
772
        name = NULL;
773
 
774
    if (service != NULL && service[0] == '*' && service[1] == 0)
775
        service = NULL;
776
 
777
    if (name == NULL && service == NULL)
778
        return EAI_NONAME;
779
 
780
    if (hints == NULL)
781
        hints = &default_hints;
782
 
783
    if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
784
                            AI_ADDRCONFIG|AI_V4MAPPED|AI_ALL))
785
        return EAI_BADFLAGS;
786
 
787
    if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
788
        return EAI_BADFLAGS;
789
 
790
    if (service && service[0])
791
    {
792
        char *c;
793
        gaih_service.name = service;
794
        gaih_service.num = strtoul (gaih_service.name, &c, 10);
795
        if (*c)
796
            gaih_service.num = -1;
797
        else
798
            /*
799
             * Can't specify a numerical socket unless a protocol
800
             * family was given.
801
             */
802
            if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
803
                return EAI_SERVICE;
804
        pservice = &gaih_service;
805
    }
806
    else
807
        pservice = NULL;
808
 
809
    if (pai)
810
        end = &p;
811
    else
812
        end = NULL;
813
 
814
    while (g->gaih)
815
    {
816
        if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
817
        {
818
            if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family))
819
                continue;
820
            j++;
821
            if (pg == NULL || pg->gaih != g->gaih)
822
            {
823
                pg = g;
824
                i = g->gaih (name, pservice, hints, end);
825
                if (i != 0)
826
                {
827
                    last_i = i;
828
 
829
                    if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
830
                        continue;
831
 
832
                    if (p)
833
                        freeaddrinfo (p);
834
 
835
                    return -(i & GAIH_EAI);
836
                }
837
                if (end)
838
                    while(*end) end = &((*end)->ai_next);
839
            }
840
        }
841
        ++g;
842
    }
843
 
844
    if (j == 0)
845
        return EAI_FAMILY;
846
 
847
    if (p)
848
    {
849
        *pai = p;
850
        return 0;
851
    }
852
 
853
    if (pai == NULL && last_i == 0)
854
        return 0;
855
 
856
    if (p)
857
        freeaddrinfo (p);
858
 
859
    return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
860
}
861
 
862
void
863
freeaddrinfo (struct addrinfo *ai)
864
{
865
    struct addrinfo *p;
866
 
867
    while (ai != NULL)
868
    {
869
        p = ai;
870
        ai = ai->ai_next;
871
        free (p);
872
    }
873
}

powered by: WebSVN 2.1.0

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