diff --git a/README.md b/README.md index 7c3bcfa..db47a3d 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,8 @@ A necessary subset of `HTTP 1.0` with following options of request header being 1. Serve files 2. CGI 3. Listen on `ipv6` -4. Multi-thread +4. Listen on unix socket +5. Multi-thread ## Compile ```bash @@ -45,11 +46,12 @@ make install ## Command line usage ```bash -simple-http-server [-d] [-p ] [-r ] [-u ] +simple-http-server [-h] [-d] [-p ] [-r ] [-u ] ``` +- **-h**: display this help. - **-d**: run as daemon. -- **-p**: if not set, choose a random one. +- **-p**: if not set, we will choose a random port. - **-r**: http root dir. - **-u**: run as this uid. diff --git a/server.c b/server.c index ac6e7c7..c485396 100644 --- a/server.c +++ b/server.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -58,6 +59,7 @@ static int headers(int, const char *); static void not_found(int); static void serve_file(int, const char *); static int startup(u_int16_t *); +static int startupunix(char *); static void unimplemented(int); /**********************************************************************/ @@ -189,7 +191,7 @@ static void cat(int client, FILE *resource) { rewind(resource); sendfile(client, fileno(resource), &len, file_size); #endif - printf("Sendfile: %lu bytes.\n", len); + printf("Sendfile: %u bytes.\n", (unsigned int)len); } /**********************************************************************/ @@ -357,7 +359,7 @@ static int get_line(int sock, char *buf, int size) { } /**********************************************************************/ -/* Handle thread quit signal +/* Handle thread quit signal */ /**********************************************************************/ static void handle_quit(int signo) { perror("handle"); @@ -455,7 +457,7 @@ static int startup(uint16_t *port) { bzero(&(name.sin_zero), 8); httpd = socket(AF_INET, SOCK_STREAM, 0); #endif - if(httpd == -1) error_die("socket"); + if(httpd < 0) error_die("socket"); if(bind(httpd,(struct sockaddr *)&name, struct_len) < 0) error_die("bind"); /* if dynamically allocating a port */ if(*port == 0) { @@ -467,7 +469,21 @@ static int startup(uint16_t *port) { #endif } if(listen(httpd, 5) < 0) error_die("listen"); - return(httpd); + return httpd; +} + +static struct sockaddr_un uname; +static int startupunix(char *path) { + int httpd = socket(AF_UNIX, SOCK_STREAM, 0); + uname.sun_family = AF_UNIX; + strncpy(uname.sun_path, path, sizeof(uname.sun_path)); + uname.sun_path[sizeof(uname.sun_path)-1] = 0; // avoid overlap + uname.sun_len = strlen(path)+1; // including null + if(httpd < 0) error_die("unix socket"); + unlink(path); // in case it already exists + if(bind(httpd, (struct sockaddr *)&uname, (void*)uname.sun_path-(void*)&uname+uname.sun_len) < 0) error_die("bind"); + if(listen(httpd, 5) < 0) error_die("listen"); + return httpd; } /**********************************************************************/ @@ -481,10 +497,10 @@ static void unimplemented(int client) { puts("501 Method Not Implemented."); } -/**********************************************************************/ +/************************************************************************/ /* simple-http-server - * Usage: simple-http-server [-d] [-p ] [-r ] [-u ] -/**********************************************************************/ + * Usage: simple-http-server [-d] [-p ] [-r ] [-u ] */ +/************************************************************************/ static pthread_attr_t attr; static pthread_t accept_thread; static socklen_t client_name_len = sizeof(client_name); @@ -514,11 +530,13 @@ static int accept_client(int server_sock) { } #define argequ(arg) (*(uint16_t*)argv[i] == *(uint16_t*)(arg)) +#define USAGE "Usage:\tsimple-http-server [-h] [-d] [-p ] [-r ] [-u ]\n -h:\tdisplay this help.\n -d:\trun as daemon.\n -p:\tif not set, we will choose a random port.\n -r:\thttp root dir.\n -u:\trun as this uid." int main(int argc, char **argv) { - if(argc > 8) puts("Usage:\tsimple-http-server [-d] [-p ] [-r ] [-u ]\n -d:\trun as daemon.\n -p:\tif not set, choose a random one.\n -r:\thttp root dir.\n -u:\trun as this uid."); + if(argc > 8) puts(USAGE); else { int as_daemon = 0; uint16_t port = 0; + char* socket_path = NULL; char *cdir = "./"; uid_t uid = -1; int server_sock = -1; @@ -526,14 +544,28 @@ int main(int argc, char **argv) { for(int i = 1; i < argc; i++) { if(!as_daemon && argequ("-d")) as_daemon = 1; - else if(argequ("-p")) port = (uint16_t)atoi(argv[i + 1]); - else if(argequ("-r")) cdir = argv[i + 1]; - else if(argequ("-u")) uid = atoi(argv[i + 1]); + else if(argequ("-p")) { + i++; + if(isdigit(argv[i][0])) port = (uint16_t)atoi(argv[i]); + else socket_path = argv[i]; + } + else if(argequ("-r")) cdir = argv[++i]; + else if(argequ("-u")) uid = atoi(argv[++i]); + else if(argequ("-h")) { + puts(USAGE); + exit(EXIT_SUCCESS); + } + else { + printf("unknown argument: %s\n", argv[i]); + puts(USAGE); + exit(EXIT_FAILURE); + } } if(chdir(cdir)) error_die("chdir"); - server_sock = startup(&port); - printf("httpd running on 0.0.0.0:%d at %s\n", port, cdir); + server_sock = (!port&&socket_path)?startupunix(socket_path):startup(&port); + if(port) printf("httpd running on 0.0.0.0:%d at %s\n", port, cdir); + else printf("httpd running on %s at %s\n", socket_path, cdir); if(as_daemon) { if(uid > 0) { setuid(uid);