diff options
| author | Robert Watson <rwatson@FreeBSD.org> | 2005-10-25 18:47:12 +0000 |
|---|---|---|
| committer | Robert Watson <rwatson@FreeBSD.org> | 2005-10-25 18:47:12 +0000 |
| commit | 636edd1f9bd4a3630a9d4e42d9b792ebdf4ca22c (patch) | |
| tree | 3d02584e3862f9706c25b7d2acbe4746e43e2c91 | |
| parent | ef74f2c9c504771cdee60d529d26b2655c882e71 (diff) | |
Notes
| -rw-r--r-- | tools/tools/netrate/httpd/httpd.c | 123 |
1 files changed, 91 insertions, 32 deletions
diff --git a/tools/tools/netrate/httpd/httpd.c b/tools/tools/netrate/httpd/httpd.c index a066c966a38a..18cb53f63a5d 100644 --- a/tools/tools/netrate/httpd/httpd.c +++ b/tools/tools/netrate/httpd/httpd.c @@ -29,6 +29,7 @@ #include <sys/types.h> #include <sys/socket.h> #include <sys/uio.h> +#include <sys/utsname.h> #include <netinet/in.h> @@ -36,6 +37,7 @@ #include <err.h> #include <fcntl.h> +#include <limits.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> @@ -44,43 +46,65 @@ /* * Simple, multi-threaded HTTP server. Very dumb. + * + * If a path is specified as an argument, only that file is served. If no + * path is specified, httpd will create one file to send per server thread. */ -#define THREADS 128 -#define BUFFER (48*1024) +#define THREADS 128 +#define BUFFER 1024 +#define FILESIZE 1024 + +#define HTTP_OK "HTTP/1.1 200 OK\n" +#define HTTP_SERVER1 "Server rwatson_httpd/1.0 (" +#define HTTP_SERVER2 ")\n" +#define HTTP_CONNECTION "Connection: close\n" +#define HTTP_CONTENT "Content-Type: text/html\n\n" -#define HTTP_OK "HTTP/1.1 200 OK\n" -#define HTTP_SERVER "Server rwatson_httpd/1.0 (FreeBSD)\n" -#define HTTP_CONNECTION "Connection: close\n" -#define HTTP_CONTENT "Content-Type: text/html\n" +struct httpd_thread_state { + pthread_t hts_thread; + int hts_fd; +} hts[THREADS]; static const char *path; -static int listen_sock; static int data_file; +static int listen_sock; +static struct utsname utsname; /* * Given an open client socket, process its request. No notion of timeout. */ static int -http_serve(int sock) +http_serve(int sock, int fd) { - struct iovec header_iovec[4]; + struct iovec header_iovec[6]; struct sf_hdtr sf_hdtr; + char buffer[BUFFER]; ssize_t len; - int ncount; - char ch; + int i, ncount; /* Read until \n\n. Not very smart. */ ncount = 0; while (1) { - len = recv(sock, &ch, sizeof(ch), 0); + len = recv(sock, buffer, BUFFER, 0); if (len < 0) { warn("recv"); return (-1); } if (len == 0) return (-1); - if (ch == '\n') - ncount++; + for (i = 0; i < len; i++) { + switch (buffer[i]) { + case '\n': + ncount++; + break; + + case '\r': + break; + + default: + ncount = 0; + } + } if (ncount == 2) break; } @@ -89,18 +113,22 @@ http_serve(int sock) bzero(&header_iovec, sizeof(header_iovec)); header_iovec[0].iov_base = HTTP_OK; header_iovec[0].iov_len = strlen(HTTP_OK); - header_iovec[1].iov_base = HTTP_SERVER; - header_iovec[1].iov_len = strlen(HTTP_SERVER); - header_iovec[2].iov_base = HTTP_CONNECTION; - header_iovec[2].iov_len = strlen(HTTP_CONNECTION); - header_iovec[3].iov_base = HTTP_CONTENT; - header_iovec[3].iov_len = strlen(HTTP_CONTENT); + header_iovec[1].iov_base = HTTP_SERVER1; + header_iovec[1].iov_len = strlen(HTTP_SERVER1); + header_iovec[2].iov_base = utsname.sysname; + header_iovec[2].iov_len = strlen(utsname.sysname); + header_iovec[3].iov_base = HTTP_SERVER2; + header_iovec[3].iov_len = strlen(HTTP_SERVER2); + header_iovec[4].iov_base = HTTP_CONNECTION; + header_iovec[4].iov_len = strlen(HTTP_CONNECTION); + header_iovec[5].iov_base = HTTP_CONTENT; + header_iovec[5].iov_len = strlen(HTTP_CONTENT); sf_hdtr.headers = header_iovec; - sf_hdtr.hdr_cnt = 4; + sf_hdtr.hdr_cnt = 6; sf_hdtr.trailers = NULL; sf_hdtr.trl_cnt = 0; - if (sendfile(data_file, sock, 0, 0, &sf_hdtr, NULL, 0) < 0) + if (sendfile(fd, sock, 0, 0, &sf_hdtr, NULL, 0) < 0) warn("sendfile"); return (0); @@ -109,13 +137,16 @@ http_serve(int sock) static void * httpd_worker(void *arg) { + struct httpd_thread_state *htsp; int sock; + htsp = arg; + while (1) { sock = accept(listen_sock, NULL, NULL); if (sock < 0) continue; - (void)http_serve(sock); + (void)http_serve(sock, htsp->hts_fd); close(sock); } } @@ -123,12 +154,17 @@ httpd_worker(void *arg) int main(int argc, char *argv[]) { - pthread_t thread_array[THREADS]; + u_char filebuffer[FILESIZE]; + char temppath[PATH_MAX]; struct sockaddr_in sin; + ssize_t len; int i; - if (argc != 3) - errx(-1, "usage: http [port] [path]"); + if (argc != 2 && argc != 3) + errx(-1, "usage: http port [path]"); + + if (uname(&utsname) < 0) + err(-1, "utsname"); listen_sock = socket(PF_INET, SOCK_STREAM, 0); if (listen_sock < 0) @@ -139,10 +175,33 @@ main(int argc, char *argv[]) sin.sin_family = AF_INET; sin.sin_port = htons(atoi(argv[1])); + /* + * If a path is specified, use it. Otherwise, create temporary files + * with some data for each thread. + */ path = argv[2]; - data_file = open(path, O_RDONLY); - if (data_file < 0) - err(-1, "open: %s", path); + if (path != NULL) { + data_file = open(path, O_RDONLY); + if (data_file < 0) + err(-1, "open: %s", path); + for (i = 0; i < THREADS; i++) + hts[i].hts_fd = data_file; + } else { + memset(filebuffer, 'A', FILESIZE - 1); + filebuffer[FILESIZE - 1] = '\n'; + for (i = 0; i < THREADS; i++) { + snprintf(temppath, PATH_MAX, "/tmp/httpd.XXXXXXXXXXX"); + hts[i].hts_fd = mkstemp(temppath); + if (hts[i].hts_fd < 0) + err(-1, "mkstemp"); + (void)unlink(temppath); + len = write(hts[i].hts_fd, filebuffer, FILESIZE); + if (len < 0) + err(-1, "write"); + if (len < FILESIZE) + errx(-1, "write: short"); + } + } if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) err(-1, "bind"); @@ -151,13 +210,13 @@ main(int argc, char *argv[]) err(-1, "listen"); for (i = 0; i < THREADS; i++) { - if (pthread_create(&thread_array[i], NULL, httpd_worker, - NULL) < 0) + if (pthread_create(&hts[i].hts_thread, NULL, httpd_worker, + &hts[i]) < 0) err(-1, "pthread_create"); } for (i = 0; i < THREADS; i++) { - if (pthread_join(thread_array[i], NULL) < 0) + if (pthread_join(hts[i].hts_thread, NULL) < 0) err(-1, "pthread_join"); } return (0); |
