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:
committed by
Adrien Destugues
parent
da93a24811
commit
6011ce6c74
@@ -17,10 +17,11 @@
|
||||
|
||||
#include "PoorManApplication.h"
|
||||
#include "PoorManWindow.h"
|
||||
#include "libhttpd.h"
|
||||
|
||||
void
|
||||
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);
|
||||
|
||||
@@ -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)
|
||||
return;
|
||||
}
|
||||
if(addr != INADDR_NONE)
|
||||
message.AddData("in_addr_t", B_ANY_TYPE, &addr, sizeof(in_addr_t));
|
||||
if(addr != NULL)
|
||||
message.AddString("addr", httpd_ntoa(addr));
|
||||
|
||||
if(color != BLACK)
|
||||
message.AddData("rgb_color", B_RGB_COLOR_TYPE, &color, sizeof(rgb_color));
|
||||
|
||||
@@ -11,20 +11,21 @@
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "constants.h" //for rgb_color BLACK
|
||||
#include "libhttpd.h" //for httpd_sockaddr
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
void poorman_log(
|
||||
const char* msg,
|
||||
bool needTimeHeader = true,
|
||||
in_addr_t addr = INADDR_NONE,
|
||||
httpd_sockaddr* addr = NULL,
|
||||
rgb_color color = BLACK
|
||||
);
|
||||
#else //c version is for libhttpd
|
||||
void poorman_log(
|
||||
const char* msg,
|
||||
bool needTimeHeader,
|
||||
in_addr_t addr,
|
||||
httpd_sockaddr* addr,
|
||||
rgb_color color
|
||||
);
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <File.h>
|
||||
#include <Debug.h>
|
||||
@@ -85,7 +86,7 @@ PoorManServer::~PoorManServer()
|
||||
status_t PoorManServer::Run()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -95,7 +96,15 @@ status_t PoorManServer::Run()
|
||||
sa4.sa_in.sin_port = htons(80);
|
||||
sa4.sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
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;
|
||||
|
||||
fListenerTid = spawn_thread(
|
||||
@@ -105,7 +114,7 @@ status_t PoorManServer::Run()
|
||||
static_cast<void*>(this)
|
||||
);
|
||||
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;
|
||||
}
|
||||
fIsRunning = true;
|
||||
@@ -204,55 +213,79 @@ int32 PoorManServer::_Listener(void* data)
|
||||
thread_id tid;
|
||||
httpd_conn* hc;
|
||||
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) {
|
||||
hc = new httpd_conn;
|
||||
hc->initialized = 0;
|
||||
PRINT(("calling httpd_get_conn()\n"));
|
||||
retval = //accept(), blocked here
|
||||
httpd_get_conn(s->fHttpdServer, s->fHttpdServer->listen4_fd, hc);
|
||||
switch (retval) {
|
||||
case GC_OK:
|
||||
break;
|
||||
case GC_FAIL:
|
||||
httpd_destroy_conn(hc);
|
||||
delete hc;
|
||||
s->fIsRunning = false;
|
||||
return -1;
|
||||
case GC_NO_MORE:
|
||||
//should not happen, since we have a blocking socket
|
||||
httpd_destroy_conn(hc);
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
//shouldn't happen
|
||||
continue;
|
||||
break;
|
||||
// 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
|
||||
}
|
||||
|
||||
if (s->fCurConns > s->fMaxConns) {
|
||||
httpd_send_err(hc, 503,
|
||||
httpd_err503title, (char *)"", httpd_err503form, (char *)"");
|
||||
httpd_write_response(hc);
|
||||
continue;
|
||||
}
|
||||
|
||||
tid = spawn_thread(
|
||||
PoorManServer::_Worker,
|
||||
"www connection",
|
||||
B_NORMAL_PRIORITY,
|
||||
static_cast<void*>(s)
|
||||
);
|
||||
if (tid < B_OK) {
|
||||
continue;
|
||||
}
|
||||
/*We don't check the return code here.
|
||||
*As we can't kill a thread that doesn't receive the
|
||||
*httpd_conn, we simply let it die itself.
|
||||
*/
|
||||
send_data(tid, 512, &hc, sizeof(httpd_conn*));
|
||||
atomic_add(&s->fCurConns, 1);
|
||||
resume_thread(tid);
|
||||
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->initialized = 0;
|
||||
|
||||
PRINT(("calling httpd_get_conn()\n"));
|
||||
retval = httpd_get_conn(s->fHttpdServer, fds[fdi].fd, hc);
|
||||
switch (retval) {
|
||||
case GC_OK:
|
||||
break;
|
||||
case GC_FAIL:
|
||||
httpd_destroy_conn(hc);
|
||||
delete hc;
|
||||
s->fIsRunning = false;
|
||||
return -1;
|
||||
case GC_NO_MORE:
|
||||
//should not happen, since we have a blocking socket
|
||||
httpd_destroy_conn(hc);
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
//shouldn't happen
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (s->fCurConns > s->fMaxConns) {
|
||||
httpd_send_err(hc, 503,
|
||||
httpd_err503title, (char *)"", httpd_err503form, (char *)"");
|
||||
httpd_write_response(hc);
|
||||
continue;
|
||||
}
|
||||
|
||||
tid = spawn_thread(
|
||||
PoorManServer::_Worker,
|
||||
"www connection",
|
||||
B_NORMAL_PRIORITY,
|
||||
static_cast<void*>(s)
|
||||
);
|
||||
if (tid < B_OK) {
|
||||
continue;
|
||||
}
|
||||
/*We don't check the return code here.
|
||||
*As we can't kill a thread that doesn't receive the
|
||||
*httpd_conn, we simply let it die itself.
|
||||
*/
|
||||
send_data(tid, 512, &hc, sizeof(httpd_conn*));
|
||||
atomic_add(&s->fCurConns, 1);
|
||||
resume_thread(tid);
|
||||
}//for
|
||||
}//while
|
||||
return 0;
|
||||
}
|
||||
@@ -374,7 +407,7 @@ status_t PoorManServer::_HandleGet(httpd_conn* hc)
|
||||
pthread_rwlock_unlock(&fWebDirLock);
|
||||
}
|
||||
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
|
||||
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);
|
||||
}
|
||||
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;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ PoorManWindow::MessageReceived(BMessage* message)
|
||||
break;
|
||||
|
||||
time_t time;
|
||||
in_addr_t address;
|
||||
const char* address;
|
||||
rgb_color color;
|
||||
const void* pointer;
|
||||
ssize_t size;
|
||||
@@ -228,10 +228,8 @@ PoorManWindow::MessageReceived(BMessage* message)
|
||||
else
|
||||
time = *static_cast<const time_t*>(pointer);
|
||||
|
||||
if (message->FindData("in_addr_t", B_ANY_TYPE, &pointer, &size) != B_OK)
|
||||
address = INADDR_NONE;
|
||||
else
|
||||
address = *static_cast<const in_addr_t*>(pointer);
|
||||
if (message->FindString("addr", &address) != B_OK)
|
||||
address = NULL;
|
||||
|
||||
if (message->FindData("rgb_color", B_RGB_COLOR_TYPE, &pointer, &size) != B_OK)
|
||||
color = BLACK;
|
||||
@@ -246,13 +244,8 @@ PoorManWindow::MessageReceived(BMessage* message)
|
||||
}
|
||||
}
|
||||
|
||||
if (address != INADDR_NONE) {
|
||||
char addr[INET_ADDRSTRLEN];
|
||||
struct in_addr sin_addr;
|
||||
sin_addr.s_addr = address;
|
||||
if (inet_ntop(AF_INET, &sin_addr, addr, sizeof(addr)) != NULL) {
|
||||
line << '(' << addr << ") ";
|
||||
}
|
||||
if (address != NULL) {
|
||||
line << '(' << address << ") ";
|
||||
}
|
||||
|
||||
line << msg;
|
||||
@@ -711,7 +704,7 @@ PoorManWindow::StartServer()
|
||||
|
||||
fStatus = true;
|
||||
UpdateStatusLabelAndMenuItem();
|
||||
poorman_log(B_TRANSLATE("done.\n"), false, INADDR_NONE, GREEN);
|
||||
poorman_log(B_TRANSLATE("done.\n"), false, NULL, GREEN);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -394,7 +394,7 @@ httpd_initialize_listen_socket( httpd_sockaddr* saP )
|
||||
if ( listen_fd < 0 )
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
(void) fcntl( listen_fd, F_SETFD, 1 );
|
||||
@@ -411,7 +411,7 @@ httpd_initialize_listen_socket( httpd_sockaddr* saP )
|
||||
{
|
||||
// syslog(
|
||||
// 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 );
|
||||
return -1;
|
||||
}
|
||||
@@ -420,7 +420,7 @@ httpd_initialize_listen_socket( httpd_sockaddr* saP )
|
||||
if ( listen( listen_fd, LISTEN_BACKLOG ) < 0 )
|
||||
{
|
||||
// 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 );
|
||||
return -1;
|
||||
}
|
||||
@@ -2695,7 +2695,7 @@ ls( httpd_conn* hc )
|
||||
{
|
||||
char logString[27+B_PATH_NAME_LENGTH+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 );
|
||||
httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl );
|
||||
free(de);
|
||||
@@ -2735,7 +2735,7 @@ ls( httpd_conn* hc )
|
||||
strcat(logString, "index file");
|
||||
|
||||
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(
|
||||
@@ -3049,7 +3049,7 @@ really_start_request( httpd_conn* hc, struct timeval* nowP )
|
||||
{
|
||||
char logString[27+B_PATH_NAME_LENGTH+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 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user