Mbed Cloud example program for workshop in W27 2018.

Dependencies:   MMA7660 LM75B

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ftcd_comm_socket.cpp Source File

ftcd_comm_socket.cpp

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2017 ARM Ltd.
00003 //
00004 // Licensed under the Apache License, Version 2.0 (the "License");
00005 // you may 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,
00012 // WITHOUT 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 
00017 // Note: this macro is needed on armcc to get the the PRI*32 macros
00018 // from inttypes.h in a C++ code.
00019 #ifndef __STDC_FORMAT_MACROS
00020 #define __STDC_FORMAT_MACROS
00021 #endif
00022 
00023 #include <stdlib.h>
00024 #include "pal.h"
00025 #include "pv_log.h"
00026 #include "ftcd_comm_socket.h"
00027 #include "fcc_malloc.h"
00028 
00029 #define NUM_OF_PENDING_CONNECTIONS 1
00030 #define NUM_OF_TRIES_TO_GET_INTERFACE_INFO 5
00031 #define TRACE_GROUP "fcsk"
00032 #define RANDOM_PORT_MIN 1024
00033 #define RANDOM_PORT_MAX 65535
00034 
00035 FtcdCommSocket::FtcdCommSocket(const void *interface_handler, ftcd_socket_domain_e domain, const uint16_t port_num, int32_t timeout)
00036 {
00037     _interface_handler = interface_handler;
00038     _required_domain_type = domain;
00039 
00040     /* If port supplied is 0, generate random port similar to UNIX convention.
00041     *  Pal currently does not support binding with port 0.
00042     */
00043     _port = port_num;
00044     if (port_num == 0) {
00045         srand(pal_osKernelSysTick());
00046 
00047         // Generate random port int the range [RANDOM_PORT_MIN, RANDOM_PORT_MAX - 1] including.
00048         _port = (rand() % (RANDOM_PORT_MAX - RANDOM_PORT_MIN)) + RANDOM_PORT_MIN;
00049     }
00050 
00051     _rcv_timeout = timeout;
00052     _current_domain_type = FTCD_AF_UNSPEC;
00053     _interface_index = 0;
00054     _net_interface_info = NULL;
00055     _server_socket = NULL;
00056     _client_socket = NULL;
00057 }
00058 
00059 FtcdCommSocket::~FtcdCommSocket()
00060 {
00061 
00062     if (_net_interface_info != NULL) {
00063         fcc_free(_net_interface_info);
00064     }
00065     if (_server_socket != NULL) {
00066         pal_close(&_server_socket);
00067     }
00068     if (_client_socket != NULL) {
00069         pal_close(&_client_socket);
00070     }
00071 }
00072 
00073 
00074 bool FtcdCommSocket::init()
00075 {
00076 
00077     int retries = NUM_OF_TRIES_TO_GET_INTERFACE_INFO;
00078     palIpV4Addr_t ip_v4_addr;
00079     char ip_and_port_string[32] = { 0 };
00080     uint32_t index = 0;
00081 
00082     //Call to pal init
00083     palStatus_t result = pal_init();
00084     if (result != PAL_SUCCESS) {
00085         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Error initializing pal");
00086         return false;
00087     }
00088 
00089     //Register connected interface handler
00090     result = pal_registerNetworkInterface((void*)_interface_handler, &_interface_index);
00091     if (result != 0) {
00092         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n pal_RegisterNetworkInterface Failed");
00093         return false;
00094     }
00095 
00096     //Allocate memory for interface info
00097     if (_net_interface_info == NULL) {
00098         _net_interface_info = (palNetInterfaceInfo_t *)fcc_malloc(sizeof(palNetInterfaceInfo_t ));
00099         if (_net_interface_info == NULL) {
00100             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Failed to allocate memory for network interface");
00101             return false;
00102         }
00103     }
00104 
00105     //Try to get interface info
00106     while (retries--) {
00107         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Trying receive interface ...");
00108         result = pal_getNetInterfaceInfo(_interface_index, _net_interface_info);
00109         if (result != 0) {
00110             pal_osDelay(200);
00111         } else {//In case we have interface info we print it
00112             if (_required_domain_type != FTCD_IPV4) {
00113                 mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Illegal domain type");
00114                 break;
00115             }
00116             //Update domain type
00117             _current_domain_type = _required_domain_type;
00118 
00119             result = pal_getSockAddrIPV4Addr(&(_net_interface_info->address), ip_v4_addr);
00120             if (result != PAL_SUCCESS) {
00121                 mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n palGetSockAddrIPV4Addr failed");
00122                 break;
00123             }
00124             memset(ip_and_port_string, 0, sizeof(ip_and_port_string));
00125             index = 0;
00126             for (uint32_t i = 0; i < sizeof(palIpV4Addr_t); i++) {
00127                 if (i < sizeof(palIpV4Addr_t) - 1) {
00128                     index += sprintf(&ip_and_port_string[index], "%d.", ip_v4_addr[i]);
00129                 } else {
00130                     index += sprintf(&ip_and_port_string[index], "%d:", ip_v4_addr[i]);
00131                     index += sprintf(&ip_and_port_string[index], "%d\n", _port);
00132                 }
00133             }
00134 
00135             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Factory Client IP Address and Port :  %s", ip_and_port_string);
00136             //open and listen to socket
00137             if (_listen()) {
00138                 return true;
00139             } else {
00140                 mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed to listen to socket");
00141             }
00142 
00143         }
00144 
00145     }
00146 
00147     mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n FCC did not succeed receive network interface !!!!!!");
00148     //If we couldn't get interface info free allocated memory
00149     fcc_free(_net_interface_info);
00150     _net_interface_info = NULL;
00151     return false;
00152 
00153 }
00154 
00155 
00156 void FtcdCommSocket::finish(void)
00157 {
00158     if (_server_socket != NULL) {
00159         pal_close(&_server_socket);
00160         _server_socket = NULL;
00161     }
00162     if (_client_socket != NULL) {
00163         pal_close(&_client_socket);
00164         _client_socket = NULL;
00165     }
00166     pal_destroy();
00167 }
00168 
00169 ftcd_comm_status_e FtcdCommSocket::is_token_detected(void)
00170 {
00171     char expected_token[] = FTCD_MSG_HEADER_TOKEN;
00172     char c;
00173     int result = PAL_SUCCESS;
00174     size_t idx = 0;
00175     palSocketLength_t addrlen = 0;
00176     palSocketAddress_t address = { 0 };
00177 
00178     result = pal_accept(_server_socket, &address, &addrlen, &_client_socket);
00179     if (result == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00180         return FTCD_COMM_NETWORK_TIMEOUT;
00181     } else if (result != PAL_SUCCESS) {
00182         return FTCD_COMM_NETWORK_CONNECTION_ERROR;
00183     }
00184 
00185     //read char by char to detect token
00186     while (idx < FTCD_MSG_HEADER_TOKEN_SIZE_BYTES) {
00187         result = _read_from_socket(reinterpret_cast<void*>(&c), 1);
00188         if (result == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00189             return FTCD_COMM_NETWORK_TIMEOUT;
00190         } else if (result != PAL_SUCCESS) {
00191             return FTCD_COMM_NETWORK_CONNECTION_ERROR;
00192         }
00193 
00194         if (c == expected_token[idx]) {
00195             idx++;
00196         } else {
00197             idx = 0;
00198         }
00199     }
00200     return FTCD_COMM_STATUS_SUCCESS;
00201 }
00202 
00203 
00204 uint32_t FtcdCommSocket::read_message_size(void)
00205 {
00206     uint32_t message_size = 0;
00207     ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS;
00208 
00209     result = _read_from_socket(reinterpret_cast<void*>(&message_size), sizeof(message_size));
00210     if (result != FTCD_COMM_STATUS_SUCCESS) {
00211         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed reading message size\r");
00212         return 0;
00213     }
00214 
00215     return message_size;
00216 }
00217 
00218 bool FtcdCommSocket::read_message(uint8_t *message_out, size_t message_size)
00219 {
00220     ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS;
00221 
00222     if (message_out == NULL) {
00223         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Invalid message buffer\r");
00224         return false;
00225     }
00226 
00227     // Read CBOR message bytes
00228     // We assume that LENGTH is NOT bigger than INT_MAX
00229     result = _read_from_socket(reinterpret_cast<void*>(message_out), message_size);
00230     if (result != FTCD_COMM_STATUS_SUCCESS) {
00231         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed reading message bytes\r");
00232         return false;
00233     }
00234     return true;
00235 }
00236 
00237 
00238 bool FtcdCommSocket::read_message_signature(uint8_t *sig, size_t sig_size)
00239 {
00240     ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS;
00241 
00242     if (sig == NULL) {
00243         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Invalid sig buffer\r");
00244         return false;
00245     }
00246 
00247     // Read signature from medium
00248     result = _read_from_socket(reinterpret_cast<void*>(sig), sig_size);
00249     if (result != FTCD_COMM_STATUS_SUCCESS) {
00250         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed reading message signature bytes\r");
00251         return false;
00252     }
00253     return true;
00254 }
00255 
00256 
00257 bool FtcdCommSocket::send(const uint8_t *data, uint32_t data_size)
00258 {
00259     bool success = true;
00260     palStatus_t result = PAL_SUCCESS;
00261     size_t sent_bytes = 0;
00262     size_t remaind_bytes = (size_t)data_size;
00263 
00264     do {
00265         result = pal_send(_client_socket, data, remaind_bytes, &sent_bytes);
00266         if (result != PAL_SUCCESS) {
00267             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed pal_send\r");
00268             success = false;
00269             break;
00270         }
00271 
00272         if (sent_bytes == 0 || sent_bytes > remaind_bytes) {
00273             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Sending response message failed");
00274             success = false;
00275             break;
00276         }
00277         remaind_bytes = remaind_bytes - sent_bytes;
00278         data += sent_bytes;
00279 
00280     } while (remaind_bytes != 0);
00281 
00282     return success;
00283 }
00284 
00285 bool FtcdCommSocket::_listen(void)
00286 {
00287     int status;
00288     palStatus_t result = PAL_SUCCESS;
00289     palSocketAddress_t address = { 0 };
00290     palIpV4Addr_t ipv4 = { 0 };
00291 
00292     //Check port number and domain type
00293     if (_port == 0) {
00294         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Wrong port number");
00295         return false;
00296     }
00297 
00298     if (_current_domain_type != FTCD_IPV4) {
00299         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Wrong domain type");
00300         return false;
00301     }
00302 
00303     //Open server and client sockets
00304     result = pal_socket((palSocketDomain_t )_current_domain_type, PAL_SOCK_STREAM_SERVER , false, _interface_index, &_server_socket);
00305     if (result != PAL_SUCCESS) {
00306         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_socket failed");
00307         return false;
00308     }
00309 
00310     result = pal_socket((palSocketDomain_t )_current_domain_type, PAL_SOCK_STREAM, false, _interface_index, &_client_socket);
00311     if (result != PAL_SUCCESS) {
00312         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_socket failed");
00313         return false;
00314     }
00315 
00316     //Get ipv4 format address from interface info structure
00317     status = pal_getSockAddrIPV4Addr(&(_net_interface_info->address), ipv4);
00318     if (status != 0) {
00319         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot palGetSockAddrIPV4Addr (status %d)", status);
00320         return false;
00321     }
00322 
00323     //Set the retrieved address to pal socket address
00324     status = pal_setSockAddrIPV4Addr(&address, ipv4);
00325     if (status != 0) {
00326         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot set socket ipv4 address (status %d)", status);
00327         return false;
00328     }
00329 
00330     //Set current port number to pal socket address
00331     status = pal_setSockAddrPort(&address, _port);
00332     if (status != 0) {
00333         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot set socket port address (status %d)", status);
00334         return false;
00335     }
00336 
00337     //set server socket timeout
00338     if (_rcv_timeout >= 0) {
00339         status = pal_setSocketOptions(_server_socket, PAL_SO_RCVTIMEO , &_rcv_timeout, sizeof(_rcv_timeout));
00340         if (status != 0) {
00341             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot set server socket timeout (status %d)", status);
00342             return false;
00343         }
00344     }
00345 
00346     status = pal_bind(_server_socket, &address, _net_interface_info->addressSize);
00347     if (status != 0) {
00348         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_bind failed (status %d)", status);
00349         return false;
00350     }
00351 
00352     status = pal_listen(_server_socket, NUM_OF_PENDING_CONNECTIONS);
00353     if (status != 0) {
00354         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_listen failed (status %d)", status);
00355         return false;
00356     }
00357 
00358     mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Factory Client is waiting for incoming connection...");
00359 
00360     return true;
00361 }
00362 
00363 
00364 ftcd_comm_status_e FtcdCommSocket::_read_from_socket(void * data_out, int data_out_size)
00365 {
00366     int status = PAL_SUCCESS;
00367     size_t bytes_received = 0;
00368 
00369     if (data_out == NULL) {
00370         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Invalid message");
00371         return FTCD_COMM_INTERNAL_ERROR;
00372     }
00373 
00374     status = pal_recv(_client_socket, data_out, data_out_size, &bytes_received);
00375     if (status == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00376         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Receive socket timeout, (status = %i)", status);
00377         return FTCD_COMM_NETWORK_TIMEOUT;
00378     } else if (status != PAL_SUCCESS) {
00379         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Receive socket error, (status = %i)", status);
00380         return FTCD_COMM_NETWORK_CONNECTION_ERROR;
00381     }
00382 
00383     /* FIXME: The socket reads up to MSS (Max Segment Size) which is 1460 bytes.
00384     A bigger message would result in a partial message read. A temporary solution
00385     is to loop through until socket emptiness */
00386 
00387     // The number of bytes we had managed to read so far
00388     int bytes_read_successfully = bytes_received;
00389 
00390     // The remaining bytes left to read
00391     int remaining_bytes = data_out_size - bytes_received;
00392 
00393     // Loop through until nothing left to read
00394     while (remaining_bytes > 0) {
00395 
00396         //Zero bytes_received before next receive
00397         bytes_received = 0;
00398 
00399         status = pal_recv(_client_socket, (uint8_t *)data_out + bytes_read_successfully, remaining_bytes, &bytes_received);
00400         if (status == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00401             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Receive socket timeout, (status = %i)", status);
00402             return FTCD_COMM_NETWORK_TIMEOUT;
00403         } else if (status != PAL_SUCCESS) {
00404             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Receive socket error, (status = %i)", status);
00405             return FTCD_COMM_NETWORK_CONNECTION_ERROR;
00406         }
00407 
00408         remaining_bytes -= bytes_received;
00409         bytes_read_successfully += bytes_received;
00410     }
00411     return FTCD_COMM_STATUS_SUCCESS;
00412 }
00413 
00414