Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

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 *interfaceHandler, ftcd_socket_domain_e domain, const uint16_t port_num, ftcd_comm_network_endianness_e network_endianness, int32_t timeout)
00036     : FtcdCommBase(network_endianness, NULL, false)
00037 {
00038     _interface_handler = interfaceHandler;
00039     _required_domain_type = domain;
00040     _port = port_num;
00041     _rcv_timeout = timeout;
00042     _current_domain_type = FTCD_AF_UNSPEC;
00043     _interface_index = 0;
00044     _net_interface_info = NULL;
00045     _server_socket = NULL;
00046     _client_socket = NULL;
00047     _connection_state = SOCKET_WAIT_FOR_CONNECTION;
00048 }
00049 
00050 FtcdCommSocket::FtcdCommSocket(const void *interfaceHandler, ftcd_socket_domain_e domain, const uint16_t port_num, ftcd_comm_network_endianness_e network_endianness, const uint8_t *header_token, bool use_signature, int32_t timeout)
00051     : FtcdCommBase(network_endianness, header_token, use_signature)
00052 
00053 {
00054     _interface_handler = interfaceHandler;
00055     _required_domain_type = domain;
00056     _port = port_num;
00057     _rcv_timeout = timeout;
00058     _current_domain_type = FTCD_AF_UNSPEC;
00059     _interface_index = 0;
00060     _net_interface_info = NULL;
00061     _server_socket = NULL;
00062     _client_socket = NULL;
00063     _connection_state = SOCKET_WAIT_FOR_CONNECTION;
00064 }
00065 
00066 FtcdCommSocket::~FtcdCommSocket()
00067 {
00068 
00069     if (_net_interface_info != NULL) {
00070         fcc_free(_net_interface_info);
00071     }
00072     if (_server_socket != NULL) {
00073         pal_close(&_server_socket);
00074     }
00075     if (_client_socket != NULL) {
00076         pal_close(&_client_socket);
00077     }
00078 }
00079 
00080 
00081 bool FtcdCommSocket::init()
00082 {
00083     int retries = NUM_OF_TRIES_TO_GET_INTERFACE_INFO;
00084     palIpV4Addr_t ip_v4_addr;
00085     char ip_and_port_string[32] = { 0 };
00086     uint32_t index = 0;
00087 
00088     //Call to pal init
00089     palStatus_t result = pal_init();
00090     if (result != PAL_SUCCESS) {
00091         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Error initializing pal");
00092         return false;
00093     }
00094 
00095     // If port is 0, generate random port
00096     // Pal currently does not support binding with port 0.
00097     if (_port == 0) {
00098         srand((unsigned int)pal_osKernelSysTick());
00099         // Generate random port int the range [RANDOM_PORT_MIN, RANDOM_PORT_MAX - 1] including.
00100         _port = (uint16_t)(rand() % (RANDOM_PORT_MAX - RANDOM_PORT_MIN) + RANDOM_PORT_MIN);
00101     }
00102 
00103     //Register connected interface handler
00104     result = pal_registerNetworkInterface((void*)_interface_handler, &_interface_index);
00105     if (result != 0) {
00106         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n pal_RegisterNetworkInterface Failed");
00107         return false;
00108     }
00109 
00110     //Allocate memory for interface info
00111     if (_net_interface_info == NULL) {
00112         _net_interface_info = (palNetInterfaceInfo_t *)fcc_malloc(sizeof(palNetInterfaceInfo_t ));
00113         if (_net_interface_info == NULL) {
00114             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Failed to allocate memory for network interface");
00115             return false;
00116         }
00117     }
00118 
00119     //Try to get interface info
00120     while (retries--) {
00121         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Trying receive interface ...");
00122         result = pal_getNetInterfaceInfo(_interface_index, _net_interface_info);
00123         if (result != 0) {
00124             pal_osDelay(200);
00125         } else {//In case we have interface info we print it
00126             if (_required_domain_type != FTCD_IPV4) {
00127                 mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Illegal domain type");
00128                 break;
00129             }
00130             //Update domain type
00131             _current_domain_type = _required_domain_type;
00132 
00133             result = pal_getSockAddrIPV4Addr(&(_net_interface_info->address), ip_v4_addr);
00134             if (result != PAL_SUCCESS) {
00135                 mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n palGetSockAddrIPV4Addr failed");
00136                 break;
00137             }
00138             memset(ip_and_port_string, 0, sizeof(ip_and_port_string));
00139             index = 0;
00140             for (uint32_t i = 0; i < sizeof(palIpV4Addr_t); i++) {
00141                 if (i < sizeof(palIpV4Addr_t) - 1) {
00142                     index += sprintf(&ip_and_port_string[index], "%d.", ip_v4_addr[i]);
00143                 } else {
00144                     index += sprintf(&ip_and_port_string[index], "%d:", ip_v4_addr[i]);
00145                     index += sprintf(&ip_and_port_string[index], "%d\n", _port);
00146                 }
00147             }
00148 
00149             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Factory Client IP Address and Port :  %s", ip_and_port_string);
00150             //open and listen to socket
00151             if (_listen()) {
00152                 return true;
00153             } else {
00154                 mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed to listen to socket");
00155             }
00156 
00157         }
00158 
00159     }
00160 
00161     mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n FCC did not succeed receive network interface !!!!!!");
00162     //If we couldn't get interface info free allocated memory
00163     fcc_free(_net_interface_info);
00164     _net_interface_info = NULL;
00165     return false;
00166 
00167 }
00168 
00169 void FtcdCommSocket::finish(void)
00170 {
00171     if (_server_socket != NULL) {
00172         pal_close(&_server_socket);
00173         _server_socket = NULL;
00174     }
00175     if (_client_socket != NULL) {
00176         pal_close(&_client_socket);
00177         _client_socket = NULL;
00178     }
00179     pal_destroy();
00180 }
00181 
00182 // no_open_connection, connection_open, connection_open_timeout
00183 ftcd_comm_status_e FtcdCommSocket::wait_for_message(uint8_t **message_out, uint32_t *message_size_out)
00184 {
00185     int result = PAL_SUCCESS;
00186     ftcd_comm_status_e comm_status = FTCD_COMM_STATUS_SUCCESS;
00187     palSocketLength_t addrlen = sizeof(palSocketAddress_t);
00188     palSocketAddress_t address = { 0 };
00189     bool reiterate;
00190 
00191     do {
00192         reiterate = false;
00193 
00194         if (_connection_state == SOCKET_WAIT_FOR_CONNECTION) {
00195             // wait to accept connection
00196             result = pal_accept(_server_socket, &address, &addrlen, &_client_socket);
00197             if (result == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00198                 // Timeout
00199                 return FTCD_COMM_NETWORK_TIMEOUT;
00200             } else if (result != PAL_SUCCESS) {
00201                 return FTCD_COMM_NETWORK_CONNECTION_ERROR;
00202             }
00203 
00204         }
00205 
00206         // Set state as accepted connection
00207         _connection_state = SOCKET_CONNECTION_ACCEPTED;
00208 
00209         // Read the message from an open connection,
00210         // if the connection has been closed by the client wait for a new connection
00211         comm_status = FtcdCommBase::wait_for_message(message_out, message_size_out);
00212         if (comm_status == FTCD_COMM_NETWORK_CONNECTION_CLOSED) {
00213             reiterate = true; // Set the reiterate flag so that we will wait for a new connection before returning from function
00214         } 
00215         if (comm_status != FTCD_COMM_STATUS_SUCCESS) { // If error reading - close the client socket and back to SOCKET_CLOSED state
00216             _connection_state = SOCKET_WAIT_FOR_CONNECTION;
00217         }
00218 
00219     } while (reiterate);
00220     return comm_status;
00221 }
00222 
00223 ftcd_comm_status_e FtcdCommSocket::is_token_detected()
00224 {
00225     char c;
00226     ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS;
00227     size_t idx = 0;
00228 
00229     //read char by char to detect token
00230     while (idx < FTCD_MSG_HEADER_TOKEN_SIZE_BYTES) {
00231         result = _read_from_socket(reinterpret_cast<void*>(&c), 1);
00232         
00233         if (result != FTCD_COMM_STATUS_SUCCESS) {
00234             return result;
00235         }
00236 
00237         if (c == _header_token[idx]) {
00238             idx++;
00239         } else {
00240             idx = 0;
00241         }
00242     }
00243     return result;
00244 }
00245 
00246 
00247 uint32_t FtcdCommSocket::read_message_size(void)
00248 {
00249     uint32_t message_size = 0;
00250     ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS;
00251 
00252     result = _read_from_socket(reinterpret_cast<void*>(&message_size), sizeof(message_size));
00253     if (result != FTCD_COMM_STATUS_SUCCESS) {
00254         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed reading message size");
00255         return 0;
00256     }
00257 
00258     return message_size;
00259 }
00260 
00261 bool FtcdCommSocket::read_message(uint8_t *message_out, size_t message_size)
00262 {
00263     ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS;
00264 
00265     if (message_out == NULL) {
00266         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Invalid message buffer");
00267         return false;
00268     }
00269 
00270     // Read CBOR message bytes
00271     // We assume that message_size is NOT bigger than INT_MAX
00272     result = _read_from_socket(reinterpret_cast<void*>(message_out), (int)message_size);
00273     if (result != FTCD_COMM_STATUS_SUCCESS) {
00274         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed reading message bytes");
00275         return false;
00276     }
00277     return true;
00278 }
00279 
00280 
00281 bool FtcdCommSocket::read_message_signature(uint8_t *sig, size_t sig_size)
00282 {
00283     ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS;
00284 
00285     if (sig == NULL) {
00286         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Invalid sig buffer");
00287         return false;
00288     }
00289 
00290     // Read signature from medium
00291     // We assume that sig_size is NOT bigger than INT_MAX
00292     result = _read_from_socket(reinterpret_cast<void*>(sig), (int)sig_size);
00293     if (result != FTCD_COMM_STATUS_SUCCESS) {
00294         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed reading message signature bytes");
00295         return false;
00296     }
00297     return true;
00298 }
00299 
00300 
00301 bool FtcdCommSocket::send(const uint8_t *data, uint32_t data_size)
00302 {
00303     bool success = true;
00304     palStatus_t result = PAL_SUCCESS;
00305     size_t sent_bytes = 0;
00306     size_t remaind_bytes = (size_t)data_size;
00307 
00308     do {
00309         if (_connection_state != SOCKET_CONNECTION_ACCEPTED) {
00310             return FTCD_COMM_NETWORK_CONNECTION_CLOSED;
00311         }
00312         result = pal_send(_client_socket, data, remaind_bytes, &sent_bytes);
00313         if (result != PAL_SUCCESS) {
00314             // Drop current client for all errors
00315             _connection_state = SOCKET_WAIT_FOR_CONNECTION;
00316             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed pal_send");
00317             success = false;
00318             break;
00319         }
00320 
00321         if (sent_bytes == 0 || sent_bytes > remaind_bytes) {
00322             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Sending response message failed");
00323             success = false;
00324             break;
00325         }
00326         remaind_bytes = remaind_bytes - sent_bytes;
00327         data += sent_bytes;
00328 
00329     } while (remaind_bytes != 0);
00330 
00331     return success;
00332 }
00333 
00334 bool FtcdCommSocket::_listen(void)
00335 {
00336     int status;
00337     palStatus_t result = PAL_SUCCESS;
00338     palSocketAddress_t address = { 0 };
00339     palIpV4Addr_t ipv4 = { 0 };
00340     int enable_reuseaddr = 1;
00341 
00342     //Check port number and domain type
00343     if (_port == 0) {
00344         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Wrong port number");
00345         return false;
00346     }
00347 
00348     if (_current_domain_type != FTCD_IPV4) {
00349         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Wrong domain type");
00350         return false;
00351     }
00352 
00353     //Open server and client sockets
00354     result = pal_socket((palSocketDomain_t )_current_domain_type, PAL_SOCK_STREAM_SERVER , false, _interface_index, &_server_socket);
00355     if (result != PAL_SUCCESS) {
00356         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_socket failed");
00357         return false;
00358     }
00359 
00360     result = pal_socket((palSocketDomain_t )_current_domain_type, PAL_SOCK_STREAM, false, _interface_index, &_client_socket);
00361     if (result != PAL_SUCCESS) {
00362         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_socket failed");
00363         return false;
00364     }
00365     // reset connection state
00366     _connection_state = SOCKET_WAIT_FOR_CONNECTION;
00367 
00368     status = pal_setSocketOptions(_server_socket, PAL_SO_REUSEADDR, &enable_reuseaddr, sizeof(enable_reuseaddr));
00369     if (status != 0) {
00370         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed to set SO_REUSEADDR (status %d)", status);
00371         return false;
00372     }
00373 
00374     //Get ipv4 format address from interface info structure
00375     status = pal_getSockAddrIPV4Addr(&(_net_interface_info->address), ipv4);
00376     if (status != 0) {
00377         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot palGetSockAddrIPV4Addr (status %d)", status);
00378         return false;
00379     }
00380 
00381     //Set the retrieved address to pal socket address
00382     status = pal_setSockAddrIPV4Addr(&address, ipv4);
00383     if (status != 0) {
00384         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot set socket ipv4 address (status %d)", status);
00385         return false;
00386     }
00387 
00388     //Set current port number to pal socket address
00389     status = pal_setSockAddrPort(&address, _port);
00390     if (status != 0) {
00391         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot set socket port address (status %d)", status);
00392         return false;
00393     }
00394 
00395     //set server socket timeout
00396     if (_rcv_timeout >= 0) {
00397         status = pal_setSocketOptions(_server_socket, PAL_SO_RCVTIMEO , &_rcv_timeout, sizeof(_rcv_timeout));
00398         if (status != 0) {
00399             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot set server socket timeout (status %d)", status);
00400             return false;
00401         }
00402     }
00403 
00404     status = pal_bind(_server_socket, &address, _net_interface_info->addressSize);
00405     if (status != 0) {
00406         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_bind failed (status %d)", status);
00407         return false;
00408     }
00409 
00410     status = pal_listen(_server_socket, NUM_OF_PENDING_CONNECTIONS);
00411     if (status != 0) {
00412         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_listen failed (status %d)", status);
00413         return false;
00414     }
00415 
00416     mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Factory Client is waiting for incoming connection...");
00417 
00418     return true;
00419 }
00420 
00421 
00422 ftcd_comm_status_e FtcdCommSocket::_read_from_socket(void * data_out, int data_out_size)
00423 {
00424     palStatus_t pal_status = PAL_SUCCESS;
00425     size_t bytes_received = 0;
00426     size_t left_to_read = data_out_size;
00427     uint8_t* buffer = (uint8_t*)data_out;
00428     while (left_to_read > 0) {
00429         if (_connection_state != SOCKET_CONNECTION_ACCEPTED) {
00430             return FTCD_COMM_NETWORK_CONNECTION_CLOSED;
00431         }
00432         bytes_received = 0;
00433         pal_status = pal_recv(_client_socket, buffer, left_to_read, &bytes_received);
00434         if (pal_status == PAL_ERR_SOCKET_CONNECTION_CLOSED ) {
00435             // Drop current client
00436             _connection_state = SOCKET_WAIT_FOR_CONNECTION;
00437             return FTCD_COMM_NETWORK_CONNECTION_CLOSED;
00438         }
00439         else if (pal_status == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00440             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Receive socket timeout");
00441             return FTCD_COMM_NETWORK_TIMEOUT;
00442         } else if (pal_status != PAL_SUCCESS) {
00443             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Receive socket error, (status = 0x%" PRIx32 ")", (uint32_t)pal_status);
00444             return FTCD_COMM_NETWORK_CONNECTION_ERROR;
00445         }
00446         buffer += bytes_received;
00447         if (left_to_read < bytes_received) {
00448             return FTCD_COMM_INTERNAL_ERROR;
00449         }
00450         left_to_read -= bytes_received;
00451     }
00452 
00453     return FTCD_COMM_STATUS_SUCCESS;
00454 }
00455 
00456