diff options
Diffstat (limited to 'libc/inet/getnet.c')
-rw-r--r-- | libc/inet/getnet.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/libc/inet/getnet.c b/libc/inet/getnet.c new file mode 100644 index 000000000..c604b63d3 --- /dev/null +++ b/libc/inet/getnet.c @@ -0,0 +1,217 @@ +/* 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 MAXALIASES 35 +#define BUFSZ (80) /* one line */ +#define SBUFSIZE (BUFSZ + 1 + (sizeof(char *) * MAXALIASES)) + +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 **alias, *cp = NULL; + char **net_aliases; + char **tok = NULL; + const size_t aliaslen = sizeof(*net_aliases) * MAXALIASES; + 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, 3, 2, "# \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 = alias = net_aliases = tok; + cp = *alias; + while (cp && *cp) { + if (alias < &net_aliases[MAXALIASES - 1]) + *alias++ = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *alias = NULL; + *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; +} + |