Permalink
Browse files

- frontend: adding IPv6 support

  • Loading branch information...
stealth committed Oct 8, 2013
1 parent 542766f commit 03fd8afcdc33429b5eb94f431137efe5aaa12a45
Showing with 84 additions and 57 deletions.
  1. +6 −5 README
  2. +7 −6 config.cc
  3. +1 −1 config.h
  4. +2 −2 frontend-main.cc
  5. +19 −3 lonely.cc
  6. +1 −1 lonely.h
  7. +3 −3 main.cc
  8. +17 −6 rproxy.cc
  9. +7 −3 sample.conf
  10. +19 −25 socket.cc
  11. +2 −2 socket.h
View
11 README
@@ -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
View
@@ -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;
@@ -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')
@@ -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;
}
View
@@ -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;
View
@@ -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
@@ -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);
}
View
@@ -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>
@@ -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);
View
@@ -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);
View
@@ -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;
@@ -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;
}
View
@@ -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)
@@ -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;
@@ -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;
View
@@ -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 /
View
@@ -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) {
@@ -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);
@@ -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;
}
View
@@ -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);

0 comments on commit 03fd8af

Please sign in to comment.