/** Close an iperf tcp session */ static void lwiperf_tcp_close(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type) { err_t err; lwip_tcp_conn_report(conn, report_type); lwiperf_list_remove(&conn->base); if (conn->conn_pcb != NULL) { tcp_arg(conn->conn_pcb, NULL); tcp_poll(conn->conn_pcb, NULL, 0); tcp_sent(conn->conn_pcb, NULL); tcp_recv(conn->conn_pcb, NULL); tcp_err(conn->conn_pcb, NULL); err = tcp_close(conn->conn_pcb); if (err != ERR_OK) { /* don't want to wait for free memory here... */ tcp_abort(conn->conn_pcb); } } else { /* no conn pcb, this is the server pcb */ err = tcp_close(conn->server_pcb); LWIP_ASSERT("error", err != ERR_OK); } LWIPERF_FREE(lwiperf_state_tcp_t, conn); }
/** Start TCP connection back to the client (either parallel or after the * receive test has finished. */ static err_t lwiperf_tx_start(lwiperf_state_tcp_t* conn) { err_t err; lwiperf_state_tcp_t* client_conn; struct tcp_pcb* newpcb; ip_addr_t remote_addr; u16_t remote_port; client_conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); if (client_conn == NULL) { return ERR_MEM; } newpcb = tcp_new(); if (newpcb == NULL) { LWIPERF_FREE(lwiperf_state_tcp_t, client_conn); return ERR_MEM; } memcpy(client_conn, conn, sizeof(lwiperf_state_tcp_t)); client_conn->base.server = 0; client_conn->server_pcb = NULL; client_conn->conn_pcb = newpcb; client_conn->time_started = sys_now(); /* TODO: set this again on 'connected' */ 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; client_conn->settings.flags = 0; /* prevent the remote side starting back as client again */ tcp_arg(newpcb, client_conn); tcp_sent(newpcb, lwiperf_tcp_client_sent); tcp_poll(newpcb, lwiperf_tcp_poll, 2U); tcp_err(newpcb, lwiperf_tcp_err); ip_addr_copy(remote_addr, conn->conn_pcb->remote_ip); remote_port = (u16_t)htonl(client_conn->settings.remote_port); err = tcp_connect(newpcb, &remote_addr, remote_port, lwiperf_tcp_client_connected); if (err != ERR_OK) { lwiperf_tcp_close(client_conn, LWIPERF_TCP_ABORTED_LOCAL); return err; } lwiperf_list_add(&client_conn->base); return ERR_OK; }
/** * @ingroup iperf * Start a TCP iperf server on a specific IP address and port and listen for * incoming connections from iperf clients. * * @returns a connection handle that can be used to abort the server * by calling @ref lwiperf_abort() */ 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; struct tcp_pcb* pcb; lwiperf_state_tcp_t* s; if (local_addr == NULL) { return NULL; } s = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); if (s == NULL) { return NULL; } memset(s, 0, sizeof(lwiperf_state_tcp_t)); s->base.tcp = 1; s->base.server = 1; s->report_fn = report_fn; s->report_arg = report_arg; pcb = tcp_new(); 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 (s->server_pcb == NULL) { if (pcb != NULL) { tcp_close(pcb); } LWIPERF_FREE(lwiperf_state_tcp_t, s); return NULL; } pcb = NULL; tcp_arg(s->server_pcb, s); tcp_accept(s->server_pcb, lwiperf_tcp_accept); lwiperf_list_add(&s->base); return s; }
/** Abort an iperf session (handle returned by lwiperf_start_tcp_server*()) */ void lwiperf_abort(void* lwiperf_session) { lwiperf_state_base_t* i, *dealloc, *last = NULL; for (i = lwiperf_all_connections; i != NULL; ) { if ((i == lwiperf_session) || (i->related_server_state == lwiperf_session)) { dealloc = i; i = i->next; if (last != NULL) { last->next = i; } LWIPERF_FREE(lwiperf_state_tcp_t, dealloc); /* TODO: type? */ } else { last = i; i = i->next; } } }