/** This is called when a new client connects for an iperf tcp session */ static err_t lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { lwiperf_state_tcp_t *s, *conn; if ((err != ERR_OK) || (newpcb == NULL) || (arg == NULL)) { return ERR_VAL; } s = (lwiperf_state_tcp_t*)arg; conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); if (conn == NULL) { return ERR_MEM; } memset(conn, 0, sizeof(lwiperf_state_tcp_t)); conn->base.tcp = 1; conn->base.server = 1; conn->base.related_server_state = &s->base; conn->server_pcb = s->server_pcb; conn->conn_pcb = newpcb; conn->time_started = sys_now(); conn->report_fn = s->report_fn; conn->report_arg = s->report_arg; /* setup the tcp rx connection */ tcp_arg(newpcb, conn); tcp_recv(newpcb, lwiperf_tcp_recv); tcp_poll(newpcb, lwiperf_tcp_poll, 2U); tcp_err(conn->conn_pcb, lwiperf_tcp_err); lwiperf_list_add(&conn->base); return ERR_OK; }
/** 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; }