[ccan] [PATCH 2/2] net: Extend to allow convenient binding to a specified local address
David Gibson
david at gibson.dropbear.id.au
Tue Sep 24 18:37:07 EST 2013
On Tue, Sep 24, 2013 at 02:12:20PM +0930, Paul 'Rusty' Russell wrote:
> David Gibson <david at gibson.dropbear.id.au> writes:
> > Currently the server/bind side functions in the net module always bind to
> > the "wildcard" address listening on all interfaces / local addresses. This
> > patch adds a new net_server_lookup_addr() function to also allow listening
> > on only a specified local address.
> >
> > Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
>
> Gah, getaddrinfo() is a terrible interface.
>
> What you really want to do is specify an interface to use (ie. loopback
> in your examples). By specifying addr as "127.0.0.1" it's unclear to me
> if we'll see any IPv6 addresses.
Well. The interface I have in mind here does take an explicit address
(well, optionally) in which case, yes, you'll only get either an IPv4
or an IPv6 address.
I did think of taking an interface name and binding to all addresses
(v4 or v6) on that interface as a possible extension. But for the use
I have in mind, I really do want to specify a single address.
> Yet if we really want to join to struct addrinfo, the user can't use
> freeaddrinfo() on it: we need to supply a free function. I guess we'll
> do that, too.
I'm not sure what you mean here.
> If this is what you want, I think I'll code up
> "net_local_server_lookup()" which does two lookups and joins them, and
> then add a net_addrinfo_free() function.
>
> Or am I missing something?
> Rusty.
>
>
>
> > ---
> > ccan/net/net.c | 11 ++--
> > ccan/net/net.h | 42 +++++++++++++++
> > ccan/net/test/run-bind.c | 138 ++++++++++++++++++++++++++++++++++++++++++++---
> > 3 files changed, 179 insertions(+), 12 deletions(-)
> >
> > diff --git a/ccan/net/net.c b/ccan/net/net.c
> > index e84380f..8877452 100644
> > --- a/ccan/net/net.c
> > +++ b/ccan/net/net.c
> > @@ -151,19 +151,20 @@ out:
> > return sockfd;
> > }
> >
> > -struct addrinfo *net_server_lookup(const char *service,
> > - int family,
> > - int socktype)
> > +struct addrinfo *net_server_lookup_addr(const char *addr,
> > + const char *service,
> > + int family,
> > + int socktype)
> > {
> > struct addrinfo *res, hints;
> >
> > memset(&hints, 0, sizeof(hints));
> > hints.ai_family = family;
> > hints.ai_socktype = socktype;
> > - hints.ai_flags = AI_PASSIVE;
> > + hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
> > hints.ai_protocol = 0;
> >
> > - if (getaddrinfo(NULL, service, &hints, &res) != 0)
> > + if (getaddrinfo(addr, service, &hints, &res) != 0)
> > return NULL;
> >
> > return res;
> > diff --git a/ccan/net/net.h b/ccan/net/net.h
> > index 9ad6de5..a14b6c8 100644
> > --- a/ccan/net/net.h
> > +++ b/ccan/net/net.h
> > @@ -1,6 +1,9 @@
> > /* Licensed under BSD-MIT - see LICENSE file for details */
> > #ifndef CCAN_NET_H
> > #define CCAN_NET_H
> > +
> > +#include <stdio.h>
> > +
> > /**
> > * net_client_lookup - look up a network name to connect to.
> > * @hostname: the name to look up
> > @@ -48,6 +51,37 @@ struct addrinfo *net_client_lookup(const char *hostname,
> > */
> > int net_connect(const struct addrinfo *addrinfo);
> >
> > +
> > +/**
> > + * net_server_lookup_addr - look up a local address and service name to bind to.
> > + * @address: local address to use
> > + * @service: the service to look up
> > + * @family: Usually AF_UNSPEC, otherwise AF_INET or AF_INET6.
> > + * @socktype: SOCK_DGRAM or SOCK_STREAM.
> > + *
> > + * This will do a synchronous lookup of a given name, returning a linked list
> > + * of results, or NULL on error. You should use freeaddrinfo() to free it.
> > + *
> > + * Example:
> > + * #include <sys/types.h>
> > + * #include <sys/socket.h>
> > + * #include <stdio.h>
> > + * #include <netdb.h>
> > + * #include <err.h>
> > + * ...
> > + * struct addrinfo *addr;
> > + *
> > + * // Get address(es) to bind for our service.
> > + * addr = net_server_lookup_addr("127.0.0.1", "8888",
> > + * AF_UNSPEC, SOCK_STREAM);
> > + * if (!addr)
> > + * errx(1, "Failed to look up 8888 on 127.0.0.1 to bind to");
> > + */
> > +struct addrinfo *net_server_lookup_addr(const char *addr,
> > + const char *service,
> > + int family,
> > + int socktype);
> > +
> > /**
> > * net_server_lookup - look up a service name to bind to.
> > * @service: the service to look up
> > @@ -71,6 +105,14 @@ int net_connect(const struct addrinfo *addrinfo);
> > * if (!addr)
> > * errx(1, "Failed to look up 8888 to bind to");
> > */
> > +static inline struct addrinfo *net_server_lookup(const char *service,
> > + int family,
> > + int socktype)
> > +{
> > + return net_server_lookup_addr(NULL, service, family, socktype);
> > +}
> > +
> > +
> > struct addrinfo *net_server_lookup(const char *service,
> > int family,
> > int socktype);
> > diff --git a/ccan/net/test/run-bind.c b/ccan/net/test/run-bind.c
> > index 9fb2081..f61284f 100644
> > --- a/ccan/net/test/run-bind.c
> > +++ b/ccan/net/test/run-bind.c
> > @@ -29,7 +29,7 @@ static int my_setsockopt(int sockfd, int level, int optname,
> >
> > #define TEST_PORT "65001"
> >
> > -static void do_connect(int family, int type)
> > +static void do_connect(const char *host, int family, int type)
> > {
> > int fd, ret;
> > struct addrinfo *addr;
> > @@ -37,7 +37,7 @@ static void do_connect(int family, int type)
> >
> > /* Just in case... */
> > alarm(5);
> > - addr = net_client_lookup(NULL, TEST_PORT, family, type);
> > + addr = net_client_lookup(host, TEST_PORT, family, type);
> > fd = net_connect(addr);
> > if (fd < 0)
> > err(1, "Failed net_connect");
> > @@ -86,7 +86,7 @@ int main(void)
> > } remote_addr;
> > socklen_t addlen = sizeof(remote_addr);
> >
> > - plan_tests(35);
> > + plan_tests(73);
> >
> > /* Simple TCP test. */
> > addr = net_server_lookup(TEST_PORT, AF_UNSPEC, SOCK_STREAM);
> > @@ -97,7 +97,67 @@ int main(void)
> > if (!fork()) {
> > for (i = 0; i < num_fds; i++)
> > close(fds[i]);
> > - do_connect(AF_UNSPEC, SOCK_STREAM);
> > + do_connect(NULL, AF_UNSPEC, SOCK_STREAM);
> > + exit(0);
> > + }
> > +
> > + i = wait_for_readable(fds, num_fds);
> > + ok1(i < num_fds);
> > + fd = accept(fds[i], NULL, NULL);
> > + ok1(fd >= 0);
> > +
> > + ret = read(fd, buf, strlen("Yay!"));
> > + ok1(ret == strlen("Yay!"));
> > + ok1(memcmp(buf, "Yay!", ret) == 0);
> > + ret = write(fd, "metoo", strlen("metoo"));
> > + ok1(ret == strlen("metoo"));
> > + ok1(wait(&status) != -1);
> > + ok1(WIFEXITED(status));
> > + ok1(WEXITSTATUS(status) == 0);
> > + close(fd);
> > + for (i = 0; i < num_fds; i++)
> > + close(fds[i]);
> > +
> > + /* TCP test with specified bind address (IPv4) */
> > + addr = net_server_lookup_addr("127.0.0.1", TEST_PORT,
> > + AF_UNSPEC, SOCK_STREAM);
> > + ok1(addr);
> > + num_fds = net_bind(addr, fds);
> > + ok1(num_fds == 1);
> > +
> > + if (!fork()) {
> > + close(fds[0]);
> > + do_connect("127.0.0.1", AF_UNSPEC, SOCK_STREAM);
> > + exit(0);
> > + }
> > +
> > + i = wait_for_readable(fds, num_fds);
> > + ok1(i < num_fds);
> > + fd = accept(fds[i], NULL, NULL);
> > + ok1(fd >= 0);
> > +
> > + ret = read(fd, buf, strlen("Yay!"));
> > + ok1(ret == strlen("Yay!"));
> > + ok1(memcmp(buf, "Yay!", ret) == 0);
> > + ret = write(fd, "metoo", strlen("metoo"));
> > + ok1(ret == strlen("metoo"));
> > + ok1(wait(&status) != -1);
> > + ok1(WIFEXITED(status));
> > + ok1(WEXITSTATUS(status) == 0);
> > + close(fd);
> > + for (i = 0; i < num_fds; i++)
> > + close(fds[i]);
> > +
> > + /* TCP test with specified bind address (IPv6) */
> > + addr = net_server_lookup_addr("::1", TEST_PORT,
> > + AF_UNSPEC, SOCK_STREAM);
> > + ok1(addr);
> > + num_fds = net_bind(addr, fds);
> > + ok1(num_fds == 1);
> > +
> > + if (!fork()) {
> > + close(fds[0]);
> > + do_connect("::1", AF_UNSPEC, SOCK_STREAM);
> > exit(0);
> > }
> >
> > @@ -127,7 +187,71 @@ int main(void)
> > if (!fork()) {
> > for (i = 0; i < num_fds; i++)
> > close(fds[i]);
> > - do_connect(AF_UNSPEC, SOCK_DGRAM);
> > + do_connect(NULL, AF_UNSPEC, SOCK_DGRAM);
> > + exit(0);
> > + }
> > +
> > + i = wait_for_readable(fds, num_fds);
> > + ok1(i < num_fds);
> > + fd = fds[i];
> > +
> > + ret = recvfrom(fd, buf, strlen("Yay!"), 0,
> > + (void *)&remote_addr, &addlen);
> > + ok1(ret == strlen("Yay!"));
> > + ok1(memcmp(buf, "Yay!", ret) == 0);
> > + ret = sendto(fd, "metoo", strlen("metoo"), 0,
> > + (void *)&remote_addr, addlen);
> > + ok1(ret == strlen("metoo"));
> > + ok1(wait(&status) >= 0);
> > + ok1(WIFEXITED(status));
> > + ok1(WEXITSTATUS(status) == 0);
> > + close(fd);
> > + for (i = 0; i < num_fds; i++)
> > + close(fds[i]);
> > +
> > + /* UDP test with specified bind address (IPv4) */
> > + addr = net_server_lookup_addr("127.0.0.1", TEST_PORT,
> > + AF_UNSPEC, SOCK_DGRAM);
> > + ok1(addr);
> > + num_fds = net_bind(addr, fds);
> > + ok1(num_fds == 1);
> > +
> > + if (!fork()) {
> > + for (i = 0; i < num_fds; i++)
> > + close(fds[i]);
> > + do_connect("127.0.01", AF_UNSPEC, SOCK_DGRAM);
> > + exit(0);
> > + }
> > +
> > + i = wait_for_readable(fds, num_fds);
> > + ok1(i < num_fds);
> > + fd = fds[i];
> > +
> > + ret = recvfrom(fd, buf, strlen("Yay!"), 0,
> > + (void *)&remote_addr, &addlen);
> > + ok1(ret == strlen("Yay!"));
> > + ok1(memcmp(buf, "Yay!", ret) == 0);
> > + ret = sendto(fd, "metoo", strlen("metoo"), 0,
> > + (void *)&remote_addr, addlen);
> > + ok1(ret == strlen("metoo"));
> > + ok1(wait(&status) >= 0);
> > + ok1(WIFEXITED(status));
> > + ok1(WEXITSTATUS(status) == 0);
> > + close(fd);
> > + for (i = 0; i < num_fds; i++)
> > + close(fds[i]);
> > +
> > + /* UDP test with specified bind address (IPv6) */
> > + addr = net_server_lookup_addr("::1", TEST_PORT,
> > + AF_UNSPEC, SOCK_DGRAM);
> > + ok1(addr);
> > + num_fds = net_bind(addr, fds);
> > + ok1(num_fds == 1);
> > +
> > + if (!fork()) {
> > + for (i = 0; i < num_fds; i++)
> > + close(fds[i]);
> > + do_connect("::1", AF_UNSPEC, SOCK_DGRAM);
> > exit(0);
> > }
> >
> > @@ -168,8 +292,8 @@ int main(void)
> > if (!fork()) {
> > for (i = 0; i < num_fds; i++)
> > close(fds[i]);
> > - do_connect(AF_INET, SOCK_STREAM);
> > - do_connect(AF_INET6, SOCK_STREAM);
> > + do_connect(NULL, AF_INET, SOCK_STREAM);
> > + do_connect(NULL, AF_INET6, SOCK_STREAM);
> > exit(0);
> > }
> >
>
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.ozlabs.org/pipermail/ccan/attachments/20130924/251ec095/attachment-0001.sig>
More information about the ccan
mailing list