http.c revision 150990
1/*- 2 * Copyright (c) 2005 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/tools/tools/netrate/http/http.c 150990 2005-10-06 08:41:08Z rwatson $ 27 */ 28 29#include <sys/types.h> 30#include <sys/socket.h> 31 32#include <netinet/in.h> 33 34#include <arpa/inet.h> 35 36#include <err.h> 37#include <pthread.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <string.h> 41#include <unistd.h> 42 43/* 44 * Simple, multi-threaded HTTP benchmark. Fetches a single URL using the 45 * specified parameters, and after a period of execution, reports on how it 46 * worked out. 47 */ 48#define THREADS 128 49#define SECONDS 20 50#define BUFFER (48*1024) 51#define HTTP 8000 52#define QUIET 1 53 54struct http_worker_description { 55 pthread_t hwd_thread; 56 u_int64_t hwd_count; 57 u_int64_t hwd_errorcount; 58}; 59 60static struct sockaddr_in sin; 61static char *path; 62static struct http_worker_description hwd[THREADS]; 63static int run_done; 64static pthread_barrier_t start_barrier; 65 66/* 67 * Given a partially processed URL, fetch it from the specified host. 68 */ 69static int 70http_fetch(struct sockaddr_in *sin, char *path, int quiet) 71{ 72 u_char buffer[BUFFER]; 73 ssize_t len; 74 size_t sofar; 75 int sock; 76 77 sock = socket(PF_INET, SOCK_STREAM, 0); 78 if (sock < 0) { 79 if (!quiet) 80 warn("socket(PF_INET, SOCK_STREAM)"); 81 return (-1); 82 } 83 84 if (connect(sock, (struct sockaddr *)sin, sizeof(*sin)) < 0) { 85 if (!quiet) 86 warn("connect"); 87 close(sock); 88 return (-1); 89 } 90 91 /* Send a request. */ 92 snprintf(buffer, BUFFER, "GET %s HTTP/1.0\n\n", path); 93 sofar = 0; 94 while (sofar < strlen(buffer)) { 95 len = send(sock, buffer, strlen(buffer), 0); 96 if (len < 0) { 97 if (!quiet) 98 warn("send"); 99 close(sock); 100 return (-1); 101 } 102 if (len == 0) { 103 if (!quiet) 104 warnx("send: len == 0"); 105 } 106 sofar += len; 107 } 108 109 /* Read until done. Not very smart. */ 110 while (1) { 111 len = recv(sock, buffer, BUFFER, 0); 112 if (len < 0) { 113 if (!quiet) 114 warn("recv"); 115 close(sock); 116 return (-1); 117 } 118 if (len == 0) 119 break; 120 } 121 122 close(sock); 123 return (0); 124} 125 126static void * 127http_worker(void *arg) 128{ 129 struct http_worker_description *hwdp; 130 int ret; 131 132 ret = pthread_barrier_wait(&start_barrier); 133 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) 134 err(-1, "pthread_barrier_wait"); 135 136 hwdp = arg; 137 while (!run_done) { 138 if (http_fetch(&sin, path, QUIET) < 0) { 139 hwdp->hwd_errorcount++; 140 continue; 141 } 142 /* Don't count transfers that didn't finish in time. */ 143 if (!run_done) 144 hwdp->hwd_count++; 145 } 146 147 return (NULL); 148} 149 150int 151main(int argc, char *argv[]) 152{ 153 u_int64_t total; 154 int i; 155 156 if (argc != 3) 157 errx(-1, "usage: http [IP] [PATH]"); 158 159 bzero(&sin, sizeof(sin)); 160 sin.sin_len = sizeof(sin); 161 sin.sin_family = AF_INET; 162 sin.sin_port = htons(HTTP); 163 sin.sin_addr.s_addr = inet_addr(argv[1]); 164 path = argv[2]; 165 166 /* 167 * Do one test retrieve so we can report the error from it, if any. 168 */ 169 if (http_fetch(&sin, path, 0) < 0) 170 exit(-1); 171 172 if (pthread_barrier_init(&start_barrier, NULL, THREADS) < 0) 173 err(-1, "pthread_mutex_init"); 174 175 for (i = 0; i < THREADS; i++) { 176 hwd[i].hwd_count = 0; 177 if (pthread_create(&hwd[i].hwd_thread, NULL, http_worker, 178 &hwd[i]) < 0) 179 err(-1, "pthread_create"); 180 } 181 sleep(SECONDS); 182 run_done = 1; 183 for (i = 0; i < THREADS; i++) { 184 if (pthread_join(hwd[i].hwd_thread, NULL) < 0) 185 err(-1, "pthread_join"); 186 } 187 total = 0; 188 for (i = 0; i < THREADS; i++) 189 total += hwd[i].hwd_count; 190 printf("%llu transfers/second\n", total / SECONDS); 191 total = 0; 192 for (i = 0; i < THREADS; i++) 193 total += hwd[i].hwd_errorcount; 194 printf("%llu errors/second\n", total / SECONDS); 195 return (0); 196} 197