📄 ab.c
字号:
static void read_connection(struct connection * c){ apr_size_t r; apr_status_t status; char *part; char respcode[4]; /* 3 digits and null */ r = sizeof(buffer);#ifdef USE_SSL if (ssl == 1) { status = SSL_read (c->ssl, buffer, r); if (status <= 0) { good++; c->read = 0; if (status < 0) printf("SSL read failed - closing connection\n"); close_connection(c); return; } r = status; } else {#endif status = apr_recv(c->aprsock, buffer, &r); if (APR_STATUS_IS_EAGAIN(status)) return; else if (r == 0 && APR_STATUS_IS_EOF(status)) { good++; close_connection(c); return; } /* catch legitimate fatal apr_recv errors */ else if (status != APR_SUCCESS) { err_except++; /* XXX: is this the right error counter? */ /* XXX: Should errors here be fatal, or should we allow a * certain number of them before completely failing? -aaron */ apr_err("apr_recv", status); }#ifdef USE_SSL }#endif totalread += r; if (c->read == 0) { c->beginread = apr_time_now(); } c->read += r; if (!c->gotheader) { char *s; int l = 4; apr_size_t space = CBUFFSIZE - c->cbx - 1; /* -1 allows for \0 term */ int tocopy = (space < r) ? space : r;#ifdef NOT_ASCII apr_size_t inbytes_left = space, outbytes_left = space; status = apr_xlate_conv_buffer(from_ascii, buffer, &inbytes_left, c->cbuff + c->cbx, &outbytes_left); if (status || inbytes_left || outbytes_left) { fprintf(stderr, "only simple translation is supported (%d/%u/%u)\n", status, inbytes_left, outbytes_left); exit(1); }#else memcpy(c->cbuff + c->cbx, buffer, space);#endif /* NOT_ASCII */ c->cbx += tocopy; space -= tocopy; c->cbuff[c->cbx] = 0; /* terminate for benefit of strstr */ if (verbosity >= 2) { printf("LOG: header received:\n%s\n", c->cbuff); } s = strstr(c->cbuff, "\r\n\r\n"); /* * this next line is so that we talk to NCSA 1.5 which blatantly * breaks the http specifaction */ if (!s) { s = strstr(c->cbuff, "\n\n"); l = 2; } if (!s) { /* read rest next time */ if (space) { return; } else { /* header is in invalid or too big - close connection */ apr_pollfd_t remove_pollfd; remove_pollfd.desc_type = APR_POLL_SOCKET; remove_pollfd.desc.s = c->aprsock; apr_pollset_remove(readbits, &remove_pollfd); apr_socket_close(c->aprsock); err_response++; if (bad++ > 10) { err("\nTest aborted after 10 failures\n\n"); } start_connect(c); } } else { /* have full header */ if (!good) { /* * this is first time, extract some interesting info */ char *p, *q; p = strstr(c->cbuff, "Server:"); q = servername; if (p) { p += 8; while (*p > 32) *q++ = *p++; } *q = 0; } /* * XXX: this parsing isn't even remotely HTTP compliant... but in * the interest of speed it doesn't totally have to be, it just * needs to be extended to handle whatever servers folks want to * test against. -djg */ /* check response code */ part = strstr(c->cbuff, "HTTP"); /* really HTTP/1.x_ */ if (part && strlen(part) > strlen("HTTP/1.x_")) { strncpy(respcode, (part + strlen("HTTP/1.x_")), 3); respcode[3] = '\0'; } else { strcpy(respcode, "500"); } if (respcode[0] != '2') { err_response++; if (verbosity >= 2) printf("WARNING: Response code not 2xx (%s)\n", respcode); } else if (verbosity >= 3) { printf("LOG: Response code = %s\n", respcode); } c->gotheader = 1; *s = 0; /* terminate at end of header */ if (keepalive && (strstr(c->cbuff, "Keep-Alive") || strstr(c->cbuff, "keep-alive"))) { /* for benefit of MSIIS */ char *cl; cl = strstr(c->cbuff, "Content-Length:"); /* handle NCSA, which sends Content-length: */ if (!cl) cl = strstr(c->cbuff, "Content-length:"); if (cl) { c->keepalive = 1; c->length = atoi(cl + 16); } } c->bread += c->cbx - (s + l - c->cbuff) + r - tocopy; totalbread += c->bread; } } else { /* outside header, everything we have read is entity body */ c->bread += r; totalbread += r; } if (c->keepalive && (c->bread >= c->length)) { /* finished a keep-alive connection */ good++; /* save out time */ if (good == 1) { /* first time here */ doclen = c->bread; } else if (c->bread != doclen) { bad++; err_length++; } if (done < requests) { struct data s; doneka++; if (done && heartbeatres && !(done % heartbeatres)) { fprintf(stderr, "Completed %ld requests\n", done); fflush(stderr); } c->done = apr_time_now(); s.read = c->read; s.starttime = c->start; s.ctime = (c->connect - c->start) / 1000; s.waittime = (c->beginread - c->endwrite) / 1000; s.time = (c->done - c->start) / 1000; stats[done++] = s; } c->keepalive = 0; c->length = 0; c->gotheader = 0; c->cbx = 0; c->read = c->bread = 0; c->start = c->connect = apr_time_now(); /* zero connect time with keep-alive */ write_request(c); }}/* --------------------------------------------------------- *//* run the tests */static void test(void){ apr_time_t now; apr_int16_t rv; long i; apr_status_t status;#ifdef NOT_ASCII apr_size_t inbytes_left, outbytes_left;#endif if (isproxy) { connecthost = apr_pstrdup(cntxt, proxyhost); connectport = proxyport; } else { connecthost = apr_pstrdup(cntxt, hostname); connectport = port; } if (!use_html) { printf("Benchmarking %s ", hostname); if (isproxy) printf("[through %s:%d] ", proxyhost, proxyport); printf("(be patient)%s", (heartbeatres ? "\n" : "...")); fflush(stdout); } now = apr_time_now(); con = calloc(concurrency * sizeof(struct connection), 1); stats = calloc(requests * sizeof(struct data), 1); if ((status = apr_pollset_create(&readbits, concurrency, cntxt, 0)) != APR_SUCCESS) { apr_err("apr_pollset_create failed", status); } /* setup request */ if (posting <= 0) { sprintf(request, "%s %s HTTP/1.0\r\n" "User-Agent: ApacheBench/%s\r\n" "%s" "%s" "%s" "Host: %s%s\r\n" "Accept: */*\r\n" "%s" "\r\n", (posting == 0) ? "GET" : "HEAD", (isproxy) ? fullurl : path, AP_AB_BASEREVISION, keepalive ? "Connection: Keep-Alive\r\n" : "", cookie, auth, host_field, colonhost, hdrs); } else { sprintf(request, "POST %s HTTP/1.0\r\n" "User-Agent: ApacheBench/%s\r\n" "%s" "%s" "%s" "Host: %s%s\r\n" "Accept: */*\r\n" "Content-length: %" APR_SIZE_T_FMT "\r\n" "Content-type: %s\r\n" "%s" "\r\n", (isproxy) ? fullurl : path, AP_AB_BASEREVISION, keepalive ? "Connection: Keep-Alive\r\n" : "", cookie, auth, host_field, colonhost, postlen, (content_type[0]) ? content_type : "text/plain", hdrs); } if (verbosity >= 2) printf("INFO: POST header == \n---\n%s\n---\n", request); reqlen = strlen(request); /* * Combine headers and (optional) post file into one contineous buffer */ if (posting == 1) { char *buff = malloc(postlen + reqlen + 1); if (!buff) { fprintf(stderr, "error creating request buffer: out of memory\n"); return; } strcpy(buff, request); strcpy(buff + reqlen, postdata); request = buff; }#ifdef NOT_ASCII inbytes_left = outbytes_left = reqlen; status = apr_xlate_conv_buffer(to_ascii, request, &inbytes_left, request, &outbytes_left); if (status || inbytes_left || outbytes_left) { fprintf(stderr, "only simple translation is supported (%d/%u/%u)\n", status, inbytes_left, outbytes_left); exit(1); }#endif /* NOT_ASCII */ /* This only needs to be done once */#ifdef USE_SSL if (ssl != 1)#endif if ((rv = apr_sockaddr_info_get(&destsa, connecthost, APR_UNSPEC, connectport, 0, cntxt)) != APR_SUCCESS) { char buf[120]; apr_snprintf(buf, sizeof(buf), "apr_sockaddr_info_get() for %s", connecthost); apr_err(buf, rv); } /* ok - lets start */ start = apr_time_now(); /* initialise lots of requests */ for (i = 0; i < concurrency; i++) { con[i].socknum = i; start_connect(&con[i]); } while (done < requests) { apr_int32_t n; apr_int32_t timed; const apr_pollfd_t *pollresults; /* check for time limit expiry */ now = apr_time_now(); timed = (apr_int32_t)apr_time_sec(now - start); if (tlimit && timed >= tlimit) { requests = done; /* so stats are correct */ break; /* no need to do another round */ } n = concurrency;#ifdef USE_SSL if (ssl == 1) status = APR_SUCCESS; else#endif status = apr_pollset_poll(readbits, aprtimeout, &n, &pollresults); if (status != APR_SUCCESS) apr_err("apr_poll", status); if (!n) { err("\nServer timed out\n\n"); } for (i = 0; i < n; i++) { const apr_pollfd_t *next_fd = &(pollresults[i]); struct connection *c = next_fd->client_data; /* * If the connection isn't connected how can we check it? */ if (c->state == STATE_UNCONNECTED) continue;#ifdef USE_SSL if (ssl == 1) rv = APR_POLLIN; else#endif rv = next_fd->rtnevents; /* * Notes: APR_POLLHUP is set after FIN is received on some * systems, so treat that like APR_POLLIN so that we try to read * again. * * Some systems return APR_POLLERR with APR_POLLHUP. We need to * call read_connection() for APR_POLLHUP, so check for * APR_POLLHUP first so that a closed connection isn't treated * like an I/O error. If it is, we never figure out that the * connection is done and we loop here endlessly calling * apr_poll(). */ if ((rv & APR_POLLIN) || (rv & APR_POLLPRI) || (rv & APR_POLLHUP)) read_connection(c); if ((rv & APR_POLLERR) || (rv & APR_POLLNVAL)) { bad++; err_except++; start_connect(c); continue; } if (rv & APR_POLLOUT) { if (c->state == STATE_CONNECTING) { apr_pollfd_t remove_pollfd; rv = apr_connect(c->aprsock, destsa); remove_pollfd.desc_type = APR_POLL_SOCKET; remove_pollfd.desc.s = c->aprsock; apr_pollset_remove(readbits, &remove_pollfd); if (rv != APR_SUCCESS) { apr_socket_close(c->aprsock); err_conn++; if (bad++ > 10) { fprintf(stderr, "\nTest aborted after 10 failures\n\n"); apr_err("apr_connect()", rv); } c->state = STATE_UNCONNECTED; start_connect(c); continue; } else { c->state = STATE_CONNECTED; write_request(c); } } else { write_request(c); } } /* * When using a select based poll every time we check the bits * are reset. In 1.3's ab we copied the FD_SET's each time * through, but here we're going to check the state and if the * connection is in STATE_READ or STATE_CONNECTING we'll add the * socket back in as APR_POLLIN. */#ifdef USE_SSL if (ssl != 1)#endif if (c->state == STATE_READ) { apr_pollfd_t new_pollfd; new_pollfd.desc_type = APR_POLL_SOCKET; new_pollfd.reqevents = APR_POLLIN; new_pollfd.desc.s = c->aprsock;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -