PoorMan: Add dual-stack IPv6 support

This change adds dual-stack IPv6 support to the PoorMan web server,
which will listen on all available IPv4 and IPv6 addresses and
respond to both.

This change also does some necessary plumbing to support the
output of nicely-formatted IPv6 addresses for request logging.

Change-Id: I0ce7691222f0233e2e098d67e6293b9e58d7486d
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3539
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Jeremy Visser
2020-12-23 10:48:38 +00:00
committed by Adrien Destugues
parent da93a24811
commit 6011ce6c74
5 changed files with 103 additions and 75 deletions
+4 -3
View File
@@ -17,10 +17,11 @@
#include "PoorManApplication.h" #include "PoorManApplication.h"
#include "PoorManWindow.h" #include "PoorManWindow.h"
#include "libhttpd.h"
void void
poorman_log(const char* msg, bool needTimeHeader, poorman_log(const char* msg, bool needTimeHeader,
in_addr_t addr, rgb_color color) httpd_sockaddr* addr, rgb_color color)
{ {
time_t now = time(NULL); time_t now = time(NULL);
@@ -38,8 +39,8 @@ poorman_log(const char* msg, bool needTimeHeader,
if(message.AddData("time_t", B_TIME_TYPE, &now, sizeof(time_t)) != B_OK) if(message.AddData("time_t", B_TIME_TYPE, &now, sizeof(time_t)) != B_OK)
return; return;
} }
if(addr != INADDR_NONE) if(addr != NULL)
message.AddData("in_addr_t", B_ANY_TYPE, &addr, sizeof(in_addr_t)); message.AddString("addr", httpd_ntoa(addr));
if(color != BLACK) if(color != BLACK)
message.AddData("rgb_color", B_RGB_COLOR_TYPE, &color, sizeof(rgb_color)); message.AddData("rgb_color", B_RGB_COLOR_TYPE, &color, sizeof(rgb_color));
+3 -2
View File
@@ -11,20 +11,21 @@
#include <netinet/in.h> #include <netinet/in.h>
#include "constants.h" //for rgb_color BLACK #include "constants.h" //for rgb_color BLACK
#include "libhttpd.h" //for httpd_sockaddr
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
void poorman_log( void poorman_log(
const char* msg, const char* msg,
bool needTimeHeader = true, bool needTimeHeader = true,
in_addr_t addr = INADDR_NONE, httpd_sockaddr* addr = NULL,
rgb_color color = BLACK rgb_color color = BLACK
); );
#else //c version is for libhttpd #else //c version is for libhttpd
void poorman_log( void poorman_log(
const char* msg, const char* msg,
bool needTimeHeader, bool needTimeHeader,
in_addr_t addr, httpd_sockaddr* addr,
rgb_color color rgb_color color
); );
#endif #endif
+40 -7
View File
@@ -15,6 +15,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <poll.h>
#include <File.h> #include <File.h>
#include <Debug.h> #include <Debug.h>
@@ -85,7 +86,7 @@ PoorManServer::~PoorManServer()
status_t PoorManServer::Run() status_t PoorManServer::Run()
{ {
if (chdir(fHttpdServer->cwd) == -1) { if (chdir(fHttpdServer->cwd) == -1) {
poorman_log("no web directory, can't start up.\n", false, INADDR_NONE, RED); poorman_log("no web directory, can't start up.\n", false, NULL, RED);
return B_ERROR; return B_ERROR;
} }
@@ -95,7 +96,15 @@ status_t PoorManServer::Run()
sa4.sa_in.sin_port = htons(80); sa4.sa_in.sin_port = htons(80);
sa4.sa_in.sin_addr.s_addr = htonl(INADDR_ANY); sa4.sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
fHttpdServer->listen4_fd = httpd_initialize_listen_socket(&sa4); fHttpdServer->listen4_fd = httpd_initialize_listen_socket(&sa4);
if (fHttpdServer->listen4_fd == -1)
httpd_sockaddr sa6;
memset(&sa6, 0, sizeof(httpd_sockaddr));
sa6.sa_in.sin_family = AF_INET6;
sa6.sa_in.sin_port = htons(80);
sa6.sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
fHttpdServer->listen6_fd = httpd_initialize_listen_socket(&sa6);
if (fHttpdServer->listen4_fd == -1 && fHttpdServer->listen6_fd == -1)
return B_ERROR; return B_ERROR;
fListenerTid = spawn_thread( fListenerTid = spawn_thread(
@@ -105,7 +114,7 @@ status_t PoorManServer::Run()
static_cast<void*>(this) static_cast<void*>(this)
); );
if (fListenerTid < B_OK) { if (fListenerTid < B_OK) {
poorman_log("can't create listener thread.\n", false, INADDR_NONE, RED); poorman_log("can't create listener thread.\n", false, NULL, RED);
return B_ERROR; return B_ERROR;
} }
fIsRunning = true; fIsRunning = true;
@@ -204,13 +213,36 @@ int32 PoorManServer::_Listener(void* data)
thread_id tid; thread_id tid;
httpd_conn* hc; httpd_conn* hc;
PoorManServer* s = static_cast<PoorManServer*>(data); PoorManServer* s = static_cast<PoorManServer*>(data);
const int nfds = 2;
pollfd fds[nfds];
// N.B. these fds could be -1, which poll() should skip
memset(&fds, 0, sizeof(fds));
fds[0].fd = s->fHttpdServer->listen4_fd;
fds[0].events = POLLIN;
fds[1].fd = s->fHttpdServer->listen6_fd;
fds[1].events = POLLIN;
while (s->fIsRunning) { while (s->fIsRunning) {
// Wait for listen4_fd or listen6_fd (or both!) to become ready:
retval = poll(fds, nfds, -1);
if (retval < 1) {
return -1; // fds no longer available
}
for (int fdi = 0; fdi < nfds; fdi++) {
if (fds[fdi].fd < 0) {
continue; // fd is disabled, e.g. ipv4-only
}
if ((fds[fdi].revents & POLLIN) != POLLIN) {
continue; // fd is unavailable, try next fd
}
hc = new httpd_conn; hc = new httpd_conn;
hc->initialized = 0; hc->initialized = 0;
PRINT(("calling httpd_get_conn()\n")); PRINT(("calling httpd_get_conn()\n"));
retval = //accept(), blocked here retval = httpd_get_conn(s->fHttpdServer, fds[fdi].fd, hc);
httpd_get_conn(s->fHttpdServer, s->fHttpdServer->listen4_fd, hc);
switch (retval) { switch (retval) {
case GC_OK: case GC_OK:
break; break;
@@ -253,6 +285,7 @@ int32 PoorManServer::_Listener(void* data)
send_data(tid, 512, &hc, sizeof(httpd_conn*)); send_data(tid, 512, &hc, sizeof(httpd_conn*));
atomic_add(&s->fCurConns, 1); atomic_add(&s->fCurConns, 1);
resume_thread(tid); resume_thread(tid);
}//for
}//while }//while
return 0; return 0;
} }
@@ -374,7 +407,7 @@ status_t PoorManServer::_HandleGet(httpd_conn* hc)
pthread_rwlock_unlock(&fWebDirLock); pthread_rwlock_unlock(&fWebDirLock);
} }
log << '/' << hc->expnfilename << '\n'; log << '/' << hc->expnfilename << '\n';
poorman_log(log.String(), true, hc->client_addr.sa_in.sin_addr.s_addr); poorman_log(log.String(), true, &hc->client_addr);
//send mime headers //send mime headers
if (send(hc->conn_fd, hc->response, hc->responselen, 0) < 0) { if (send(hc->conn_fd, hc->response, hc->responselen, 0) < 0) {
@@ -398,7 +431,7 @@ status_t PoorManServer::_HandleGet(httpd_conn* hc)
pthread_rwlock_unlock(&fWebDirLock); pthread_rwlock_unlock(&fWebDirLock);
} }
log << '/' << hc->expnfilename << '\n'; log << '/' << hc->expnfilename << '\n';
poorman_log(log.String(), true, hc->client_addr.sa_in.sin_addr.s_addr, RED); poorman_log(log.String(), true, &hc->client_addr, RED);
delete [] buf; delete [] buf;
return B_ERROR; return B_ERROR;
} }
+6 -13
View File
@@ -214,7 +214,7 @@ PoorManWindow::MessageReceived(BMessage* message)
break; break;
time_t time; time_t time;
in_addr_t address; const char* address;
rgb_color color; rgb_color color;
const void* pointer; const void* pointer;
ssize_t size; ssize_t size;
@@ -228,10 +228,8 @@ PoorManWindow::MessageReceived(BMessage* message)
else else
time = *static_cast<const time_t*>(pointer); time = *static_cast<const time_t*>(pointer);
if (message->FindData("in_addr_t", B_ANY_TYPE, &pointer, &size) != B_OK) if (message->FindString("addr", &address) != B_OK)
address = INADDR_NONE; address = NULL;
else
address = *static_cast<const in_addr_t*>(pointer);
if (message->FindData("rgb_color", B_RGB_COLOR_TYPE, &pointer, &size) != B_OK) if (message->FindData("rgb_color", B_RGB_COLOR_TYPE, &pointer, &size) != B_OK)
color = BLACK; color = BLACK;
@@ -246,13 +244,8 @@ PoorManWindow::MessageReceived(BMessage* message)
} }
} }
if (address != INADDR_NONE) { if (address != NULL) {
char addr[INET_ADDRSTRLEN]; line << '(' << address << ") ";
struct in_addr sin_addr;
sin_addr.s_addr = address;
if (inet_ntop(AF_INET, &sin_addr, addr, sizeof(addr)) != NULL) {
line << '(' << addr << ") ";
}
} }
line << msg; line << msg;
@@ -711,7 +704,7 @@ PoorManWindow::StartServer()
fStatus = true; fStatus = true;
UpdateStatusLabelAndMenuItem(); UpdateStatusLabelAndMenuItem();
poorman_log(B_TRANSLATE("done.\n"), false, INADDR_NONE, GREEN); poorman_log(B_TRANSLATE("done.\n"), false, NULL, GREEN);
return B_OK; return B_OK;
} }
+6 -6
View File
@@ -394,7 +394,7 @@ httpd_initialize_listen_socket( httpd_sockaddr* saP )
if ( listen_fd < 0 ) if ( listen_fd < 0 )
{ {
// syslog( LOG_CRIT, "socket %.80s - %m", httpd_ntoa( saP ) ); // syslog( LOG_CRIT, "socket %.80s - %m", httpd_ntoa( saP ) );
poorman_log("can't create socket.\n", false, INADDR_NONE, RED); poorman_log("can't create socket.\n", false, NULL, RED);
return -1; return -1;
} }
(void) fcntl( listen_fd, F_SETFD, 1 ); (void) fcntl( listen_fd, F_SETFD, 1 );
@@ -411,7 +411,7 @@ httpd_initialize_listen_socket( httpd_sockaddr* saP )
{ {
// syslog( // syslog(
// LOG_CRIT, "bind %.80s - %m", httpd_ntoa( saP ) ); // LOG_CRIT, "bind %.80s - %m", httpd_ntoa( saP ) );
poorman_log("can't bind to socket.\n", false, INADDR_NONE, RED); poorman_log("can't bind to socket.\n", false, NULL, RED);
(void) close( listen_fd ); (void) close( listen_fd );
return -1; return -1;
} }
@@ -420,7 +420,7 @@ httpd_initialize_listen_socket( httpd_sockaddr* saP )
if ( listen( listen_fd, LISTEN_BACKLOG ) < 0 ) if ( listen( listen_fd, LISTEN_BACKLOG ) < 0 )
{ {
// syslog( LOG_CRIT, "listen - %m" ); // syslog( LOG_CRIT, "listen - %m" );
poorman_log("can't listen to socket.\n", false, INADDR_NONE, RED); poorman_log("can't listen to socket.\n", false, NULL, RED);
(void) close( listen_fd ); (void) close( listen_fd );
return -1; return -1;
} }
@@ -2695,7 +2695,7 @@ ls( httpd_conn* hc )
{ {
char logString[27+B_PATH_NAME_LENGTH+1]; char logString[27+B_PATH_NAME_LENGTH+1];
sprintf(logString, "Error 404 File not found: %s\n", hc->decodedurl+1); sprintf(logString, "Error 404 File not found: %s\n", hc->decodedurl+1);
poorman_log(logString, true, hc->client_addr.sa_in.sin_addr.s_addr, RED); poorman_log(logString, true, &hc->client_addr, RED);
// syslog( LOG_ERR, "opendir %.80s - %m", hc->expnfilename ); // syslog( LOG_ERR, "opendir %.80s - %m", hc->expnfilename );
httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl ); httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl );
free(de); free(de);
@@ -2735,7 +2735,7 @@ ls( httpd_conn* hc )
strcat(logString, "index file"); strcat(logString, "index file");
strcat(logString, ". Sending directory listing.\n"); strcat(logString, ". Sending directory listing.\n");
poorman_log(logString, true, hc->client_addr.sa_in.sin_addr.s_addr, BLACK); poorman_log(logString, true, &hc->client_addr, BLACK);
} }
send_mime( send_mime(
@@ -3049,7 +3049,7 @@ really_start_request( httpd_conn* hc, struct timeval* nowP )
{ {
char logString[27+B_PATH_NAME_LENGTH+1]; char logString[27+B_PATH_NAME_LENGTH+1];
sprintf(logString, "Error 404 File not found: %s\n", hc->decodedurl+1); sprintf(logString, "Error 404 File not found: %s\n", hc->decodedurl+1);
poorman_log(logString, true, hc->client_addr.sa_in.sin_addr.s_addr, RED); poorman_log(logString, true, &hc->client_addr, RED);
httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl ); httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl );
return -1; return -1;
} }