xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.1.0/src/apps/lwiperf/lwiperf.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /**
2*10465441SEvalZero  * @file
3*10465441SEvalZero  * lwIP iPerf server implementation
4*10465441SEvalZero  */
5*10465441SEvalZero 
6*10465441SEvalZero /**
7*10465441SEvalZero  * @defgroup iperf Iperf server
8*10465441SEvalZero  * @ingroup apps
9*10465441SEvalZero  *
10*10465441SEvalZero  * This is a simple performance measuring client/server to check your bandwith using
11*10465441SEvalZero  * iPerf2 on a PC as server/client.
12*10465441SEvalZero  * It is currently a minimal implementation providing a TCP client/server only.
13*10465441SEvalZero  *
14*10465441SEvalZero  * @todo:
15*10465441SEvalZero  * - implement UDP mode
16*10465441SEvalZero  * - protect combined sessions handling (via 'related_master_state') against reallocation
17*10465441SEvalZero  *   (this is a pointer address, currently, so if the same memory is allocated again,
18*10465441SEvalZero  *    session pairs (tx/rx) can be confused on reallocation)
19*10465441SEvalZero  */
20*10465441SEvalZero 
21*10465441SEvalZero /*
22*10465441SEvalZero  * Copyright (c) 2014 Simon Goldschmidt
23*10465441SEvalZero  * All rights reserved.
24*10465441SEvalZero  *
25*10465441SEvalZero  * Redistribution and use in source and binary forms, with or without modification,
26*10465441SEvalZero  * are permitted provided that the following conditions are met:
27*10465441SEvalZero  *
28*10465441SEvalZero  * 1. Redistributions of source code must retain the above copyright notice,
29*10465441SEvalZero  *    this list of conditions and the following disclaimer.
30*10465441SEvalZero  * 2. Redistributions in binary form must reproduce the above copyright notice,
31*10465441SEvalZero  *    this list of conditions and the following disclaimer in the documentation
32*10465441SEvalZero  *    and/or other materials provided with the distribution.
33*10465441SEvalZero  * 3. The name of the author may not be used to endorse or promote products
34*10465441SEvalZero  *    derived from this software without specific prior written permission.
35*10465441SEvalZero  *
36*10465441SEvalZero  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
37*10465441SEvalZero  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
38*10465441SEvalZero  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
39*10465441SEvalZero  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
40*10465441SEvalZero  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
41*10465441SEvalZero  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42*10465441SEvalZero  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43*10465441SEvalZero  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
44*10465441SEvalZero  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
45*10465441SEvalZero  * OF SUCH DAMAGE.
46*10465441SEvalZero  *
47*10465441SEvalZero  * This file is part of the lwIP TCP/IP stack.
48*10465441SEvalZero  *
49*10465441SEvalZero  * Author: Simon Goldschmidt
50*10465441SEvalZero  */
51*10465441SEvalZero 
52*10465441SEvalZero #include "lwip/apps/lwiperf.h"
53*10465441SEvalZero 
54*10465441SEvalZero #include "lwip/tcp.h"
55*10465441SEvalZero #include "lwip/sys.h"
56*10465441SEvalZero 
57*10465441SEvalZero #include <string.h>
58*10465441SEvalZero 
59*10465441SEvalZero /* Currently, only TCP is implemented */
60*10465441SEvalZero #if LWIP_TCP && LWIP_CALLBACK_API
61*10465441SEvalZero 
62*10465441SEvalZero /** Specify the idle timeout (in seconds) after that the test fails */
63*10465441SEvalZero #ifndef LWIPERF_TCP_MAX_IDLE_SEC
64*10465441SEvalZero #define LWIPERF_TCP_MAX_IDLE_SEC    10U
65*10465441SEvalZero #endif
66*10465441SEvalZero #if LWIPERF_TCP_MAX_IDLE_SEC > 255
67*10465441SEvalZero #error LWIPERF_TCP_MAX_IDLE_SEC must fit into an u8_t
68*10465441SEvalZero #endif
69*10465441SEvalZero 
70*10465441SEvalZero /** Change this if you don't want to lwiperf to listen to any IP version */
71*10465441SEvalZero #ifndef LWIPERF_SERVER_IP_TYPE
72*10465441SEvalZero #define LWIPERF_SERVER_IP_TYPE      IPADDR_TYPE_ANY
73*10465441SEvalZero #endif
74*10465441SEvalZero 
75*10465441SEvalZero /* File internal memory allocation (struct lwiperf_*): this defaults to
76*10465441SEvalZero    the heap */
77*10465441SEvalZero #ifndef LWIPERF_ALLOC
78*10465441SEvalZero #define LWIPERF_ALLOC(type)         mem_malloc(sizeof(type))
79*10465441SEvalZero #define LWIPERF_FREE(type, item)    mem_free(item)
80*10465441SEvalZero #endif
81*10465441SEvalZero 
82*10465441SEvalZero /** If this is 1, check that received data has the correct format */
83*10465441SEvalZero #ifndef LWIPERF_CHECK_RX_DATA
84*10465441SEvalZero #define LWIPERF_CHECK_RX_DATA       0
85*10465441SEvalZero #endif
86*10465441SEvalZero 
87*10465441SEvalZero /** This is the Iperf settings struct sent from the client */
88*10465441SEvalZero typedef struct _lwiperf_settings {
89*10465441SEvalZero #define LWIPERF_FLAGS_ANSWER_TEST 0x80000000
90*10465441SEvalZero #define LWIPERF_FLAGS_ANSWER_NOW  0x00000001
91*10465441SEvalZero   u32_t flags;
92*10465441SEvalZero   u32_t num_threads; /* unused for now */
93*10465441SEvalZero   u32_t remote_port;
94*10465441SEvalZero   u32_t buffer_len; /* unused for now */
95*10465441SEvalZero   u32_t win_band; /* TCP window / UDP rate: unused for now */
96*10465441SEvalZero   u32_t amount; /* pos. value: bytes?; neg. values: time (unit is 10ms: 1/100 second) */
97*10465441SEvalZero } lwiperf_settings_t;
98*10465441SEvalZero 
99*10465441SEvalZero /** Basic connection handle */
100*10465441SEvalZero struct _lwiperf_state_base;
101*10465441SEvalZero typedef struct _lwiperf_state_base lwiperf_state_base_t;
102*10465441SEvalZero struct _lwiperf_state_base {
103*10465441SEvalZero   /* linked list */
104*10465441SEvalZero   lwiperf_state_base_t *next;
105*10465441SEvalZero   /* 1=tcp, 0=udp */
106*10465441SEvalZero   u8_t tcp;
107*10465441SEvalZero   /* 1=server, 0=client */
108*10465441SEvalZero   u8_t server;
109*10465441SEvalZero   /* master state used to abort sessions (e.g. listener, main client) */
110*10465441SEvalZero   lwiperf_state_base_t *related_master_state;
111*10465441SEvalZero };
112*10465441SEvalZero 
113*10465441SEvalZero /** Connection handle for a TCP iperf session */
114*10465441SEvalZero typedef struct _lwiperf_state_tcp {
115*10465441SEvalZero   lwiperf_state_base_t base;
116*10465441SEvalZero   struct tcp_pcb *server_pcb;
117*10465441SEvalZero   struct tcp_pcb *conn_pcb;
118*10465441SEvalZero   u32_t time_started;
119*10465441SEvalZero   lwiperf_report_fn report_fn;
120*10465441SEvalZero   void *report_arg;
121*10465441SEvalZero   u8_t poll_count;
122*10465441SEvalZero   u8_t next_num;
123*10465441SEvalZero   /* 1=start server when client is closed */
124*10465441SEvalZero   u8_t client_tradeoff_mode;
125*10465441SEvalZero   u32_t bytes_transferred;
126*10465441SEvalZero   lwiperf_settings_t settings;
127*10465441SEvalZero   u8_t have_settings_buf;
128*10465441SEvalZero   u8_t specific_remote;
129*10465441SEvalZero   ip_addr_t remote_addr;
130*10465441SEvalZero } lwiperf_state_tcp_t;
131*10465441SEvalZero 
132*10465441SEvalZero /** List of active iperf sessions */
133*10465441SEvalZero static lwiperf_state_base_t *lwiperf_all_connections;
134*10465441SEvalZero /** A const buffer to send from: we want to measure sending, not copying! */
135*10465441SEvalZero static const u8_t lwiperf_txbuf_const[1600] = {
136*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
137*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
138*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
139*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
140*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
141*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
142*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
143*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
144*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
145*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
146*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
147*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
148*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
149*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
150*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
151*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
152*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
153*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
154*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
155*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
156*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
157*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
158*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
159*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
160*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
161*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
162*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
163*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
164*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
165*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
166*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
167*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
168*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
169*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
170*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
171*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
172*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
173*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
174*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
175*10465441SEvalZero   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
176*10465441SEvalZero };
177*10465441SEvalZero 
178*10465441SEvalZero static err_t lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb);
179*10465441SEvalZero static void lwiperf_tcp_err(void *arg, err_t err);
180*10465441SEvalZero static err_t lwiperf_start_tcp_server_impl(const ip_addr_t *local_addr, u16_t local_port,
181*10465441SEvalZero                                            lwiperf_report_fn report_fn, void *report_arg,
182*10465441SEvalZero                                            lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **state);
183*10465441SEvalZero 
184*10465441SEvalZero 
185*10465441SEvalZero /** Add an iperf session to the 'active' list */
186*10465441SEvalZero static void
lwiperf_list_add(lwiperf_state_base_t * item)187*10465441SEvalZero lwiperf_list_add(lwiperf_state_base_t *item)
188*10465441SEvalZero {
189*10465441SEvalZero   item->next = lwiperf_all_connections;
190*10465441SEvalZero   lwiperf_all_connections = item;
191*10465441SEvalZero }
192*10465441SEvalZero 
193*10465441SEvalZero /** Remove an iperf session from the 'active' list */
194*10465441SEvalZero static void
lwiperf_list_remove(lwiperf_state_base_t * item)195*10465441SEvalZero lwiperf_list_remove(lwiperf_state_base_t *item)
196*10465441SEvalZero {
197*10465441SEvalZero   lwiperf_state_base_t *prev = NULL;
198*10465441SEvalZero   lwiperf_state_base_t *iter;
199*10465441SEvalZero   for (iter = lwiperf_all_connections; iter != NULL; prev = iter, iter = iter->next) {
200*10465441SEvalZero     if (iter == item) {
201*10465441SEvalZero       if (prev == NULL) {
202*10465441SEvalZero         lwiperf_all_connections = iter->next;
203*10465441SEvalZero       } else {
204*10465441SEvalZero         prev->next = iter->next;
205*10465441SEvalZero       }
206*10465441SEvalZero       /* @debug: ensure this item is listed only once */
207*10465441SEvalZero       for (iter = iter->next; iter != NULL; iter = iter->next) {
208*10465441SEvalZero         LWIP_ASSERT("duplicate entry", iter != item);
209*10465441SEvalZero       }
210*10465441SEvalZero       break;
211*10465441SEvalZero     }
212*10465441SEvalZero   }
213*10465441SEvalZero }
214*10465441SEvalZero 
215*10465441SEvalZero static lwiperf_state_base_t *
lwiperf_list_find(lwiperf_state_base_t * item)216*10465441SEvalZero lwiperf_list_find(lwiperf_state_base_t *item)
217*10465441SEvalZero {
218*10465441SEvalZero   lwiperf_state_base_t *iter;
219*10465441SEvalZero   for (iter = lwiperf_all_connections; iter != NULL; iter = iter->next) {
220*10465441SEvalZero     if (iter == item) {
221*10465441SEvalZero       return item;
222*10465441SEvalZero     }
223*10465441SEvalZero   }
224*10465441SEvalZero   return NULL;
225*10465441SEvalZero }
226*10465441SEvalZero 
227*10465441SEvalZero /** Call the report function of an iperf tcp session */
228*10465441SEvalZero static void
lwip_tcp_conn_report(lwiperf_state_tcp_t * conn,enum lwiperf_report_type report_type)229*10465441SEvalZero lwip_tcp_conn_report(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_type)
230*10465441SEvalZero {
231*10465441SEvalZero   if ((conn != NULL) && (conn->report_fn != NULL)) {
232*10465441SEvalZero     u32_t now, duration_ms, bandwidth_kbitpsec;
233*10465441SEvalZero     now = sys_now();
234*10465441SEvalZero     duration_ms = now - conn->time_started;
235*10465441SEvalZero     if (duration_ms == 0) {
236*10465441SEvalZero       bandwidth_kbitpsec = 0;
237*10465441SEvalZero     } else {
238*10465441SEvalZero       bandwidth_kbitpsec = (conn->bytes_transferred / duration_ms) * 8U;
239*10465441SEvalZero     }
240*10465441SEvalZero     conn->report_fn(conn->report_arg, report_type,
241*10465441SEvalZero                     &conn->conn_pcb->local_ip, conn->conn_pcb->local_port,
242*10465441SEvalZero                     &conn->conn_pcb->remote_ip, conn->conn_pcb->remote_port,
243*10465441SEvalZero                     conn->bytes_transferred, duration_ms, bandwidth_kbitpsec);
244*10465441SEvalZero   }
245*10465441SEvalZero }
246*10465441SEvalZero 
247*10465441SEvalZero /** Close an iperf tcp session */
248*10465441SEvalZero static void
lwiperf_tcp_close(lwiperf_state_tcp_t * conn,enum lwiperf_report_type report_type)249*10465441SEvalZero lwiperf_tcp_close(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_type)
250*10465441SEvalZero {
251*10465441SEvalZero   err_t err;
252*10465441SEvalZero 
253*10465441SEvalZero   lwiperf_list_remove(&conn->base);
254*10465441SEvalZero   lwip_tcp_conn_report(conn, report_type);
255*10465441SEvalZero   if (conn->conn_pcb != NULL) {
256*10465441SEvalZero     tcp_arg(conn->conn_pcb, NULL);
257*10465441SEvalZero     tcp_poll(conn->conn_pcb, NULL, 0);
258*10465441SEvalZero     tcp_sent(conn->conn_pcb, NULL);
259*10465441SEvalZero     tcp_recv(conn->conn_pcb, NULL);
260*10465441SEvalZero     tcp_err(conn->conn_pcb, NULL);
261*10465441SEvalZero     err = tcp_close(conn->conn_pcb);
262*10465441SEvalZero     if (err != ERR_OK) {
263*10465441SEvalZero       /* don't want to wait for free memory here... */
264*10465441SEvalZero       tcp_abort(conn->conn_pcb);
265*10465441SEvalZero     }
266*10465441SEvalZero   } else {
267*10465441SEvalZero     /* no conn pcb, this is the listener pcb */
268*10465441SEvalZero     err = tcp_close(conn->server_pcb);
269*10465441SEvalZero     LWIP_ASSERT("error", err == ERR_OK);
270*10465441SEvalZero   }
271*10465441SEvalZero   LWIPERF_FREE(lwiperf_state_tcp_t, conn);
272*10465441SEvalZero }
273*10465441SEvalZero 
274*10465441SEvalZero /** Try to send more data on an iperf tcp session */
275*10465441SEvalZero static err_t
lwiperf_tcp_client_send_more(lwiperf_state_tcp_t * conn)276*10465441SEvalZero lwiperf_tcp_client_send_more(lwiperf_state_tcp_t *conn)
277*10465441SEvalZero {
278*10465441SEvalZero   int send_more;
279*10465441SEvalZero   err_t err;
280*10465441SEvalZero   u16_t txlen;
281*10465441SEvalZero   u16_t txlen_max;
282*10465441SEvalZero   void *txptr;
283*10465441SEvalZero   u8_t apiflags;
284*10465441SEvalZero 
285*10465441SEvalZero   LWIP_ASSERT("conn invalid", (conn != NULL) && conn->base.tcp && (conn->base.server == 0));
286*10465441SEvalZero 
287*10465441SEvalZero   do {
288*10465441SEvalZero     send_more = 0;
289*10465441SEvalZero     if (conn->settings.amount & PP_HTONL(0x80000000)) {
290*10465441SEvalZero       /* this session is time-limited */
291*10465441SEvalZero       u32_t now = sys_now();
292*10465441SEvalZero       u32_t diff_ms = now - conn->time_started;
293*10465441SEvalZero       u32_t time = (u32_t) - (s32_t)lwip_htonl(conn->settings.amount);
294*10465441SEvalZero       u32_t time_ms = time * 10;
295*10465441SEvalZero       if (diff_ms >= time_ms) {
296*10465441SEvalZero         /* time specified by the client is over -> close the connection */
297*10465441SEvalZero         lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT);
298*10465441SEvalZero         return ERR_OK;
299*10465441SEvalZero       }
300*10465441SEvalZero     } else {
301*10465441SEvalZero       /* this session is byte-limited */
302*10465441SEvalZero       u32_t amount_bytes = lwip_htonl(conn->settings.amount);
303*10465441SEvalZero       /* @todo: this can send up to 1*MSS more than requested... */
304*10465441SEvalZero       if (amount_bytes >= conn->bytes_transferred) {
305*10465441SEvalZero         /* all requested bytes transferred -> close the connection */
306*10465441SEvalZero         lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT);
307*10465441SEvalZero         return ERR_OK;
308*10465441SEvalZero       }
309*10465441SEvalZero     }
310*10465441SEvalZero 
311*10465441SEvalZero     if (conn->bytes_transferred < 24) {
312*10465441SEvalZero       /* transmit the settings a first time */
313*10465441SEvalZero       txptr = &((u8_t *)&conn->settings)[conn->bytes_transferred];
314*10465441SEvalZero       txlen_max = (u16_t)(24 - conn->bytes_transferred);
315*10465441SEvalZero       apiflags = TCP_WRITE_FLAG_COPY;
316*10465441SEvalZero     } else if (conn->bytes_transferred < 48) {
317*10465441SEvalZero       /* transmit the settings a second time */
318*10465441SEvalZero       txptr = &((u8_t *)&conn->settings)[conn->bytes_transferred - 24];
319*10465441SEvalZero       txlen_max = (u16_t)(48 - conn->bytes_transferred);
320*10465441SEvalZero       apiflags = TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE;
321*10465441SEvalZero       send_more = 1;
322*10465441SEvalZero     } else {
323*10465441SEvalZero       /* transmit data */
324*10465441SEvalZero       /* @todo: every x bytes, transmit the settings again */
325*10465441SEvalZero       txptr = LWIP_CONST_CAST(void *, &lwiperf_txbuf_const[conn->bytes_transferred % 10]);
326*10465441SEvalZero       txlen_max = TCP_MSS;
327*10465441SEvalZero       if (conn->bytes_transferred == 48) { /* @todo: fix this for intermediate settings, too */
328*10465441SEvalZero         txlen_max = TCP_MSS - 24;
329*10465441SEvalZero       }
330*10465441SEvalZero       apiflags = 0; /* no copying needed */
331*10465441SEvalZero       send_more = 1;
332*10465441SEvalZero     }
333*10465441SEvalZero     txlen = txlen_max;
334*10465441SEvalZero     do {
335*10465441SEvalZero       err = tcp_write(conn->conn_pcb, txptr, txlen, apiflags);
336*10465441SEvalZero       if (err ==  ERR_MEM) {
337*10465441SEvalZero         txlen /= 2;
338*10465441SEvalZero       }
339*10465441SEvalZero     } while ((err == ERR_MEM) && (txlen >= (TCP_MSS / 2)));
340*10465441SEvalZero 
341*10465441SEvalZero     if (err == ERR_OK) {
342*10465441SEvalZero       conn->bytes_transferred += txlen;
343*10465441SEvalZero     } else {
344*10465441SEvalZero       send_more = 0;
345*10465441SEvalZero     }
346*10465441SEvalZero   } while (send_more);
347*10465441SEvalZero 
348*10465441SEvalZero   tcp_output(conn->conn_pcb);
349*10465441SEvalZero   return ERR_OK;
350*10465441SEvalZero }
351*10465441SEvalZero 
352*10465441SEvalZero /** TCP sent callback, try to send more data */
353*10465441SEvalZero static err_t
lwiperf_tcp_client_sent(void * arg,struct tcp_pcb * tpcb,u16_t len)354*10465441SEvalZero lwiperf_tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
355*10465441SEvalZero {
356*10465441SEvalZero   lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
357*10465441SEvalZero   /* @todo: check 'len' (e.g. to time ACK of all data)? for now, we just send more... */
358*10465441SEvalZero   LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
359*10465441SEvalZero   LWIP_UNUSED_ARG(tpcb);
360*10465441SEvalZero   LWIP_UNUSED_ARG(len);
361*10465441SEvalZero 
362*10465441SEvalZero   conn->poll_count = 0;
363*10465441SEvalZero 
364*10465441SEvalZero   return lwiperf_tcp_client_send_more(conn);
365*10465441SEvalZero }
366*10465441SEvalZero 
367*10465441SEvalZero /** TCP connected callback (active connection), send data now */
368*10465441SEvalZero static err_t
lwiperf_tcp_client_connected(void * arg,struct tcp_pcb * tpcb,err_t err)369*10465441SEvalZero lwiperf_tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
370*10465441SEvalZero {
371*10465441SEvalZero   lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
372*10465441SEvalZero   LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
373*10465441SEvalZero   LWIP_UNUSED_ARG(tpcb);
374*10465441SEvalZero   if (err != ERR_OK) {
375*10465441SEvalZero     lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
376*10465441SEvalZero     return ERR_OK;
377*10465441SEvalZero   }
378*10465441SEvalZero   conn->poll_count = 0;
379*10465441SEvalZero   conn->time_started = sys_now();
380*10465441SEvalZero   return lwiperf_tcp_client_send_more(conn);
381*10465441SEvalZero }
382*10465441SEvalZero 
383*10465441SEvalZero /** Start TCP connection back to the client (either parallel or after the
384*10465441SEvalZero  * receive test has finished.
385*10465441SEvalZero  */
386*10465441SEvalZero static err_t
lwiperf_tx_start_impl(const ip_addr_t * remote_ip,u16_t remote_port,lwiperf_settings_t * settings,lwiperf_report_fn report_fn,void * report_arg,lwiperf_state_base_t * related_master_state,lwiperf_state_tcp_t ** new_conn)387*10465441SEvalZero lwiperf_tx_start_impl(const ip_addr_t *remote_ip, u16_t remote_port, lwiperf_settings_t *settings, lwiperf_report_fn report_fn,
388*10465441SEvalZero                       void *report_arg, lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **new_conn)
389*10465441SEvalZero {
390*10465441SEvalZero   err_t err;
391*10465441SEvalZero   lwiperf_state_tcp_t *client_conn;
392*10465441SEvalZero   struct tcp_pcb *newpcb;
393*10465441SEvalZero   ip_addr_t remote_addr;
394*10465441SEvalZero 
395*10465441SEvalZero   LWIP_ASSERT("remote_ip != NULL", remote_ip != NULL);
396*10465441SEvalZero   LWIP_ASSERT("remote_ip != NULL", settings != NULL);
397*10465441SEvalZero   LWIP_ASSERT("new_conn != NULL", new_conn != NULL);
398*10465441SEvalZero   *new_conn = NULL;
399*10465441SEvalZero 
400*10465441SEvalZero   client_conn = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
401*10465441SEvalZero   if (client_conn == NULL) {
402*10465441SEvalZero     return ERR_MEM;
403*10465441SEvalZero   }
404*10465441SEvalZero   newpcb = tcp_new_ip_type(IP_GET_TYPE(remote_ip));
405*10465441SEvalZero   if (newpcb == NULL) {
406*10465441SEvalZero     LWIPERF_FREE(lwiperf_state_tcp_t, client_conn);
407*10465441SEvalZero     return ERR_MEM;
408*10465441SEvalZero   }
409*10465441SEvalZero   memset(client_conn, 0, sizeof(lwiperf_state_tcp_t));
410*10465441SEvalZero   client_conn->base.tcp = 1;
411*10465441SEvalZero   client_conn->base.related_master_state = related_master_state;
412*10465441SEvalZero   client_conn->conn_pcb = newpcb;
413*10465441SEvalZero   client_conn->time_started = sys_now(); /* @todo: set this again on 'connected' */
414*10465441SEvalZero   client_conn->report_fn = report_fn;
415*10465441SEvalZero   client_conn->report_arg = report_arg;
416*10465441SEvalZero   client_conn->next_num = 4; /* initial nr is '4' since the header has 24 byte */
417*10465441SEvalZero   client_conn->bytes_transferred = 0;
418*10465441SEvalZero   memcpy(&client_conn->settings, settings, sizeof(*settings));
419*10465441SEvalZero   client_conn->have_settings_buf = 1;
420*10465441SEvalZero 
421*10465441SEvalZero   tcp_arg(newpcb, client_conn);
422*10465441SEvalZero   tcp_sent(newpcb, lwiperf_tcp_client_sent);
423*10465441SEvalZero   tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
424*10465441SEvalZero   tcp_err(newpcb, lwiperf_tcp_err);
425*10465441SEvalZero 
426*10465441SEvalZero   ip_addr_copy(remote_addr, *remote_ip);
427*10465441SEvalZero 
428*10465441SEvalZero   err = tcp_connect(newpcb, &remote_addr, remote_port, lwiperf_tcp_client_connected);
429*10465441SEvalZero   if (err != ERR_OK) {
430*10465441SEvalZero     lwiperf_tcp_close(client_conn, LWIPERF_TCP_ABORTED_LOCAL);
431*10465441SEvalZero     return err;
432*10465441SEvalZero   }
433*10465441SEvalZero   lwiperf_list_add(&client_conn->base);
434*10465441SEvalZero   *new_conn = client_conn;
435*10465441SEvalZero   return ERR_OK;
436*10465441SEvalZero }
437*10465441SEvalZero 
438*10465441SEvalZero static err_t
lwiperf_tx_start_passive(lwiperf_state_tcp_t * conn)439*10465441SEvalZero lwiperf_tx_start_passive(lwiperf_state_tcp_t *conn)
440*10465441SEvalZero {
441*10465441SEvalZero   err_t ret;
442*10465441SEvalZero   lwiperf_state_tcp_t *new_conn = NULL;
443*10465441SEvalZero   u16_t remote_port = (u16_t)lwip_htonl(conn->settings.remote_port);
444*10465441SEvalZero 
445*10465441SEvalZero   ret = lwiperf_tx_start_impl(&conn->conn_pcb->remote_ip, remote_port, &conn->settings, conn->report_fn, conn->report_arg,
446*10465441SEvalZero     conn->base.related_master_state, &new_conn);
447*10465441SEvalZero   if (ret == ERR_OK) {
448*10465441SEvalZero     LWIP_ASSERT("new_conn != NULL", new_conn != NULL);
449*10465441SEvalZero     new_conn->settings.flags = 0; /* prevent the remote side starting back as client again */
450*10465441SEvalZero   }
451*10465441SEvalZero   return ret;
452*10465441SEvalZero }
453*10465441SEvalZero 
454*10465441SEvalZero /** Receive data on an iperf tcp session */
455*10465441SEvalZero static err_t
lwiperf_tcp_recv(void * arg,struct tcp_pcb * tpcb,struct pbuf * p,err_t err)456*10465441SEvalZero lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
457*10465441SEvalZero {
458*10465441SEvalZero   u8_t tmp;
459*10465441SEvalZero   u16_t tot_len;
460*10465441SEvalZero   u32_t packet_idx;
461*10465441SEvalZero   struct pbuf *q;
462*10465441SEvalZero   lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
463*10465441SEvalZero 
464*10465441SEvalZero   LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb);
465*10465441SEvalZero   LWIP_UNUSED_ARG(tpcb);
466*10465441SEvalZero 
467*10465441SEvalZero   if (err != ERR_OK) {
468*10465441SEvalZero     lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
469*10465441SEvalZero     return ERR_OK;
470*10465441SEvalZero   }
471*10465441SEvalZero   if (p == NULL) {
472*10465441SEvalZero     /* connection closed -> test done */
473*10465441SEvalZero     if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
474*10465441SEvalZero       if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_NOW)) == 0) {
475*10465441SEvalZero         /* client requested transmission after end of test */
476*10465441SEvalZero         lwiperf_tx_start_passive(conn);
477*10465441SEvalZero       }
478*10465441SEvalZero     }
479*10465441SEvalZero     lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_SERVER);
480*10465441SEvalZero     return ERR_OK;
481*10465441SEvalZero   }
482*10465441SEvalZero   tot_len = p->tot_len;
483*10465441SEvalZero 
484*10465441SEvalZero   conn->poll_count = 0;
485*10465441SEvalZero 
486*10465441SEvalZero   if ((!conn->have_settings_buf) || ((conn->bytes_transferred - 24) % (1024 * 128) == 0)) {
487*10465441SEvalZero     /* wait for 24-byte header */
488*10465441SEvalZero     if (p->tot_len < sizeof(lwiperf_settings_t)) {
489*10465441SEvalZero       lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
490*10465441SEvalZero       pbuf_free(p);
491*10465441SEvalZero       return ERR_OK;
492*10465441SEvalZero     }
493*10465441SEvalZero     if (!conn->have_settings_buf) {
494*10465441SEvalZero       if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) {
495*10465441SEvalZero         lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
496*10465441SEvalZero         pbuf_free(p);
497*10465441SEvalZero         return ERR_OK;
498*10465441SEvalZero       }
499*10465441SEvalZero       conn->have_settings_buf = 1;
500*10465441SEvalZero       if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
501*10465441SEvalZero         if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_NOW)) {
502*10465441SEvalZero           /* client requested parallel transmission test */
503*10465441SEvalZero           err_t err2 = lwiperf_tx_start_passive(conn);
504*10465441SEvalZero           if (err2 != ERR_OK) {
505*10465441SEvalZero             lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR);
506*10465441SEvalZero             pbuf_free(p);
507*10465441SEvalZero             return ERR_OK;
508*10465441SEvalZero           }
509*10465441SEvalZero         }
510*10465441SEvalZero       }
511*10465441SEvalZero     } else {
512*10465441SEvalZero       if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
513*10465441SEvalZero         if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) {
514*10465441SEvalZero           lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
515*10465441SEvalZero           pbuf_free(p);
516*10465441SEvalZero           return ERR_OK;
517*10465441SEvalZero         }
518*10465441SEvalZero       }
519*10465441SEvalZero     }
520*10465441SEvalZero     conn->bytes_transferred += sizeof(lwiperf_settings_t);
521*10465441SEvalZero     if (conn->bytes_transferred <= 24) {
522*10465441SEvalZero       conn->time_started = sys_now();
523*10465441SEvalZero       tcp_recved(tpcb, p->tot_len);
524*10465441SEvalZero       pbuf_free(p);
525*10465441SEvalZero       return ERR_OK;
526*10465441SEvalZero     }
527*10465441SEvalZero     conn->next_num = 4; /* 24 bytes received... */
528*10465441SEvalZero     tmp = pbuf_remove_header(p, 24);
529*10465441SEvalZero     LWIP_ASSERT("pbuf_remove_header failed", tmp == 0);
530*10465441SEvalZero     LWIP_UNUSED_ARG(tmp); /* for LWIP_NOASSERT */
531*10465441SEvalZero   }
532*10465441SEvalZero 
533*10465441SEvalZero   packet_idx = 0;
534*10465441SEvalZero   for (q = p; q != NULL; q = q->next) {
535*10465441SEvalZero #if LWIPERF_CHECK_RX_DATA
536*10465441SEvalZero     const u8_t *payload = (const u8_t *)q->payload;
537*10465441SEvalZero     u16_t i;
538*10465441SEvalZero     for (i = 0; i < q->len; i++) {
539*10465441SEvalZero       u8_t val = payload[i];
540*10465441SEvalZero       u8_t num = val - '0';
541*10465441SEvalZero       if (num == conn->next_num) {
542*10465441SEvalZero         conn->next_num++;
543*10465441SEvalZero         if (conn->next_num == 10) {
544*10465441SEvalZero           conn->next_num = 0;
545*10465441SEvalZero         }
546*10465441SEvalZero       } else {
547*10465441SEvalZero         lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
548*10465441SEvalZero         pbuf_free(p);
549*10465441SEvalZero         return ERR_OK;
550*10465441SEvalZero       }
551*10465441SEvalZero     }
552*10465441SEvalZero #endif
553*10465441SEvalZero     packet_idx += q->len;
554*10465441SEvalZero   }
555*10465441SEvalZero   LWIP_ASSERT("count mismatch", packet_idx == p->tot_len);
556*10465441SEvalZero   conn->bytes_transferred += packet_idx;
557*10465441SEvalZero   tcp_recved(tpcb, tot_len);
558*10465441SEvalZero   pbuf_free(p);
559*10465441SEvalZero   return ERR_OK;
560*10465441SEvalZero }
561*10465441SEvalZero 
562*10465441SEvalZero /** Error callback, iperf tcp session aborted */
563*10465441SEvalZero static void
lwiperf_tcp_err(void * arg,err_t err)564*10465441SEvalZero lwiperf_tcp_err(void *arg, err_t err)
565*10465441SEvalZero {
566*10465441SEvalZero   lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
567*10465441SEvalZero   LWIP_UNUSED_ARG(err);
568*10465441SEvalZero   lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
569*10465441SEvalZero }
570*10465441SEvalZero 
571*10465441SEvalZero /** TCP poll callback, try to send more data */
572*10465441SEvalZero static err_t
lwiperf_tcp_poll(void * arg,struct tcp_pcb * tpcb)573*10465441SEvalZero lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb)
574*10465441SEvalZero {
575*10465441SEvalZero   lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
576*10465441SEvalZero   LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb);
577*10465441SEvalZero   LWIP_UNUSED_ARG(tpcb);
578*10465441SEvalZero   if (++conn->poll_count >= LWIPERF_TCP_MAX_IDLE_SEC) {
579*10465441SEvalZero     lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
580*10465441SEvalZero     return ERR_OK; /* lwiperf_tcp_close frees conn */
581*10465441SEvalZero   }
582*10465441SEvalZero 
583*10465441SEvalZero   if (!conn->base.server) {
584*10465441SEvalZero     lwiperf_tcp_client_send_more(conn);
585*10465441SEvalZero   }
586*10465441SEvalZero 
587*10465441SEvalZero   return ERR_OK;
588*10465441SEvalZero }
589*10465441SEvalZero 
590*10465441SEvalZero /** This is called when a new client connects for an iperf tcp session */
591*10465441SEvalZero static err_t
lwiperf_tcp_accept(void * arg,struct tcp_pcb * newpcb,err_t err)592*10465441SEvalZero lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
593*10465441SEvalZero {
594*10465441SEvalZero   lwiperf_state_tcp_t *s, *conn;
595*10465441SEvalZero   if ((err != ERR_OK) || (newpcb == NULL) || (arg == NULL)) {
596*10465441SEvalZero     return ERR_VAL;
597*10465441SEvalZero   }
598*10465441SEvalZero 
599*10465441SEvalZero   s = (lwiperf_state_tcp_t *)arg;
600*10465441SEvalZero   LWIP_ASSERT("invalid session", s->base.server);
601*10465441SEvalZero   LWIP_ASSERT("invalid listen pcb", s->server_pcb != NULL);
602*10465441SEvalZero   LWIP_ASSERT("invalid conn pcb", s->conn_pcb == NULL);
603*10465441SEvalZero   if (s->specific_remote) {
604*10465441SEvalZero     LWIP_ASSERT("s->base.related_master_state != NULL", s->base.related_master_state != NULL);
605*10465441SEvalZero     if (!ip_addr_cmp(&newpcb->remote_ip, &s->remote_addr)) {
606*10465441SEvalZero       /* this listener belongs to a client session, and this is not the correct remote */
607*10465441SEvalZero       return ERR_VAL;
608*10465441SEvalZero     }
609*10465441SEvalZero   } else {
610*10465441SEvalZero     LWIP_ASSERT("s->base.related_master_state == NULL", s->base.related_master_state == NULL);
611*10465441SEvalZero   }
612*10465441SEvalZero 
613*10465441SEvalZero   conn = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
614*10465441SEvalZero   if (conn == NULL) {
615*10465441SEvalZero     return ERR_MEM;
616*10465441SEvalZero   }
617*10465441SEvalZero   memset(conn, 0, sizeof(lwiperf_state_tcp_t));
618*10465441SEvalZero   conn->base.tcp = 1;
619*10465441SEvalZero   conn->base.server = 1;
620*10465441SEvalZero   conn->base.related_master_state = &s->base;
621*10465441SEvalZero   conn->conn_pcb = newpcb;
622*10465441SEvalZero   conn->time_started = sys_now();
623*10465441SEvalZero   conn->report_fn = s->report_fn;
624*10465441SEvalZero   conn->report_arg = s->report_arg;
625*10465441SEvalZero 
626*10465441SEvalZero   /* setup the tcp rx connection */
627*10465441SEvalZero   tcp_arg(newpcb, conn);
628*10465441SEvalZero   tcp_recv(newpcb, lwiperf_tcp_recv);
629*10465441SEvalZero   tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
630*10465441SEvalZero   tcp_err(conn->conn_pcb, lwiperf_tcp_err);
631*10465441SEvalZero 
632*10465441SEvalZero   if (s->specific_remote) {
633*10465441SEvalZero     /* this listener belongs to a client, so make the client the master of the newly created connection */
634*10465441SEvalZero     conn->base.related_master_state = s->base.related_master_state;
635*10465441SEvalZero     /* if dual mode or (tradeoff mode AND client is done): close the listener */
636*10465441SEvalZero     if (!s->client_tradeoff_mode || !lwiperf_list_find(s->base.related_master_state)) {
637*10465441SEvalZero       /* prevent report when closing: this is expected */
638*10465441SEvalZero       s->report_fn = NULL;
639*10465441SEvalZero       lwiperf_tcp_close(s, LWIPERF_TCP_ABORTED_LOCAL);
640*10465441SEvalZero     }
641*10465441SEvalZero   }
642*10465441SEvalZero   lwiperf_list_add(&conn->base);
643*10465441SEvalZero   return ERR_OK;
644*10465441SEvalZero }
645*10465441SEvalZero 
646*10465441SEvalZero /**
647*10465441SEvalZero  * @ingroup iperf
648*10465441SEvalZero  * Start a TCP iperf server on the default TCP port (5001) and listen for
649*10465441SEvalZero  * incoming connections from iperf clients.
650*10465441SEvalZero  *
651*10465441SEvalZero  * @returns a connection handle that can be used to abort the server
652*10465441SEvalZero  *          by calling @ref lwiperf_abort()
653*10465441SEvalZero  */
654*10465441SEvalZero void *
lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn,void * report_arg)655*10465441SEvalZero lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void *report_arg)
656*10465441SEvalZero {
657*10465441SEvalZero   return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT,
658*10465441SEvalZero                                   report_fn, report_arg);
659*10465441SEvalZero }
660*10465441SEvalZero 
661*10465441SEvalZero /**
662*10465441SEvalZero  * @ingroup iperf
663*10465441SEvalZero  * Start a TCP iperf server on a specific IP address and port and listen for
664*10465441SEvalZero  * incoming connections from iperf clients.
665*10465441SEvalZero  *
666*10465441SEvalZero  * @returns a connection handle that can be used to abort the server
667*10465441SEvalZero  *          by calling @ref lwiperf_abort()
668*10465441SEvalZero  */
669*10465441SEvalZero void *
lwiperf_start_tcp_server(const ip_addr_t * local_addr,u16_t local_port,lwiperf_report_fn report_fn,void * report_arg)670*10465441SEvalZero lwiperf_start_tcp_server(const ip_addr_t *local_addr, u16_t local_port,
671*10465441SEvalZero                          lwiperf_report_fn report_fn, void *report_arg)
672*10465441SEvalZero {
673*10465441SEvalZero   err_t err;
674*10465441SEvalZero   lwiperf_state_tcp_t *state = NULL;
675*10465441SEvalZero 
676*10465441SEvalZero   err = lwiperf_start_tcp_server_impl(local_addr, local_port, report_fn, report_arg,
677*10465441SEvalZero     NULL, &state);
678*10465441SEvalZero   if (err == ERR_OK) {
679*10465441SEvalZero     return state;
680*10465441SEvalZero   }
681*10465441SEvalZero   return NULL;
682*10465441SEvalZero }
683*10465441SEvalZero 
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)684*10465441SEvalZero static err_t lwiperf_start_tcp_server_impl(const ip_addr_t *local_addr, u16_t local_port,
685*10465441SEvalZero                                            lwiperf_report_fn report_fn, void *report_arg,
686*10465441SEvalZero                                            lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **state)
687*10465441SEvalZero {
688*10465441SEvalZero   err_t err;
689*10465441SEvalZero   struct tcp_pcb *pcb;
690*10465441SEvalZero   lwiperf_state_tcp_t *s;
691*10465441SEvalZero 
692*10465441SEvalZero   LWIP_ASSERT_CORE_LOCKED();
693*10465441SEvalZero 
694*10465441SEvalZero   LWIP_ASSERT("state != NULL", state != NULL);
695*10465441SEvalZero 
696*10465441SEvalZero   if (local_addr == NULL) {
697*10465441SEvalZero     return ERR_ARG;
698*10465441SEvalZero   }
699*10465441SEvalZero 
700*10465441SEvalZero   s = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
701*10465441SEvalZero   if (s == NULL) {
702*10465441SEvalZero     return ERR_MEM;
703*10465441SEvalZero   }
704*10465441SEvalZero   memset(s, 0, sizeof(lwiperf_state_tcp_t));
705*10465441SEvalZero   s->base.tcp = 1;
706*10465441SEvalZero   s->base.server = 1;
707*10465441SEvalZero   s->base.related_master_state = related_master_state;
708*10465441SEvalZero   s->report_fn = report_fn;
709*10465441SEvalZero   s->report_arg = report_arg;
710*10465441SEvalZero 
711*10465441SEvalZero   pcb = tcp_new_ip_type(LWIPERF_SERVER_IP_TYPE);
712*10465441SEvalZero   if (pcb == NULL) {
713*10465441SEvalZero     return ERR_MEM;
714*10465441SEvalZero   }
715*10465441SEvalZero   err = tcp_bind(pcb, local_addr, local_port);
716*10465441SEvalZero   if (err != ERR_OK) {
717*10465441SEvalZero     return err;
718*10465441SEvalZero   }
719*10465441SEvalZero   s->server_pcb = tcp_listen_with_backlog(pcb, 1);
720*10465441SEvalZero   if (s->server_pcb == NULL) {
721*10465441SEvalZero     if (pcb != NULL) {
722*10465441SEvalZero       tcp_close(pcb);
723*10465441SEvalZero     }
724*10465441SEvalZero     LWIPERF_FREE(lwiperf_state_tcp_t, s);
725*10465441SEvalZero     return ERR_MEM;
726*10465441SEvalZero   }
727*10465441SEvalZero   pcb = NULL;
728*10465441SEvalZero 
729*10465441SEvalZero   tcp_arg(s->server_pcb, s);
730*10465441SEvalZero   tcp_accept(s->server_pcb, lwiperf_tcp_accept);
731*10465441SEvalZero 
732*10465441SEvalZero   lwiperf_list_add(&s->base);
733*10465441SEvalZero   *state = s;
734*10465441SEvalZero   return ERR_OK;
735*10465441SEvalZero }
736*10465441SEvalZero 
737*10465441SEvalZero /**
738*10465441SEvalZero  * @ingroup iperf
739*10465441SEvalZero  * Start a TCP iperf client to the default TCP port (5001).
740*10465441SEvalZero  *
741*10465441SEvalZero  * @returns a connection handle that can be used to abort the client
742*10465441SEvalZero  *          by calling @ref lwiperf_abort()
743*10465441SEvalZero  */
lwiperf_start_tcp_client_default(const ip_addr_t * remote_addr,lwiperf_report_fn report_fn,void * report_arg)744*10465441SEvalZero void* lwiperf_start_tcp_client_default(const ip_addr_t* remote_addr,
745*10465441SEvalZero                                lwiperf_report_fn report_fn, void* report_arg)
746*10465441SEvalZero {
747*10465441SEvalZero   return lwiperf_start_tcp_client(remote_addr, LWIPERF_TCP_PORT_DEFAULT, LWIPERF_CLIENT,
748*10465441SEvalZero                                   report_fn, report_arg);
749*10465441SEvalZero }
750*10465441SEvalZero 
751*10465441SEvalZero /**
752*10465441SEvalZero  * @ingroup iperf
753*10465441SEvalZero  * Start a TCP iperf client to a specific IP address and port.
754*10465441SEvalZero  *
755*10465441SEvalZero  * @returns a connection handle that can be used to abort the client
756*10465441SEvalZero  *          by calling @ref lwiperf_abort()
757*10465441SEvalZero  */
lwiperf_start_tcp_client(const ip_addr_t * remote_addr,u16_t remote_port,enum lwiperf_client_type type,lwiperf_report_fn report_fn,void * report_arg)758*10465441SEvalZero void* lwiperf_start_tcp_client(const ip_addr_t* remote_addr, u16_t remote_port,
759*10465441SEvalZero   enum lwiperf_client_type type, lwiperf_report_fn report_fn, void* report_arg)
760*10465441SEvalZero {
761*10465441SEvalZero   err_t ret;
762*10465441SEvalZero   lwiperf_settings_t settings;
763*10465441SEvalZero   lwiperf_state_tcp_t *state = NULL;
764*10465441SEvalZero 
765*10465441SEvalZero   memset(&settings, 0, sizeof(settings));
766*10465441SEvalZero   switch (type) {
767*10465441SEvalZero   case LWIPERF_CLIENT:
768*10465441SEvalZero     /* Unidirectional tx only test */
769*10465441SEvalZero     settings.flags = 0;
770*10465441SEvalZero     break;
771*10465441SEvalZero   case LWIPERF_DUAL:
772*10465441SEvalZero     /* Do a bidirectional test simultaneously */
773*10465441SEvalZero     settings.flags = htonl(LWIPERF_FLAGS_ANSWER_TEST | LWIPERF_FLAGS_ANSWER_NOW);
774*10465441SEvalZero     break;
775*10465441SEvalZero   case LWIPERF_TRADEOFF:
776*10465441SEvalZero     /* Do a bidirectional test individually */
777*10465441SEvalZero     settings.flags = htonl(LWIPERF_FLAGS_ANSWER_TEST);
778*10465441SEvalZero     break;
779*10465441SEvalZero   default:
780*10465441SEvalZero     /* invalid argument */
781*10465441SEvalZero     return NULL;
782*10465441SEvalZero   }
783*10465441SEvalZero   settings.num_threads = htonl(1);
784*10465441SEvalZero   settings.remote_port = htonl(LWIPERF_TCP_PORT_DEFAULT);
785*10465441SEvalZero   /* TODO: implement passing duration/amount of bytes to transfer */
786*10465441SEvalZero   settings.amount = htonl((u32_t)-1000);
787*10465441SEvalZero 
788*10465441SEvalZero   ret = lwiperf_tx_start_impl(remote_addr, remote_port, &settings, report_fn, report_arg, NULL, &state);
789*10465441SEvalZero   if (ret == ERR_OK) {
790*10465441SEvalZero     LWIP_ASSERT("state != NULL", state != NULL);
791*10465441SEvalZero     if (type != LWIPERF_CLIENT) {
792*10465441SEvalZero       /* start corresponding server now */
793*10465441SEvalZero       lwiperf_state_tcp_t *server = NULL;
794*10465441SEvalZero       ret = lwiperf_start_tcp_server_impl(&state->conn_pcb->local_ip, LWIPERF_TCP_PORT_DEFAULT,
795*10465441SEvalZero         report_fn, report_arg, (lwiperf_state_base_t *)state, &server);
796*10465441SEvalZero       if (ret != ERR_OK) {
797*10465441SEvalZero         /* starting server failed, abort client */
798*10465441SEvalZero         lwiperf_abort(state);
799*10465441SEvalZero         return NULL;
800*10465441SEvalZero       }
801*10465441SEvalZero       /* make this server accept one connection only */
802*10465441SEvalZero       server->specific_remote = 1;
803*10465441SEvalZero       server->remote_addr = state->conn_pcb->remote_ip;
804*10465441SEvalZero       if (type == LWIPERF_TRADEOFF) {
805*10465441SEvalZero         /* tradeoff means that the remote host connects only after the client is done,
806*10465441SEvalZero            so keep the listen pcb open until the client is done */
807*10465441SEvalZero         server->client_tradeoff_mode = 1;
808*10465441SEvalZero       }
809*10465441SEvalZero     }
810*10465441SEvalZero     return state;
811*10465441SEvalZero   }
812*10465441SEvalZero   return NULL;
813*10465441SEvalZero }
814*10465441SEvalZero 
815*10465441SEvalZero /**
816*10465441SEvalZero  * @ingroup iperf
817*10465441SEvalZero  * Abort an iperf session (handle returned by lwiperf_start_tcp_server*())
818*10465441SEvalZero  */
819*10465441SEvalZero void
lwiperf_abort(void * lwiperf_session)820*10465441SEvalZero lwiperf_abort(void *lwiperf_session)
821*10465441SEvalZero {
822*10465441SEvalZero   lwiperf_state_base_t *i, *dealloc, *last = NULL;
823*10465441SEvalZero 
824*10465441SEvalZero   LWIP_ASSERT_CORE_LOCKED();
825*10465441SEvalZero 
826*10465441SEvalZero   for (i = lwiperf_all_connections; i != NULL; ) {
827*10465441SEvalZero     if ((i == lwiperf_session) || (i->related_master_state == lwiperf_session)) {
828*10465441SEvalZero       dealloc = i;
829*10465441SEvalZero       i = i->next;
830*10465441SEvalZero       if (last != NULL) {
831*10465441SEvalZero         last->next = i;
832*10465441SEvalZero       }
833*10465441SEvalZero       LWIPERF_FREE(lwiperf_state_tcp_t, dealloc); /* @todo: type? */
834*10465441SEvalZero     } else {
835*10465441SEvalZero       last = i;
836*10465441SEvalZero       i = i->next;
837*10465441SEvalZero     }
838*10465441SEvalZero   }
839*10465441SEvalZero }
840*10465441SEvalZero 
841*10465441SEvalZero #endif /* LWIP_TCP && LWIP_CALLBACK_API */
842