Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers udpsocket_echotest_burst.cpp Source File

udpsocket_echotest_burst.cpp

00001 /*
00002  * Copyright (c) 2018, ARM Limited, All Rights Reserved
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00006  * not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00013  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "mbed.h"
00019 #include MBED_CONF_APP_HEADER_FILE
00020 #include "UDPSocket.h"
00021 #include "greentea-client/test_env.h"
00022 #include "unity/unity.h"
00023 #include "utest.h"
00024 #include "udp_tests.h"
00025 
00026 using namespace utest::v1;
00027 
00028 namespace
00029 {
00030     static const int SIGNAL_SIGIO = 0x1;
00031     static const int SIGIO_TIMEOUT = 5000; //[ms]
00032     static const int RECV_TIMEOUT = 1; //[s]
00033 
00034     static const int BURST_CNT = 100;
00035     static const int BURST_PKTS = 5;
00036     static const int PKG_SIZES[BURST_PKTS] = {100, 200, 300, 120, 500};
00037     static const int RECV_TOTAL = 1220;
00038 
00039     static const double EXPECTED_LOSS_RATIO = 0.0;
00040     static const double TOLERATED_LOSS_RATIO = 0.3;
00041 
00042     typedef struct pkg {
00043         int len;
00044         char *payload;
00045     } pkg_t;
00046     pkg_t tx_buffers[BURST_PKTS];
00047     char rx_buffer[500] = {0};
00048 }
00049 
00050 void prepare_tx_buffers() {
00051     // TX buffers to be preserved for comparison
00052     for (int x = 0; x < BURST_PKTS; x++) {
00053         tx_buffers[x].len = PKG_SIZES[x];
00054         tx_buffers[x].payload = (char*) (malloc(PKG_SIZES[x]));
00055         TEST_ASSERT_NOT_NULL(tx_buffers[x].payload);
00056         fill_tx_buffer_ascii(tx_buffers[x].payload, tx_buffers[x].len);
00057     }
00058 }
00059 
00060 void free_tx_buffers() {
00061     for (int x = 0; x < BURST_PKTS; x++) {
00062         free(tx_buffers[x].payload);
00063     }
00064 }
00065 
00066 static void _sigio_handler(osThreadId id) {
00067     osSignalSet(id, SIGNAL_SIGIO);
00068 }
00069 
00070 void UDPSOCKET_ECHOTEST_BURST()
00071 {
00072     SocketAddress udp_addr;
00073     get_interface()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &udp_addr);
00074     udp_addr.set_port(MBED_CONF_APP_ECHO_SERVER_PORT);
00075 
00076     UDPSocket sock;
00077     const int TIMEOUT = 5000; // [ms]
00078     TEST_ASSERT_EQUAL(NSAPI_ERROR_OK , sock.open(get_interface()));
00079     sock.set_timeout(TIMEOUT);
00080     sock.sigio(callback(_sigio_handler, Thread::gettid()));
00081 
00082     // TX buffers to be preserved for comparison
00083     prepare_tx_buffers();
00084 
00085     int bt_total = 0;
00086     int ok_bursts = 0;
00087     int pkg_fail = 0;
00088     int recvd = 0;
00089     int recv_timeout = RECV_TIMEOUT;;
00090     SocketAddress temp_addr;
00091     for (int i = 0; i < BURST_CNT; i++) {
00092         for (int x = 0; x < BURST_PKTS; x++) {
00093             TEST_ASSERT_EQUAL(tx_buffers[x].len, sock.sendto(udp_addr, tx_buffers[x].payload, tx_buffers[x].len));
00094         }
00095 
00096         bt_total = 0;
00097         recvd = 0;
00098         for (int j = 0; j < BURST_PKTS; j++) {
00099             recvd = sock.recvfrom(&temp_addr, rx_buffer, 500);
00100             if (recvd == NSAPI_ERROR_WOULD_BLOCK ) {
00101                 if(osSignalWait(SIGNAL_SIGIO, SIGIO_TIMEOUT).status == osEventTimeout) {
00102                     pkg_fail += BURST_PKTS-j;
00103                     break;
00104                 }
00105             } else if (recvd < 0) {
00106                 pkg_fail += BURST_PKTS-j; // Assume all the following packets of the burst to be lost
00107                 printf("[%02d] network error %d\n", i, recvd);
00108                 wait(recv_timeout);
00109                 recv_timeout *= 2; // Back off,
00110                 break;
00111             } else if (temp_addr != udp_addr) {
00112                 printf("[%02d] packet from wrong address\n", i);
00113                 --j;
00114                 continue;
00115             }
00116 
00117             recv_timeout = recv_timeout > RECV_TIMEOUT ? recv_timeout/2 : RECV_TIMEOUT;
00118 
00119             // Packets might arrive unordered
00120             for (int k = 0; k < BURST_PKTS; k++) {
00121                 if (tx_buffers[k].len == recvd &&
00122                     (memcmp(tx_buffers[k].payload, rx_buffer, recvd) == 0)) {
00123                     bt_total += recvd;
00124                 }
00125             }
00126         }
00127 
00128         if (bt_total == RECV_TOTAL) {
00129             ok_bursts++;
00130         } else {
00131             drop_bad_packets(sock, TIMEOUT);
00132             printf("[%02d] burst failure\n", i);
00133         }
00134     }
00135 
00136     free_tx_buffers();
00137 
00138     double loss_ratio = 1 - ((double)(BURST_CNT*BURST_PKTS-pkg_fail) / (double)(BURST_CNT*BURST_PKTS));
00139     printf("Packets sent: %d, packets received %d, loss ratio %.2lf\r\n",
00140         BURST_CNT*BURST_PKTS, BURST_CNT*BURST_PKTS-pkg_fail, loss_ratio);
00141     // Packet loss up to 30% tolerated
00142     TEST_ASSERT_DOUBLE_WITHIN(TOLERATED_LOSS_RATIO, EXPECTED_LOSS_RATIO, loss_ratio);
00143     // 70% of the bursts need to be successful
00144     TEST_ASSERT_INT_WITHIN(3*(BURST_CNT/10), BURST_CNT, ok_bursts);
00145 
00146     TEST_ASSERT_EQUAL(NSAPI_ERROR_OK , sock.close());
00147 }
00148 
00149 void UDPSOCKET_ECHOTEST_BURST_NONBLOCK()
00150 {
00151     SocketAddress udp_addr;
00152     get_interface()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &udp_addr);
00153     udp_addr.set_port(MBED_CONF_APP_ECHO_SERVER_PORT);
00154 
00155     UDPSocket sock;
00156     TEST_ASSERT_EQUAL(NSAPI_ERROR_OK , sock.open(get_interface()));
00157     sock.set_blocking(false);
00158     sock.sigio(callback(_sigio_handler, Thread::gettid()));
00159 
00160     // TX buffers to be preserved for comparison
00161     prepare_tx_buffers();
00162 
00163     int ok_bursts = 0;
00164     int pkg_fail = 0;
00165     SocketAddress temp_addr;
00166     int recvd = 0;
00167     int bt_total = 0;
00168     for (int i = 0; i < BURST_CNT; i++) {
00169         for (int x = 0; x < BURST_PKTS; x++) {
00170             TEST_ASSERT_EQUAL(tx_buffers[x].len, sock.sendto(udp_addr, tx_buffers[x].payload, tx_buffers[x].len));
00171         }
00172 
00173         recvd = 0;
00174         bt_total = 0;
00175         for (int j = 0; j < BURST_PKTS; j++) {
00176             recvd = sock.recvfrom(&temp_addr, rx_buffer, 500);
00177             if (recvd == NSAPI_ERROR_WOULD_BLOCK ) {
00178                 if(osSignalWait(SIGNAL_SIGIO, SIGIO_TIMEOUT).status == osEventTimeout) {
00179                     pkg_fail += BURST_PKTS-j;
00180                     break;
00181                 }
00182                 --j;
00183                 continue;
00184             } else if (recvd < 0) {
00185                 pkg_fail++;
00186                 continue;
00187             } else if (temp_addr != udp_addr) {
00188                 continue;
00189             }
00190 
00191             // Packets might arrive unordered
00192             for (int k = 0; k < BURST_PKTS; k++) {
00193                 if (tx_buffers[k].len == recvd &&
00194                     (memcmp(tx_buffers[k].payload, rx_buffer, recvd) == 0)) {
00195                     bt_total += recvd;
00196                     goto PKT_OK;
00197                 }
00198             }
00199             printf("[bt#%02d] corrupted packet...", i);
00200             pkg_fail++;
00201             break;
00202 PKT_OK:
00203             continue;
00204         }
00205 
00206         if (bt_total == RECV_TOTAL) {
00207             ok_bursts++;
00208         } else {
00209             drop_bad_packets(sock, -1); // timeout equivalent to set_blocking(false)
00210             sock.set_blocking(false);
00211         }
00212     }
00213 
00214     free_tx_buffers();
00215 
00216     double loss_ratio = 1 - ((double)(BURST_CNT*BURST_PKTS-pkg_fail) / (double)(BURST_CNT*BURST_PKTS));
00217     printf("Packets sent: %d, packets received %d, loss ratio %.2lf\r\n",
00218         BURST_CNT*BURST_PKTS, BURST_CNT*BURST_PKTS-pkg_fail, loss_ratio);
00219     // Packet loss up to 30% tolerated
00220     TEST_ASSERT_DOUBLE_WITHIN(TOLERATED_LOSS_RATIO, EXPECTED_LOSS_RATIO, loss_ratio);
00221     // 70% of the bursts need to be successful
00222     TEST_ASSERT_INT_WITHIN(3*(BURST_CNT/10), BURST_CNT, ok_bursts);
00223 
00224     TEST_ASSERT_EQUAL(NSAPI_ERROR_OK , sock.close());
00225 }
00226