Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-os by
lwip_lwiperf.c
00001 /** 00002 * @file 00003 * lwIP iPerf server implementation 00004 */ 00005 00006 /** 00007 * @defgroup iperf Iperf server 00008 * @ingroup apps 00009 * 00010 * This is a simple performance measuring server to check your bandwith using 00011 * iPerf2 on a PC as client. 00012 * It is currently a minimal implementation providing an IPv4 TCP server only. 00013 * 00014 * @todo: implement UDP mode and IPv6 00015 */ 00016 00017 /* 00018 * Copyright (c) 2014 Simon Goldschmidt 00019 * All rights reserved. 00020 * 00021 * Redistribution and use in source and binary forms, with or without modification, 00022 * are permitted provided that the following conditions are met: 00023 * 00024 * 1. Redistributions of source code must retain the above copyright notice, 00025 * this list of conditions and the following disclaimer. 00026 * 2. Redistributions in binary form must reproduce the above copyright notice, 00027 * this list of conditions and the following disclaimer in the documentation 00028 * and/or other materials provided with the distribution. 00029 * 3. The name of the author may not be used to endorse or promote products 00030 * derived from this software without specific prior written permission. 00031 * 00032 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00033 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00034 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00035 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00036 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00037 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00038 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00039 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00040 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00041 * OF SUCH DAMAGE. 00042 * 00043 * This file is part of the lwIP TCP/IP stack. 00044 * 00045 * Author: Simon Goldschmidt 00046 */ 00047 00048 #include "lwip/apps/lwiperf.h" 00049 00050 #include "lwip/tcp.h" 00051 #include "lwip/sys.h" 00052 00053 #include <string.h> 00054 00055 /* Currently, only TCP-over-IPv4 is implemented (does iperf support IPv6 anyway?) */ 00056 #if LWIP_IPV4 && LWIP_TCP 00057 00058 /** Specify the idle timeout (in seconds) after that the test fails */ 00059 #ifndef LWIPERF_TCP_MAX_IDLE_SEC 00060 #define LWIPERF_TCP_MAX_IDLE_SEC 10U 00061 #endif 00062 #if LWIPERF_TCP_MAX_IDLE_SEC > 255 00063 #error LWIPERF_TCP_MAX_IDLE_SEC must fit into an u8_t 00064 #endif 00065 00066 /* File internal memory allocation (struct lwiperf_*): this defaults to 00067 the heap */ 00068 #ifndef LWIPERF_ALLOC 00069 #define LWIPERF_ALLOC(type) mem_malloc(sizeof(type)) 00070 #define LWIPERF_FREE(type, item) mem_free(item) 00071 #endif 00072 00073 /** If this is 1, check that received data has the correct format */ 00074 #ifndef LWIPERF_CHECK_RX_DATA 00075 #define LWIPERF_CHECK_RX_DATA 0 00076 #endif 00077 00078 /** This is the Iperf settings struct sent from the client */ 00079 typedef struct _lwiperf_settings { 00080 #define LWIPERF_FLAGS_ANSWER_TEST 0x80000000 00081 #define LWIPERF_FLAGS_ANSWER_NOW 0x00000001 00082 u32_t flags; 00083 u32_t num_threads; /* unused for now */ 00084 u32_t remote_port; 00085 u32_t buffer_len; /* unused for now */ 00086 u32_t win_band; /* TCP window / UDP rate: unused for now */ 00087 u32_t amount; /* pos. value: bytes?; neg. values: time (unit is 10ms: 1/100 second) */ 00088 } lwiperf_settings_t; 00089 00090 /** Basic connection handle */ 00091 struct _lwiperf_state_base; 00092 typedef struct _lwiperf_state_base lwiperf_state_base_t; 00093 struct _lwiperf_state_base { 00094 /* 1=tcp, 0=udp */ 00095 u8_t tcp; 00096 /* 1=server, 0=client */ 00097 u8_t server; 00098 lwiperf_state_base_t* next; 00099 lwiperf_state_base_t* related_server_state; 00100 }; 00101 00102 /** Connection handle for a TCP iperf session */ 00103 typedef struct _lwiperf_state_tcp { 00104 lwiperf_state_base_t base; 00105 struct tcp_pcb* server_pcb; 00106 struct tcp_pcb* conn_pcb; 00107 u32_t time_started; 00108 lwiperf_report_fn report_fn; 00109 void* report_arg; 00110 u8_t poll_count; 00111 u8_t next_num; 00112 u32_t bytes_transferred; 00113 lwiperf_settings_t settings; 00114 u8_t have_settings_buf; 00115 } lwiperf_state_tcp_t; 00116 00117 /** List of active iperf sessions */ 00118 static lwiperf_state_base_t* lwiperf_all_connections; 00119 /** A const buffer to send from: we want to measure sending, not copying! */ 00120 static const u8_t lwiperf_txbuf_const[1600] = { 00121 '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', 00122 '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', 00123 '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', 00124 '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', 00125 '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', 00126 '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', 00127 '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', 00128 '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', 00129 '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', 00130 '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', 00131 '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', 00132 '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', 00133 '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', 00134 '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', 00135 '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', 00136 '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', 00137 '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', 00138 '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', 00139 '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', 00140 '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', 00141 '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', 00142 '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', 00143 '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', 00144 '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', 00145 '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', 00146 '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', 00147 '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', 00148 '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', 00149 '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', 00150 '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', 00151 '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', 00152 '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', 00153 '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', 00154 '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', 00155 '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', 00156 '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', 00157 '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', 00158 '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', 00159 '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', 00160 '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', 00161 }; 00162 00163 static err_t lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb); 00164 static void lwiperf_tcp_err(void *arg, err_t err); 00165 00166 /** Add an iperf session to the 'active' list */ 00167 static void 00168 lwiperf_list_add(lwiperf_state_base_t* item) 00169 { 00170 if (lwiperf_all_connections == NULL) { 00171 lwiperf_all_connections = item; 00172 } else { 00173 item = lwiperf_all_connections; 00174 } 00175 } 00176 00177 /** Remove an iperf session from the 'active' list */ 00178 static void 00179 lwiperf_list_remove(lwiperf_state_base_t* item) 00180 { 00181 lwiperf_state_base_t* prev = NULL; 00182 lwiperf_state_base_t* iter; 00183 for (iter = lwiperf_all_connections; iter != NULL; prev = iter, iter = iter->next) { 00184 if (iter == item) { 00185 if (prev == NULL) { 00186 lwiperf_all_connections = iter->next; 00187 } else { 00188 prev->next = item; 00189 } 00190 /* @debug: ensure this item is listed only once */ 00191 for (iter = iter->next; iter != NULL; iter = iter->next) { 00192 LWIP_ASSERT("duplicate entry", iter != item); 00193 } 00194 break; 00195 } 00196 } 00197 } 00198 00199 /** Call the report function of an iperf tcp session */ 00200 static void 00201 lwip_tcp_conn_report(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type) 00202 { 00203 if ((conn != NULL) && (conn->report_fn != NULL)) { 00204 u32_t now, duration_ms, bandwidth_kbitpsec; 00205 now = sys_now(); 00206 duration_ms = now - conn->time_started; 00207 if (duration_ms == 0) { 00208 bandwidth_kbitpsec = 0; 00209 } else { 00210 bandwidth_kbitpsec = (conn->bytes_transferred / duration_ms) * 8U; 00211 } 00212 conn->report_fn(conn->report_arg, report_type, 00213 &conn->conn_pcb->local_ip, conn->conn_pcb->local_port, 00214 &conn->conn_pcb->remote_ip, conn->conn_pcb->remote_port, 00215 conn->bytes_transferred, duration_ms, bandwidth_kbitpsec); 00216 } 00217 } 00218 00219 /** Close an iperf tcp session */ 00220 static void 00221 lwiperf_tcp_close(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type) 00222 { 00223 err_t err; 00224 00225 lwip_tcp_conn_report(conn, report_type); 00226 lwiperf_list_remove(&conn->base); 00227 if (conn->conn_pcb != NULL) { 00228 tcp_arg(conn->conn_pcb, NULL); 00229 tcp_poll(conn->conn_pcb, NULL, 0); 00230 tcp_sent(conn->conn_pcb, NULL); 00231 tcp_recv(conn->conn_pcb, NULL); 00232 tcp_err(conn->conn_pcb, NULL); 00233 err = tcp_close(conn->conn_pcb); 00234 if (err != ERR_OK) { 00235 /* don't want to wait for free memory here... */ 00236 tcp_abort(conn->conn_pcb); 00237 } 00238 } else { 00239 /* no conn pcb, this is the server pcb */ 00240 err = tcp_close(conn->server_pcb); 00241 LWIP_ASSERT("error", err != ERR_OK); 00242 } 00243 LWIPERF_FREE(lwiperf_state_tcp_t, conn); 00244 } 00245 00246 /** Try to send more data on an iperf tcp session */ 00247 static err_t 00248 lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn) 00249 { 00250 int send_more; 00251 err_t err; 00252 u16_t txlen; 00253 u16_t txlen_max; 00254 void* txptr; 00255 u8_t apiflags; 00256 00257 LWIP_ASSERT("conn invalid", (conn != NULL) && conn->base.tcp && (conn->base.server == 0)); 00258 00259 do { 00260 send_more = 0; 00261 if (conn->settings.amount & PP_HTONL(0x80000000)) { 00262 /* this session is time-limited */ 00263 u32_t now = sys_now(); 00264 u32_t diff_ms = now - conn->time_started; 00265 u32_t time = (u32_t)-(s32_t)htonl(conn->settings.amount); 00266 u32_t time_ms = time * 10; 00267 if (diff_ms >= time_ms) { 00268 /* time specified by the client is over -> close the connection */ 00269 lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT); 00270 return ERR_OK; 00271 } 00272 } else { 00273 /* this session is byte-limited */ 00274 u32_t amount_bytes = htonl(conn->settings.amount); 00275 /* @todo: this can send up to 1*MSS more than requested... */ 00276 if (amount_bytes >= conn->bytes_transferred) { 00277 /* all requested bytes transferred -> close the connection */ 00278 lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT); 00279 return ERR_OK; 00280 } 00281 } 00282 00283 if (conn->bytes_transferred < 24) { 00284 /* transmit the settings a first time */ 00285 txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred]; 00286 txlen_max = (u16_t)(24 - conn->bytes_transferred); 00287 apiflags = TCP_WRITE_FLAG_COPY; 00288 } else if (conn->bytes_transferred < 48) { 00289 /* transmit the settings a second time */ 00290 txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred - 24]; 00291 txlen_max = (u16_t)(48 - conn->bytes_transferred); 00292 apiflags = TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE; 00293 send_more = 1; 00294 } else { 00295 /* transmit data */ 00296 /* @todo: every x bytes, transmit the settings again */ 00297 txptr = (void*)(size_t)&lwiperf_txbuf_const[conn->bytes_transferred % 10]; 00298 txlen_max = TCP_MSS; 00299 if (conn->bytes_transferred == 48) { /* @todo: fix this for intermediate settings, too */ 00300 txlen_max = TCP_MSS - 24; 00301 } 00302 apiflags = 0; /* no copying needed */ 00303 send_more = 1; 00304 } 00305 txlen = txlen_max; 00306 do { 00307 err = tcp_write(conn->conn_pcb, txptr, txlen, apiflags); 00308 if (err == ERR_MEM) { 00309 txlen /= 2; 00310 } 00311 } while ((err == ERR_MEM) && (txlen >= (TCP_MSS/2))); 00312 00313 if (err == ERR_OK) { 00314 conn->bytes_transferred += txlen; 00315 } else { 00316 send_more = 0; 00317 } 00318 } while(send_more); 00319 00320 tcp_output(conn->conn_pcb); 00321 return ERR_OK; 00322 } 00323 00324 /** TCP sent callback, try to send more data */ 00325 static err_t 00326 lwiperf_tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) 00327 { 00328 lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; 00329 /* @todo: check 'len' (e.g. to time ACK of all data)? for now, we just send more... */ 00330 LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb); 00331 LWIP_UNUSED_ARG(tpcb); 00332 LWIP_UNUSED_ARG(len); 00333 00334 conn->poll_count = 0; 00335 00336 return lwiperf_tcp_client_send_more(conn); 00337 } 00338 00339 /** TCP connected callback (active connection), send data now */ 00340 static err_t 00341 lwiperf_tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err) 00342 { 00343 lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; 00344 LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb); 00345 LWIP_UNUSED_ARG(tpcb); 00346 if (err != ERR_OK) { 00347 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); 00348 return ERR_OK; 00349 } 00350 conn->poll_count = 0; 00351 conn->time_started = sys_now(); 00352 return lwiperf_tcp_client_send_more(conn); 00353 } 00354 00355 /** Start TCP connection back to the client (either parallel or after the 00356 * receive test has finished. 00357 */ 00358 static err_t 00359 lwiperf_tx_start(lwiperf_state_tcp_t* conn) 00360 { 00361 err_t err; 00362 lwiperf_state_tcp_t* client_conn; 00363 struct tcp_pcb* newpcb; 00364 ip_addr_t remote_addr; 00365 u16_t remote_port; 00366 00367 client_conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); 00368 if (client_conn == NULL) { 00369 return ERR_MEM; 00370 } 00371 newpcb = tcp_new(); 00372 if (newpcb == NULL) { 00373 LWIPERF_FREE(lwiperf_state_tcp_t, client_conn); 00374 return ERR_MEM; 00375 } 00376 00377 memcpy(client_conn, conn, sizeof(lwiperf_state_tcp_t)); 00378 client_conn->base.server = 0; 00379 client_conn->server_pcb = NULL; 00380 client_conn->conn_pcb = newpcb; 00381 client_conn->time_started = sys_now(); /* @todo: set this again on 'connected' */ 00382 client_conn->poll_count = 0; 00383 client_conn->next_num = 4; /* initial nr is '4' since the header has 24 byte */ 00384 client_conn->bytes_transferred = 0; 00385 client_conn->settings.flags = 0; /* prevent the remote side starting back as client again */ 00386 00387 tcp_arg(newpcb, client_conn); 00388 tcp_sent(newpcb, lwiperf_tcp_client_sent); 00389 tcp_poll(newpcb, lwiperf_tcp_poll, 2U); 00390 tcp_err(newpcb, lwiperf_tcp_err); 00391 00392 ip_addr_copy(remote_addr, conn->conn_pcb->remote_ip); 00393 remote_port = (u16_t)htonl(client_conn->settings.remote_port); 00394 00395 err = tcp_connect(newpcb, &remote_addr, remote_port, lwiperf_tcp_client_connected); 00396 if (err != ERR_OK) { 00397 lwiperf_tcp_close(client_conn, LWIPERF_TCP_ABORTED_LOCAL); 00398 return err; 00399 } 00400 lwiperf_list_add(&client_conn->base); 00401 return ERR_OK; 00402 } 00403 00404 /** Receive data on an iperf tcp session */ 00405 static err_t 00406 lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) 00407 { 00408 u16_t tot_len; 00409 u32_t packet_idx; 00410 struct pbuf* q; 00411 lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; 00412 00413 LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb); 00414 LWIP_UNUSED_ARG(tpcb); 00415 00416 if (err != ERR_OK) { 00417 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); 00418 return ERR_OK; 00419 } 00420 if (p == NULL) { 00421 /* connection closed -> test done */ 00422 if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) == 00423 PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) { 00424 /* client requested transmission after end of test */ 00425 lwiperf_tx_start(conn); 00426 } 00427 lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_SERVER); 00428 return ERR_OK; 00429 } 00430 tot_len = p->tot_len; 00431 00432 conn->poll_count = 0; 00433 00434 if ((!conn->have_settings_buf) || ((conn->bytes_transferred -24) % (1024*128) == 0)) { 00435 /* wait for 24-byte header */ 00436 if (p->tot_len < sizeof(lwiperf_settings_t)) { 00437 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); 00438 pbuf_free(p); 00439 return ERR_VAL; 00440 } 00441 if (!conn->have_settings_buf) { 00442 if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) { 00443 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL); 00444 pbuf_free(p); 00445 return ERR_VAL; 00446 } 00447 conn->have_settings_buf = 1; 00448 if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) == 00449 PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) { 00450 /* client requested parallel transmission test */ 00451 err_t err2 = lwiperf_tx_start(conn); 00452 if (err2 != ERR_OK) { 00453 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR); 00454 pbuf_free(p); 00455 return err2; 00456 } 00457 } 00458 } else { 00459 if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) { 00460 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); 00461 pbuf_free(p); 00462 return ERR_VAL; 00463 } 00464 } 00465 conn->bytes_transferred += sizeof(lwiperf_settings_t); 00466 if (conn->bytes_transferred <= 24) { 00467 conn->time_started = sys_now(); 00468 tcp_recved(tpcb, p->tot_len); 00469 pbuf_free(p); 00470 return ERR_OK; 00471 } 00472 conn->next_num = 4; /* 24 bytes received... */ 00473 err = pbuf_header(p, -24); 00474 LWIP_ASSERT("pbuf_header failed", err == ERR_OK); 00475 } 00476 00477 packet_idx = 0; 00478 for (q = p; q != NULL; q = q->next) { 00479 #if LWIPERF_CHECK_RX_DATA 00480 const u8_t* payload = (const u8_t*)q->payload; 00481 u16_t i; 00482 for (i = 0; i < q->len; i++) { 00483 u8_t val = payload[i]; 00484 u8_t num = val - '0'; 00485 if (num == conn->next_num) { 00486 conn->next_num++; 00487 if (conn->next_num == 10) { 00488 conn->next_num = 0; 00489 } 00490 } else { 00491 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); 00492 pbuf_free(p); 00493 return ERR_VAL; 00494 } 00495 } 00496 packet_idx += i; 00497 #else 00498 packet_idx += q->len; 00499 #endif 00500 } 00501 LWIP_ASSERT("count mismatch", packet_idx == p->tot_len); 00502 conn->bytes_transferred += packet_idx; 00503 tcp_recved(tpcb, tot_len); 00504 pbuf_free(p); 00505 return ERR_OK; 00506 } 00507 00508 /** Error callback, iperf tcp session aborted */ 00509 static void 00510 lwiperf_tcp_err(void *arg, err_t err) 00511 { 00512 lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; 00513 LWIP_UNUSED_ARG(err); 00514 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); 00515 } 00516 00517 /** TCP poll callback, try to send more data */ 00518 static err_t 00519 lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb) 00520 { 00521 lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; 00522 LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb); 00523 LWIP_UNUSED_ARG(tpcb); 00524 if (++conn->poll_count >= LWIPERF_TCP_MAX_IDLE_SEC) { 00525 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL); 00526 return ERR_OK; /* lwiperf_tcp_close frees conn */ 00527 } 00528 00529 if (!conn->base.server) { 00530 lwiperf_tcp_client_send_more(conn); 00531 } 00532 00533 return ERR_OK; 00534 } 00535 00536 /** This is called when a new client connects for an iperf tcp session */ 00537 static err_t 00538 lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) 00539 { 00540 lwiperf_state_tcp_t *s, *conn; 00541 if ((err != ERR_OK) || (newpcb == NULL) || (arg == NULL)) { 00542 return ERR_VAL; 00543 } 00544 00545 s = (lwiperf_state_tcp_t*)arg; 00546 conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); 00547 if (conn == NULL) { 00548 return ERR_MEM; 00549 } 00550 memset(conn, 0, sizeof(lwiperf_state_tcp_t)); 00551 conn->base.tcp = 1; 00552 conn->base.server = 1; 00553 conn->base.related_server_state = &s->base; 00554 conn->server_pcb = s->server_pcb; 00555 conn->conn_pcb = newpcb; 00556 conn->time_started = sys_now(); 00557 conn->report_fn = s->report_fn; 00558 conn->report_arg = s->report_arg; 00559 00560 /* setup the tcp rx connection */ 00561 tcp_arg(newpcb, conn); 00562 tcp_recv(newpcb, lwiperf_tcp_recv); 00563 tcp_poll(newpcb, lwiperf_tcp_poll, 2U); 00564 tcp_err(conn->conn_pcb, lwiperf_tcp_err); 00565 00566 lwiperf_list_add(&conn->base); 00567 return ERR_OK; 00568 } 00569 00570 /** 00571 * @ingroup iperf 00572 * Start a TCP iperf server on the default TCP port (5001) and listen for 00573 * incoming connections from iperf clients. 00574 * 00575 * @returns a connection handle that can be used to abort the server 00576 * by calling @ref lwiperf_abort() 00577 */ 00578 void* 00579 lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg) 00580 { 00581 return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT, 00582 report_fn, report_arg); 00583 } 00584 00585 /** 00586 * @ingroup iperf 00587 * Start a TCP iperf server on a specific IP address and port and listen for 00588 * incoming connections from iperf clients. 00589 * 00590 * @returns a connection handle that can be used to abort the server 00591 * by calling @ref lwiperf_abort() 00592 */ 00593 void* 00594 lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port, 00595 lwiperf_report_fn report_fn, void* report_arg) 00596 { 00597 err_t err; 00598 struct tcp_pcb* pcb; 00599 lwiperf_state_tcp_t* s; 00600 00601 if (local_addr == NULL) { 00602 return NULL; 00603 } 00604 00605 s = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); 00606 if (s == NULL) { 00607 return NULL; 00608 } 00609 memset(s, 0, sizeof(lwiperf_state_tcp_t)); 00610 s->base.tcp = 1; 00611 s->base.server = 1; 00612 s->report_fn = report_fn; 00613 s->report_arg = report_arg; 00614 00615 pcb = tcp_new(); 00616 if (pcb != NULL) { 00617 err = tcp_bind(pcb, local_addr, local_port); 00618 if (err == ERR_OK) { 00619 s->server_pcb = tcp_listen_with_backlog(pcb, 1); 00620 } 00621 } 00622 if (s->server_pcb == NULL) { 00623 if (pcb != NULL) { 00624 tcp_close(pcb); 00625 } 00626 LWIPERF_FREE(lwiperf_state_tcp_t, s); 00627 return NULL; 00628 } 00629 pcb = NULL; 00630 00631 tcp_arg(s->server_pcb, s); 00632 tcp_accept(s->server_pcb, lwiperf_tcp_accept); 00633 00634 lwiperf_list_add(&s->base); 00635 return s; 00636 } 00637 00638 /** 00639 * @ingroup iperf 00640 * Abort an iperf session (handle returned by lwiperf_start_tcp_server*()) 00641 */ 00642 void 00643 lwiperf_abort(void* lwiperf_session) 00644 { 00645 lwiperf_state_base_t* i, *dealloc, *last = NULL; 00646 00647 for (i = lwiperf_all_connections; i != NULL; ) { 00648 if ((i == lwiperf_session) || (i->related_server_state == lwiperf_session)) { 00649 dealloc = i; 00650 i = i->next; 00651 if (last != NULL) { 00652 last->next = i; 00653 } 00654 LWIPERF_FREE(lwiperf_state_tcp_t, dealloc); /* @todo: type? */ 00655 } else { 00656 last = i; 00657 i = i->next; 00658 } 00659 } 00660 } 00661 00662 #endif /* LWIP_IPV4 && LWIP_TCP */
Generated on Tue Jul 12 2022 13:15:53 by
1.7.2
