BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file
3 * lwIP iPerf server implementation
4 */
5  
6 /**
7 * @defgroup iperf Iperf server
8 * @ingroup apps
9 *
10 * This is a simple performance measuring server to check your bandwith using
11 * iPerf2 on a PC as client.
12 * It is currently a minimal implementation providing an IPv4 TCP server only.
13 *
14 * @todo: implement UDP mode and IPv6
15 */
16  
17 /*
18 * Copyright (c) 2014 Simon Goldschmidt
19 * All rights reserved.
20 *
21 * Redistribution and use in source and binary forms, with or without modification,
22 * are permitted provided that the following conditions are met:
23 *
24 * 1. Redistributions of source code must retain the above copyright notice,
25 * this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright notice,
27 * this list of conditions and the following disclaimer in the documentation
28 * and/or other materials provided with the distribution.
29 * 3. The name of the author may not be used to endorse or promote products
30 * derived from this software without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
33 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
34 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
35 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
36 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
37 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
41 * OF SUCH DAMAGE.
42 *
43 * This file is part of the lwIP TCP/IP stack.
44 *
45 * Author: Simon Goldschmidt
46 */
47  
48 #include "lwip/apps/lwiperf.h"
49  
50 #include "lwip/tcp.h"
51 #include "lwip/sys.h"
52  
53 #include <string.h>
54  
55 /* Currently, only TCP-over-IPv4 is implemented (does iperf support IPv6 anyway?) */
56 #if LWIP_IPV4 && LWIP_TCP && LWIP_CALLBACK_API
57  
58 /** Specify the idle timeout (in seconds) after that the test fails */
59 #ifndef LWIPERF_TCP_MAX_IDLE_SEC
60 #define LWIPERF_TCP_MAX_IDLE_SEC 10U
61 #endif
62 #if LWIPERF_TCP_MAX_IDLE_SEC > 255
63 #error LWIPERF_TCP_MAX_IDLE_SEC must fit into an u8_t
64 #endif
65  
66 /* File internal memory allocation (struct lwiperf_*): this defaults to
67 the heap */
68 #ifndef LWIPERF_ALLOC
69 #define LWIPERF_ALLOC(type) mem_malloc(sizeof(type))
70 #define LWIPERF_FREE(type, item) mem_free(item)
71 #endif
72  
73 /** If this is 1, check that received data has the correct format */
74 #ifndef LWIPERF_CHECK_RX_DATA
75 #define LWIPERF_CHECK_RX_DATA 0
76 #endif
77  
78 /** This is the Iperf settings struct sent from the client */
79 typedef struct _lwiperf_settings {
80 #define LWIPERF_FLAGS_ANSWER_TEST 0x80000000
81 #define LWIPERF_FLAGS_ANSWER_NOW 0x00000001
82 u32_t flags;
83 u32_t num_threads; /* unused for now */
84 u32_t remote_port;
85 u32_t buffer_len; /* unused for now */
86 u32_t win_band; /* TCP window / UDP rate: unused for now */
87 u32_t amount; /* pos. value: bytes?; neg. values: time (unit is 10ms: 1/100 second) */
88 } lwiperf_settings_t;
89  
90 /** Basic connection handle */
91 struct _lwiperf_state_base;
92 typedef struct _lwiperf_state_base lwiperf_state_base_t;
93 struct _lwiperf_state_base {
94 /* 1=tcp, 0=udp */
95 u8_t tcp;
96 /* 1=server, 0=client */
97 u8_t server;
98 lwiperf_state_base_t *next;
99 lwiperf_state_base_t *related_server_state;
100 };
101  
102 /** Connection handle for a TCP iperf session */
103 typedef struct _lwiperf_state_tcp {
104 lwiperf_state_base_t base;
105 struct tcp_pcb *server_pcb;
106 struct tcp_pcb *conn_pcb;
107 u32_t time_started;
108 lwiperf_report_fn report_fn;
109 void *report_arg;
110 u8_t poll_count;
111 u8_t next_num;
112 u32_t bytes_transferred;
113 lwiperf_settings_t settings;
114 u8_t have_settings_buf;
115 } lwiperf_state_tcp_t;
116  
117 /** List of active iperf sessions */
118 static lwiperf_state_base_t *lwiperf_all_connections;
119 /** A const buffer to send from: we want to measure sending, not copying! */
120 static const u8_t lwiperf_txbuf_const[1600] = {
121 '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',
122 '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',
123 '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',
124 '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',
125 '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',
126 '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',
127 '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',
128 '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',
129 '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',
130 '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',
131 '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',
132 '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',
133 '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',
134 '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',
135 '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',
136 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 '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 };
162  
163 static err_t lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb);
164 static void lwiperf_tcp_err(void *arg, err_t err);
165  
166 /** Add an iperf session to the 'active' list */
167 static void
168 lwiperf_list_add(lwiperf_state_base_t *item)
169 {
170 if (lwiperf_all_connections == NULL) {
171 lwiperf_all_connections = item;
172 } else {
173 item = lwiperf_all_connections;
174 }
175 }
176  
177 /** Remove an iperf session from the 'active' list */
178 static void
179 lwiperf_list_remove(lwiperf_state_base_t *item)
180 {
181 lwiperf_state_base_t *prev = NULL;
182 lwiperf_state_base_t *iter;
183 for (iter = lwiperf_all_connections; iter != NULL; prev = iter, iter = iter->next) {
184 if (iter == item) {
185 if (prev == NULL) {
186 lwiperf_all_connections = iter->next;
187 } else {
188 prev->next = item;
189 }
190 /* @debug: ensure this item is listed only once */
191 for (iter = iter->next; iter != NULL; iter = iter->next) {
192 LWIP_ASSERT("duplicate entry", iter != item);
193 }
194 break;
195 }
196 }
197 }
198  
199 /** Call the report function of an iperf tcp session */
200 static void
201 lwip_tcp_conn_report(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_type)
202 {
203 if ((conn != NULL) && (conn->report_fn != NULL)) {
204 u32_t now, duration_ms, bandwidth_kbitpsec;
205 now = sys_now();
206 duration_ms = now - conn->time_started;
207 if (duration_ms == 0) {
208 bandwidth_kbitpsec = 0;
209 } else {
210 bandwidth_kbitpsec = (conn->bytes_transferred / duration_ms) * 8U;
211 }
212 conn->report_fn(conn->report_arg, report_type,
213 &conn->conn_pcb->local_ip, conn->conn_pcb->local_port,
214 &conn->conn_pcb->remote_ip, conn->conn_pcb->remote_port,
215 conn->bytes_transferred, duration_ms, bandwidth_kbitpsec);
216 }
217 }
218  
219 /** Close an iperf tcp session */
220 static void
221 lwiperf_tcp_close(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_type)
222 {
223 err_t err;
224  
225 lwip_tcp_conn_report(conn, report_type);
226 lwiperf_list_remove(&conn->base);
227 if (conn->conn_pcb != NULL) {
228 tcp_arg(conn->conn_pcb, NULL);
229 tcp_poll(conn->conn_pcb, NULL, 0);
230 tcp_sent(conn->conn_pcb, NULL);
231 tcp_recv(conn->conn_pcb, NULL);
232 tcp_err(conn->conn_pcb, NULL);
233 err = tcp_close(conn->conn_pcb);
234 if (err != ERR_OK) {
235 /* don't want to wait for free memory here... */
236 tcp_abort(conn->conn_pcb);
237 }
238 } else {
239 /* no conn pcb, this is the server pcb */
240 err = tcp_close(conn->server_pcb);
241 LWIP_ASSERT("error", err != ERR_OK);
242 }
243 LWIPERF_FREE(lwiperf_state_tcp_t, conn);
244 }
245  
246 /** Try to send more data on an iperf tcp session */
247 static err_t
248 lwiperf_tcp_client_send_more(lwiperf_state_tcp_t *conn)
249 {
250 int send_more;
251 err_t err;
252 u16_t txlen;
253 u16_t txlen_max;
254 void *txptr;
255 u8_t apiflags;
256  
257 LWIP_ASSERT("conn invalid", (conn != NULL) && conn->base.tcp && (conn->base.server == 0));
258  
259 do {
260 send_more = 0;
261 if (conn->settings.amount & PP_HTONL(0x80000000)) {
262 /* this session is time-limited */
263 u32_t now = sys_now();
264 u32_t diff_ms = now - conn->time_started;
265 u32_t time = (u32_t) - (s32_t)lwip_htonl(conn->settings.amount);
266 u32_t time_ms = time * 10;
267 if (diff_ms >= time_ms) {
268 /* time specified by the client is over -> close the connection */
269 lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT);
270 return ERR_OK;
271 }
272 } else {
273 /* this session is byte-limited */
274 u32_t amount_bytes = lwip_htonl(conn->settings.amount);
275 /* @todo: this can send up to 1*MSS more than requested... */
276 if (amount_bytes >= conn->bytes_transferred) {
277 /* all requested bytes transferred -> close the connection */
278 lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT);
279 return ERR_OK;
280 }
281 }
282  
283 if (conn->bytes_transferred < 24) {
284 /* transmit the settings a first time */
285 txptr = &((u8_t *)&conn->settings)[conn->bytes_transferred];
286 txlen_max = (u16_t)(24 - conn->bytes_transferred);
287 apiflags = TCP_WRITE_FLAG_COPY;
288 } else if (conn->bytes_transferred < 48) {
289 /* transmit the settings a second time */
290 txptr = &((u8_t *)&conn->settings)[conn->bytes_transferred - 24];
291 txlen_max = (u16_t)(48 - conn->bytes_transferred);
292 apiflags = TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE;
293 send_more = 1;
294 } else {
295 /* transmit data */
296 /* @todo: every x bytes, transmit the settings again */
297 txptr = LWIP_CONST_CAST(void *, &lwiperf_txbuf_const[conn->bytes_transferred % 10]);
298 txlen_max = TCP_MSS;
299 if (conn->bytes_transferred == 48) { /* @todo: fix this for intermediate settings, too */
300 txlen_max = TCP_MSS - 24;
301 }
302 apiflags = 0; /* no copying needed */
303 send_more = 1;
304 }
305 txlen = txlen_max;
306 do {
307 err = tcp_write(conn->conn_pcb, txptr, txlen, apiflags);
308 if (err == ERR_MEM) {
309 txlen /= 2;
310 }
311 } while ((err == ERR_MEM) && (txlen >= (TCP_MSS / 2)));
312  
313 if (err == ERR_OK) {
314 conn->bytes_transferred += txlen;
315 } else {
316 send_more = 0;
317 }
318 } while (send_more);
319  
320 tcp_output(conn->conn_pcb);
321 return ERR_OK;
322 }
323  
324 /** TCP sent callback, try to send more data */
325 static err_t
326 lwiperf_tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
327 {
328 lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
329 /* @todo: check 'len' (e.g. to time ACK of all data)? for now, we just send more... */
330 LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
331 LWIP_UNUSED_ARG(tpcb);
332 LWIP_UNUSED_ARG(len);
333  
334 conn->poll_count = 0;
335  
336 return lwiperf_tcp_client_send_more(conn);
337 }
338  
339 /** TCP connected callback (active connection), send data now */
340 static err_t
341 lwiperf_tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
342 {
343 lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
344 LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
345 LWIP_UNUSED_ARG(tpcb);
346 if (err != ERR_OK) {
347 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
348 return ERR_OK;
349 }
350 conn->poll_count = 0;
351 conn->time_started = sys_now();
352 return lwiperf_tcp_client_send_more(conn);
353 }
354  
355 /** Start TCP connection back to the client (either parallel or after the
356 * receive test has finished.
357 */
358 static err_t
359 lwiperf_tx_start(lwiperf_state_tcp_t *conn)
360 {
361 err_t err;
362 lwiperf_state_tcp_t *client_conn;
363 struct tcp_pcb *newpcb;
364 ip_addr_t remote_addr;
365 u16_t remote_port;
366  
367 client_conn = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
368 if (client_conn == NULL) {
369 return ERR_MEM;
370 }
371 newpcb = tcp_new();
372 if (newpcb == NULL) {
373 LWIPERF_FREE(lwiperf_state_tcp_t, client_conn);
374 return ERR_MEM;
375 }
376  
377 MEMCPY(client_conn, conn, sizeof(lwiperf_state_tcp_t));
378 client_conn->base.server = 0;
379 client_conn->server_pcb = NULL;
380 client_conn->conn_pcb = newpcb;
381 client_conn->time_started = sys_now(); /* @todo: set this again on 'connected' */
382 client_conn->poll_count = 0;
383 client_conn->next_num = 4; /* initial nr is '4' since the header has 24 byte */
384 client_conn->bytes_transferred = 0;
385 client_conn->settings.flags = 0; /* prevent the remote side starting back as client again */
386  
387 tcp_arg(newpcb, client_conn);
388 tcp_sent(newpcb, lwiperf_tcp_client_sent);
389 tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
390 tcp_err(newpcb, lwiperf_tcp_err);
391  
392 ip_addr_copy(remote_addr, conn->conn_pcb->remote_ip);
393 remote_port = (u16_t)lwip_htonl(client_conn->settings.remote_port);
394  
395 err = tcp_connect(newpcb, &remote_addr, remote_port, lwiperf_tcp_client_connected);
396 if (err != ERR_OK) {
397 lwiperf_tcp_close(client_conn, LWIPERF_TCP_ABORTED_LOCAL);
398 return err;
399 }
400 lwiperf_list_add(&client_conn->base);
401 return ERR_OK;
402 }
403  
404 /** Receive data on an iperf tcp session */
405 static err_t
406 lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
407 {
408 u8_t tmp;
409 u16_t tot_len;
410 u32_t packet_idx;
411 struct pbuf *q;
412 lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
413  
414 LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb);
415 LWIP_UNUSED_ARG(tpcb);
416  
417 if (err != ERR_OK) {
418 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
419 return ERR_OK;
420 }
421 if (p == NULL) {
422 /* connection closed -> test done */
423 if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST | LWIPERF_FLAGS_ANSWER_NOW)) ==
424 PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
425 /* client requested transmission after end of test */
426 lwiperf_tx_start(conn);
427 }
428 lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_SERVER);
429 return ERR_OK;
430 }
431 tot_len = p->tot_len;
432  
433 conn->poll_count = 0;
434  
435 if ((!conn->have_settings_buf) || ((conn->bytes_transferred - 24) % (1024 * 128) == 0)) {
436 /* wait for 24-byte header */
437 if (p->tot_len < sizeof(lwiperf_settings_t)) {
438 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
439 pbuf_free(p);
440 return ERR_VAL;
441 }
442 if (!conn->have_settings_buf) {
443 if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) {
444 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
445 pbuf_free(p);
446 return ERR_VAL;
447 }
448 conn->have_settings_buf = 1;
449 if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST | LWIPERF_FLAGS_ANSWER_NOW)) ==
450 PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST | LWIPERF_FLAGS_ANSWER_NOW)) {
451 /* client requested parallel transmission test */
452 err_t err2 = lwiperf_tx_start(conn);
453 if (err2 != ERR_OK) {
454 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR);
455 pbuf_free(p);
456 return err2;
457 }
458 }
459 } else {
460 if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) {
461 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
462 pbuf_free(p);
463 return ERR_VAL;
464 }
465 }
466 conn->bytes_transferred += sizeof(lwiperf_settings_t);
467 if (conn->bytes_transferred <= 24) {
468 conn->time_started = sys_now();
469 tcp_recved(tpcb, p->tot_len);
470 pbuf_free(p);
471 return ERR_OK;
472 }
473 conn->next_num = 4; /* 24 bytes received... */
474 tmp = pbuf_remove_header(p, 24);
475 LWIP_ASSERT("pbuf_remove_header failed", tmp == 0);
476 }
477  
478 packet_idx = 0;
479 for (q = p; q != NULL; q = q->next) {
480 #if LWIPERF_CHECK_RX_DATA
481 const u8_t *payload = (const u8_t *)q->payload;
482 u16_t i;
483 for (i = 0; i < q->len; i++) {
484 u8_t val = payload[i];
485 u8_t num = val - '0';
486 if (num == conn->next_num) {
487 conn->next_num++;
488 if (conn->next_num == 10) {
489 conn->next_num = 0;
490 }
491 } else {
492 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
493 pbuf_free(p);
494 return ERR_VAL;
495 }
496 }
497 #endif
498 packet_idx += q->len;
499 }
500 LWIP_ASSERT("count mismatch", packet_idx == p->tot_len);
501 conn->bytes_transferred += packet_idx;
502 tcp_recved(tpcb, tot_len);
503 pbuf_free(p);
504 return ERR_OK;
505 }
506  
507 /** Error callback, iperf tcp session aborted */
508 static void
509 lwiperf_tcp_err(void *arg, err_t err)
510 {
511 lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
512 LWIP_UNUSED_ARG(err);
513 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
514 }
515  
516 /** TCP poll callback, try to send more data */
517 static err_t
518 lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb)
519 {
520 lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
521 LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb);
522 LWIP_UNUSED_ARG(tpcb);
523 if (++conn->poll_count >= LWIPERF_TCP_MAX_IDLE_SEC) {
524 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
525 return ERR_OK; /* lwiperf_tcp_close frees conn */
526 }
527  
528 if (!conn->base.server) {
529 lwiperf_tcp_client_send_more(conn);
530 }
531  
532 return ERR_OK;
533 }
534  
535 /** This is called when a new client connects for an iperf tcp session */
536 static err_t
537 lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
538 {
539 lwiperf_state_tcp_t *s, *conn;
540 if ((err != ERR_OK) || (newpcb == NULL) || (arg == NULL)) {
541 return ERR_VAL;
542 }
543  
544 s = (lwiperf_state_tcp_t *)arg;
545 conn = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
546 if (conn == NULL) {
547 return ERR_MEM;
548 }
549 memset(conn, 0, sizeof(lwiperf_state_tcp_t));
550 conn->base.tcp = 1;
551 conn->base.server = 1;
552 conn->base.related_server_state = &s->base;
553 conn->server_pcb = s->server_pcb;
554 conn->conn_pcb = newpcb;
555 conn->time_started = sys_now();
556 conn->report_fn = s->report_fn;
557 conn->report_arg = s->report_arg;
558  
559 /* setup the tcp rx connection */
560 tcp_arg(newpcb, conn);
561 tcp_recv(newpcb, lwiperf_tcp_recv);
562 tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
563 tcp_err(conn->conn_pcb, lwiperf_tcp_err);
564  
565 lwiperf_list_add(&conn->base);
566 return ERR_OK;
567 }
568  
569 /**
570 * @ingroup iperf
571 * Start a TCP iperf server on the default TCP port (5001) and listen for
572 * incoming connections from iperf clients.
573 *
574 * @returns a connection handle that can be used to abort the server
575 * by calling @ref lwiperf_abort()
576 */
577 void *
578 lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void *report_arg)
579 {
580 return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT,
581 report_fn, report_arg);
582 }
583  
584 /**
585 * @ingroup iperf
586 * Start a TCP iperf server on a specific IP address and port and listen for
587 * incoming connections from iperf clients.
588 *
589 * @returns a connection handle that can be used to abort the server
590 * by calling @ref lwiperf_abort()
591 */
592 void *
593 lwiperf_start_tcp_server(const ip_addr_t *local_addr, u16_t local_port,
594 lwiperf_report_fn report_fn, void *report_arg)
595 {
596 err_t err;
597 struct tcp_pcb *pcb;
598 lwiperf_state_tcp_t *s;
599  
600 if (local_addr == NULL) {
601 return NULL;
602 }
603  
604 s = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
605 if (s == NULL) {
606 return NULL;
607 }
608 memset(s, 0, sizeof(lwiperf_state_tcp_t));
609 s->base.tcp = 1;
610 s->base.server = 1;
611 s->report_fn = report_fn;
612 s->report_arg = report_arg;
613  
614 pcb = tcp_new();
615 if (pcb != NULL) {
616 err = tcp_bind(pcb, local_addr, local_port);
617 if (err == ERR_OK) {
618 s->server_pcb = tcp_listen_with_backlog(pcb, 1);
619 }
620 }
621 if (s->server_pcb == NULL) {
622 if (pcb != NULL) {
623 tcp_close(pcb);
624 }
625 LWIPERF_FREE(lwiperf_state_tcp_t, s);
626 return NULL;
627 }
628 pcb = NULL;
629  
630 tcp_arg(s->server_pcb, s);
631 tcp_accept(s->server_pcb, lwiperf_tcp_accept);
632  
633 lwiperf_list_add(&s->base);
634 return s;
635 }
636  
637 /**
638 * @ingroup iperf
639 * Abort an iperf session (handle returned by lwiperf_start_tcp_server*())
640 */
641 void
642 lwiperf_abort(void *lwiperf_session)
643 {
644 lwiperf_state_base_t *i, *dealloc, *last = NULL;
645  
646 for (i = lwiperf_all_connections; i != NULL; ) {
647 if ((i == lwiperf_session) || (i->related_server_state == lwiperf_session)) {
648 dealloc = i;
649 i = i->next;
650 if (last != NULL) {
651 last->next = i;
652 }
653 LWIPERF_FREE(lwiperf_state_tcp_t, dealloc); /* @todo: type? */
654 } else {
655 last = i;
656 i = i->next;
657 }
658 }
659 }
660  
661 #endif /* LWIP_IPV4 && LWIP_TCP && LWIP_CALLBACK_API */