takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers cmd_socket.cpp Source File

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 }