lwiperf: implemented "dual" client mode

This commit is contained in:
Simon Goldschmidt 2018-06-17 21:04:57 +02:00
parent a057caee45
commit 58b5a5fc5a

View File

@ -119,6 +119,8 @@ typedef struct _lwiperf_state_tcp {
u32_t bytes_transferred;
lwiperf_settings_t settings;
u8_t have_settings_buf;
u8_t specific_remote;
ip_addr_t remote_addr;
} lwiperf_state_tcp_t;
/** List of active iperf sessions */
@ -169,6 +171,10 @@ static const u8_t lwiperf_txbuf_const[1600] = {
static err_t lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb);
static void lwiperf_tcp_err(void *arg, err_t err);
static err_t lwiperf_start_tcp_server_impl(const ip_addr_t *local_addr, u16_t local_port,
lwiperf_report_fn report_fn, void *report_arg,
lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **state);
/** Add an iperf session to the 'active' list */
static void
@ -200,6 +206,18 @@ lwiperf_list_remove(lwiperf_state_base_t *item)
}
}
static lwiperf_state_base_t *
lwiperf_list_find(lwiperf_state_base_t *item)
{
lwiperf_state_base_t *iter;
for (iter = lwiperf_all_connections; iter != NULL; iter = iter->next) {
if (iter == item) {
return item;
}
}
return NULL;
}
/** Call the report function of an iperf tcp session */
static void
lwip_tcp_conn_report(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_type)
@ -226,8 +244,8 @@ lwiperf_tcp_close(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_typ
{
err_t err;
lwip_tcp_conn_report(conn, report_type);
lwiperf_list_remove(&conn->base);
lwip_tcp_conn_report(conn, report_type);
if (conn->conn_pcb != NULL) {
tcp_arg(conn->conn_pcb, NULL);
tcp_poll(conn->conn_pcb, NULL, 0);
@ -240,9 +258,9 @@ lwiperf_tcp_close(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_typ
tcp_abort(conn->conn_pcb);
}
} else {
/* no conn pcb, this is the server pcb */
/* no conn pcb, this is the listener pcb */
err = tcp_close(conn->server_pcb);
LWIP_ASSERT("error", err != ERR_OK);
LWIP_ASSERT("error", err == ERR_OK);
}
LWIPERF_FREE(lwiperf_state_tcp_t, conn);
}
@ -382,17 +400,13 @@ lwiperf_tx_start_impl(const ip_addr_t *remote_ip, u16_t remote_port, lwiperf_set
LWIPERF_FREE(lwiperf_state_tcp_t, client_conn);
return ERR_MEM;
}
memset(client_conn, 0, sizeof(lwiperf_state_tcp_t));
client_conn->base.tcp = 1;
client_conn->base.server = 0;
client_conn->base.next = NULL;
client_conn->base.related_master_state = related_master_state;
client_conn->server_pcb = NULL;
client_conn->conn_pcb = newpcb;
client_conn->time_started = sys_now(); /* @todo: set this again on 'connected' */
client_conn->report_fn = report_fn;
client_conn->report_arg = report_arg;
client_conn->poll_count = 0;
client_conn->next_num = 4; /* initial nr is '4' since the header has 24 byte */
client_conn->bytes_transferred = 0;
memcpy(&client_conn->settings, settings, sizeof(*settings));
@ -576,6 +590,19 @@ lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
}
s = (lwiperf_state_tcp_t *)arg;
LWIP_ASSERT("invalid session", s->base.server);
LWIP_ASSERT("invalid listen pcb", s->server_pcb != NULL);
LWIP_ASSERT("invalid conn pcb", s->conn_pcb == NULL);
if (s->specific_remote) {
LWIP_ASSERT("s->base.related_master_state != NULL", s->base.related_master_state != NULL);
if (!ip_addr_cmp(&newpcb->remote_ip, &s->remote_addr)) {
/* this listener belongs to a client session, and this is not the correct remote */
return ERR_VAL;
}
} else {
LWIP_ASSERT("s->base.related_master_state == NULL", s->base.related_master_state == NULL);
}
conn = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
if (conn == NULL) {
return ERR_MEM;
@ -584,7 +611,6 @@ lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
conn->base.tcp = 1;
conn->base.server = 1;
conn->base.related_master_state = &s->base;
conn->server_pcb = s->server_pcb;
conn->conn_pcb = newpcb;
conn->time_started = sys_now();
conn->report_fn = s->report_fn;
@ -596,6 +622,12 @@ lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
tcp_err(conn->conn_pcb, lwiperf_tcp_err);
if (s->specific_remote) {
/* this listener belongs to a client, so close it and make the client the master */
conn->base.related_master_state = s->base.related_master_state;
s->report_fn = NULL;
lwiperf_tcp_close(s, LWIPERF_TCP_ABORTED_LOCAL);
}
lwiperf_list_add(&conn->base);
return ERR_OK;
}
@ -626,6 +658,21 @@ lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void *report_arg)
void *
lwiperf_start_tcp_server(const ip_addr_t *local_addr, u16_t local_port,
lwiperf_report_fn report_fn, void *report_arg)
{
err_t err;
lwiperf_state_tcp_t *state = NULL;
err = lwiperf_start_tcp_server_impl(local_addr, local_port, report_fn, report_arg,
NULL, &state);
if (err == ERR_OK) {
return state;
}
return NULL;
}
static err_t lwiperf_start_tcp_server_impl(const ip_addr_t *local_addr, u16_t local_port,
lwiperf_report_fn report_fn, void *report_arg,
lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **state)
{
err_t err;
struct tcp_pcb *pcb;
@ -633,33 +680,38 @@ lwiperf_start_tcp_server(const ip_addr_t *local_addr, u16_t local_port,
LWIP_ASSERT_CORE_LOCKED();
LWIP_ASSERT("state != NULL", state != NULL);
if (local_addr == NULL) {
return NULL;
return ERR_ARG;
}
s = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
if (s == NULL) {
return NULL;
return ERR_MEM;
}
memset(s, 0, sizeof(lwiperf_state_tcp_t));
s->base.tcp = 1;
s->base.server = 1;
s->base.related_master_state = related_master_state;
s->report_fn = report_fn;
s->report_arg = report_arg;
pcb = tcp_new_ip_type(LWIPERF_SERVER_IP_TYPE);
if (pcb != NULL) {
err = tcp_bind(pcb, local_addr, local_port);
if (err == ERR_OK) {
s->server_pcb = tcp_listen_with_backlog(pcb, 1);
}
if (pcb == NULL) {
return ERR_MEM;
}
err = tcp_bind(pcb, local_addr, local_port);
if (err != ERR_OK) {
return err;
}
s->server_pcb = tcp_listen_with_backlog(pcb, 1);
if (s->server_pcb == NULL) {
if (pcb != NULL) {
tcp_close(pcb);
}
LWIPERF_FREE(lwiperf_state_tcp_t, s);
return NULL;
return ERR_MEM;
}
pcb = NULL;
@ -667,7 +719,8 @@ lwiperf_start_tcp_server(const ip_addr_t *local_addr, u16_t local_port,
tcp_accept(s->server_pcb, lwiperf_tcp_accept);
lwiperf_list_add(&s->base);
return s;
*state = s;
return ERR_OK;
}
/**
@ -698,19 +751,49 @@ void* lwiperf_start_tcp_client(const ip_addr_t* remote_addr, u16_t remote_port,
lwiperf_settings_t settings;
lwiperf_state_tcp_t *state = NULL;
LWIP_UNUSED_ARG(type); /* TODO: implement dual/tradeoff */
memset(&settings, 0, sizeof(settings));
settings.flags = htonl(LWIPERF_FLAGS_ANSWER_TEST);
switch (type) {
case LWIPERF_CLIENT:
/* Unidirectional tx only test */
settings.flags = 0;
break;
case LWIPERF_DUAL:
/* Do a bidirectional test simultaneously */
settings.flags = htonl(LWIPERF_FLAGS_ANSWER_TEST | LWIPERF_FLAGS_ANSWER_NOW);
break;
case LWIPERF_TRADEOFF:
/* Do a bidirectional test individually */
return NULL;
/* TODO: implement this!
settings.flags = htonl(LWIPERF_FLAGS_ANSWER_TEST);
break;*/
default:
/* invalid argument */
return NULL;
}
settings.num_threads = htonl(1);
settings.remote_port = htonl(remote_port);
settings.remote_port = htonl(LWIPERF_TCP_PORT_DEFAULT);
/* TODO: implement passing duration/amount of bytes to transfer */
settings.amount = htonl((u32_t)-1000);
ret = lwiperf_tx_start_impl(remote_addr, remote_port, &settings, report_fn, report_arg, NULL, &state);
if (ret == ERR_OK) {
if (state != NULL) {
return state;
LWIP_ASSERT("state != NULL", state != NULL);
if (type == LWIPERF_DUAL) {
/* start corresponding server now */
lwiperf_state_tcp_t *server = NULL;
ret = lwiperf_start_tcp_server_impl(&state->conn_pcb->local_ip, LWIPERF_TCP_PORT_DEFAULT,
report_fn, report_arg, (lwiperf_state_base_t *)state, &server);
if (ret != ERR_OK) {
/* starting server failed, abort client */
lwiperf_abort(state);
return NULL;
}
/* make this server accept one connection only */
server->specific_remote = 1;
server->remote_addr = state->conn_pcb->remote_ip;
}
return state;
}
return NULL;
}