|
Packit |
3adb1e |
/* ====================================================================
|
|
Packit |
3adb1e |
* Licensed to the Apache Software Foundation (ASF) under one
|
|
Packit |
3adb1e |
* or more contributor license agreements. See the NOTICE file
|
|
Packit |
3adb1e |
* distributed with this work for additional information
|
|
Packit |
3adb1e |
* regarding copyright ownership. The ASF licenses this file
|
|
Packit |
3adb1e |
* to you under the Apache License, Version 2.0 (the
|
|
Packit |
3adb1e |
* "License"); you may not use this file except in compliance
|
|
Packit |
3adb1e |
* with the License. You may obtain a copy of the License at
|
|
Packit |
3adb1e |
*
|
|
Packit |
3adb1e |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
3adb1e |
*
|
|
Packit |
3adb1e |
* Unless required by applicable law or agreed to in writing,
|
|
Packit |
3adb1e |
* software distributed under the License is distributed on an
|
|
Packit |
3adb1e |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
Packit |
3adb1e |
* KIND, either express or implied. See the License for the
|
|
Packit |
3adb1e |
* specific language governing permissions and limitations
|
|
Packit |
3adb1e |
* under the License.
|
|
Packit |
3adb1e |
* ====================================================================
|
|
Packit |
3adb1e |
*/
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include "apr.h"
|
|
Packit |
3adb1e |
#include "apr_pools.h"
|
|
Packit |
3adb1e |
#include <apr_poll.h>
|
|
Packit |
3adb1e |
#include <apr_version.h>
|
|
Packit |
3adb1e |
#include <stdlib.h>
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include "serf.h"
|
|
Packit |
3adb1e |
#include "serf_private.h" /* for serf__log and serf__bucket_stream_create */
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include "test_server.h"
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#define BUFSIZE 8192
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Cleanup callback for a server. */
|
|
Packit |
3adb1e |
static apr_status_t cleanup_server(void *baton)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
serv_ctx_t *servctx = baton;
|
|
Packit |
3adb1e |
apr_status_t status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (servctx->serv_sock)
|
|
Packit |
3adb1e |
status = apr_socket_close(servctx->serv_sock);
|
|
Packit |
3adb1e |
else
|
|
Packit |
3adb1e |
status = APR_EGENERAL;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (servctx->client_sock) {
|
|
Packit |
3adb1e |
apr_socket_close(servctx->client_sock);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Replay support functions */
|
|
Packit |
3adb1e |
static void next_message(serv_ctx_t *servctx)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
servctx->cur_message++;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static void next_action(serv_ctx_t *servctx)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
servctx->cur_action++;
|
|
Packit |
3adb1e |
servctx->action_buf_pos = 0;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static apr_status_t
|
|
Packit |
3adb1e |
socket_write(serv_ctx_t *serv_ctx, const char *data,
|
|
Packit |
3adb1e |
apr_size_t *len)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
return apr_socket_send(serv_ctx->client_sock, data, len);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static apr_status_t
|
|
Packit |
3adb1e |
socket_read(serv_ctx_t *serv_ctx, char *data,
|
|
Packit |
3adb1e |
apr_size_t *len)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
return apr_socket_recv(serv_ctx->client_sock, data, len);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static apr_status_t
|
|
Packit |
3adb1e |
create_client_socket(apr_socket_t **skt,
|
|
Packit |
3adb1e |
serv_ctx_t *servctx,
|
|
Packit |
3adb1e |
const char *url)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
apr_sockaddr_t *address;
|
|
Packit |
3adb1e |
apr_uri_t uri;
|
|
Packit |
3adb1e |
apr_status_t status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = apr_uri_parse(servctx->pool, url, &uri);
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = apr_sockaddr_info_get(&address,
|
|
Packit |
3adb1e |
uri.hostname,
|
|
Packit |
3adb1e |
APR_UNSPEC,
|
|
Packit |
3adb1e |
uri.port,
|
|
Packit |
3adb1e |
0,
|
|
Packit |
3adb1e |
servctx->pool);
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = apr_socket_create(skt,
|
|
Packit |
3adb1e |
address->family,
|
|
Packit |
3adb1e |
SOCK_STREAM,
|
|
Packit |
3adb1e |
#if APR_MAJOR_VERSION > 0
|
|
Packit |
3adb1e |
APR_PROTO_TCP,
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
servctx->pool);
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Set the socket to be non-blocking */
|
|
Packit |
3adb1e |
status = apr_socket_timeout_set(*skt, 0);
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = apr_socket_connect(*skt, address);
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS && !APR_STATUS_IS_EINPROGRESS(status))
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
return APR_EAGAIN;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Verify received requests and take the necessary actions
|
|
Packit |
3adb1e |
(return a response, kill the connection ...) */
|
|
Packit |
3adb1e |
static apr_status_t replay(serv_ctx_t *servctx,
|
|
Packit |
3adb1e |
apr_int16_t rtnevents,
|
|
Packit |
3adb1e |
apr_pool_t *pool)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
apr_status_t status = APR_SUCCESS;
|
|
Packit |
3adb1e |
test_server_action_t *action;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (rtnevents & APR_POLLIN) {
|
|
Packit |
3adb1e |
if (servctx->message_list == NULL) {
|
|
Packit |
3adb1e |
/* we're not expecting any requests to reach this server! */
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"Received request where none was expected.\n");
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return SERF_ERROR_ISSUE_IN_TESTSUITE;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (servctx->cur_action >= servctx->action_count) {
|
|
Packit |
3adb1e |
char buf[128];
|
|
Packit |
3adb1e |
apr_size_t len = sizeof(buf);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = servctx->read(servctx, buf, &len;;
|
|
Packit |
3adb1e |
if (! APR_STATUS_IS_EAGAIN(status)) {
|
|
Packit |
3adb1e |
/* we're out of actions! */
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"Received more requests than expected.\n");
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return SERF_ERROR_ISSUE_IN_TESTSUITE;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
action = &servctx->action_list[servctx->cur_action];
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"POLLIN while replaying action %d, kind: %d.\n",
|
|
Packit |
3adb1e |
servctx->cur_action, action->kind);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Read the remaining data from the client and kill the socket. */
|
|
Packit |
3adb1e |
if (action->kind == SERVER_IGNORE_AND_KILL_CONNECTION) {
|
|
Packit |
3adb1e |
char buf[128];
|
|
Packit |
3adb1e |
apr_size_t len = sizeof(buf);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = servctx->read(servctx, buf, &len;;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (status == APR_EOF) {
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"Killing this connection.\n");
|
|
Packit |
3adb1e |
apr_socket_close(servctx->client_sock);
|
|
Packit |
3adb1e |
servctx->client_sock = NULL;
|
|
Packit |
3adb1e |
next_action(servctx);
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else if (action->kind == SERVER_RECV ||
|
|
Packit |
3adb1e |
(action->kind == SERVER_RESPOND &&
|
|
Packit |
3adb1e |
servctx->outstanding_responses == 0)) {
|
|
Packit |
3adb1e |
apr_size_t msg_len, len;
|
|
Packit |
3adb1e |
char buf[128];
|
|
Packit |
3adb1e |
test_server_message_t *message;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
message = &servctx->message_list[servctx->cur_message];
|
|
Packit |
3adb1e |
msg_len = strlen(message->text);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
do
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
len = msg_len - servctx->message_buf_pos;
|
|
Packit |
3adb1e |
if (len > sizeof(buf))
|
|
Packit |
3adb1e |
len = sizeof(buf);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = servctx->read(servctx, buf, &len;;
|
|
Packit |
3adb1e |
if (SERF_BUCKET_READ_ERROR(status))
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (status == APR_EOF) {
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"Server: Client hung up the connection.\n");
|
|
Packit |
3adb1e |
break;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
if (servctx->options & TEST_SERVER_DUMP)
|
|
Packit |
3adb1e |
fwrite(buf, len, 1, stdout);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (strncmp(buf,
|
|
Packit |
3adb1e |
message->text + servctx->message_buf_pos,
|
|
Packit |
3adb1e |
len) != 0) {
|
|
Packit |
3adb1e |
/* ## TODO: Better diagnostics. */
|
|
Packit |
3adb1e |
printf("Expected: (\n");
|
|
Packit |
3adb1e |
fwrite(message->text + servctx->message_buf_pos, len, 1,
|
|
Packit |
3adb1e |
stdout);
|
|
Packit |
3adb1e |
printf(")\n");
|
|
Packit |
3adb1e |
printf("Actual: (\n");
|
|
Packit |
3adb1e |
fwrite(buf, len, 1, stdout);
|
|
Packit |
3adb1e |
printf(")\n");
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return SERF_ERROR_ISSUE_IN_TESTSUITE;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
servctx->message_buf_pos += len;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (servctx->message_buf_pos >= msg_len) {
|
|
Packit |
3adb1e |
next_message(servctx);
|
|
Packit |
3adb1e |
servctx->message_buf_pos -= msg_len;
|
|
Packit |
3adb1e |
if (action->kind == SERVER_RESPOND)
|
|
Packit |
3adb1e |
servctx->outstanding_responses++;
|
|
Packit |
3adb1e |
if (action->kind == SERVER_RECV)
|
|
Packit |
3adb1e |
next_action(servctx);
|
|
Packit |
3adb1e |
break;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
} while (!status);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else if (action->kind == PROXY_FORWARD) {
|
|
Packit |
3adb1e |
apr_size_t len;
|
|
Packit |
3adb1e |
char buf[BUFSIZE];
|
|
Packit |
3adb1e |
serf_bucket_t *tmp;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Read all incoming data from the client to forward it to the
|
|
Packit |
3adb1e |
server later. */
|
|
Packit |
3adb1e |
do
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
len = BUFSIZE;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = servctx->read(servctx, buf, &len;;
|
|
Packit |
3adb1e |
if (SERF_BUCKET_READ_ERROR(status))
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"proxy: reading %d bytes %.*s from client with "
|
|
Packit |
3adb1e |
"status %d.\n",
|
|
Packit |
3adb1e |
len, len, buf, status);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (status == APR_EOF) {
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"Proxy: client hung up the connection. Reset the "
|
|
Packit |
3adb1e |
"connection to the server.\n");
|
|
Packit |
3adb1e |
/* We have to stop forwarding, if a new connection opens
|
|
Packit |
3adb1e |
the CONNECT request should not be forwarded to the
|
|
Packit |
3adb1e |
server. */
|
|
Packit |
3adb1e |
next_action(servctx);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
if (!servctx->servstream)
|
|
Packit |
3adb1e |
servctx->servstream = serf__bucket_stream_create(
|
|
Packit |
3adb1e |
servctx->allocator,
|
|
Packit |
3adb1e |
detect_eof,servctx);
|
|
Packit |
3adb1e |
if (len) {
|
|
Packit |
3adb1e |
tmp = serf_bucket_simple_copy_create(buf, len,
|
|
Packit |
3adb1e |
servctx->allocator);
|
|
Packit |
3adb1e |
serf_bucket_aggregate_append(servctx->servstream, tmp);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
} while (!status);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
if (rtnevents & APR_POLLOUT) {
|
|
Packit |
3adb1e |
action = &servctx->action_list[servctx->cur_action];
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"POLLOUT when replaying action %d, kind: %d.\n", servctx->cur_action,
|
|
Packit |
3adb1e |
action->kind);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (action->kind == SERVER_RESPOND && servctx->outstanding_responses) {
|
|
Packit |
3adb1e |
apr_size_t msg_len;
|
|
Packit |
3adb1e |
apr_size_t len;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
msg_len = strlen(action->text);
|
|
Packit |
3adb1e |
len = msg_len - servctx->action_buf_pos;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = servctx->send(servctx,
|
|
Packit |
3adb1e |
action->text + servctx->action_buf_pos,
|
|
Packit |
3adb1e |
&len;;
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (servctx->options & TEST_SERVER_DUMP)
|
|
Packit |
3adb1e |
fwrite(action->text + servctx->action_buf_pos, len, 1, stdout);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
servctx->action_buf_pos += len;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (servctx->action_buf_pos >= msg_len) {
|
|
Packit |
3adb1e |
next_action(servctx);
|
|
Packit |
3adb1e |
servctx->outstanding_responses--;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else if (action->kind == SERVER_KILL_CONNECTION ||
|
|
Packit |
3adb1e |
action->kind == SERVER_IGNORE_AND_KILL_CONNECTION) {
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"Killing this connection.\n");
|
|
Packit |
3adb1e |
apr_socket_close(servctx->client_sock);
|
|
Packit |
3adb1e |
servctx->client_sock = NULL;
|
|
Packit |
3adb1e |
next_action(servctx);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else if (action->kind == PROXY_FORWARD) {
|
|
Packit |
3adb1e |
apr_size_t len;
|
|
Packit |
3adb1e |
char *buf;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (!servctx->proxy_client_sock) {
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__, "Proxy: setting up connection "
|
|
Packit |
3adb1e |
"to server.\n");
|
|
Packit |
3adb1e |
status = create_client_socket(&servctx->proxy_client_sock,
|
|
Packit |
3adb1e |
servctx, action->text);
|
|
Packit |
3adb1e |
if (!servctx->clientstream)
|
|
Packit |
3adb1e |
servctx->clientstream = serf__bucket_stream_create(
|
|
Packit |
3adb1e |
servctx->allocator,
|
|
Packit |
3adb1e |
detect_eof,servctx);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Send all data received from the server to the client. */
|
|
Packit |
3adb1e |
do
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
apr_size_t readlen;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
readlen = BUFSIZE;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = serf_bucket_read(servctx->clientstream, readlen,
|
|
Packit |
3adb1e |
&buf, &readlen);
|
|
Packit |
3adb1e |
if (SERF_BUCKET_READ_ERROR(status))
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
if (!readlen)
|
|
Packit |
3adb1e |
break;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
len = readlen;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"proxy: sending %d bytes to client.\n", len);
|
|
Packit |
3adb1e |
status = servctx->send(servctx, buf, &len;;
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS) {
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (len != readlen) /* abort for now, return buf to aggregate
|
|
Packit |
3adb1e |
if not everything could be sent. */
|
|
Packit |
3adb1e |
return APR_EGENERAL;
|
|
Packit |
3adb1e |
} while (!status);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else if (rtnevents & APR_POLLIN) {
|
|
Packit |
3adb1e |
/* ignore */
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else {
|
|
Packit |
3adb1e |
printf("Unknown rtnevents: %d\n", rtnevents);
|
|
Packit |
3adb1e |
abort();
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Exchange data between proxy and server */
|
|
Packit |
3adb1e |
static apr_status_t proxy_replay(serv_ctx_t *servctx,
|
|
Packit |
3adb1e |
apr_int16_t rtnevents,
|
|
Packit |
3adb1e |
apr_pool_t *pool)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
apr_status_t status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (rtnevents & APR_POLLIN) {
|
|
Packit |
3adb1e |
apr_size_t len;
|
|
Packit |
3adb1e |
char buf[BUFSIZE];
|
|
Packit |
3adb1e |
serf_bucket_t *tmp;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__, "proxy_replay: POLLIN\n");
|
|
Packit |
3adb1e |
/* Read all incoming data from the server to forward it to the
|
|
Packit |
3adb1e |
client later. */
|
|
Packit |
3adb1e |
do
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
len = BUFSIZE;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = apr_socket_recv(servctx->proxy_client_sock, buf, &len;;
|
|
Packit |
3adb1e |
if (SERF_BUCKET_READ_ERROR(status))
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"proxy: reading %d bytes %.*s from server.\n",
|
|
Packit |
3adb1e |
len, len, buf);
|
|
Packit |
3adb1e |
tmp = serf_bucket_simple_copy_create(buf, len,
|
|
Packit |
3adb1e |
servctx->allocator);
|
|
Packit |
3adb1e |
serf_bucket_aggregate_append(servctx->clientstream, tmp);
|
|
Packit |
3adb1e |
} while (!status);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (rtnevents & APR_POLLOUT) {
|
|
Packit |
3adb1e |
apr_size_t len;
|
|
Packit |
3adb1e |
char *buf;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__, "proxy_replay: POLLOUT\n");
|
|
Packit |
3adb1e |
/* Send all data received from the client to the server. */
|
|
Packit |
3adb1e |
do
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
apr_size_t readlen;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
readlen = BUFSIZE;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (!servctx->servstream)
|
|
Packit |
3adb1e |
servctx->servstream = serf__bucket_stream_create(
|
|
Packit |
3adb1e |
servctx->allocator,
|
|
Packit |
3adb1e |
detect_eof,servctx);
|
|
Packit |
3adb1e |
status = serf_bucket_read(servctx->servstream, BUFSIZE,
|
|
Packit |
3adb1e |
&buf, &readlen);
|
|
Packit |
3adb1e |
if (SERF_BUCKET_READ_ERROR(status))
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
if (!readlen)
|
|
Packit |
3adb1e |
break;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
len = readlen;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"proxy: sending %d bytes %.*s to server.\n",
|
|
Packit |
3adb1e |
len, len, buf);
|
|
Packit |
3adb1e |
status = apr_socket_send(servctx->proxy_client_sock, buf, &len;;
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS) {
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (len != readlen) /* abort for now */
|
|
Packit |
3adb1e |
return APR_EGENERAL;
|
|
Packit |
3adb1e |
} while (!status);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else if (rtnevents & APR_POLLIN) {
|
|
Packit |
3adb1e |
/* ignore */
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else {
|
|
Packit |
3adb1e |
printf("Unknown rtnevents: %d\n", rtnevents);
|
|
Packit |
3adb1e |
abort();
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_status_t run_test_server(serv_ctx_t *servctx,
|
|
Packit |
3adb1e |
apr_short_interval_time_t duration,
|
|
Packit |
3adb1e |
apr_pool_t *pool)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
apr_status_t status;
|
|
Packit |
3adb1e |
apr_pollset_t *pollset;
|
|
Packit |
3adb1e |
apr_int32_t num;
|
|
Packit |
3adb1e |
const apr_pollfd_t *desc;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* create a new pollset */
|
|
Packit |
3adb1e |
#ifdef BROKEN_WSAPOLL
|
|
Packit |
3adb1e |
status = apr_pollset_create_ex(&pollset, 32, pool, 0,
|
|
Packit |
3adb1e |
APR_POLLSET_SELECT);
|
|
Packit |
3adb1e |
#else
|
|
Packit |
3adb1e |
status = apr_pollset_create(&pollset, 32, pool, 0);
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Don't accept new connection while processing client connection. At
|
|
Packit |
3adb1e |
least for present time.*/
|
|
Packit |
3adb1e |
if (servctx->client_sock) {
|
|
Packit |
3adb1e |
apr_pollfd_t pfd = { 0 };
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
pfd.desc_type = APR_POLL_SOCKET;
|
|
Packit |
3adb1e |
pfd.desc.s = servctx->client_sock;
|
|
Packit |
3adb1e |
pfd.reqevents = APR_POLLIN | APR_POLLOUT;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = apr_pollset_add(pollset, &pfd;;
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
goto cleanup;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (servctx->proxy_client_sock) {
|
|
Packit |
3adb1e |
apr_pollfd_t pfd = { 0 };
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
pfd.desc_type = APR_POLL_SOCKET;
|
|
Packit |
3adb1e |
pfd.desc.s = servctx->proxy_client_sock;
|
|
Packit |
3adb1e |
pfd.reqevents = APR_POLLIN | APR_POLLOUT;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = apr_pollset_add(pollset, &pfd;;
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
goto cleanup;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else {
|
|
Packit |
3adb1e |
apr_pollfd_t pfd = { 0 };
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
pfd.desc_type = APR_POLL_SOCKET;
|
|
Packit |
3adb1e |
pfd.desc.s = servctx->serv_sock;
|
|
Packit |
3adb1e |
pfd.reqevents = APR_POLLIN;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = apr_pollset_add(pollset, &pfd;;
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
goto cleanup;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = apr_pollset_poll(pollset, APR_USEC_PER_SEC >> 1, &num, &desc);
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
goto cleanup;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
while (num--) {
|
|
Packit |
3adb1e |
if (desc->desc.s == servctx->serv_sock) {
|
|
Packit |
3adb1e |
status = apr_socket_accept(&servctx->client_sock, servctx->serv_sock,
|
|
Packit |
3adb1e |
servctx->pool);
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
goto cleanup;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log_skt(TEST_VERBOSE, __FILE__, servctx->client_sock,
|
|
Packit |
3adb1e |
"server/proxy accepted incoming connection.\n");
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_socket_opt_set(servctx->client_sock, APR_SO_NONBLOCK, 1);
|
|
Packit |
3adb1e |
apr_socket_timeout_set(servctx->client_sock, 0);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = APR_SUCCESS;
|
|
Packit |
3adb1e |
goto cleanup;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (desc->desc.s == servctx->client_sock) {
|
|
Packit |
3adb1e |
if (servctx->handshake) {
|
|
Packit |
3adb1e |
status = servctx->handshake(servctx);
|
|
Packit |
3adb1e |
if (status)
|
|
Packit |
3adb1e |
goto cleanup;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Replay data to socket. */
|
|
Packit |
3adb1e |
status = replay(servctx, desc->rtnevents, pool);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (APR_STATUS_IS_EOF(status)) {
|
|
Packit |
3adb1e |
apr_socket_close(servctx->client_sock);
|
|
Packit |
3adb1e |
servctx->client_sock = NULL;
|
|
Packit |
3adb1e |
if (servctx->reset)
|
|
Packit |
3adb1e |
servctx->reset(servctx);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* If this is a proxy and the client closed the connection, also
|
|
Packit |
3adb1e |
close the connection to the server. */
|
|
Packit |
3adb1e |
if (servctx->proxy_client_sock) {
|
|
Packit |
3adb1e |
apr_socket_close(servctx->proxy_client_sock);
|
|
Packit |
3adb1e |
servctx->proxy_client_sock = NULL;
|
|
Packit |
3adb1e |
goto cleanup;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else if (APR_STATUS_IS_EAGAIN(status)) {
|
|
Packit |
3adb1e |
status = APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else if (status != APR_SUCCESS) {
|
|
Packit |
3adb1e |
/* Real error. */
|
|
Packit |
3adb1e |
goto cleanup;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
if (desc->desc.s == servctx->proxy_client_sock) {
|
|
Packit |
3adb1e |
/* Replay data to proxy socket. */
|
|
Packit |
3adb1e |
status = proxy_replay(servctx, desc->rtnevents, pool);
|
|
Packit |
3adb1e |
if (APR_STATUS_IS_EOF(status)) {
|
|
Packit |
3adb1e |
apr_socket_close(servctx->proxy_client_sock);
|
|
Packit |
3adb1e |
servctx->proxy_client_sock = NULL;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else if (APR_STATUS_IS_EAGAIN(status)) {
|
|
Packit |
3adb1e |
status = APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else if (status != APR_SUCCESS) {
|
|
Packit |
3adb1e |
/* Real error. */
|
|
Packit |
3adb1e |
goto cleanup;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
desc++;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
cleanup:
|
|
Packit |
3adb1e |
apr_pollset_destroy(pollset);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Setup the context needed to start a TCP server on adress.
|
|
Packit |
3adb1e |
message_list is a list of expected requests.
|
|
Packit |
3adb1e |
action_list is the list of responses to be returned in order.
|
|
Packit |
3adb1e |
*/
|
|
Packit |
3adb1e |
void setup_test_server(serv_ctx_t **servctx_p,
|
|
Packit |
3adb1e |
apr_sockaddr_t *address,
|
|
Packit |
3adb1e |
test_server_message_t *message_list,
|
|
Packit |
3adb1e |
apr_size_t message_count,
|
|
Packit |
3adb1e |
test_server_action_t *action_list,
|
|
Packit |
3adb1e |
apr_size_t action_count,
|
|
Packit |
3adb1e |
apr_int32_t options,
|
|
Packit |
3adb1e |
apr_pool_t *pool)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
serv_ctx_t *servctx;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
servctx = apr_pcalloc(pool, sizeof(*servctx));
|
|
Packit |
3adb1e |
apr_pool_cleanup_register(pool, servctx,
|
|
Packit |
3adb1e |
cleanup_server,
|
|
Packit |
3adb1e |
apr_pool_cleanup_null);
|
|
Packit |
3adb1e |
*servctx_p = servctx;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
servctx->serv_addr = address;
|
|
Packit |
3adb1e |
servctx->options = options;
|
|
Packit |
3adb1e |
servctx->pool = pool;
|
|
Packit |
3adb1e |
servctx->allocator = serf_bucket_allocator_create(pool, NULL, NULL);
|
|
Packit |
3adb1e |
servctx->message_list = message_list;
|
|
Packit |
3adb1e |
servctx->message_count = message_count;
|
|
Packit |
3adb1e |
servctx->action_list = action_list;
|
|
Packit |
3adb1e |
servctx->action_count = action_count;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Start replay from first action. */
|
|
Packit |
3adb1e |
servctx->cur_action = 0;
|
|
Packit |
3adb1e |
servctx->action_buf_pos = 0;
|
|
Packit |
3adb1e |
servctx->outstanding_responses = 0;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
servctx->read = socket_read;
|
|
Packit |
3adb1e |
servctx->send = socket_write;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
*servctx_p = servctx;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_status_t start_test_server(serv_ctx_t *servctx)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
apr_status_t status;
|
|
Packit |
3adb1e |
apr_socket_t *serv_sock;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* create server socket */
|
|
Packit |
3adb1e |
#if APR_VERSION_AT_LEAST(1, 0, 0)
|
|
Packit |
3adb1e |
status = apr_socket_create(&serv_sock, servctx->serv_addr->family,
|
|
Packit |
3adb1e |
SOCK_STREAM, 0,
|
|
Packit |
3adb1e |
servctx->pool);
|
|
Packit |
3adb1e |
#else
|
|
Packit |
3adb1e |
status = apr_socket_create(&serv_sock, servctx->serv_addr->family,
|
|
Packit |
3adb1e |
SOCK_STREAM,
|
|
Packit |
3adb1e |
servctx->pool);
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_socket_opt_set(serv_sock, APR_SO_NONBLOCK, 1);
|
|
Packit |
3adb1e |
apr_socket_timeout_set(serv_sock, 0);
|
|
Packit |
3adb1e |
apr_socket_opt_set(serv_sock, APR_SO_REUSEADDR, 1);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = apr_socket_bind(serv_sock, servctx->serv_addr);
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* listen for clients */
|
|
Packit |
3adb1e |
status = apr_socket_listen(serv_sock, SOMAXCONN);
|
|
Packit |
3adb1e |
if (status != APR_SUCCESS)
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
servctx->serv_sock = serv_sock;
|
|
Packit |
3adb1e |
servctx->client_sock = NULL;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|