/******************************************************************************* * * single_document_webserver.c * * AUTHOR: * Dan Harkless * * COPYRIGHT: * This file is Copyright (C) 2000 by Dan Harkless, and is released under the * GNU General Public License . * * USAGE: * % single_document_webserver [] * * EXAMPLE: * % single_document_webserver under_construction.html 8080 * * DESCRIPTION: * A very simple webserver that just outputs a fixed HTML file for every HTTP * request it gets. This can be useful if you need to output some kind of * "under construction" or "we are experiencing technical difficulties" type of * page but can't or don't want to use a full-blown webserver. Note that if * you refer to any graphics in your HTML file, they'll need to be absolute * URLs to images served by another machine. * * By default this program binds to port 80, but you can specify an alternate * port if desired. The port is bound to on all interfaces / addresses, * which may or may not be what you want on multi-homed hosts. * * COMPILATION: * AIX/...: % cc single_document_webserver.c -o single_document_webserver * Solaris: % cc single_document_webserver.c -lsocket \ * -o single_document_webserver * * DATE MODIFICATION * ========== ================================================================== * 2000-09-19 Original. * *******************************************************************************/ #include /* must precede */ #include /* must precede */ #include /* for errno */ #include /* for O_RDONLY */ #include /* for struct sockaddr_in, etc. */ #include /* for fprintf(), etc. */ #include /* for EXIT_FAILURE, etc. */ #include /* for strerror(), etc. */ #include /* for socket(), etc. */ #include /* for close() */ #define HTTP_HEADER "HTTP/1.0 200 OK\nContent-Type: text/html\n\n" #define MAX_LISTEN_QUEUE 1024 /* arbitrary but should always be OK */ char* our_program_name_global; void die(char* failed_syscall) { fprintf(stderr, "%s: %s(): %s. Aborting.\n", our_program_name_global, failed_syscall, strerror(errno)); exit(EXIT_FAILURE); } int main(int argc, char** argv) { char* HTML_filename; char* last_slash_in_argv_0 = strrchr(argv[0], '/'); int HTML_fd, listen_fd, port; struct sockaddr_in server_address; if (last_slash_in_argv_0 == NULL) our_program_name_global = argv[0]; else our_program_name_global = last_slash_in_argv_0 + 1; if (argc < 2 || argc > 3) { fputs("Usage: single_document_webserver []\n", stderr); return EXIT_FAILURE; } HTML_filename = argv[1]; HTML_fd = open(HTML_filename, O_RDONLY); if (HTML_fd < 0) die("open"); if (argc == 3) port = atoi(argv[2]); else port = 80; listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd < 0) die("socket"); memset(&server_address, 0, sizeof(server_address)); server_address.sin_addr.s_addr = htonl(INADDR_ANY); server_address.sin_family = AF_INET; server_address.sin_port = htons(port); if (bind(listen_fd, (struct sockaddr*)&server_address, sizeof(server_address)) < 0) die("bind"); if (listen(listen_fd, MAX_LISTEN_QUEUE) < 0) die("listen"); while (1) { char buffer[BUFSIZ]; char char_1_back=' ', char_2_back=' ', char_3_back=' ', this_char=' '; int accept_fd = accept(listen_fd, (struct sockaddr*)NULL, NULL); int result; if (accept_fd < 0) die("accept"); /* Eat HTTP commands. */ do { /* Read byte-by-byte to ease detection of "\r\n\r\n". */ result = read(accept_fd, buffer, 1); if (result < 0) die("read"); else if (result == 0) break; /* client closed connection before "\r\n\r\n" */ char_3_back = char_2_back; char_2_back = char_1_back; char_1_back = this_char; this_char = buffer[0]; } while (!(char_3_back == '\r' && char_2_back == '\n' && char_1_back == '\r' && this_char == '\n')); if (result != 0) { /* Output the HTTP header. */ if (write(accept_fd, HTTP_HEADER, sizeof(HTTP_HEADER) - 1) < 0) die("write"); /* Rewind the HTML file. */ if (lseek(HTML_fd, 0, SEEK_SET) == -1) /* "< 0" not cool here */ die("lseek"); /* Output the HTML file. */ do { result = read(HTML_fd, buffer, BUFSIZ); if (result < 0) die("read"); if (write(accept_fd, buffer, result) < 0) die("write"); } while (result > 0); } /* Close this network connection. */ if (close(accept_fd) < 0) die("close"); } return EXIT_SUCCESS; /* never reached -- here to make the compiler happy */ }