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 OmniWheels 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 && LWIP_CALLBACK_API 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)lwip_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 = lwip_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 = LWIP_CONST_CAST(void*, &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)lwip_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 u8_t tmp; 00409 u16_t tot_len; 00410 u32_t packet_idx; 00411 struct pbuf* q; 00412 lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; 00413 00414 LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb); 00415 LWIP_UNUSED_ARG(tpcb); 00416 00417 if (err != ERR_OK) { 00418 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); 00419 return ERR_OK; 00420 } 00421 if (p == NULL) { 00422 /* connection closed -> test done */ 00423 if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) == 00424 PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) { 00425 /* client requested transmission after end of test */ 00426 lwiperf_tx_start(conn); 00427 } 00428 lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_SERVER); 00429 return ERR_OK; 00430 } 00431 tot_len = p->tot_len; 00432 00433 conn->poll_count = 0; 00434 00435 if ((!conn->have_settings_buf) || ((conn->bytes_transferred -24) % (1024*128) == 0)) { 00436 /* wait for 24-byte header */ 00437 if (p->tot_len < sizeof(lwiperf_settings_t)) { 00438 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); 00439 pbuf_free(p); 00440 return ERR_VAL; 00441 } 00442 if (!conn->have_settings_buf) { 00443 if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) { 00444 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL); 00445 pbuf_free(p); 00446 return ERR_VAL; 00447 } 00448 conn->have_settings_buf = 1; 00449 if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) == 00450 PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) { 00451 /* client requested parallel transmission test */ 00452 err_t err2 = lwiperf_tx_start(conn); 00453 if (err2 != ERR_OK) { 00454 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR); 00455 pbuf_free(p); 00456 return err2; 00457 } 00458 } 00459 } else { 00460 if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) { 00461 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); 00462 pbuf_free(p); 00463 return ERR_VAL; 00464 } 00465 } 00466 conn->bytes_transferred += sizeof(lwiperf_settings_t); 00467 if (conn->bytes_transferred <= 24) { 00468 conn->time_started = sys_now(); 00469 tcp_recved(tpcb, p->tot_len); 00470 pbuf_free(p); 00471 return ERR_OK; 00472 } 00473 conn->next_num = 4; /* 24 bytes received... */ 00474 tmp = pbuf_header(p, -24); 00475 LWIP_ASSERT("pbuf_header failed", tmp == 0); 00476 } 00477 00478 packet_idx = 0; 00479 for (q = p; q != NULL; q = q->next) { 00480 #if LWIPERF_CHECK_RX_DATA 00481 const u8_t* payload = (const u8_t*)q->payload; 00482 u16_t i; 00483 for (i = 0; i < q->len; i++) { 00484 u8_t val = payload[i]; 00485 u8_t num = val - '0'; 00486 if (num == conn->next_num) { 00487 conn->next_num++; 00488 if (conn->next_num == 10) { 00489 conn->next_num = 0; 00490 } 00491 } else { 00492 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); 00493 pbuf_free(p); 00494 return ERR_VAL; 00495 } 00496 } 00497 #endif 00498 packet_idx += q->len; 00499 } 00500 LWIP_ASSERT("count mismatch", packet_idx == p->tot_len); 00501 conn->bytes_transferred += packet_idx; 00502 tcp_recved(tpcb, tot_len); 00503 pbuf_free(p); 00504 return ERR_OK; 00505 } 00506 00507 /** Error callback, iperf tcp session aborted */ 00508 static void 00509 lwiperf_tcp_err(void *arg, err_t err) 00510 { 00511 lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; 00512 LWIP_UNUSED_ARG(err); 00513 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); 00514 } 00515 00516 /** TCP poll callback, try to send more data */ 00517 static err_t 00518 lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb) 00519 { 00520 lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; 00521 LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb); 00522 LWIP_UNUSED_ARG(tpcb); 00523 if (++conn->poll_count >= LWIPERF_TCP_MAX_IDLE_SEC) { 00524 lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL); 00525 return ERR_OK; /* lwiperf_tcp_close frees conn */ 00526 } 00527 00528 if (!conn->base.server) { 00529 lwiperf_tcp_client_send_more(conn); 00530 } 00531 00532 return ERR_OK; 00533 } 00534 00535 /** This is called when a new client connects for an iperf tcp session */ 00536 static err_t 00537 lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) 00538 { 00539 lwiperf_state_tcp_t *s, *conn; 00540 if ((err != ERR_OK) || (newpcb == NULL) || (arg == NULL)) { 00541 return ERR_VAL; 00542 } 00543 00544 s = (lwiperf_state_tcp_t*)arg; 00545 conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); 00546 if (conn == NULL) { 00547 return ERR_MEM; 00548 } 00549 memset(conn, 0, sizeof(lwiperf_state_tcp_t)); 00550 conn->base.tcp = 1; 00551 conn->base.server = 1; 00552 conn->base.related_server_state = &s->base; 00553 conn->server_pcb = s->server_pcb; 00554 conn->conn_pcb = newpcb; 00555 conn->time_started = sys_now(); 00556 conn->report_fn = s->report_fn; 00557 conn->report_arg = s->report_arg; 00558 00559 /* setup the tcp rx connection */ 00560 tcp_arg(newpcb, conn); 00561 tcp_recv(newpcb, lwiperf_tcp_recv); 00562 tcp_poll(newpcb, lwiperf_tcp_poll, 2U); 00563 tcp_err(conn->conn_pcb, lwiperf_tcp_err); 00564 00565 lwiperf_list_add(&conn->base); 00566 return ERR_OK; 00567 } 00568 00569 /** 00570 * @ingroup iperf 00571 * Start a TCP iperf server on the default TCP port (5001) and listen for 00572 * incoming connections from iperf clients. 00573 * 00574 * @returns a connection handle that can be used to abort the server 00575 * by calling @ref lwiperf_abort() 00576 */ 00577 void* 00578 lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg) 00579 { 00580 return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT, 00581 report_fn, report_arg); 00582 } 00583 00584 /** 00585 * @ingroup iperf 00586 * Start a TCP iperf server on a specific IP address and port and listen for 00587 * incoming connections from iperf clients. 00588 * 00589 * @returns a connection handle that can be used to abort the server 00590 * by calling @ref lwiperf_abort() 00591 */ 00592 void* 00593 lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port, 00594 lwiperf_report_fn report_fn, void* report_arg) 00595 { 00596 err_t err; 00597 struct tcp_pcb* pcb; 00598 lwiperf_state_tcp_t* s; 00599 00600 if (local_addr == NULL) { 00601 return NULL; 00602 } 00603 00604 s = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); 00605 if (s == NULL) { 00606 return NULL; 00607 } 00608 memset(s, 0, sizeof(lwiperf_state_tcp_t)); 00609 s->base.tcp = 1; 00610 s->base.server = 1; 00611 s->report_fn = report_fn; 00612 s->report_arg = report_arg; 00613 00614 pcb = tcp_new(); 00615 if (pcb != NULL) { 00616 err = tcp_bind(pcb, local_addr, local_port); 00617 if (err == ERR_OK) { 00618 s->server_pcb = tcp_listen_with_backlog(pcb, 1); 00619 } 00620 } 00621 if (s->server_pcb == NULL) { 00622 if (pcb != NULL) { 00623 tcp_close(pcb); 00624 } 00625 LWIPERF_FREE(lwiperf_state_tcp_t, s); 00626 return NULL; 00627 } 00628 pcb = NULL; 00629 00630 tcp_arg(s->server_pcb, s); 00631 tcp_accept(s->server_pcb, lwiperf_tcp_accept); 00632 00633 lwiperf_list_add(&s->base); 00634 return s; 00635 } 00636 00637 /** 00638 * @ingroup iperf 00639 * Abort an iperf session (handle returned by lwiperf_start_tcp_server*()) 00640 */ 00641 void 00642 lwiperf_abort(void* lwiperf_session) 00643 { 00644 lwiperf_state_base_t* i, *dealloc, *last = NULL; 00645 00646 for (i = lwiperf_all_connections; i != NULL; ) { 00647 if ((i == lwiperf_session) || (i->related_server_state == lwiperf_session)) { 00648 dealloc = i; 00649 i = i->next; 00650 if (last != NULL) { 00651 last->next = i; 00652 } 00653 LWIPERF_FREE(lwiperf_state_tcp_t, dealloc); /* @todo: type? */ 00654 } else { 00655 last = i; 00656 i = i->next; 00657 } 00658 } 00659 } 00660 00661 #endif /* LWIP_IPV4 && LWIP_TCP && LWIP_CALLBACK_API */
Generated on Fri Jul 22 2022 04:53:52 by
1.7.2
