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.
cmd_socket.cpp
00001 /* 00002 * Copyright (c) 2018 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 #include "mbed.h" 00017 #include "NetworkStack.h" 00018 #include "UDPSocket.h" 00019 #include "TCPSocket.h" 00020 #include "TCPServer.h" 00021 #include "NetworkInterface.h" 00022 #include "SocketAddress.h" 00023 #include "Queue.h" 00024 00025 #include <vector> 00026 #include <cctype> 00027 #include <cassert> 00028 #include <cstring> 00029 #ifndef __STDC_FORMAT_MACROS 00030 #define __STDC_FORMAT_MACROS 00031 #endif 00032 #include <inttypes.h> 00033 00034 #include "mbed-client-cli/ns_cmdline.h" 00035 #include "mbed-trace/mbed_trace.h" 00036 #include "strconv.h" 00037 00038 #define TRACE_GROUP "Asck" 00039 00040 #include "cmd_ifconfig.h" 00041 #include "cmd_socket.h" 00042 00043 #define SIGNAL_SIGIO 0x1 00044 #define PACKET_SIZE_ARRAY_LEN 5 00045 00046 #define MAN_SOCKET "\r\nSOCKET API\r\n"\ 00047 "\r\n"\ 00048 "socket <operation> [options]\r\n\r\n"\ 00049 " new <type>\r\n" \ 00050 " type: UDPSocket|TCPSocket|TCPServer\r\n"\ 00051 " return socket id\r\n"\ 00052 " <id> delete\r\n"\ 00053 " remote the space allocated for Socket\r\n"\ 00054 " <id> open\r\n"\ 00055 " <id> close\r\n"\ 00056 " <id> bind [port] <port> [addr <addr>]\r\n"\ 00057 " <id> set_blocking <bool>\r\n"\ 00058 " <id> set_timeout <ms>\r\n"\ 00059 " <id> register_sigio_cb\r\n"\ 00060 " <id> set_RFC_864_pattern_check <true|false>\r\n"\ 00061 "\r\nFor UDPSocket\r\n"\ 00062 " <id> sendto <addr> <port> (\"msg\" | --data_len <len>)\r\n"\ 00063 " \"msg\" Send packet with defined string content\r\n"\ 00064 " --data_len Send packet with random content with size <len>\r\n"\ 00065 " <id> recvfrom <len>\r\n"\ 00066 " <id> start_udp_receiver_thread --max_data_len <len> [--packets <N>]\r\n"\ 00067 " --max_data_len Size of input buffer to fill up\r\n"\ 00068 " --packets Receive N number of packets, default 1\r\n"\ 00069 "\r\nFor TCPSocket\r\n"\ 00070 " <id> connect <host> <port>\r\n"\ 00071 " <id> send (\"msg\" | --data_len <len>)\r\n"\ 00072 " <id> recv <len>\r\n"\ 00073 " <id> start_tcp_receiver_thread --data_len <len> [--max_recv_len <L>] [--repeat <N>]\r\n"\ 00074 " --data_len Size of input buffer to fill up\r\n"\ 00075 " --max_recv_len Read maximum of L bytes in at a time. Default full buffer <len>\r\n"\ 00076 " --repeat Repeat buffer filling N times, default 1\r\n"\ 00077 " <id> join_tcp_receiver_thread\r\n"\ 00078 " <id> start_bg_traffic_thread\r\n"\ 00079 " <id> join_bg_traffic_thread\r\n"\ 00080 " <id> setsockopt_keepalive <seconds[0-7200]>\r\n"\ 00081 " <id> getsockopt_keepalive\r\n"\ 00082 "\r\nFor TCPServer\r\n"\ 00083 " <id> listen [backlog]\r\n"\ 00084 " <id> accept <new_id>\r\n"\ 00085 " accept new connection into <new_id> socket. Requires <new_id> to be pre-allocated.\r\n"\ 00086 "\r\nOther options\r\n"\ 00087 " print-mode [--string|--hex|--disabled] [--col-width <width>]" 00088 00089 class SInfo; 00090 static Queue<SInfo, 10> event_queue; 00091 static int id_count = 0; 00092 00093 class SInfo { 00094 public: 00095 enum SocketType { 00096 TCP_CLIENT, 00097 TCP_SERVER, 00098 UDP 00099 }; 00100 SInfo(TCPSocket *sock): 00101 _id(id_count++), 00102 _sock(sock), 00103 _type(SInfo::TCP_CLIENT), 00104 _blocking(true), 00105 _dataLen(0), 00106 _maxRecvLen(0), 00107 _repeatBufferFill(1), 00108 _receivedTotal(0), 00109 _receiverThread(NULL), 00110 _receiveBuffer(NULL), 00111 _senderThreadId(NULL), 00112 _receiverThreadId(NULL), 00113 _packetSizes(NULL), 00114 _check_pattern(false) 00115 { 00116 assert(sock); 00117 } 00118 SInfo(TCPServer *sock): 00119 _id(id_count++), 00120 _sock(sock), 00121 _type(SInfo::TCP_SERVER), 00122 _blocking(true), 00123 _dataLen(0), 00124 _maxRecvLen(0), 00125 _repeatBufferFill(1), 00126 _receivedTotal(0), 00127 _receiverThread(NULL), 00128 _receiveBuffer(NULL), 00129 _senderThreadId(NULL), 00130 _receiverThreadId(NULL), 00131 _packetSizes(NULL), 00132 _check_pattern(false) 00133 { 00134 assert(sock); 00135 } 00136 SInfo(UDPSocket *sock): 00137 _id(id_count++), 00138 _sock(sock), 00139 _type(SInfo::UDP), 00140 _blocking(true), 00141 _dataLen(0), 00142 _maxRecvLen(0), 00143 _repeatBufferFill(1), 00144 _receivedTotal(0), 00145 _receiverThread(NULL), 00146 _receiveBuffer(NULL), 00147 _senderThreadId(NULL), 00148 _receiverThreadId(NULL), 00149 _packetSizes(NULL), 00150 _check_pattern(false) 00151 { 00152 assert(sock); 00153 } 00154 ~SInfo() 00155 { 00156 this->_sock->sigio(Callback<void()>()); 00157 if (this->_receiverThread) { 00158 this->_receiverThread->terminate(); 00159 delete this->_receiverThread; 00160 } 00161 if (this->_receiveBuffer) { 00162 delete this->_receiveBuffer; 00163 } 00164 delete this->_sock; 00165 } 00166 int id() const 00167 { 00168 return this->_id; 00169 } 00170 Socket &socket() 00171 { 00172 return *(this->_sock); 00173 } 00174 Socket &socket() const 00175 { 00176 return *(this->_sock); 00177 } 00178 TCPSocket *tcp_socket() 00179 { 00180 return this->_type == SInfo::TCP_CLIENT ? static_cast<TCPSocket *>(this->_sock) : NULL; 00181 } 00182 TCPServer *tcp_server() 00183 { 00184 return this->_type == SInfo::TCP_SERVER ? static_cast<TCPServer *>(this->_sock) : NULL; 00185 } 00186 UDPSocket *udp_socket() 00187 { 00188 return this->_type == SInfo::UDP ? static_cast<UDPSocket *>(this->_sock) : NULL; 00189 } 00190 SInfo::SocketType type() const 00191 { 00192 return this->_type; 00193 } 00194 void setDataCount(int dataCount) 00195 { 00196 this->_dataLen = dataCount; 00197 } 00198 int getDataCount() 00199 { 00200 return this->_dataLen; 00201 } 00202 void setReceiverThread(Thread *receiverThread) 00203 { 00204 this->_receiverThread = receiverThread; 00205 } 00206 Thread *getReceiverThread() 00207 { 00208 return this->_receiverThread; 00209 } 00210 void setReceiveBuffer(uint8_t *receiveBuffer) 00211 { 00212 this->_receiveBuffer = receiveBuffer; 00213 } 00214 uint8_t *getReceiveBuffer() 00215 { 00216 return this->_receiveBuffer; 00217 } 00218 void setMaxRecvLen(int recvLen) 00219 { 00220 this->_maxRecvLen = recvLen; 00221 } 00222 int getMaxRecvLen() 00223 { 00224 return this->_maxRecvLen; 00225 } 00226 void setRepeatBufferFill(int n) 00227 { 00228 this->_repeatBufferFill = n; 00229 } 00230 int getRepeatBufferFill() 00231 { 00232 return this->_repeatBufferFill; 00233 } 00234 void setRecvTotal(int n) 00235 { 00236 this->_receivedTotal = n; 00237 } 00238 int getRecvTotal() 00239 { 00240 return this->_receivedTotal; 00241 } 00242 void setSenderThreadId(osThreadId threadID) 00243 { 00244 this->_senderThreadId = threadID; 00245 } 00246 void setReceiverThreadId(osThreadId threadID) 00247 { 00248 this->_receiverThreadId = threadID; 00249 } 00250 osThreadId getSenderThreadId() 00251 { 00252 return this->_senderThreadId; 00253 } 00254 osThreadId getReceiverThreadId() 00255 { 00256 return this->_receiverThreadId; 00257 } 00258 void setPacketSizeArray(int *ptr) 00259 { 00260 this->_packetSizes = ptr; 00261 } 00262 int *getPacketSizeArray() 00263 { 00264 return this->_packetSizes; 00265 } 00266 void setUnavailable() 00267 { 00268 this->_available = false; 00269 } 00270 void setAvailable() 00271 { 00272 this->_available = true; 00273 } 00274 bool available() 00275 { 00276 return this->_available; 00277 } 00278 void set_pattern_check(bool enabled) 00279 { 00280 _check_pattern = enabled; 00281 }; 00282 bool check_pattern(void *buffer, size_t len); 00283 00284 const char *type_str() const 00285 { 00286 const char *str; 00287 switch (this->_type) { 00288 case SInfo::TCP_CLIENT: 00289 str = "TCPSocket"; 00290 break; 00291 case SInfo::TCP_SERVER: 00292 str = "TCPServer"; 00293 break; 00294 case SInfo::UDP: 00295 str = "UDPSocket"; 00296 break; 00297 default: 00298 assert(0); 00299 break; 00300 } 00301 return str; 00302 } 00303 bool blocking() const 00304 { 00305 return this->_blocking; 00306 } 00307 void set_blocking(bool blocking) 00308 { 00309 socket().set_blocking(blocking); 00310 this->_blocking = blocking; 00311 } 00312 bool can_connect() 00313 { 00314 return (this->type() == SInfo::TCP_CLIENT); 00315 } 00316 bool can_bind() 00317 { 00318 return (this->type() == SInfo::UDP || this->type() == SInfo::TCP_SERVER); 00319 } 00320 bool can_send() 00321 { 00322 return (this->type() == SInfo::TCP_CLIENT); 00323 } 00324 bool can_recv() 00325 { 00326 return (this->type() == SInfo::TCP_CLIENT); 00327 } 00328 bool can_sendto() 00329 { 00330 return (this->type() == SInfo::UDP); 00331 } 00332 bool can_recvfrom() 00333 { 00334 return (this->type() == SInfo::UDP); 00335 } 00336 bool can_listen() 00337 { 00338 return (this->type() == SInfo::TCP_SERVER); 00339 } 00340 bool can_accept() 00341 { 00342 return (this->type() == SInfo::TCP_SERVER); 00343 } 00344 private: 00345 const int _id; 00346 Socket *_sock; 00347 const SInfo::SocketType _type; 00348 bool _blocking; 00349 int _dataLen; 00350 int _maxRecvLen; 00351 int _repeatBufferFill; 00352 int _receivedTotal; 00353 Thread *_receiverThread; 00354 uint8_t *_receiveBuffer; 00355 osThreadId _senderThreadId; 00356 osThreadId _receiverThreadId; 00357 int *_packetSizes; 00358 bool _available; 00359 bool _check_pattern; 00360 00361 SInfo(); 00362 }; 00363 00364 static std::vector<SInfo *> m_sockets; 00365 00366 static enum { 00367 PRINT_DISABLED, 00368 PRINT_STRING, 00369 PRINT_HEX 00370 } printing_mode = PRINT_STRING; 00371 static int printing_col_width = 20; 00372 00373 static int cmd_socket(int argc, char *argv[]); 00374 static void print_data(const uint8_t *buf, int len); 00375 static void print_data_as_string(const uint8_t *buf, int len, int col_width); 00376 static void print_data_as_hex(const uint8_t *buf, int len, int col_width); 00377 00378 /** Generate RFC 864 example pattern. 00379 * 00380 * Pattern is 72 chraracter lines of the ASCII printing characters ending with "\r\n". 00381 * There are 95 printing characters in the ASCII character set. 00382 * Example: `nc echo.mbedcloudtesting.com 19 | dd bs=1 count=222` 00383 * !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefg 00384 * !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgh 00385 * "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghi 00386 * 00387 * NOTE: Pattern starts with space, not ! 00388 * 00389 * \param offset Start pattern from offset 00390 * \param len Length of pattern to generate. 00391 */ 00392 static void generate_RFC_864_pattern(size_t offset, uint8_t *buf, size_t len) 00393 { 00394 while (len--) { 00395 if (offset % 74 == 72) { 00396 *buf++ = '\r'; 00397 } else if (offset % 74 == 73) { 00398 *buf++ = '\n'; 00399 } else { 00400 *buf++ = ' ' + (offset % 74 + offset / 74) % 95 ; 00401 } 00402 offset++; 00403 } 00404 } 00405 00406 bool SInfo::check_pattern(void *buffer, size_t len) 00407 { 00408 if (!_check_pattern) { 00409 return true; 00410 } 00411 void *buf = malloc(len); 00412 if (!buf) { 00413 return false; 00414 } 00415 size_t offset = _receivedTotal; 00416 generate_RFC_864_pattern(offset, (uint8_t *)buf, len); 00417 bool match = memcmp(buf, buffer, len) == 0; 00418 if (!match) { 00419 cmd_printf("Pattern check failed\r\nWAS:%.*s\r\nREF:%.*s\r\n", len, (char *)buffer, len, (char *)buf); 00420 } 00421 free(buf); 00422 return match; 00423 } 00424 00425 static void sigio_handler(SInfo *info) 00426 { 00427 if (info->getReceiverThreadId()) { 00428 osSignalSet(info->getReceiverThreadId(), SIGNAL_SIGIO); 00429 } 00430 if (info->getSenderThreadId()) { 00431 osSignalSet(info->getSenderThreadId(), SIGNAL_SIGIO); 00432 } 00433 } 00434 00435 void cmd_socket_init(void) 00436 { 00437 cmd_add("socket", cmd_socket, "socket", MAN_SOCKET); 00438 } 00439 00440 int handle_nsapi_error(const char *function, nsapi_error_t ret) 00441 { 00442 if (ret != NSAPI_ERROR_OK ) { 00443 cmd_printf("%s returned: %d -> %s\r\n", function, ret, networkstack_error_to_str(ret)); 00444 return CMDLINE_RETCODE_FAIL; 00445 } 00446 return CMDLINE_RETCODE_SUCCESS; 00447 } 00448 00449 int handle_nsapi_size_or_error(const char *function, nsapi_size_or_error_t ret) 00450 { 00451 if (ret < 0) { 00452 return handle_nsapi_error(function, ret); 00453 } else { 00454 cmd_printf("%s returned: %d\r\n", function, ret); 00455 } 00456 return CMDLINE_RETCODE_SUCCESS; 00457 } 00458 00459 static SInfo *get_sinfo(int id) 00460 { 00461 00462 for (std::vector<SInfo *>::iterator it = m_sockets.begin(); it != m_sockets.end(); it++) { 00463 if ((*it)->id() == id) { 00464 return *it; 00465 } 00466 } 00467 return NULL; 00468 } 00469 00470 static int del_sinfo(SInfo *info) 00471 { 00472 for (std::vector<SInfo *>::iterator it = m_sockets.begin(); it != m_sockets.end(); it++) { 00473 if ((*it) == info) { 00474 delete info; 00475 m_sockets.erase(it); 00476 return CMDLINE_RETCODE_SUCCESS; 00477 } 00478 } 00479 return CMDLINE_RETCODE_FAIL; 00480 } 00481 00482 static int cmd_socket_new(int argc, char *argv[]) 00483 { 00484 const char *s; 00485 SInfo *info; 00486 00487 if (cmd_parameter_last(argc, argv)) { 00488 s = cmd_parameter_last(argc, argv); 00489 if (strcmp(s, "UDPSocket") == 0) { 00490 tr_debug("Creating a new UDPSocket"); 00491 info = new SInfo(new UDPSocket); 00492 } else if (strcmp(s, "TCPSocket") == 0) { 00493 tr_debug("Creating a new TCPSocket"); 00494 info = new SInfo(new TCPSocket); 00495 } else if (strcmp(s, "TCPServer") == 0) { 00496 tr_debug("Creating a new TCPServer"); 00497 info = new SInfo(new TCPServer); 00498 } else { 00499 cmd_printf("unsupported protocol: %s\r\n", s); 00500 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00501 } 00502 } else { 00503 cmd_printf("Must specify socket type\r\n"); 00504 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00505 } 00506 // Note, this cannot fail. We either succeed or "new" woud call exit(1) in failure. 00507 // We did not ask no_throw version of it. 00508 cmd_printf("new socket. sid: %d\r\n", info->id()); 00509 m_sockets.push_back(info); 00510 return CMDLINE_RETCODE_SUCCESS; 00511 } 00512 00513 static void udp_receiver_thread(SInfo *info) 00514 { 00515 SocketAddress addr; 00516 int i = 0, received = 0; 00517 int n = info->getRepeatBufferFill(); 00518 int *packetSizes = info->getPacketSizeArray(); 00519 nsapi_size_or_error_t ret = 0; 00520 00521 info->setReceiverThreadId(Thread::gettid()); 00522 00523 while (i < n) { 00524 ret = static_cast<UDPSocket &>(info->socket()).recvfrom(&addr, info->getReceiveBuffer() + received, info->getDataCount() - received); 00525 if (ret > 0) { 00526 if (!info->check_pattern(info->getReceiveBuffer() + received, ret)) { 00527 return; 00528 } 00529 received += ret; 00530 packetSizes[i % PACKET_SIZE_ARRAY_LEN] = ret; 00531 i++; 00532 info->setRecvTotal(info->getRecvTotal() + ret); 00533 } else if (ret == NSAPI_ERROR_WOULD_BLOCK ) { 00534 Thread::signal_wait(SIGNAL_SIGIO); 00535 } else { 00536 handle_nsapi_size_or_error("Thread: UDPSocket::recvfrom()", ret); 00537 return; 00538 } 00539 } 00540 } 00541 00542 static nsapi_size_or_error_t start_udp_receiver_thread(SInfo *info, int argc, char *argv[]) 00543 { 00544 int32_t max_size; 00545 int32_t n = 1; 00546 00547 if (!cmd_parameter_int(argc, argv, "--max_data_len", &max_size)) { 00548 cmd_printf("Need data max data size\r\n"); 00549 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00550 } 00551 if (cmd_parameter_index(argc, argv, "--packets") > 0) { 00552 if (!cmd_parameter_int(argc, argv, "--packets", &n)) { 00553 cmd_printf("Need number of packets\r\n"); 00554 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00555 } 00556 } 00557 uint8_t *dataIn = (uint8_t *)malloc(max_size + 1); 00558 if (!dataIn) { 00559 cmd_printf("malloc() failed\r\n"); 00560 return CMDLINE_RETCODE_FAIL; 00561 } 00562 int *packetSizes = new (nothrow) int[PACKET_SIZE_ARRAY_LEN]; 00563 if (!packetSizes) { 00564 cmd_printf("Allocation failed\r\n"); 00565 return CMDLINE_RETCODE_FAIL; 00566 } 00567 for (int i = 0; i < PACKET_SIZE_ARRAY_LEN; i++) { 00568 packetSizes[i] = 0; 00569 } 00570 memset(dataIn, 0x00, max_size + 1); 00571 info->setReceiveBuffer(dataIn); 00572 info->setDataCount(max_size); 00573 info->setRepeatBufferFill(n); 00574 info->setPacketSizeArray(packetSizes); 00575 info->setReceiverThread(new Thread()); 00576 info->getReceiverThread()->start(callback(udp_receiver_thread, info)); 00577 return CMDLINE_RETCODE_SUCCESS; 00578 } 00579 00580 static nsapi_size_or_error_t udp_sendto_command_handler(SInfo *info, int argc, char *argv[]) 00581 { 00582 char *host; 00583 int32_t port; 00584 00585 if (!cmd_parameter_val(argc, argv, "sendto", &host)) { 00586 cmd_printf("Need host name\r\n"); 00587 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00588 } 00589 if (!cmd_parameter_int(argc, argv, host, &port)) { 00590 cmd_printf("Need port number\r\n"); 00591 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00592 } 00593 // Replace NULL-strings with NULL 00594 host = strcmp(host, "NULL") ? host : NULL; 00595 00596 int32_t len; 00597 void *data; 00598 if (cmd_parameter_int(argc, argv, "--data_len", &len)) { 00599 data = malloc(len); 00600 if (!data) { 00601 cmd_printf("Failed to allocate memory\r\n"); 00602 return CMDLINE_RETCODE_FAIL; 00603 } 00604 } else { 00605 // Replace NULL-strings with NULL 00606 if (strcmp(argv[5], "NULL") == 0) { 00607 data = NULL; 00608 len = 0; 00609 } else { 00610 data = argv[5]; 00611 len = strlen(argv[5]); 00612 } 00613 } 00614 00615 nsapi_size_or_error_t ret = static_cast<UDPSocket &>(info->socket()).sendto(host, port, data, len); 00616 if (ret > 0) { 00617 cmd_printf("sent: %d bytes\r\n", ret); 00618 } 00619 if (data != argv[5]) { 00620 free(data); 00621 } 00622 00623 return handle_nsapi_size_or_error("UDPSocket::sendto()", ret); 00624 } 00625 00626 static nsapi_size_or_error_t udp_recvfrom_command_handler(SInfo *info, int argc, char *argv[]) 00627 { 00628 SocketAddress addr; 00629 int32_t len; 00630 00631 if (!cmd_parameter_int(argc, argv, "recvfrom", &len)) { 00632 cmd_printf("Need len\r\n"); 00633 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00634 } 00635 00636 void *data = malloc(len); 00637 if (!data) { 00638 cmd_printf("malloc() failed\r\n"); 00639 return CMDLINE_RETCODE_FAIL; 00640 } 00641 nsapi_size_or_error_t ret = static_cast<UDPSocket &>(info->socket()).recvfrom(&addr, data, len); 00642 if (ret > 0) { 00643 cmd_printf("UDPSocket::recvfrom, addr=%s port=%d\r\n", addr.get_ip_address(), addr.get_port()); 00644 cmd_printf("received: %d bytes\r\n", ret); 00645 print_data((const uint8_t *)data, len); 00646 if (!info->check_pattern(data, len)) { 00647 ret = -1; 00648 } 00649 info->setRecvTotal(info->getRecvTotal() + ret); 00650 } 00651 free(data); 00652 return handle_nsapi_size_or_error("UDPSocket::recvfrom()", ret); 00653 } 00654 00655 static void tcp_receiver_thread(SInfo *info) 00656 { 00657 int i, received; 00658 int n = info->getRepeatBufferFill(); 00659 int recv_len = info->getMaxRecvLen(); 00660 int bufferSize = info->getDataCount(); 00661 nsapi_size_or_error_t ret = 0; 00662 00663 info->setReceiverThreadId(Thread::gettid()); 00664 00665 for (i = 0; i < n; i++) { 00666 received = 0; 00667 while (received < bufferSize) { 00668 ret = static_cast<TCPSocket &>(info->socket()).recv(info->getReceiveBuffer() + received, recv_len - received); 00669 if (ret > 0) { 00670 if (!info->check_pattern(info->getReceiveBuffer() + received, ret)) { 00671 return; 00672 } 00673 received += ret; 00674 info->setRecvTotal(info->getRecvTotal() + ret); 00675 } else if (ret == NSAPI_ERROR_WOULD_BLOCK ) { 00676 Thread::signal_wait(SIGNAL_SIGIO); 00677 } else { 00678 handle_nsapi_size_or_error("Thread: TCPSocket::recv()", ret); 00679 return; 00680 } 00681 } 00682 } 00683 } 00684 00685 static nsapi_size_or_error_t start_tcp_receiver_thread(SInfo *info, int argc, char *argv[]) 00686 { 00687 int32_t len; 00688 int32_t recv_len; 00689 int32_t n = 1; 00690 00691 if (!cmd_parameter_int(argc, argv, "--data_len", &len)) { 00692 cmd_printf("Need data len\r\n"); 00693 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00694 } 00695 recv_len = len; 00696 00697 if (cmd_parameter_index(argc, argv, "--max_recv_len") > 0) { 00698 if (!cmd_parameter_int(argc, argv, "--max_recv_len", &recv_len)) { 00699 cmd_printf("Need max recv len\r\n"); 00700 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00701 } 00702 } 00703 00704 if (cmd_parameter_index(argc, argv, "--repeat") > 0) { 00705 if (!cmd_parameter_int(argc, argv, "--repeat", &n)) { 00706 cmd_printf("Need repeat number\r\n"); 00707 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00708 } 00709 } 00710 00711 uint8_t *dataIn = (uint8_t *)malloc(len + 1); 00712 if (!dataIn) { 00713 cmd_printf("malloc() failed\r\n"); 00714 return CMDLINE_RETCODE_FAIL; 00715 } 00716 00717 info->setReceiveBuffer(dataIn); 00718 info->setDataCount(len); 00719 info->setMaxRecvLen(recv_len); 00720 info->setRepeatBufferFill(n); 00721 info->setReceiverThread(new Thread()); 00722 info->getReceiverThread()->start(callback(tcp_receiver_thread, info)); 00723 return CMDLINE_RETCODE_SUCCESS; 00724 } 00725 00726 static nsapi_size_or_error_t tcp_send_command_handler(SInfo *info, int argc, char *argv[]) 00727 { 00728 int32_t len; 00729 void *data; 00730 nsapi_size_or_error_t ret = 0; 00731 00732 info->setSenderThreadId(Thread::gettid()); 00733 00734 if (cmd_parameter_int(argc, argv, "--data_len", &len)) { 00735 data = malloc(len); 00736 if (!data) { 00737 cmd_printf("Failed to allocate memory\r\n"); 00738 return CMDLINE_RETCODE_FAIL; 00739 } 00740 } else { 00741 data = argv[3]; 00742 len = strlen(argv[3]); 00743 } 00744 00745 ret = static_cast<TCPSocket &>(info->socket()).send(data, len); 00746 00747 if (ret > 0) { 00748 cmd_printf("sent: %d bytes\r\n", ret); 00749 } 00750 if (data != argv[3]) { 00751 free(data); 00752 } 00753 return handle_nsapi_size_or_error("TCPSocket::send()", ret); 00754 } 00755 00756 static nsapi_size_or_error_t tcp_recv_command_handler(SInfo *info, int argc, char *argv[]) 00757 { 00758 int32_t len; 00759 00760 if (!cmd_parameter_int(argc, argv, "recv", &len)) { 00761 cmd_printf("Need length\r\n"); 00762 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00763 } 00764 00765 void *data = malloc(len); 00766 if (!data) { 00767 cmd_printf("malloc() failed\r\n"); 00768 return CMDLINE_RETCODE_FAIL; 00769 } 00770 00771 nsapi_size_or_error_t ret = static_cast<TCPSocket &>(info->socket()).recv(data, len); 00772 if (ret > 0) { 00773 cmd_printf("received: %d bytes\r\n", ret); 00774 print_data((const uint8_t *)data, ret); 00775 if (!info->check_pattern(data, ret)) { 00776 ret = -1; 00777 } 00778 info->setRecvTotal(info->getRecvTotal() + ret); 00779 } 00780 free(data); 00781 return handle_nsapi_size_or_error("TCPSocket::recv()", ret); 00782 } 00783 00784 static nsapi_size_or_error_t recv_all(char *const rbuffer, const int expt_len, SInfo *const info) 00785 { 00786 int rtotal, rbytes; 00787 char *rhead; 00788 00789 rtotal = 0; 00790 rhead = rbuffer; 00791 00792 while (rtotal < expt_len) { 00793 rbytes = info->tcp_socket()->recv(rhead, expt_len); 00794 if (rbytes <= 0) { // Connection closed abruptly 00795 rbuffer[rtotal] = '\0'; 00796 return rbytes; 00797 } 00798 rtotal += rbytes; 00799 rhead = rbuffer + rtotal; 00800 } 00801 rbuffer[rtotal] = '\0'; 00802 info->setRecvTotal(info->getRecvTotal() + rtotal); 00803 return rtotal; 00804 } 00805 00806 static void bg_traffic_thread(SInfo *info) 00807 { 00808 static const int data_len = 10; 00809 char sbuffer[data_len + 1] = "dummydata_"; 00810 char rbuffer[data_len + 1]; 00811 int scount, rtotal = 0; 00812 info->setSenderThreadId(Thread::gettid()); 00813 00814 for (;;) { 00815 if (!info->available()) { 00816 (void)handle_nsapi_size_or_error(__func__, rtotal); 00817 break; 00818 } 00819 sbuffer[data_len - 1] = 'A' + (rand() % 26); 00820 scount = info->tcp_socket()->send(sbuffer, data_len); 00821 rtotal = recv_all(rbuffer, data_len, info); 00822 00823 if (scount != rtotal || (strcmp(sbuffer, rbuffer) != 0)) { 00824 info->setUnavailable(); 00825 00826 tr_err("Background received data does not match to sent data"); 00827 tr_err("Background sent: \"%s\"", sbuffer); 00828 tr_err("Background received: \"%s\"", rbuffer); 00829 } 00830 wait_ms(10); 00831 } 00832 } 00833 00834 static nsapi_size_or_error_t start_bg_traffic_thread(SInfo *info, int argc, char *argv[]) 00835 { 00836 info->setReceiverThread(new Thread()); 00837 info->setAvailable(); 00838 info->getReceiverThread()->start(callback(bg_traffic_thread, info)); 00839 return CMDLINE_RETCODE_SUCCESS; 00840 } 00841 00842 static void thread_clean_up(SInfo *info) 00843 { 00844 if (info->getReceiverThread()) { 00845 delete info->getReceiverThread(); 00846 info->setReceiverThread(NULL); 00847 } 00848 if (info->getReceiveBuffer()) { 00849 delete info->getReceiveBuffer(); 00850 info->setReceiveBuffer(NULL); 00851 } 00852 if (info->getPacketSizeArray()) { 00853 delete[] info->getPacketSizeArray(); 00854 info->setPacketSizeArray(NULL); 00855 } 00856 } 00857 00858 static int cmd_socket(int argc, char *argv[]) 00859 { 00860 if (cmd_parameter_index(argc, argv, "new") == 1) { 00861 return cmd_socket_new(argc, argv); 00862 } else if (cmd_parameter_index(argc, argv, "print-mode") > 0) { 00863 if (cmd_parameter_index(argc, argv, "--string") > 0) { 00864 printing_mode = PRINT_STRING; 00865 } else if (cmd_parameter_index(argc, argv, "--hex") > 0) { 00866 printing_mode = PRINT_HEX; 00867 } else if (cmd_parameter_index(argc, argv, "--disabled") > 0) { 00868 printing_mode = PRINT_DISABLED; 00869 } 00870 int32_t parsed_col_width = 0; 00871 if (cmd_parameter_int(argc, argv, "--col-width", &parsed_col_width)) { 00872 if (parsed_col_width <= 0) { 00873 cmd_printf("Printing column width must be > 0"); 00874 return CMDLINE_RETCODE_FAIL; 00875 } 00876 if (printing_mode == PRINT_HEX && parsed_col_width > 42) { 00877 cmd_printf("Maximum column width for hex data is 42 bytes"); 00878 return CMDLINE_RETCODE_FAIL; 00879 } 00880 printing_col_width = (int)parsed_col_width; 00881 } 00882 // Allow print-mode to be used as a parameter to other commands 00883 if (cmd_parameter_index(argc, argv, "print-mode") == 1) { 00884 return CMDLINE_RETCODE_SUCCESS; 00885 } 00886 } 00887 00888 // Rest of the commands require Socket 00889 SInfo *info = get_sinfo(strtol(argv[1], NULL, 10)); 00890 if (!info) { 00891 cmd_printf("Invalid socket id %s\r\n", argv[1]); 00892 return CMDLINE_RETCODE_FAIL; 00893 } 00894 00895 bool enable_pattern_check; 00896 if (cmd_parameter_bool(argc, argv, "set_RFC_864_pattern_check", &enable_pattern_check)) { 00897 info->set_pattern_check(enable_pattern_check); 00898 return CMDLINE_RETCODE_SUCCESS; 00899 } 00900 00901 // Helper macro for checking the which command was given 00902 #define COMMAND_IS(cmd) (cmd_parameter_index(argc, argv, cmd) == 2) 00903 00904 /* 00905 * Generic Socket commands: 00906 * delete, open, close, bind, set_blocking, set_timeout 00907 */ 00908 00909 if (COMMAND_IS("delete")) { 00910 return del_sinfo(info); 00911 00912 } else if (COMMAND_IS("open")) { 00913 NetworkInterface *interface; 00914 00915 interface = get_interface(); // get default interface 00916 00917 if (!interface) { 00918 cmd_printf("Invalid interface\r\n"); 00919 return CMDLINE_RETCODE_FAIL; 00920 } 00921 00922 switch (info->type()) { 00923 case SInfo::TCP_CLIENT: 00924 return handle_nsapi_error("Socket::open()", info->tcp_socket()->open(interface)); 00925 case SInfo::UDP: 00926 return handle_nsapi_error("Socket::open()", info->udp_socket()->open(interface)); 00927 case SInfo::TCP_SERVER: 00928 return handle_nsapi_error("Socket::open()", info->tcp_server()->open(interface)); 00929 } 00930 00931 } else if (COMMAND_IS("close")) { 00932 return handle_nsapi_error("Socket::close()", info->socket().close()); 00933 00934 } else if (COMMAND_IS("bind")) { 00935 int32_t port = 0; 00936 char *addr; 00937 00938 if (!cmd_parameter_int(argc, argv, "port", &port) && !cmd_parameter_int(argc, argv, "bind", &port) && port <= 0 && port > 65535) { 00939 printf("Missing or invalid port number\n"); 00940 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00941 } 00942 00943 if (cmd_parameter_val(argc, argv, "addr", &addr)) { 00944 // Replace NULL-strings with NULL 00945 addr = strcmp(addr, "NULL") ? addr : NULL; 00946 cmd_printf("Socket::bind(%s, %" PRId32 ")\r\n", addr, port); 00947 SocketAddress tmp(addr, port); 00948 return handle_nsapi_error("Socket::bind(addr, port)", info->socket().bind(tmp)); 00949 } else { 00950 cmd_printf("Socket::bind(%" PRId32 ")\r\n", port); 00951 SocketAddress tmp(NULL, port); 00952 return handle_nsapi_error("Socket::bind(port)", info->socket().bind(tmp)); 00953 } 00954 00955 } else if (COMMAND_IS("set_blocking")) { 00956 bool val; 00957 if (!cmd_parameter_bool(argc, argv, "set_blocking", &val)) { 00958 cmd_printf("Need boolean value"); 00959 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00960 } 00961 info->set_blocking(val); 00962 return CMDLINE_RETCODE_SUCCESS; 00963 00964 } else if (COMMAND_IS("set_timeout")) { 00965 int32_t ms; 00966 if (!cmd_parameter_int(argc, argv, "set_timeout", &ms)) { 00967 cmd_printf("Need timeout value"); 00968 return CMDLINE_RETCODE_INVALID_PARAMETERS; 00969 } 00970 if (ms == -1) { 00971 info->set_blocking(true); 00972 } else { 00973 info->set_blocking(false); 00974 } 00975 00976 info->socket().set_timeout(ms); 00977 return CMDLINE_RETCODE_SUCCESS; 00978 00979 } else if (COMMAND_IS("register_sigio_cb")) { 00980 info->socket().sigio(callback(sigio_handler, info)); 00981 return CMDLINE_RETCODE_SUCCESS; 00982 } 00983 00984 00985 /* 00986 * Commands related to UDPSocket: 00987 * sendto, recvfrom 00988 */ 00989 if ((COMMAND_IS("sendto") || COMMAND_IS("recvfrom") || COMMAND_IS("start_udp_receiver_thread") 00990 || COMMAND_IS("last_data_received")) && info->type() != SInfo::UDP) { 00991 cmd_printf("Not UDPSocket\r\n"); 00992 return CMDLINE_RETCODE_FAIL; 00993 } 00994 00995 if (COMMAND_IS("sendto")) { 00996 return udp_sendto_command_handler(info, argc, argv); 00997 } else if (COMMAND_IS("recvfrom")) { 00998 return udp_recvfrom_command_handler(info, argc, argv); 00999 } else if (COMMAND_IS("start_udp_receiver_thread")) { 01000 return start_udp_receiver_thread(info, argc, argv); 01001 } else if (COMMAND_IS("last_data_received")) { 01002 print_data((const uint8_t *)info->getReceiveBuffer(), info->getDataCount()); 01003 if (info->getPacketSizeArray()) { 01004 int *packetSizes = info->getPacketSizeArray(); 01005 cmd_printf("packet_sizes: "); 01006 for (int i = 0; i < PACKET_SIZE_ARRAY_LEN; i++) { 01007 cmd_printf("%d ", packetSizes[i]); 01008 } 01009 cmd_printf("\r\n"); 01010 } 01011 if (info->getReceiverThread()) { 01012 info->getReceiverThread()->terminate(); 01013 } 01014 thread_clean_up(info); 01015 01016 return handle_nsapi_error("UDPSocket::last_data_received()", NSAPI_ERROR_OK ); 01017 } 01018 01019 /* 01020 * Commands related to TCPSocket 01021 * connect, send, recv 01022 */ 01023 if ((COMMAND_IS("connect") || COMMAND_IS("recv") 01024 || COMMAND_IS("start_tcp_receiver_thread") || COMMAND_IS("join_tcp_receiver_thread") 01025 || COMMAND_IS("start_bg_traffic_thread") || COMMAND_IS("join_bg_traffic_thread") 01026 || COMMAND_IS("setsockopt_keepalive") || COMMAND_IS("getsockopt_keepalive")) 01027 && info->type() != SInfo::TCP_CLIENT) { 01028 cmd_printf("Not TCPSocket\r\n"); 01029 return CMDLINE_RETCODE_FAIL; 01030 } 01031 01032 if (COMMAND_IS("connect")) { 01033 char *host; 01034 int32_t port; 01035 01036 if (!cmd_parameter_val(argc, argv, "connect", &host)) { 01037 cmd_printf("Need host name\r\n"); 01038 return CMDLINE_RETCODE_INVALID_PARAMETERS; 01039 } 01040 if (!cmd_parameter_int(argc, argv, host, &port)) { 01041 cmd_printf("Need port number\r\n"); 01042 return CMDLINE_RETCODE_INVALID_PARAMETERS; 01043 } 01044 if (strcmp(host, "NULL") == 0) { 01045 host = NULL; 01046 } 01047 01048 cmd_printf("Host name: %s port: %" PRId32 "\r\n", host, port); 01049 return handle_nsapi_error("TCPSocket::connect()", static_cast<TCPSocket &>(info->socket()).connect(host, port)); 01050 01051 } else if (COMMAND_IS("send")) { 01052 return tcp_send_command_handler(info, argc, argv); 01053 01054 } else if (COMMAND_IS("recv")) { 01055 return tcp_recv_command_handler(info, argc, argv); 01056 01057 } else if (COMMAND_IS("start_tcp_receiver_thread")) { 01058 return start_tcp_receiver_thread(info, argc, argv); 01059 01060 } else if (COMMAND_IS("join_tcp_receiver_thread")) { 01061 info->getReceiverThread()->join(); 01062 print_data((const uint8_t *)info->getReceiveBuffer(), info->getDataCount()); 01063 cmd_printf("received: %d bytes\r\n", info->getRecvTotal()); 01064 01065 thread_clean_up(info); 01066 01067 return CMDLINE_RETCODE_SUCCESS; 01068 01069 } else if (COMMAND_IS("start_bg_traffic_thread")) { 01070 return start_bg_traffic_thread(info, argc, argv); 01071 01072 } else if (COMMAND_IS("join_bg_traffic_thread")) { 01073 int bg_thread_success = CMDLINE_RETCODE_SUCCESS; 01074 01075 if (!info->available()) { // Tells that background thread stumbled to an issue and stopped prematurely 01076 bg_thread_success = CMDLINE_RETCODE_FAIL; 01077 } 01078 01079 info->setUnavailable(); 01080 info->getReceiverThread()->join(); 01081 thread_clean_up(info); 01082 01083 return bg_thread_success; 01084 } else if (COMMAND_IS("setsockopt_keepalive")) { 01085 int32_t seconds; 01086 nsapi_error_t ret; 01087 if (!cmd_parameter_int(argc, argv, "setsockopt_keepalive", &seconds)) { 01088 cmd_printf("Need keep-alive value(0-7200seconds)"); 01089 return CMDLINE_RETCODE_INVALID_PARAMETERS; 01090 } 01091 01092 ret = info->socket().setsockopt(NSAPI_SOCKET , NSAPI_KEEPALIVE , &seconds, sizeof(seconds)); 01093 01094 return handle_nsapi_error("TCPSocket::setsockopt()", ret); 01095 } else if (COMMAND_IS("getsockopt_keepalive")) { 01096 int32_t optval; 01097 unsigned optlen = sizeof(optval); 01098 nsapi_error_t ret; 01099 01100 ret = info->socket().getsockopt(NSAPI_SOCKET , NSAPI_KEEPALIVE , &optval, &optlen); 01101 01102 if (optlen != sizeof(int)) { 01103 return CMDLINE_RETCODE_FAIL; 01104 } 01105 if (ret < 0) { 01106 return handle_nsapi_error("TCPSocket::getsockopt()", ret); 01107 } 01108 return handle_nsapi_size_or_error("TCPSocket::getsockopt()", optval); 01109 } 01110 01111 /* 01112 * Commands for TCPServer 01113 * listen, accept 01114 */ 01115 if ((COMMAND_IS("listen") || COMMAND_IS("accept")) && info->type() != SInfo::TCP_SERVER) { 01116 cmd_printf("Not TCPServer\r\n"); 01117 return CMDLINE_RETCODE_FAIL; 01118 } 01119 if (COMMAND_IS("listen")) { 01120 int32_t backlog; 01121 if (cmd_parameter_int(argc, argv, "listen", &backlog)) { 01122 return handle_nsapi_error("TCPServer::listen()", static_cast<TCPServer &>(info->socket()).listen(backlog)); 01123 } else { 01124 return handle_nsapi_error("TCPServer::listen()", static_cast<TCPServer &>(info->socket()).listen()); 01125 } 01126 01127 } else if (COMMAND_IS("accept")) { 01128 SocketAddress addr; 01129 int32_t id; 01130 if (!cmd_parameter_int(argc, argv, "accept", &id)) { 01131 cmd_printf("Need new socket id\r\n"); 01132 return CMDLINE_RETCODE_INVALID_PARAMETERS; 01133 } 01134 SInfo *new_info = get_sinfo(id); 01135 if (!new_info) { 01136 cmd_printf("Invalid socket id\r\n"); 01137 return CMDLINE_RETCODE_FAIL; 01138 } 01139 TCPSocket *new_sock = static_cast<TCPSocket *>(&new_info->socket()); 01140 nsapi_error_t ret = static_cast<TCPServer &>(info->socket()).accept(new_sock, &addr); 01141 if (ret == NSAPI_ERROR_OK ) { 01142 cmd_printf("TCPServer::accept() new socket sid: %d connection from %s port %d\r\n", 01143 new_info->id(), addr.get_ip_address(), addr.get_port()); 01144 } 01145 return handle_nsapi_error("TCPServer::accept()", ret); 01146 } 01147 return CMDLINE_RETCODE_INVALID_PARAMETERS; 01148 } 01149 01150 void print_data(const uint8_t *buf, int len) 01151 { 01152 switch (printing_mode) { 01153 case PRINT_STRING: 01154 print_data_as_string(buf, len, printing_col_width); 01155 break; 01156 case PRINT_HEX: 01157 print_data_as_hex(buf, len, printing_col_width); 01158 break; 01159 case PRINT_DISABLED: 01160 break; 01161 default: 01162 assert(0); 01163 } 01164 } 01165 01166 void print_data_as_string(const uint8_t *buf, int len, int col_width) 01167 { 01168 int printable_bytes; 01169 for (printable_bytes = 0; printable_bytes < len; printable_bytes++) { 01170 if (!isprint(buf[printable_bytes])) { 01171 break; 01172 } 01173 } 01174 01175 cmd_mutex_lock(); 01176 cmd_printf("string data, printing %d bytes:\r\n", len); 01177 for (int i = 0; i < printable_bytes; i += col_width) { 01178 if (printable_bytes - i > col_width) { 01179 cmd_printf("%04d: %.*s\r\n", i, col_width, buf + i); 01180 } else { 01181 cmd_printf("%04d: %.*s\r\n", i, printable_bytes - i, buf + i); 01182 } 01183 } 01184 cmd_printf("Printed %d bytes\r\n", printable_bytes); 01185 01186 if (len != printable_bytes) { 01187 cmd_printf("Error! Couldn't print all data. " 01188 "Unprintable character: 0x%02x found at index: %d\r\n", 01189 buf[printable_bytes], printable_bytes); 01190 } 01191 cmd_mutex_unlock(); 01192 } 01193 01194 void print_data_as_hex(const uint8_t *buf, int len, int col_width) 01195 { 01196 cmd_mutex_lock(); 01197 cmd_printf("hex data, printing %d bytes:\r\n", len); 01198 for (int i = 0; i < len; i += col_width) { 01199 if (len - i > col_width) { 01200 cmd_printf("%04d: %s:\r\n", i, print_array(buf + i, col_width)); 01201 } else { 01202 cmd_printf("%04d: %s\r\n", i, print_array(buf + i, len - i)); 01203 } 01204 } 01205 cmd_printf("Printed %d bytes\r\n", len); 01206 cmd_mutex_unlock(); 01207 }
Generated on Tue Aug 9 2022 00:37:04 by
1.7.2