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