| /* vi: set sw=4 ts=4: */ |
| /* |
| * Copyright (C) 2010 Bernhard Reutner-Fischer <uclibc@uclibc.org> |
| * |
| * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball. |
| */ |
| |
| /* /etc/networks |
| # network-name number [aliases ...] |
| loopback 127.0.0.0 # optional aliases |
| |
| network-name: symbolic name of the netwkork |
| number: official number of the network in dotted quad |
| aliases: case sensitive optional space or tab separated list of other names |
| */ |
| |
| #include <features.h> |
| #include <netdb.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <netinet/in.h> |
| #include <arpa/inet.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include "internal/parse_config.h" |
| |
| #include <bits/uClibc_mutex.h> |
| __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); |
| |
| #define MINTOKENS 2 |
| #define MAXALIASES 8 |
| #define MAXTOKENS (MINTOKENS + MAXALIASES + 1) |
| #define BUFSZ (255) /* one line */ |
| #define SBUFSIZE (BUFSZ + 1 + (sizeof(char *) * MAXTOKENS)) |
| |
| static parser_t *netp = NULL; |
| static struct netent nete; |
| static char *netbuf = NULL; |
| static smallint net_stayopen; |
| |
| void setnetent(int stayopen) |
| { |
| __UCLIBC_MUTEX_LOCK(mylock); |
| if (netp) |
| config_close(netp); |
| netp = config_open(_PATH_NETWORKS); |
| if (stayopen) |
| net_stayopen = 1; |
| __UCLIBC_MUTEX_UNLOCK(mylock); |
| } |
| libc_hidden_def(setnetent) |
| |
| void endnetent(void) |
| { |
| __UCLIBC_MUTEX_LOCK(mylock); |
| if (netp) { |
| config_close(netp); |
| netp = NULL; |
| } |
| net_stayopen = 0; |
| __UCLIBC_MUTEX_UNLOCK(mylock); |
| } |
| libc_hidden_def(endnetent) |
| |
| int getnetent_r(struct netent *result_buf, |
| char *buf, size_t buflen, struct netent **result, |
| int *h_errnop |
| ) |
| { |
| char **tok = NULL; |
| const size_t aliaslen = sizeof(char *) * MAXTOKENS; |
| int ret = ERANGE; |
| |
| *result = NULL; |
| if (buflen < aliaslen |
| || (buflen - aliaslen) < BUFSZ + 1) |
| goto DONE_NOUNLOCK; |
| |
| __UCLIBC_MUTEX_LOCK(mylock); |
| ret = ENOENT; |
| if (netp == NULL) |
| setnetent(net_stayopen); |
| if (netp == NULL) |
| goto DONE; |
| netp->data = buf; |
| netp->data_len = aliaslen; |
| netp->line_len = buflen - aliaslen; |
| /* <name>[[:space:]]<netnumber>[[:space:]][<aliases>] */ |
| if (!config_read(netp, &tok, MAXTOKENS-1, MINTOKENS, "# \t/", PARSE_NORMAL)) { |
| goto DONE; |
| } |
| result_buf->n_name = *(tok++); |
| { |
| struct addrinfo hints, *addri; |
| # define sa4_to_uint32(sa) \ |
| (ntohl(((struct sockaddr_in*)sa)->sin_addr.s_addr)) |
| #ifdef __UCLIBC_HAS_IPV6__ |
| # define sa6_to_uint8(sa) \ |
| (ntohl(((struct sockaddr_in6*)sa)->sin6_addr.s6_addr)) |
| #endif |
| memset(&hints, 0, sizeof(struct addrinfo)); |
| hints.ai_family = AF_UNSPEC; |
| hints.ai_flags = AI_NUMERICHOST; |
| getaddrinfo(*(tok++), NULL, &hints, &addri); |
| result_buf->n_addrtype = addri->ai_family; |
| result_buf->n_net = |
| #if 0 /*FIXME: implement me! def __UCLIBC_HAS_IPV6__ */ |
| addri->ai_family == AF_INET6 ? sa6_to_uint8(addri->ai_addr) : |
| #endif |
| sa4_to_uint32(addri->ai_addr); |
| freeaddrinfo(addri); |
| } |
| result_buf->n_aliases = tok; |
| *result = result_buf; |
| ret = 0; |
| DONE: |
| __UCLIBC_MUTEX_UNLOCK(mylock); |
| DONE_NOUNLOCK: |
| errno = ret; |
| return errno; |
| } |
| libc_hidden_def(getnetent_r) |
| |
| static void __initbuf(void) |
| { |
| if (!netbuf) { |
| netbuf = malloc(SBUFSIZE); |
| if (!netbuf) |
| abort(); |
| } |
| } |
| |
| struct netent *getnetent(void) |
| { |
| struct netent *result; |
| int herrnop; |
| |
| __initbuf(); |
| getnetent_r(&nete, netbuf, SBUFSIZE, &result, &herrnop); |
| return result; |
| } |
| |
| int getnetbyname_r(const char *name, |
| struct netent *result_buf, char *buf, size_t buflen, |
| struct netent **result, |
| int *h_errnop |
| ) |
| { |
| register char **cp; |
| int ret, herrnop; |
| |
| __UCLIBC_MUTEX_LOCK(mylock); |
| setnetent(net_stayopen); |
| while (!(ret = getnetent_r(result_buf, buf, buflen, result, &herrnop))) { |
| if (strcmp(name, result_buf->n_name) == 0) |
| break; |
| for (cp = result_buf->n_aliases; *cp; cp++) |
| if (strcmp(name, *cp) == 0) |
| goto gotname; |
| } |
| gotname: |
| if (!net_stayopen) |
| endnetent(); |
| __UCLIBC_MUTEX_UNLOCK(mylock); |
| return *result ? 0 : ret; |
| } |
| libc_hidden_def(getnetbyname_r) |
| |
| struct netent *getnetbyname(const char *name) |
| { |
| struct netent *result; |
| int herrnop; |
| |
| __initbuf(); |
| getnetbyname_r(name, &nete, netbuf, SBUFSIZE, &result, &herrnop); |
| return result; |
| } |
| |
| int getnetbyaddr_r(uint32_t net, int type, |
| struct netent *result_buf, char *buf, |
| size_t buflen, struct netent **result, |
| int *h_errnop) |
| { |
| int ret, herrnop; |
| |
| __UCLIBC_MUTEX_LOCK(mylock); |
| setnetent(net_stayopen); |
| while (!(ret = getnetent_r(result_buf, buf, buflen, result, &herrnop))) { |
| if (net == result_buf->n_net && type == result_buf->n_addrtype) |
| break; |
| } |
| if (!net_stayopen) |
| endnetent(); |
| __UCLIBC_MUTEX_UNLOCK(mylock); |
| return *result ? 0 : ret; |
| } |
| libc_hidden_def(getnetbyaddr_r) |
| |
| struct netent *getnetbyaddr(uint32_t net, int type) |
| { |
| struct netent *result; |
| int herrnop; |
| |
| __initbuf(); |
| getnetbyaddr_r(net, type, &nete, netbuf, SBUFSIZE, &result, &herrnop); |
| return result; |
| } |
| |