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