Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

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 #define FTCD_SEM_TIMEOUT ( (_rcv_timeout == INFINITE_SOCKET_TIMEOUT) ? (PAL_RTOS_WAIT_FOREVER) : (_rcv_timeout) )
00036 
00037 // Cabllback triggered by socket events
00038 // Non-blocking async sockets are used with blocking wrappers that wait on _async_sem.
00039 // This callback signals the waiting semaphore in the blocking wrappers
00040 
00041 // We must be sure that we do not have a situations where sem is being waited and then 2 releases prior to the next wait:
00042 
00043 
00044 /* Scenario 1 (All according to plan)
00045 ************************************************************************************************************************************************************************************************************************************************************************************
00046 Network thread/threads: ----------------------------------------------_socket_event_ready_cb -> take _lock -> signal (release) _aync_sem=1 ----------------------------------------------------------- _socket_event_ready_cb -> take _lock -> signal (release) _aync_sem=1
00047 
00048 
00049 
00050 application thread:     _wait_for_socket_event (on _async_sem=0) --------------------------------------------------------------------------_aync_sem=0------- release _lock ------------- _wait_for_socket_event --------------------------------------------------------------->>>
00051 ************************************************************************************************************************************************************************************************************************************************************************************
00052 */
00053 
00054 /* Scenario 2 (Event signals _async_sem before release _lock in _wait_for_socket_event)
00055 ************************************************************************************************************************************************************************************************************************************************************************************
00056 Network thread/threads: ----------------------------------------------_socket_event_ready_cb -> take _lock -> signal (release) _aync_sem=1 ---- _socket_event_ready_cb -> ----try to take _lock and fail (locked)-------------------------------------------------------------------
00057 
00058 
00059 
00060 application thread:     _wait_for_socket_event (on _async_sem=0) --------------------------------------------------------------------------_aync_sem=0--------------------------------------------------------- release _lock ------next action attempt and probably fail---- _wait_for_socket_event (block)-->>>
00061 ************************************************************************************************************************************************************************************************************************************************************************************
00062 */
00063 
00064 /* Scenario 3 (Multiple events are invoked before _wait_for_socket_event() stops blocking)
00065 ************************************************************************************************************************************************************************************************************************************************************************************
00066 Network thread/threads: ----------------------------------------------_socket_event_ready_cb -> take _lock -> signal (release) _aync_sem=1 ---- _socket_event_ready_cb -> try to take _lock and fail (locked) ------------------------------------
00067 
00068 
00069 
00070 application thread:     _wait_for_socket_event (on _async_sem=0) ---------------------------------------------------------------------------------------------------------------------------------------_aync_sem=0--release _lock---------next action attempt and probably succeed (2nd event)-->>>
00071 ************************************************************************************************************************************************************************************************************************************************************************************
00072 */
00073 
00074 
00075 
00076 void FtcdCommSocket::_socket_event_ready_cb(void *socket_obj)
00077 {
00078     palStatus_t pal_status;
00079     // No need for NULL check, we pass a valid pointer
00080     FtcdCommSocket *obj = static_cast<FtcdCommSocket *>(socket_obj);
00081     // Do not print log, may be called from ISR
00082 
00083     // First lock - this prevents a scenario where sem count is greater then n (1 in our case) which is undefined behavior
00084     pal_status = pal_osSemaphoreWait(obj->_lock, 0, NULL);
00085 
00086     // If lock is taken by another thread - do not signal _async_sem because its count is 1. 
00087     // This scenario will happen if _socket_event_ready_cb() is triggered twice, before _lock is released in _wait_for_socket_event()
00088     // No need to signal _async_sem because it is already free
00089     // Note that our blocking wrappers first try to do the operation, and then block until an event occurs
00090     if (pal_status != PAL_SUCCESS) { 
00091         return;
00092     }
00093 
00094     // After we take the lock, we may signal sem
00095     (void)pal_osSemaphoreRelease(obj->_async_sem);
00096 }
00097 
00098 palStatus_t FtcdCommSocket::_wait_for_socket_event()
00099 {
00100     palStatus_t pal_status;
00101     // Wait for signal from a new event, signaled by _socket_event_ready_cb()
00102     pal_status = pal_osSemaphoreWait(_async_sem, FTCD_SEM_TIMEOUT, NULL);
00103 
00104     // Unlock the lock so that one more signal may be signaled from an event
00105     (void)pal_osSemaphoreRelease((palSemaphoreID_t)_lock);
00106 
00107     return pal_status;
00108 }
00109 
00110 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)
00111     : FtcdCommBase(network_endianness, NULL, false)
00112 {
00113     _interface_handler = interfaceHandler;
00114     _required_domain_type = domain;
00115     _port = port_num;
00116     _rcv_timeout = timeout;
00117     _current_domain_type = FTCD_AF_UNSPEC;
00118     _interface_index = 0;
00119     _net_interface_info = NULL;
00120     _server_socket = NULL;
00121     _client_socket = NULL;
00122     _connection_state = SOCKET_WAIT_FOR_CONNECTION;
00123     (void)pal_osSemaphoreCreate(1, &_async_sem);
00124     (void)pal_osSemaphoreCreate(1, &_lock);
00125 
00126 }
00127 
00128 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)
00129     : FtcdCommBase(network_endianness, header_token, use_signature)
00130 
00131 {
00132     _interface_handler = interfaceHandler;
00133     _required_domain_type = domain;
00134     _port = port_num;
00135     _rcv_timeout = timeout;
00136     _current_domain_type = FTCD_AF_UNSPEC;
00137     _interface_index = 0;
00138     _net_interface_info = NULL;
00139     _server_socket = NULL;
00140     _client_socket = NULL;
00141     _connection_state = SOCKET_WAIT_FOR_CONNECTION;
00142     (void)pal_osSemaphoreCreate(1, &_async_sem);
00143     (void)pal_osSemaphoreCreate(1, &_lock);
00144 }
00145 
00146 FtcdCommSocket::~FtcdCommSocket()
00147 {
00148 
00149     if (_net_interface_info != NULL) {
00150         fcc_free(_net_interface_info);
00151     }
00152     if (_server_socket != NULL) {
00153         pal_close(&_server_socket);
00154     }
00155     if (_client_socket != NULL) {
00156         pal_close(&_client_socket);
00157     }
00158 }
00159 
00160 
00161 bool FtcdCommSocket::init()
00162 {
00163     int retries = NUM_OF_TRIES_TO_GET_INTERFACE_INFO;
00164     palIpV4Addr_t ip_v4_addr;
00165     char ip_and_port_string[32] = { 0 };
00166     uint32_t index = 0;
00167 
00168     //Call to pal init
00169     palStatus_t result = pal_init();
00170     if (result != PAL_SUCCESS) {
00171         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Error initializing pal");
00172         return false;
00173     }
00174 
00175     // If port is 0, generate random port
00176     // Pal currently does not support binding with port 0.
00177     if (_port == 0) {
00178         srand((unsigned int)pal_osKernelSysTick());
00179         // Generate random port int the range [RANDOM_PORT_MIN, RANDOM_PORT_MAX - 1] including.
00180         _port = (uint16_t)(rand() % (RANDOM_PORT_MAX - RANDOM_PORT_MIN) + RANDOM_PORT_MIN);
00181     }
00182 
00183     //Register connected interface handler
00184     result = pal_registerNetworkInterface((void*)_interface_handler, &_interface_index);
00185     if (result != 0) {
00186         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n pal_RegisterNetworkInterface Failed");
00187         return false;
00188     }
00189 
00190     //Allocate memory for interface info
00191     if (_net_interface_info == NULL) {
00192         _net_interface_info = (palNetInterfaceInfo_t*)fcc_malloc(sizeof(palNetInterfaceInfo_t));
00193         if (_net_interface_info == NULL) {
00194             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Failed to allocate memory for network interface");
00195             return false;
00196         }
00197     }
00198 
00199     //Try to get interface info
00200     while (retries--) {
00201         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Trying receive interface ...");
00202         result = pal_getNetInterfaceInfo(_interface_index, _net_interface_info);
00203         if (result != 0) {
00204             pal_osDelay(200);
00205         } else {//In case we have interface info we print it
00206             if (_required_domain_type != FTCD_IPV4) {
00207                 mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Illegal domain type");
00208                 break;
00209             }
00210             //Update domain type
00211             _current_domain_type = _required_domain_type;
00212 
00213             result = pal_getSockAddrIPV4Addr(&(_net_interface_info->address), ip_v4_addr);
00214             if (result != PAL_SUCCESS) {
00215                 mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n palGetSockAddrIPV4Addr failed");
00216                 break;
00217             }
00218             memset(ip_and_port_string, 0, sizeof(ip_and_port_string));
00219             index = 0;
00220             for (uint32_t i = 0; i < sizeof(palIpV4Addr_t); i++) {
00221                 if (i < sizeof(palIpV4Addr_t) - 1) {
00222                     index += sprintf(&ip_and_port_string[index], "%d.", ip_v4_addr[i]);
00223                 } else {
00224                     index += sprintf(&ip_and_port_string[index], "%d:", ip_v4_addr[i]);
00225                     index += sprintf(&ip_and_port_string[index], "%d\n", _port);
00226                 }
00227             }
00228 
00229             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Factory Client IP Address and Port :  %s", ip_and_port_string);
00230             //open and listen to socket
00231             if (_listen()) {
00232                 return true;
00233             } else {
00234                 mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed to listen to socket");
00235             }
00236 
00237         }
00238 
00239     }
00240 
00241     mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n FCC did not succeed receive network interface !!!!!!");
00242     //If we couldn't get interface info free allocated memory
00243     fcc_free(_net_interface_info);
00244     _net_interface_info = NULL;
00245     return false;
00246 
00247 }
00248 
00249 void FtcdCommSocket::finish(void)
00250 {
00251     if (_server_socket != NULL) {
00252         pal_close(&_server_socket);
00253         _server_socket = NULL;
00254     }
00255     if (_client_socket != NULL) {
00256         pal_close(&_client_socket);
00257         _client_socket = NULL;
00258     }
00259     pal_destroy();
00260 }
00261 
00262 
00263 /* 
00264  There are 2 possible scenarios where _accept() is called:
00265  1. Very likely: sem=1 -> _listen(), sem=0 -> create socket -> _accept(), sem=0(block) -> _socket_event_ready_cb(), sem=1 -> accept() resumes, sem=0 -> nonblocking pal_accept()
00266  2. Very unlikely: sem=1 -> _listen(), sem=0 -> create socket -> _socket_event_ready_cb(), sem=1 -> _accept() never blocks, sem=0 -> nonblocking pal_accept()
00267 */
00268 palStatus_t FtcdCommSocket::_accept(palSocket_t socket, palSocketAddress_t* address, palSocketLength_t* addressLen, palSocket_t* acceptedSocket)
00269 {
00270     palStatus_t pal_status, result;
00271 
00272     while (true) {
00273         pal_status = pal_accept(socket, address, addressLen, acceptedSocket);
00274         if (pal_status == PAL_ERR_SOCKET_WOULD_BLOCK ) { // Async socket has no connection to accept - wait on semaphore and try again
00275             pal_status = _wait_for_socket_event();
00276             if (pal_status == PAL_ERR_RTOS_TIMEOUT ) { // Semaphore timeout means no event was triggered for _rcv_timeout ms so we return a WOULDBLOCK error according to blocking socket convention
00277                 result = PAL_ERR_SOCKET_WOULD_BLOCK ;
00278                 break;
00279             } else if (pal_status != PAL_SUCCESS){ // Should not happen - some unknown semaphore error
00280                 result = pal_status;
00281                 break;
00282             }
00283             // else: Semaphore signaled by event try accepting again
00284 
00285         } else { // Either success, or error other than PAL_ERR_SOCKET_WOULD_BLOCK, return the status
00286             result = pal_status;
00287             break;
00288         }
00289     }
00290                     
00291     return result;
00292 }
00293 
00294 // no_open_connection, connection_open, connection_open_timeout
00295 ftcd_comm_status_e FtcdCommSocket::wait_for_message(uint8_t **message_out, uint32_t *message_size_out)
00296 {
00297     int result = PAL_SUCCESS;
00298     ftcd_comm_status_e comm_status = FTCD_COMM_STATUS_SUCCESS;
00299     palSocketLength_t addrlen = sizeof(palSocketAddress_t);
00300     palSocketAddress_t address = { 0 , { 0 } };
00301     bool reiterate;
00302 
00303     do {
00304         reiterate = false;
00305 
00306         if (_connection_state == SOCKET_WAIT_FOR_CONNECTION) {
00307             // wait to accept connection
00308             result = _accept(_server_socket, &address, &addrlen, &_client_socket);
00309             if (result == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00310                 // Timeout
00311                 return FTCD_COMM_NETWORK_TIMEOUT;
00312             } else if (result != PAL_SUCCESS) {
00313                 return FTCD_COMM_NETWORK_CONNECTION_ERROR;
00314             }
00315 
00316         }
00317 
00318         // Set state as accepted connection
00319         _connection_state = SOCKET_CONNECTION_ACCEPTED;
00320 
00321         // Read the message from an open connection,
00322         // if the connection has been closed by the client wait for a new connection
00323         comm_status = FtcdCommBase::wait_for_message(message_out, message_size_out);
00324         if (comm_status == FTCD_COMM_NETWORK_CONNECTION_CLOSED) {
00325             reiterate = true; // Set the reiterate flag so that we will wait for a new connection before returning from function
00326         } 
00327         if (comm_status != FTCD_COMM_STATUS_SUCCESS) { // If error reading - close the client socket and back to SOCKET_CLOSED state
00328             _connection_state = SOCKET_WAIT_FOR_CONNECTION;
00329         }
00330 
00331     } while (reiterate);
00332     return comm_status;
00333 }
00334 
00335 ftcd_comm_status_e FtcdCommSocket::is_token_detected()
00336 {
00337     char c;
00338     ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS;
00339     size_t idx = 0;
00340 
00341     //read char by char to detect token
00342     while (idx < FTCD_MSG_HEADER_TOKEN_SIZE_BYTES) {
00343         result = _read_from_socket(reinterpret_cast<void*>(&c), 1);
00344         
00345         if (result != FTCD_COMM_STATUS_SUCCESS) {
00346             return result;
00347         }
00348 
00349         if (c == _header_token[idx]) {
00350             idx++;
00351         } else {
00352             idx = 0;
00353         }
00354     }
00355     return result;
00356 }
00357 
00358 
00359 uint32_t FtcdCommSocket::read_message_size(void)
00360 {
00361     uint32_t message_size = 0;
00362     ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS;
00363 
00364     result = _read_from_socket(reinterpret_cast<void*>(&message_size), sizeof(message_size));
00365     if (result != FTCD_COMM_STATUS_SUCCESS) {
00366         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed reading message size");
00367         return 0;
00368     }
00369 
00370     return message_size;
00371 }
00372 
00373 bool FtcdCommSocket::read_message(uint8_t *message_out, size_t message_size)
00374 {
00375     ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS;
00376 
00377     if (message_out == NULL) {
00378         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Invalid message buffer");
00379         return false;
00380     }
00381 
00382     // Read CBOR message bytes
00383     // We assume that message_size is NOT bigger than INT_MAX
00384     result = _read_from_socket(reinterpret_cast<void*>(message_out), (int)message_size);
00385     if (result != FTCD_COMM_STATUS_SUCCESS) {
00386         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed reading message bytes");
00387         return false;
00388     }
00389     return true;
00390 }
00391 
00392 
00393 bool FtcdCommSocket::read_message_signature(uint8_t *sig, size_t sig_size)
00394 {
00395     ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS;
00396 
00397     if (sig == NULL) {
00398         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Invalid sig buffer");
00399         return false;
00400     }
00401 
00402     // Read signature from medium
00403     // We assume that sig_size is NOT bigger than INT_MAX
00404     result = _read_from_socket(reinterpret_cast<void*>(sig), (int)sig_size);
00405     if (result != FTCD_COMM_STATUS_SUCCESS) {
00406         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed reading message signature bytes");
00407         return false;
00408     }
00409     return true;
00410 }
00411 
00412 #define MS_BETWEEN_SOCKET_SEND_RETRIES 500
00413 palStatus_t FtcdCommSocket::_send(palSocket_t socket, const void* buf, size_t len, size_t* sentDataSize)
00414 {
00415     palStatus_t result = PAL_SUCCESS;
00416     
00417     // in blocking mode (linux socket) - pal_send will block until the buffer is copied into the kernel's networking stack buffer
00418     // In our case, non-blocking (linux socket) - will return a EWOULDBLOCK error if the kernel's buffer, so we will wait and retry (should work on first try)
00419 
00420     while (true) {
00421         result = pal_send(socket, buf, len, sentDataSize);
00422         if (result == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00423             pal_osDelay(MS_BETWEEN_SOCKET_SEND_RETRIES);
00424         } else { // If any other error, or success - return the status
00425             break;
00426         }
00427     }
00428 
00429     return result;
00430 }
00431 
00432 bool FtcdCommSocket::send(const uint8_t *data, uint32_t data_size)
00433 {
00434     bool success = true;
00435     palStatus_t result = PAL_SUCCESS;
00436     size_t sent_bytes = 0;
00437     size_t remaind_bytes = (size_t)data_size;
00438 
00439     do {
00440         if (_connection_state != SOCKET_CONNECTION_ACCEPTED) {
00441             return FTCD_COMM_NETWORK_CONNECTION_CLOSED;
00442         }
00443         result = _send(_client_socket, data, remaind_bytes, &sent_bytes);
00444         if (result != PAL_SUCCESS) {
00445             // Drop current client for all errors
00446             _connection_state = SOCKET_WAIT_FOR_CONNECTION;
00447             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed pal_send");
00448             success = false;
00449             break;
00450         }
00451 
00452         if (sent_bytes == 0 || sent_bytes > remaind_bytes) {
00453             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Sending response message failed");
00454             success = false;
00455             break;
00456         }
00457         remaind_bytes = remaind_bytes - sent_bytes;
00458         data += sent_bytes;
00459 
00460     } while (remaind_bytes != 0);
00461 
00462     return success;
00463 }
00464 
00465 bool FtcdCommSocket::_listen(void)
00466 {
00467     int status;
00468     palStatus_t result = PAL_SUCCESS;
00469     palSocketAddress_t address = { 0 , { 0 } };
00470     palIpV4Addr_t ipv4 = { 0 };
00471     int enable_reuseaddr = 1;
00472 
00473     //Check port number and domain type
00474     if (_port == 0) {
00475         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Wrong port number");
00476         return false;
00477     }
00478 
00479     if (_current_domain_type != FTCD_IPV4) {
00480         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Wrong domain type");
00481         return false;
00482     }
00483 
00484     // Decrement sem count to 0 prior to socket creation. This assures that no socket async event may occur while sem=1 (the initial value)
00485     // Following call to pal_osSemaphoreWait will block
00486     result = pal_osSemaphoreWait(_async_sem, PAL_RTOS_WAIT_FOREVER, NULL);
00487     if (PAL_SUCCESS != result) {
00488         return false;
00489     }
00490 
00491     //Open server and client sockets
00492     result = pal_asynchronousSocketWithArgument((palSocketDomain_t)_current_domain_type, PAL_SOCK_STREAM_SERVER, true, _interface_index, _socket_event_ready_cb, (void*)this, &_server_socket);
00493     if (result != PAL_SUCCESS) {
00494         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_socket failed");
00495         return false;
00496     }
00497 
00498     result = pal_asynchronousSocketWithArgument((palSocketDomain_t)_current_domain_type, PAL_SOCK_STREAM, true, _interface_index, _socket_event_ready_cb, (void*)this, &_client_socket);
00499 
00500     if (result != PAL_SUCCESS) {
00501         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_socket failed");
00502         return false;
00503     }
00504     // reset connection state
00505     _connection_state = SOCKET_WAIT_FOR_CONNECTION;
00506 
00507     status = pal_setSocketOptions(_server_socket, PAL_SO_REUSEADDR, &enable_reuseaddr, sizeof(enable_reuseaddr));
00508     if (status != 0) {
00509         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed to set SO_REUSEADDR (status %d)", status);
00510         return false;
00511     }
00512 
00513     //Get ipv4 format address from interface info structure
00514     status = pal_getSockAddrIPV4Addr(&(_net_interface_info->address), ipv4);
00515     if (status != 0) {
00516         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot palGetSockAddrIPV4Addr (status %d)", status);
00517         return false;
00518     }
00519 
00520     //Set the retrieved address to pal socket address
00521     status = pal_setSockAddrIPV4Addr(&address, ipv4);
00522     if (status != 0) {
00523         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot set socket ipv4 address (status %d)", status);
00524         return false;
00525     }
00526 
00527     //Set current port number to pal socket address
00528     status = pal_setSockAddrPort(&address, _port);
00529     if (status != 0) {
00530         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot set socket port address (status %d)", status);
00531         return false;
00532     }
00533 
00534     //set server socket timeout
00535     if (_rcv_timeout >= 0) {
00536         status = pal_setSocketOptions(_server_socket, PAL_SO_RCVTIMEO, &_rcv_timeout, sizeof(_rcv_timeout));
00537         if (status != 0) {
00538             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot set server socket timeout (status %d)", status);
00539             return false;
00540         }
00541     }
00542 
00543     status = pal_bind(_server_socket, &address, _net_interface_info->addressSize);
00544     if (status != 0) {
00545         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_bind failed (status %d)", status);
00546         return false;
00547     }
00548 
00549     status = pal_listen(_server_socket, NUM_OF_PENDING_CONNECTIONS);
00550     if (status != 0) {
00551         mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_listen failed (status %d)", status);
00552         return false;
00553     }
00554 
00555     mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Factory Client is waiting for incoming connection...");
00556 
00557     return true;
00558 }
00559 
00560 palStatus_t FtcdCommSocket::_recv(palSocket_t socket, void* buf, size_t len, size_t* recievedDataSize)
00561 {
00562     palStatus_t pal_status, result;
00563 
00564     while (true) {
00565         pal_status = pal_recv(socket, buf, len, recievedDataSize);
00566         if (pal_status == PAL_ERR_SOCKET_WOULD_BLOCK ) { // // The event was not a receive event - wait for next one
00567             pal_status = _wait_for_socket_event();
00568             if (pal_status == PAL_ERR_RTOS_TIMEOUT ) { // Semaphore timeout means no event was triggered for _rcv_timeout ms so we return a WOULDBLOCK error according to blocking socket convention
00569                 result = PAL_ERR_SOCKET_WOULD_BLOCK ;
00570                 break;
00571             } else if (pal_status != PAL_SUCCESS) { // Should not happen - some unknown semaphore error
00572                 result = pal_status;
00573                 break;
00574             }
00575             // else: Semaphore signaled by event try receiving again
00576 
00577         } else { // Either success, or error other than PAL_ERR_SOCKET_WOULD_BLOCK, return the status
00578             result = pal_status;
00579             break;
00580         }
00581     }
00582 
00583     return result;
00584 
00585 }
00586 
00587 ftcd_comm_status_e FtcdCommSocket::_read_from_socket(void * data_out, int data_out_size)
00588 {
00589     palStatus_t pal_status = PAL_SUCCESS;
00590     size_t bytes_received = 0;
00591     size_t left_to_read = data_out_size;
00592     uint8_t* buffer = (uint8_t*)data_out;
00593     while (left_to_read > 0) {
00594         if (_connection_state != SOCKET_CONNECTION_ACCEPTED) {
00595             return FTCD_COMM_NETWORK_CONNECTION_CLOSED;
00596         }
00597         bytes_received = 0;
00598         pal_status = _recv(_client_socket, buffer, left_to_read, &bytes_received);
00599         if (pal_status == PAL_ERR_SOCKET_CONNECTION_CLOSED ) {
00600             // Drop current client
00601             _connection_state = SOCKET_WAIT_FOR_CONNECTION;
00602             return FTCD_COMM_NETWORK_CONNECTION_CLOSED;
00603         }
00604         else if (pal_status == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00605             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Receive socket timeout");
00606             return FTCD_COMM_NETWORK_TIMEOUT;
00607         } else if (pal_status != PAL_SUCCESS) {
00608             mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Receive socket error, (status = 0x%" PRIx32 ")", (uint32_t)pal_status);
00609             return FTCD_COMM_NETWORK_CONNECTION_ERROR;
00610         }
00611         buffer += bytes_received;
00612         if (left_to_read < bytes_received) {
00613             return FTCD_COMM_INTERNAL_ERROR;
00614         }
00615         left_to_read -= bytes_received;
00616     }
00617 
00618     return FTCD_COMM_STATUS_SUCCESS;
00619 }
00620