Skip to content

Commit

Permalink
- frontend: adding IPv6 support
Browse files Browse the repository at this point in the history
  • Loading branch information
stealth committed Oct 8, 2013
1 parent 542766f commit 03fd8af
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 57 deletions.
11 changes: 6 additions & 5 deletions README
Expand Up @@ -155,11 +155,12 @@ IPv6
----

Since version > 0.91 lophttpd also supports IPv6, by simply using "-6"
command-line switch. The default bind goes to "::0" then, so
if you want to bind to a specific IPv6 address, you have to
add -I switch *after* -6. You can either run IPv4 or IPv6 in once
instance, not both. But you can run two lophttpd's: one with IPv4
and one with IPv6 if needed.
command-line switch. The default bind goes to "::" unless
given -l local bind address.
You can either run IPv4 or IPv6 in one instance, not both. But you can run
two lophttpd's: one with IPv4 and one with IPv6 if needed.
Frontend reverse proxy also supports IPv6, both on the frontend and
the backend side. You can even mix IPv4 and IPv6 backend nodes.


Proxies
Expand Down
13 changes: 7 additions & 6 deletions config.cc
Expand Up @@ -21,7 +21,7 @@ namespace httpd_config
string user = "wwwrun", logfile = "/var/log/lophttpd", log_provider = "file";
uid_t user_uid = 99, user_gid = 99;
string host = "0.0.0.0", port = "80";
int cores = 1, af = AF_INET;
int cores = 1;

// on multicore there is only one master
int master = 1;
Expand Down Expand Up @@ -58,7 +58,6 @@ int parse(const string &cfile)
struct addrinfo *ai = NULL, hints;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET;
while (fgets(buf, sizeof(buf), f)) {
ptr = buf;
while (*ptr == ' ' || *ptr == '\t')
Expand All @@ -73,14 +72,16 @@ int parse(const string &cfile)

string opath = "";
backend b;
strtok(ptr, " \t\n#");

// No '#' token in 'map' allowed due to port specifier
strtok(ptr, " \t");
opath = ptr;
ptr = strtok(NULL, " \t\n#");
ptr = strtok(NULL, " \t\n");

memset(host, 0, sizeof(host));
memset(path, 0, sizeof(path));
if (strchr(ptr + 5, ':')) {
if (sscanf(ptr, "http://%255[^:]:%hu/%255c", host, &b.port, path) == 0) {
if (strchr(ptr + 5, '#')) {
if (sscanf(ptr, "http://%255[^#]#%hu/%255c", host, &b.port, path) == 0) {
err = "rproxy_config::parse::sscanf: invalid 'map' config.";
return -1;
}
Expand Down
2 changes: 1 addition & 1 deletion config.h
Expand Up @@ -18,7 +18,7 @@ namespace httpd_config
extern std::string user, logfile, log_provider;
extern uid_t user_uid, user_gid;
extern std::string host, port;
extern int cores, master, af;
extern int cores, master;
extern uint16_t mss;
extern uint32_t max_connections;
extern uint32_t ncache;
Expand Down
4 changes: 2 additions & 2 deletions frontend-main.cc
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 Sebastian Krahmer.
* Copyright (C) 2012-2013 Sebastian Krahmer.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -117,7 +117,7 @@ int main(int argc, char **argv)
return -1;
}

if (proxy->init(rproxy_config::host, rproxy_config::port, AF_INET) < 0) {
if (proxy->init(rproxy_config::host, rproxy_config::port) < 0) {
proxy->log(proxy->why());
exit(-1);
}
Expand Down
22 changes: 19 additions & 3 deletions lonely.cc
Expand Up @@ -46,6 +46,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/time.h>
#include <map>
#include <sys/stat.h>
Expand Down Expand Up @@ -147,29 +148,44 @@ const char *lonely<state_engine>::why()


template<typename state_engine>
int lonely<state_engine>::init(const string &host, const string &port, int a)
int lonely<state_engine>::init(const string &host, const string &port)
{
struct timeval tv;
int r = 0;

gettimeofday(&tv, NULL);
cur_time = tv.tv_sec;
cur_usec = tv.tv_usec;

af = a;
addrinfo hints, *ai = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;

if ((r = getaddrinfo(host.c_str(), port.c_str(), &hints, &ai)) != 0) {
err = "lonely::init:: getaddrinfo: ";
err += gai_strerror(r);
return -1;
}

af = ai->ai_family;

int sock_fd = socket(af, SOCK_STREAM, 0);
if (sock_fd < 0) {
freeaddrinfo(ai);
err = "lonely::init::socket:";
err += strerror(errno);
return -1;
}

// bind & listen
if (bind_local(sock_fd, host, port, 1, af) < 0) {
if (bind_local(sock_fd, ai->ai_addr, ai->ai_addrlen, 1) < 0) {
freeaddrinfo(ai);
err = ns_socket::why();
return -1;
}

freeaddrinfo(ai);

socklen_t olen = sizeof(so_sndbuf);
getsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &so_sndbuf, &olen);

Expand Down
2 changes: 1 addition & 1 deletion lonely.h
Expand Up @@ -129,7 +129,7 @@ class lonely {

virtual ~lonely() { delete [] pfds; delete logger; }

int init(const std::string &, const std::string &, int a = AF_INET);
int init(const std::string &, const std::string &);

int open_log(const std::string &, const std::string &, int core);

Expand Down
6 changes: 3 additions & 3 deletions main.cc
Expand Up @@ -170,8 +170,8 @@ int main(int argc, char **argv)
while ((c = getopt(argc, argv, "iHhR:p:l:L:u:n:S:I:6B:qU:rEQN:C:K:e:s:")) != -1) {
switch (c) {
case '6':
httpd_config::host = "::0";
httpd_config::af = AF_INET6;
if (httpd_config::host == "0.0.0.0")
httpd_config::host = "::";
break;
case 'i':
httpd_config::gen_index = 1;
Expand Down Expand Up @@ -290,7 +290,7 @@ int main(int argc, char **argv)
}
}

if (httpd->init(httpd_config::host, httpd_config::port, httpd_config::af) < 0) {
if (httpd->init(httpd_config::host, httpd_config::port) < 0) {
cerr<<httpd->why()<<endl;
return -1;
}
Expand Down
23 changes: 17 additions & 6 deletions rproxy.cc
Expand Up @@ -62,9 +62,15 @@ int rproxy::loop()
size_t n = 0;
struct tm tm;
struct timeval tv;
sockaddr_in sin;
socklen_t slen = sizeof(sin);

sockaddr_in sin4;
sockaddr_in6 sin6;
sockaddr *sin = (sockaddr *)&sin4;
socklen_t slen = sizeof(sin4);

if (af == AF_INET6) {
sin = (sockaddr *)&sin6;
slen = sizeof(sin6);
}

for (;;) {
if (poll(pfds, max_fd + 1, 1000) < 0)
Expand Down Expand Up @@ -133,7 +139,7 @@ int rproxy::loop()
pfds[i].revents = 0;
for (;;) {
heavy_load = 0;
afd = flavor::accept(i, (struct sockaddr *)&sin, &slen, flavor::NONBLOCK);
afd = flavor::accept(i, sin, &slen, flavor::NONBLOCK);
if (afd < 0) {
if (errno == EMFILE || errno == ENFILE)
heavy_load = 1;
Expand All @@ -154,8 +160,13 @@ int rproxy::loop()
}
}

if (inet_ntop(af, &sin.sin_addr, from, sizeof(from)) < 0)
continue;
if (af == AF_INET) {
if (inet_ntop(af, &sin4.sin_addr, from, sizeof(from)) < 0)
continue;
} else {
if (inet_ntop(af, &sin6.sin6_addr, from, sizeof(from)) < 0)
continue;
}

fd2peer[afd]->from_ip = from;
fd2peer[afd]->fd = afd;
Expand Down
10 changes: 7 additions & 3 deletions sample.conf
Expand Up @@ -21,19 +21,23 @@ logprovider file
#
#

# :port specifier is not required for port 80
# #port specifier is not required for port 80
#
# The URI must match what a potential "Location:" redirect reply from one of
# the backends also would contain as URI (without sub paths)
# and it must be resolvable by DNS if its not an IP address. Otherwise redirects
# do not work.
#
map /foo http://127.0.0.1:8080/
# '#' comments in the same line as the 'map' command are not allowed as it would
# clash with port specifier
#

map /foo http://127.0.0.1#8080/

# multiple assignments for the same /path are possile
# (load balancing)

map /foo http://127.0.0.2:8080/
map /foo http://127.0.0.2#8080/
#...

# The path component is always required, even if its just /
Expand Down
44 changes: 19 additions & 25 deletions socket.cc
Expand Up @@ -87,33 +87,17 @@ int reuse(int sock)
}


int bind_local(int sock, const string &host, const string &port, bool do_listen, int af)
int bind_local(int sock, const struct sockaddr *s, socklen_t slen, bool do_listen)
{
struct addrinfo *ai = NULL, hints;
int r;

memset(&hints, 0, sizeof(hints));

hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;

if ((r = getaddrinfo(host.c_str(), port.c_str(), &hints, &ai)) < 0) {
error = "ns_socket::bind_local::getaddrinfo:";
error += gai_strerror(r);
return -1;
}

if (reuse(sock) < 0)
return -1;

if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
if (bind(sock, s, slen) < 0) {
error = "ns_socket::bind_local::bind: ";
error += strerror(errno);
return -1;
}

freeaddrinfo(ai);

if (do_listen) {
if (listen(sock, 100000) < 0) {
if (listen(sock, 10000) < 0) {
Expand All @@ -130,22 +114,32 @@ int bind_local(int sock, const string &host, const string &port, bool do_listen,
}


int bind_local(int sock, u_int16_t port, bool do_listen, int tries)
int bind_local(int sock, uint16_t port, int af, bool do_listen, int tries)
{
struct sockaddr_in saddr;
sockaddr_in sin4;
sockaddr_in6 sin6;
sockaddr *sin = (sockaddr *)&sin4;
socklen_t slen = sizeof(sin4);

if (af == AF_INET6) {
sin = (sockaddr *)&sin6;
slen = sizeof(sin6);
}

// XXX: static since connect will ne non-blocking, thus bind() will never fail
static int i = 0;

memset(&saddr, 0, sizeof(saddr));
memset(&sin4, 0, sizeof(sin4));
memset(&sin6, 0, sizeof(sin6));

saddr.sin_family = AF_INET;
sin4.sin_family = sin6.sin6_family = af;

if (reuse(sock) < 0)
return -1;

for (; i < tries; ++i) {
saddr.sin_port = htons(port + i);
if (bind(sock, (struct sockaddr*)&saddr, sizeof(saddr)) < 0 &&
sin4.sin_port = sin6.sin6_port = htons(port + i);
if (bind(sock, sin, slen) < 0 &&
(errno != EADDRINUSE || i == tries - 1)) {
error = "ns_socket::bind_local::bind: ";
error += strerror(errno);
Expand Down Expand Up @@ -180,7 +174,7 @@ int tcp_connect_nb(const struct addrinfo &ai, uint16_t local_port)
//int one = 1;
//setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one ,sizeof(one));
if (local_port > 0) {
if (bind_local(sock, local_port, 0, 1000) < 0)
if (bind_local(sock, local_port, ai.ai_family, 0, 1000) < 0)
return -1;
}

Expand Down
4 changes: 2 additions & 2 deletions socket.h
Expand Up @@ -49,9 +49,9 @@ int reuse(int sock);

int dstaddr(int sock, sockaddr_in *dst);

int bind_local(int sock, const std::string &h, const std::string &p, bool do_listen, int af = AF_INET);
int bind_local(int sock, const sockaddr *, socklen_t, bool do_listen);

int bind_local(int sock, u_int16_t port, bool do_listen, int tries);
int bind_local(int sock, uint16_t port, bool do_listen, int tries);

int tcp_connect_nb(const struct addrinfo &, uint16_t);

Expand Down

0 comments on commit 03fd8af

Please sign in to comment.