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 pal_plat_network.c Source File

pal_plat_network.c

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 #define _GNU_SOURCE // This is for ppoll found in poll.h
00018 #include "pal.h"
00019 #include "pal_plat_network.h"
00020 #include "pal_rtos.h"
00021 
00022 #include <string.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <unistd.h>
00026 #include <string.h>
00027 #include <sys/time.h>
00028 #include <sys/types.h>
00029 #include <sys/socket.h>
00030 #include <netinet/in.h>
00031 #include <sys/ioctl.h>
00032 #include <net/if.h>
00033 #include <netdb.h>
00034 #include <ifaddrs.h>
00035 #include <errno.h>
00036 #if PAL_NET_ASYNCHRONOUS_SOCKET_API
00037 #include <pthread.h>
00038 #include <poll.h>
00039 #include <signal.h>
00040 #include <fcntl.h>
00041 #include <time.h>
00042 #include <assert.h>
00043 #endif
00044 
00045 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00046 #include <netinet/tcp.h>
00047 #endif
00048 
00049 // invalid socket based on posix
00050 #define PAL_LINUX_INVALID_SOCKET (-1)
00051 
00052 
00053 typedef struct palNetInterfaceName{
00054     char interfaceName[PAL_NET_MAX_IF_NAME_LENGTH];
00055 } palNetInterfaceName_t;
00056 
00057 PAL_PRIVATE palNetInterfaceName_t s_palNetworkInterfacesSupported[PAL_MAX_SUPORTED_NET_INTERFACES];
00058 
00059 PAL_PRIVATE  uint32_t s_palNumOfInterfaces = 0;
00060 PAL_PRIVATE  uint32_t s_pal_network_initialized = 0;
00061 
00062 PAL_PRIVATE palStatus_t translateErrorToPALError(int errnoValue)
00063 {
00064     palStatus_t status;
00065     switch (errnoValue)
00066     {
00067     case EAI_MEMORY:
00068         status = PAL_ERR_NO_MEMORY ;
00069         break;
00070     case EWOULDBLOCK:
00071         status = PAL_ERR_SOCKET_WOULD_BLOCK ;
00072         break;
00073     case ENOTSOCK:
00074         status = PAL_ERR_SOCKET_INVALID_VALUE ;
00075         break;
00076     case EPERM:
00077     case EACCES:
00078         status = PAL_ERR_SOCKET_OPERATION_NOT_PERMITTED ;
00079         break;
00080     case ETIMEDOUT:
00081         status = PAL_ERR_TIMEOUT_EXPIRED ;
00082         break;
00083     case EISCONN:
00084         status = PAL_ERR_SOCKET_ALREADY_CONNECTED ;
00085         break;
00086     case EINPROGRESS:
00087         status = PAL_ERR_SOCKET_IN_PROGRES ;
00088         break;
00089     case EALREADY:
00090         status = PAL_ERR_SOCKET_ALREADY_CONNECTED ;
00091         break;
00092     case EINVAL:
00093         status = PAL_ERR_SOCKET_INVALID_VALUE ;
00094         break;
00095     case EADDRINUSE:
00096         status = PAL_ERR_SOCKET_ADDRESS_IN_USE ;
00097         break;
00098     case ECONNABORTED:
00099         status = PAL_ERR_SOCKET_CONNECTION_ABORTED ;
00100         break;
00101     case ENOBUFS:
00102     case ENOMEM:
00103         status = PAL_ERR_SOCKET_NO_BUFFERS ;
00104         break;
00105     case EINTR:
00106         status = PAL_ERR_SOCKET_INTERRUPTED ;
00107         break;
00108     default:
00109         status = PAL_ERR_SOCKET_GENERIC ;
00110         break;
00111     }
00112     return status;
00113 }
00114 
00115 #if PAL_NET_ASYNCHRONOUS_SOCKET_API
00116 static pthread_t s_pollThread = NULLPTR;
00117 static palMutexID_t s_mutexSocketCallbacks = 0;
00118 static palMutexID_t s_mutexSocketEventFilter = 0;
00119 static palSemaphoreID_t s_socketCallbackSemaphore = 0;
00120 static palSemaphoreID_t s_socketCallbackSignalSemaphore = 0;
00121 
00122 
00123 
00124 // These must be updated only when protected by s_mutexSocketCallbacks
00125 static palAsyncSocketCallback_t  s_callbacks[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {0};
00126 static void* s_callbackArgs[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = { 0 };
00127 static struct pollfd s_fds[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {{0,0,0}};
00128 static uint32_t s_callbackFilter[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {0};
00129 static nfds_t s_nfds = 0;
00130 static volatile bool s_socketThreadTerminateSignaled = false;
00131 
00132 // The below function is the signal handler API, doing nothing.
00133 // The idea is to signal the asyncSocketManager thread with pthread_kill(s_pollThread, SIGUSR1) command
00134 // which make the ppoll API to be interrupted.
00135 
00136 static uint64_t s_palUSR1Counter =0;
00137 static void sigusr2(int signo) {
00138     (void)signo;
00139     s_palUSR1Counter++;
00140     pal_osSemaphoreRelease(s_socketCallbackSignalSemaphore);
00141 }
00142 
00143 static uint64_t s_palIOCounter =0;
00144 
00145 static void sig_io_handler(int signo) {
00146     (void)signo;
00147 
00148     s_palIOCounter++;
00149     pal_osSemaphoreRelease(s_socketCallbackSignalSemaphore);
00150 }
00151 
00152 
00153 static const unsigned int PAL_SOCKETS_TERMINATE = 10000;
00154 
00155 
00156 PAL_PRIVATE void clearSocketFilter( int socketFD)
00157 {
00158     palStatus_t result = PAL_SUCCESS;
00159     int i = 0;
00160     result = pal_osMutexWait(s_mutexSocketEventFilter, PAL_RTOS_WAIT_FOREVER);
00161     if (PAL_SUCCESS != result)
00162     {
00163         PAL_LOG(ERR, "error waiting for mutex"); // we want to zero the flag even if this fails beacuse it is better to get an extra event than miss one.
00164     }
00165     for (i = 0; i < PAL_NET_TEST_MAX_ASYNC_SOCKETS; i++)
00166     {
00167 
00168         if (s_fds[i].fd == socketFD)
00169         {
00170             s_callbackFilter[i] = 0;
00171             break;
00172         }
00173     }
00174     result = pal_osMutexRelease(s_mutexSocketEventFilter);
00175     if (PAL_SUCCESS != result)
00176     {
00177         PAL_LOG(ERR, "error releasing mutex");
00178     }
00179 }
00180 
00181 
00182 // Thread function.
00183 PAL_PRIVATE void asyncSocketManager(void const* arg)
00184 {
00185     PAL_UNUSED_ARG(arg); // unused
00186     int res;
00187     palAsyncSocketCallback_t  callbacks[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {0};
00188     void* callbackArgs[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {0};
00189     struct pollfd fds[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {{0,0,0}};
00190     nfds_t nfds = 0;
00191     struct sigaction s;
00192     sigset_t blockedSignals;
00193     palStatus_t result = PAL_SUCCESS;
00194     uint64_t lastIOCounter=0;
00195     uint64_t lastUSRCounter=0;
00196 
00197     const struct timespec timeout_zero = {0, 0};
00198 
00199     // Initialize the signal handler. SIG_IGN and SIG_DFL do not work
00200     s.sa_handler = sigusr2;
00201     sigemptyset(&s.sa_mask);
00202     s.sa_flags = 0;
00203     sigaction(SIGUSR1, &s, NULL);
00204 
00205     s.sa_handler = sig_io_handler;
00206     sigemptyset(&s.sa_mask);
00207     s.sa_flags =  SA_RESTART ;
00208     sigaction(SIGIO, &s, NULL);
00209 
00210     // Block the timer signal from interrupting ppoll(), as it does not have a signal handler.
00211     // The timer signal is already blocked on all the threads created after pal_init(), but
00212     // the ppoll() will change that situation with the given sigmask.
00213     // Without this, the libc's default signal handler will kick in and kill the process.
00214     sigemptyset(&blockedSignals);
00215     sigaddset(&blockedSignals, PAL_TIMER_SIGNAL);
00216 
00217     s_pollThread = pthread_self(); // save the thread id for signal usage
00218     // Tell the calling thread that we have finished initialization
00219     result = pal_osSemaphoreRelease(s_socketCallbackSemaphore);
00220     if (result != PAL_SUCCESS)
00221     {
00222         PAL_LOG(ERR, "Error in async socket manager on semaphore release");
00223     }
00224 
00225 
00226     while (result == PAL_SUCCESS) //As long as all goes well loop forever
00227     {
00228         // block until a SIGIO signal is received
00229         if (lastUSRCounter == s_palUSR1Counter) // no updates to the sockets that need to be polled (wait for next IO)  - if there were updates skip waiting and proceeed to poll
00230         {
00231             pal_osSemaphoreWait(s_socketCallbackSignalSemaphore, PAL_RTOS_WAIT_FOREVER, NULL);
00232         }
00233 
00234         // Critical section to update globals
00235         result = pal_osMutexWait(s_mutexSocketCallbacks, PAL_RTOS_WAIT_FOREVER);
00236         if (PAL_SUCCESS != result)
00237         {
00238             PAL_LOG(ERR, "Error in async socket manager on mutex wait");
00239             break;
00240         }
00241 
00242         // Check for thread termination request
00243         if(s_nfds == PAL_SOCKETS_TERMINATE)
00244         {
00245             result = pal_osMutexRelease(s_mutexSocketCallbacks);
00246             if (result != PAL_SUCCESS)
00247             {
00248                 PAL_LOG(ERR, "Error in async socket manager on mutex release during termination");
00249             }
00250             s_nfds = 0; // Reset s_ndfs
00251             s_socketThreadTerminateSignaled = true; // mark that the thread has receieved the termination request
00252             // Break out of while(1)
00253             break;
00254         }
00255         // Update the list of sockets to watch from the global list
00256         nfds = s_nfds;
00257         if(nfds)
00258         {
00259             memcpy(callbacks, s_callbacks, nfds*sizeof(callbacks[0]));
00260             memcpy(callbackArgs, s_callbackArgs, nfds * sizeof(void*));
00261             memcpy(fds, s_fds, nfds*sizeof(fds[0]));
00262 
00263             for (int i=0; i < nfds; i++)
00264             {
00265                 fds[i].events = POLLIN|POLLOUT|POLLRDHUP|POLLERR;
00266                 fds[i].revents = 0;
00267                 s_callbackFilter[i] = 0;
00268             }
00269         }
00270         result = pal_osMutexRelease(s_mutexSocketCallbacks);
00271         if (result != PAL_SUCCESS)
00272         {
00273             PAL_LOG(ERR, "Error in async socket manager on mutex release");
00274             break;
00275         }
00276 
00277         // Wait for a socket event or pthread_kill(s_pollThread, SIGUSR1) event
00278         lastUSRCounter = s_palUSR1Counter;
00279         res = ppoll(&fds[0], nfds, &timeout_zero, &blockedSignals);
00280 
00281 
00282         // Notes:
00283         // If a POLLIN event occurred and recv from the socket results in 0 bytes being read, it means that
00284         // the remote socket was closed. Unless this is dealt with in the callback (for example by closing the
00285         // socket) the next call to ppoll will also immediately return with the same result.
00286         if(res >0 || errno == EINTR)
00287         {
00288             unsigned int i;
00289             errno = 0;
00290             // Some event was triggered, so iterate over all watched fds's and call the relevant callbacks.
00291                 if (lastIOCounter< s_palIOCounter)
00292                 {
00293                     lastIOCounter = s_palIOCounter;
00294                     for( i = 0; i < nfds; i++)
00295                     {
00296                         if(fds[i].revents)
00297                         {
00298                             uint32_t filter = POLLOUT|POLLHUP; // filter for specific event that is triggered for non-connected sockets- this event combination shouldn't exist in an active socket.
00299 
00300 
00301                             if ((fds[i].revents != filter) && ((fds[i].revents != POLLOUT) || (fds[i].revents != s_callbackFilter[i])) ) // this is handlign for a special scenario when a specific event which shouldnt happen is sent to all unconnected sockets in Linux triggering an unwanted callback.
00302                             {
00303                                 callbacks[i](callbackArgs[i]);
00304                             }
00305                             result = pal_osMutexWait(s_mutexSocketEventFilter, PAL_RTOS_WAIT_FOREVER);
00306                             if (PAL_SUCCESS != result)
00307                             {
00308                                 PAL_LOG(ERR, "error waiting for mutex");
00309                             }
00310                             else
00311                             {
00312                                 s_callbackFilter[i] = fds[i].revents;
00313                                 result = pal_osMutexRelease(s_mutexSocketEventFilter);
00314                                 if (PAL_SUCCESS != result)
00315                                 {
00316                                     PAL_LOG(ERR, "error releasing mutex");
00317                                 }
00318                             }
00319 
00320 
00321                         }
00322                     }
00323                 }
00324 
00325 
00326         }
00327         else if (res == 0)
00328         {
00329             // Timeout
00330         }
00331         else
00332         {
00333             PAL_LOG(ERR, "Error in async socket manager");
00334         }
00335     }  // while
00336 }
00337 #endif // PAL_NET_ASYNCHRONOUS_SOCKET_API
00338 
00339 PAL_PRIVATE palStatus_t pal_plat_SockAddrToSocketAddress(const palSocketAddress_t* palAddr, struct sockaddr* output)
00340 {
00341     palStatus_t result = PAL_SUCCESS;
00342     uint16_t port = 0;
00343     bool found = false;
00344 
00345     result = pal_getSockAddrPort(palAddr, &port);
00346     if (result != PAL_SUCCESS)
00347     {
00348         return result;
00349     }
00350 
00351 #if PAL_SUPPORT_IP_V4
00352     if (PAL_AF_INET == palAddr->addressType)
00353     {
00354         palIpV4Addr_t ipV4Addr = { 0 };
00355         struct sockaddr_in* ip4addr = (struct sockaddr_in*)output;
00356         ip4addr->sin_family = AF_INET;
00357         ip4addr->sin_port = PAL_HTONS(port);
00358         result = pal_getSockAddrIPV4Addr(palAddr, ipV4Addr);
00359         if (result == PAL_SUCCESS)
00360         {
00361             memcpy(&ip4addr->sin_addr, ipV4Addr, sizeof(ip4addr->sin_addr));
00362         }
00363         found = true;
00364     }
00365 
00366 #endif // PAL_SUPPORT_IP_V4
00367 #if PAL_SUPPORT_IP_V6
00368     if (PAL_AF_INET6  == palAddr->addressType)
00369     {
00370         palIpV6Addr_t ipV6Addr = {0};
00371         struct sockaddr_in6* ip6addr = (struct sockaddr_in6*)output;
00372         ip6addr->sin6_family = AF_INET6;
00373         ip6addr->sin6_scope_id = 0; // we assume there will not be several interfaces with the same IP.
00374         ip6addr->sin6_flowinfo = 0;
00375         ip6addr->sin6_port = PAL_HTONS(port);
00376         result = pal_getSockAddrIPV6Addr(palAddr, ipV6Addr);
00377         if (result == PAL_SUCCESS)
00378         {
00379             memcpy(&ip6addr->sin6_addr, ipV6Addr, sizeof(ip6addr->sin6_addr));
00380         }
00381         found = true;
00382     }
00383 #endif
00384 
00385     if (false == found)
00386     {
00387         return PAL_ERR_SOCKET_INVALID_ADDRESS ;
00388     }
00389 
00390     return result;
00391 }
00392 
00393 PAL_PRIVATE palStatus_t pal_plat_socketAddressToPalSockAddr(struct sockaddr* input, palSocketAddress_t* out, palSocketLength_t* length)
00394 {
00395     palStatus_t result = PAL_SUCCESS;
00396     bool found = false;
00397 
00398 #if PAL_SUPPORT_IP_V4
00399     if (input->sa_family == AF_INET)
00400     {
00401         palIpV4Addr_t ipV4Addr;
00402         struct sockaddr_in* ip4addr = (struct sockaddr_in*)input;
00403 
00404         memcpy(ipV4Addr, &ip4addr->sin_addr, PAL_IPV4_ADDRESS_SIZE);
00405         result = pal_setSockAddrIPV4Addr(out, ipV4Addr);
00406         if (result == PAL_SUCCESS)
00407         {
00408             result = pal_setSockAddrPort(out, PAL_NTOHS(ip4addr->sin_port));
00409         }
00410         *length = sizeof(struct sockaddr_in);
00411         found = true;
00412     }
00413 #endif //PAL_SUPPORT_IP_V4
00414 #if PAL_SUPPORT_IP_V6
00415     if (input->sa_family == AF_INET6)
00416     {
00417         palIpV6Addr_t ipV6Addr;
00418         struct sockaddr_in6* ip6addr = (struct sockaddr_in6*)input;
00419         memcpy(ipV6Addr, &ip6addr->sin6_addr, PAL_IPV6_ADDRESS_SIZE);
00420         result = pal_setSockAddrIPV6Addr(out, ipV6Addr);
00421         if (result == PAL_SUCCESS)
00422         {
00423             result = pal_setSockAddrPort(out, PAL_NTOHS(ip6addr->sin6_port));
00424         }
00425         *length = sizeof(struct sockaddr_in6);
00426         found = true;
00427     }
00428 #endif // PAL_SUPPORT_IP_V6
00429 
00430     if (false == found)
00431     { // we got unspeicified in one of the tests, so Don't fail , but don't translate address.  // re-chcking
00432         result = PAL_ERR_SOCKET_INVALID_ADDRESS_FAMILY ;
00433     }
00434 
00435     return result;
00436 }
00437 
00438 palStatus_t pal_plat_socketsInit(void* context)
00439 {
00440     PAL_UNUSED_ARG(context);
00441     palStatus_t result = PAL_SUCCESS;
00442 
00443     if (s_pal_network_initialized == 1)
00444     {
00445         return PAL_SUCCESS; // already initialized.
00446     }
00447 
00448 
00449 #if PAL_NET_ASYNCHRONOUS_SOCKET_API
00450 
00451     result = pal_osMutexCreate(&s_mutexSocketCallbacks);
00452     if (result != PAL_SUCCESS)
00453     {
00454         return result;
00455     }
00456 
00457     result = pal_osMutexCreate(&s_mutexSocketEventFilter);
00458     if (PAL_SUCCESS != result)
00459     {
00460         return result;
00461     }
00462 
00463 
00464     result = pal_osSemaphoreCreate(0, &s_socketCallbackSignalSemaphore);
00465     if (result != PAL_SUCCESS)
00466     {
00467         // todo: clean up the mess created so far
00468         return result;
00469     }
00470 
00471     // Sleep at first wait
00472     result = pal_osSemaphoreCreate(0, &s_socketCallbackSemaphore);
00473     if (result != PAL_SUCCESS)
00474     {
00475         if (pal_osMutexDelete(&s_mutexSocketCallbacks) != PAL_SUCCESS) //cleanup allocated resources
00476         {
00477             // TODO print error using logging mechanism when available.
00478         }
00479         return result;
00480     }
00481 
00482     s_socketThreadTerminateSignaled = false;
00483     palThreadID_t threadID = NULLPTR;
00484     result = pal_osThreadCreateWithAlloc(asyncSocketManager, NULL, PAL_osPriorityReservedSockets , PAL_NET_TEST_ASYNC_SOCKET_MANAGER_THREAD_STACK_SIZE, NULL, &threadID);
00485     if (PAL_SUCCESS != result)
00486     {
00487         if (PAL_ERR_RTOS_PRIORITY  == result)
00488         {
00489             result = PAL_ERR_SOCKET_OPERATION_NOT_PERMITTED ;
00490         }
00491         else
00492         {
00493             result = PAL_ERR_SOCKET_GENERIC ;
00494         }
00495     }
00496     else
00497     {
00498         // Wait here for the thread to be initialized.
00499         result = pal_osSemaphoreWait(s_socketCallbackSemaphore, PAL_RTOS_WAIT_FOREVER, NULL);
00500         if (PAL_SUCCESS != result)
00501         {
00502             goto end;
00503         }
00504         result = pal_osSemaphoreDelete(&s_socketCallbackSemaphore);
00505         if (PAL_SUCCESS != result)
00506         {
00507             goto end;
00508         }
00509     }
00510 #endif
00511 
00512 end:
00513     if (PAL_SUCCESS == result)
00514     {
00515         s_pal_network_initialized = 1;
00516     }
00517 
00518 
00519     return result;
00520 }
00521 
00522 palStatus_t pal_plat_registerNetworkInterface (void* context, uint32_t* interfaceIndex)
00523 {
00524     palStatus_t result = PAL_SUCCESS;
00525     uint32_t index = 0;
00526     bool found = false;
00527 
00528     for (index = 0; index < s_palNumOfInterfaces; index++) // if specific context already registered return existing index instead of registering again.
00529     {
00530         if (memcmp(s_palNetworkInterfacesSupported[index].interfaceName, (const char *)context, strlen(s_palNetworkInterfacesSupported[index].interfaceName)) == 0)
00531         {
00532             found = true;
00533             *interfaceIndex = index;
00534             break;
00535         }
00536     }
00537     if (false == found)
00538     {
00539         if (s_palNumOfInterfaces < PAL_MAX_SUPORTED_NET_INTERFACES)
00540         {
00541             strncpy(s_palNetworkInterfacesSupported[s_palNumOfInterfaces].interfaceName, (const char *)context, PAL_NET_MAX_IF_NAME_LENGTH-1);
00542             s_palNetworkInterfacesSupported[s_palNumOfInterfaces].interfaceName[PAL_NET_MAX_IF_NAME_LENGTH-1] = '\0';
00543             *interfaceIndex = s_palNumOfInterfaces;
00544             ++s_palNumOfInterfaces;
00545         }
00546         else
00547         {
00548             result = PAL_ERR_SOCKET_MAX_NUMBER_OF_INTERFACES_REACHED ;
00549         }
00550     }
00551 
00552     return result;
00553 }
00554 
00555 palStatus_t pal_plat_socketsTerminate (void* context)
00556 {
00557     PAL_UNUSED_ARG(context);
00558     palStatus_t result = PAL_SUCCESS;
00559     palStatus_t firstError = PAL_SUCCESS;
00560 
00561 #if PAL_NET_ASYNCHRONOUS_SOCKET_API
00562     // Critical section to update globals
00563     result = pal_osMutexWait(s_mutexSocketCallbacks, PAL_RTOS_WAIT_FOREVER);
00564     if (result != PAL_SUCCESS)
00565     {
00566         // TODO print error using logging mechanism when available.
00567         firstError = result;
00568     }
00569 
00570     s_nfds = PAL_SOCKETS_TERMINATE;
00571     result = pal_osSemaphoreRelease(s_socketCallbackSignalSemaphore);
00572     if ((PAL_SUCCESS != result) && (PAL_SUCCESS == firstError))
00573     {
00574         // TODO print error using logging mechanism when available.
00575         firstError = result;
00576     }
00577     // Tell the poll thread to interrupt so that it can check for termination.
00578     if(s_pollThread != NULLPTR)
00579     {
00580         pthread_kill(s_pollThread, SIGUSR1);
00581     }
00582     
00583     result = pal_osMutexRelease(s_mutexSocketCallbacks);
00584     if ((PAL_SUCCESS != result) && (PAL_SUCCESS == firstError))
00585     {
00586         // TODO print error using logging mechanism when available.
00587         firstError = result;
00588     }
00589 
00590     while (!s_socketThreadTerminateSignaled)
00591     {
00592         pal_osDelay(10);
00593     }
00594 
00595     result = pal_osSemaphoreDelete(&s_socketCallbackSignalSemaphore);
00596     if ((PAL_SUCCESS != result) && (PAL_SUCCESS == firstError))
00597     {
00598         // TODO print error using logging mechanism when available.
00599         firstError = result;
00600     }
00601 
00602     result = pal_osMutexDelete(&s_mutexSocketEventFilter);
00603     if ((PAL_SUCCESS != result) && (PAL_SUCCESS == firstError))
00604     {
00605         // TODO print error using logging mechanism when available.
00606         firstError = result;
00607     }
00608 
00609     result = pal_osMutexDelete(&s_mutexSocketCallbacks);
00610     if ((PAL_SUCCESS != result ) && (PAL_SUCCESS == firstError))
00611     {
00612         // TODO print error using logging mechanism when available.
00613         firstError = result;
00614     }
00615 #endif // PAL_NET_ASYNCHRONOUS_SOCKET_API
00616 
00617     s_pal_network_initialized = 0;
00618 
00619     return firstError;
00620 }
00621 
00622 /*
00623  * NOTE!!!!
00624  * When creating socket in Linux, we ignore interfaceNum provided.
00625  * The socket should be bound to interface pal_plat_bind API (bind to address reflects the bound between
00626  * socket and interface).
00627  */
00628 palStatus_t pal_plat_socket (palSocketDomain_t  domain, palSocketType_t  type, bool nonBlockingSocket, uint32_t interfaceNum, palSocket_t* sockt)
00629 {
00630     int result = PAL_SUCCESS;
00631     intptr_t sockfd;
00632     int sockBehavior = 0;
00633 
00634     PAL_VALIDATE_ARGUMENTS(interfaceNum >= s_palNumOfInterfaces && PAL_NET_DEFAULT_INTERFACE != interfaceNum);
00635 
00636     // These are the same in Linux
00637     if(type == PAL_SOCK_STREAM_SERVER )
00638     {
00639         type = PAL_SOCK_STREAM;
00640     }
00641 
00642     // Compile time check that PAL values are the same as Linux values
00643     PAL_ASSERT_STATIC(AF_INET == PAL_AF_INET);
00644     PAL_ASSERT_STATIC(AF_INET6 == PAL_AF_INET6 );
00645     PAL_ASSERT_STATIC(AF_UNSPEC == PAL_AF_UNSPEC);
00646     PAL_ASSERT_STATIC(SOCK_DGRAM == (unsigned int)PAL_SOCK_DGRAM );
00647     PAL_ASSERT_STATIC(SOCK_STREAM == (unsigned int)PAL_SOCK_STREAM);
00648 
00649     if (nonBlockingSocket)
00650     {
00651         sockBehavior = SOCK_NONBLOCK;
00652     }
00653 
00654     // SOCK_NONBLOCK since Linux 2.6.27
00655     sockfd = socket(domain, type | sockBehavior , 0);
00656     // Note - though it is not an error, if we get sockfd == 0 then we probably (accidentally closed fd 0 somewhere else)
00657     if (sockfd == PAL_LINUX_INVALID_SOCKET)
00658     {
00659         result = translateErrorToPALError(errno);
00660     }
00661     else
00662     {
00663         *sockt = (palSocket_t )sockfd;
00664     }
00665     return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized)
00666 }
00667 
00668 
00669 // Assume input timeout value is in milliseconds.
00670 palStatus_t pal_plat_setSocketOptions (palSocket_t socket, int optionName, const void* optionValue, palSocketLength_t optionLength)
00671 {
00672     int result = PAL_SUCCESS;
00673     int linuxName;
00674     PAL_UNUSED_ARG(optionLength);
00675 
00676 
00677     struct timeval timeout;
00678     timeout.tv_sec =  0;
00679     timeout.tv_usec = 0;
00680 
00681     switch (optionName)
00682     {
00683     case PAL_SO_SNDTIMEO :
00684         linuxName = SO_SNDTIMEO;
00685         timeout.tv_sec = (*(int *)optionValue)/1000 ;
00686         timeout.tv_usec = ((*(int *)optionValue)%1000)*1000 ;
00687         break;
00688     case PAL_SO_RCVTIMEO :
00689         linuxName = SO_RCVTIMEO;
00690         timeout.tv_sec = (*(int *)optionValue)/1000 ;
00691         timeout.tv_usec = ((*(int *)optionValue)%1000)*1000 ;
00692         break;
00693 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00694     case PAL_SO_KEEPALIVE :
00695         linuxName = SO_KEEPALIVE;
00696         break;
00697     case PAL_SO_KEEPIDLE :
00698         linuxName = TCP_KEEPIDLE;
00699         break;
00700     case PAL_SO_KEEPINTVL :
00701         linuxName = TCP_KEEPINTVL;
00702         break;
00703 #endif
00704     case PAL_SO_REUSEADDR:
00705         linuxName = SO_REUSEADDR;
00706         break;
00707     default:
00708         // Unsupported option
00709         result = PAL_ERR_SOCKET_OPTION_NOT_SUPPORTED ;
00710     }
00711 
00712     if (PAL_SUCCESS == result)
00713     {
00714         if (PAL_SO_SNDTIMEO  == optionName || PAL_SO_RCVTIMEO  == optionName)
00715         {
00716             result = setsockopt ((intptr_t)socket, SOL_SOCKET, linuxName, &timeout, sizeof(timeout));
00717         }
00718 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00719         else if (PAL_SO_KEEPIDLE  == optionName || PAL_SO_KEEPINTVL  == optionName)
00720         {
00721             result = setsockopt ((intptr_t)socket, SOL_TCP, linuxName, (int *)optionValue, optionLength);
00722         }
00723 #endif
00724         else
00725         {
00726             result = setsockopt ((intptr_t)socket, SOL_SOCKET, linuxName, (int *)optionValue, optionLength);
00727         }
00728 
00729         if(-1 == result)
00730         {
00731             result = translateErrorToPALError(errno);
00732         }
00733     }
00734 
00735     return result;
00736 }
00737 
00738 palStatus_t pal_plat_isNonBlocking (palSocket_t socket, bool* isNonBlocking)
00739 {
00740     int flags = fcntl((intptr_t)socket, F_GETFL);
00741 
00742     if (0 != (flags & O_NONBLOCK))
00743     {
00744         *isNonBlocking = true;
00745     }
00746     else
00747     {
00748         *isNonBlocking = false;
00749     }
00750     return PAL_SUCCESS;
00751 }
00752 
00753 
00754 palStatus_t pal_plat_bind (palSocket_t socket, palSocketAddress_t* myAddress, palSocketLength_t addressLength)
00755 {
00756     int result = PAL_SUCCESS;
00757     int res = 0;
00758     struct sockaddr_storage internalAddr = {0} ;
00759 
00760     result = pal_plat_SockAddrToSocketAddress(myAddress, (struct sockaddr *)&internalAddr);
00761     if (result == PAL_SUCCESS)
00762     {
00763         res = bind((intptr_t)socket, (struct sockaddr *)&internalAddr, addressLength);
00764         if (res == -1)
00765         {
00766             result = translateErrorToPALError(errno);
00767         }
00768     }
00769 
00770     return result;
00771 }
00772 
00773 
00774 palStatus_t pal_plat_receiveFrom (palSocket_t socket, void* buffer, size_t length, palSocketAddress_t* from, palSocketLength_t* fromLength, size_t* bytesReceived)
00775 {
00776     palStatus_t result = PAL_SUCCESS;
00777     ssize_t res;
00778     struct sockaddr_storage internalAddr;
00779     socklen_t addrlen;
00780 
00781     clearSocketFilter((intptr_t)socket);
00782     addrlen = sizeof(struct sockaddr_storage);
00783     res = recvfrom((intptr_t)socket, buffer, length, 0 ,(struct sockaddr *)&internalAddr, &addrlen);
00784     if(res == -1)
00785     {
00786         result = translateErrorToPALError(errno);
00787     }
00788     else // only return address / bytesReceived in case of success
00789     {
00790         if ((NULL != from) && (NULL != fromLength))
00791         {
00792             result = pal_plat_socketAddressToPalSockAddr((struct sockaddr *)&internalAddr, from, fromLength);
00793         }
00794         *bytesReceived = res;
00795     }
00796 
00797     return result;
00798 }
00799 
00800 palStatus_t pal_plat_sendTo (palSocket_t socket, const void* buffer, size_t length, const palSocketAddress_t* to, palSocketLength_t toLength, size_t* bytesSent)
00801 {
00802     palStatus_t result = PAL_SUCCESS;
00803     ssize_t res;
00804 
00805     clearSocketFilter((intptr_t)socket);
00806     res = sendto((intptr_t)socket, buffer, length, 0, (struct sockaddr *)to, toLength);
00807     if(res == -1)
00808     {
00809         result = translateErrorToPALError(errno);
00810     }
00811     else
00812     {
00813         *bytesSent = res;
00814     }
00815 
00816     return result;
00817 }
00818 
00819 palStatus_t pal_plat_close (palSocket_t* socket)
00820 {
00821     palStatus_t result = PAL_SUCCESS;
00822     int res;
00823     unsigned int i,j;
00824 
00825     if  (*socket == (void *)PAL_LINUX_INVALID_SOCKET) // socket already closed - return success.
00826     {
00827         PAL_LOG(DBG, "socket close called on socket which was already closed");
00828         return result;
00829     }
00830 #if PAL_NET_ASYNCHRONOUS_SOCKET_API
00831     // Critical section to update globals
00832     result = pal_osMutexWait(s_mutexSocketCallbacks, PAL_RTOS_WAIT_FOREVER);
00833     if (result != PAL_SUCCESS)
00834     {
00835         // TODO print error using logging mechanism when available.
00836         return result;
00837     }
00838 
00839     for(i= 0 ; i < s_nfds; i++)
00840     {
00841         // check if we have we found the socket being closed
00842         if (s_fds[i].fd == (intptr_t)*socket)
00843         {
00844             // Remove from async socket list
00845             // Close the gap in the socket data structures.
00846             for(j = i; j < s_nfds - 1; j++)
00847             {
00848                 s_fds[j].fd = s_fds[j+1].fd;
00849                 s_fds[j].events = s_fds[j+1].events;
00850                 s_callbacks[j] = s_callbacks[j+1];
00851                 s_callbackArgs[j] = s_callbackArgs[j+1];
00852             }
00853             // Blank out the last one
00854             s_fds[j].fd = 0;
00855             s_callbacks[j] = 0;
00856             s_callbackArgs[j] = 0;
00857             s_nfds--;
00858             // Tell the poll thread to remove the socket
00859             pthread_kill(s_pollThread, SIGUSR1);
00860             break;
00861         }
00862     }
00863     result = pal_osMutexRelease(s_mutexSocketCallbacks);
00864     if (result != PAL_SUCCESS)
00865     {
00866         // TODO print error using logging mechanism when available.
00867         return result;
00868     }
00869 #endif // PAL_NET_ASYNCHRONOUS_SOCKET_API
00870     // In Linux it is ok to close a socket while it is being polled, but may not be on other os's
00871     res = close((intptr_t) *socket);
00872     if(res == -1)
00873         result = translateErrorToPALError(errno);
00874     else
00875     {
00876         *socket = (void *)PAL_LINUX_INVALID_SOCKET;
00877     }
00878     return result;
00879 }
00880 
00881 palStatus_t pal_plat_getNumberOfNetInterfaces ( uint32_t* numInterfaces)
00882 {
00883     *numInterfaces =  s_palNumOfInterfaces;
00884     return PAL_SUCCESS;
00885 }
00886 
00887 palStatus_t pal_plat_getNetInterfaceInfo (uint32_t interfaceNum, palNetInterfaceInfo_t  * interfaceInfo)
00888 {
00889     palStatus_t result = PAL_SUCCESS;
00890     struct ifaddrs *ifap,*ifa;
00891     int res,n;
00892     uint32_t found = 0;
00893 
00894     PAL_VALIDATE_ARGUMENTS (interfaceNum >= s_palNumOfInterfaces);
00895 
00896     res = getifaddrs(&ifap);
00897     if(res < 0)
00898     {
00899         result = translateErrorToPALError(errno);
00900     }
00901     else
00902     {
00903         for (ifa = ifap, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++)
00904         {
00905             if (ifa->ifa_addr == NULL)
00906                 continue;
00907             int family = ifa->ifa_addr->sa_family;
00908             if (strcmp(s_palNetworkInterfacesSupported[interfaceNum].interfaceName, ifa->ifa_name) == 0)
00909             {
00910                 if (family == AF_INET || family == AF_INET6)
00911                 {
00912                     found = 1;
00913                     if (family == AF_INET)
00914                     {
00915                         interfaceInfo->addressSize = sizeof(struct sockaddr_in);
00916                     }
00917                     else
00918                     {
00919                         interfaceInfo->addressSize = sizeof(struct sockaddr_in6);
00920                     }
00921 
00922                     strncpy(interfaceInfo->interfaceName, s_palNetworkInterfacesSupported[interfaceNum].interfaceName, strlen(s_palNetworkInterfacesSupported[interfaceNum].interfaceName));
00923 
00924                     result = pal_plat_socketAddressToPalSockAddr(ifa->ifa_addr, &interfaceInfo->address, &interfaceInfo->addressSize);
00925 
00926                     break;
00927                 }
00928             }
00929         }
00930         // free what was allocated by getifaddrs
00931         freeifaddrs(ifap);
00932     }
00933 
00934     //interface not found error
00935     if (found != 1 && result == PAL_SUCCESS)
00936     {
00937         PAL_LOG(ERR, "Network failed reading interface info");
00938         result = PAL_ERR_GENERIC_FAILURE;
00939     }
00940 
00941     return result;
00942 }
00943 
00944 
00945 #if PAL_NET_TCP_AND_TLS_SUPPORT // functionality below supported only in case TCP is supported.
00946 palStatus_t pal_plat_listen (palSocket_t socket, int backlog)
00947 {
00948     palStatus_t result = PAL_SUCCESS;
00949     int res;
00950 
00951     res = listen((intptr_t)socket,backlog);
00952     if(res == -1)
00953     {
00954         result = translateErrorToPALError(errno);
00955     }
00956     return result;
00957 }
00958 
00959 
00960 palStatus_t pal_plat_accept (palSocket_t socket, palSocketAddress_t * address, palSocketLength_t* addressLen, palSocket_t* acceptedSocket)
00961 {
00962     intptr_t res = 0;
00963     palStatus_t result = PAL_SUCCESS;
00964     struct sockaddr_storage internalAddr = {0} ;
00965     socklen_t internalAddrLen = sizeof(internalAddr);
00966 
00967     // XXX: the whole addressLen -concept is broken as the address is fixed size anyway.
00968     if (*addressLen < sizeof(palSocketAddress_t))
00969     {
00970         return PAL_ERR_SOCKET_INVALID_ADDRESS ;
00971     }
00972 
00973     res = accept((intptr_t)socket,(struct sockaddr *)&internalAddr, &internalAddrLen);
00974     if(res == -1)
00975     {
00976         result = translateErrorToPALError(errno);
00977     }
00978     else
00979     {
00980         *acceptedSocket = (palSocket_t*)res;
00981         *addressLen = sizeof(palSocketAddress_t);
00982         result = pal_plat_socketAddressToPalSockAddr((struct sockaddr *)&internalAddr, address, &internalAddrLen);
00983     }
00984 
00985     return result;
00986 }
00987 
00988 
00989 palStatus_t pal_plat_connect (palSocket_t socket, const palSocketAddress_t* address, palSocketLength_t addressLen)
00990 {
00991     int result = PAL_SUCCESS;
00992     int res;
00993     struct sockaddr_storage internalAddr = {0} ;
00994 
00995     result = pal_plat_SockAddrToSocketAddress(address, (struct sockaddr *)&internalAddr);
00996     if (result == PAL_SUCCESS)
00997     {
00998         res = connect((intptr_t)socket,(struct sockaddr *)&internalAddr, addressLen);
00999         if(res == -1)
01000         {
01001             result = translateErrorToPALError(errno);
01002         }
01003     }
01004 
01005     return result;
01006 }
01007 
01008 palStatus_t pal_plat_recv (palSocket_t socket, void *buffer, size_t len, size_t* recievedDataSize)
01009 {
01010     palStatus_t result = PAL_SUCCESS;
01011     ssize_t res;
01012 
01013     clearSocketFilter((intptr_t)socket);
01014     res = recv((intptr_t)socket, buffer, len, 0);
01015     if(res ==  -1)
01016     {
01017         result = translateErrorToPALError(errno);
01018     }
01019     else
01020     {
01021         if (0 == res)
01022         {
01023             result = PAL_ERR_SOCKET_CONNECTION_CLOSED ;
01024         }
01025         *recievedDataSize = res;
01026     }
01027     return result;
01028 }
01029 
01030 palStatus_t pal_plat_send (palSocket_t socket, const void *buf, size_t len, size_t *sentDataSize)
01031 {
01032     palStatus_t result = PAL_SUCCESS;
01033     ssize_t res;
01034 
01035     clearSocketFilter((intptr_t)socket);
01036 
01037     res = send((intptr_t)socket, buf, len, 0);
01038     if(res == -1)
01039     {
01040         result = translateErrorToPALError(errno);
01041     }
01042     else
01043     {
01044         *sentDataSize = res;
01045     }
01046 
01047     return result;
01048 }
01049 
01050 #endif //PAL_NET_TCP_AND_TLS_SUPPORT
01051 
01052 
01053 #if PAL_NET_ASYNCHRONOUS_SOCKET_API
01054 palStatus_t pal_plat_asynchronousSocket (palSocketDomain_t  domain, palSocketType_t  type, bool nonBlockingSocket, uint32_t interfaceNum, palAsyncSocketCallback_t  callback, void* callbackArgument, palSocket_t* socket)
01055 {
01056 
01057     int err;
01058     int flags;
01059     palStatus_t result = pal_plat_socket (domain,  type,  nonBlockingSocket,  interfaceNum, socket);
01060 
01061 
01062 
01063         // initialize the socket to be ASYNC so we get SIGIO's for it
01064         // XXX: this needs to be conditionalized as the blocking IO might have some use also.
01065         err = fcntl((intptr_t)*socket, F_SETOWN, getpid());
01066         assert(err != -1);
01067 
01068         flags = fcntl((intptr_t)*socket, F_GETFL, 0);
01069         assert(flags >= 0);
01070 
01071         flags |= O_ASYNC;
01072 
01073         err = fcntl((intptr_t)*socket, F_SETFL, flags);
01074 
01075         if (err == -1)
01076         {
01077             result = translateErrorToPALError(errno);
01078         }
01079 
01080 
01081     if (result == PAL_SUCCESS)
01082     {
01083         // Critical section to update globals
01084         result = pal_osMutexWait(s_mutexSocketCallbacks, PAL_RTOS_WAIT_FOREVER);
01085         if (result != PAL_SUCCESS)
01086         {
01087             // TODO print error using logging mechanism when available.
01088             return result;
01089         }
01090         s_fds[s_nfds].fd = (intptr_t)*socket;
01091         s_fds[s_nfds].events = POLLIN|POLLERR;  //TODO POLLOUT missing is not documented
01092         s_callbacks[s_nfds] = callback;
01093         s_callbackArgs[s_nfds] = callbackArgument;
01094         s_nfds++;
01095         result = pal_osMutexRelease(s_mutexSocketCallbacks);
01096         if (result != PAL_SUCCESS)
01097         {
01098             // TODO print error using logging mechanism when available.
01099             return result;
01100         }
01101         // Tell the poll thread to add the new socket
01102         pthread_kill(s_pollThread, SIGUSR1);
01103     }
01104 
01105     return result;
01106 
01107 }
01108 
01109 #endif
01110 
01111 #if PAL_NET_DNS_SUPPORT
01112 
01113 palStatus_t pal_plat_getAddressInfo (const char *url, palSocketAddress_t *address, palSocketLength_t* length)
01114 {
01115     palStatus_t result = PAL_SUCCESS;
01116     palSocketAddress_t localAddress = {0};
01117     palSocketAddress_t zeroAddress = {0};
01118     struct addrinfo *pAddrInf = NULL;
01119     struct addrinfo hints = {0};
01120     int res;
01121     int supportedAddressType1 = 0;
01122     int supportedAddressType2 = 0;
01123     hints.ai_family = AF_UNSPEC;
01124 
01125 #if PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_ANY
01126     supportedAddressType1 = AF_INET;
01127     supportedAddressType2 = AF_INET6;
01128     hints.ai_family = AF_UNSPEC;
01129 #elif PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_IPV4_ONLY
01130     supportedAddressType1 = AF_INET;
01131     supportedAddressType2 = AF_INET;
01132     hints.ai_family = AF_INET;
01133 #elif PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_IPV6_ONLY
01134     supportedAddressType1 = AF_INET6;
01135     supportedAddressType2 = AF_INET6;
01136     hints.ai_family = AF_INET6;
01137 #else
01138 #error PAL_NET_DNS_IP_SUPPORT is not defined to a valid value.
01139 #endif
01140 
01141     res = getaddrinfo(url, NULL, &hints, &pAddrInf);
01142     if(res < 0)
01143     {
01144         result = translateErrorToPALError(errno);
01145     }
01146     else
01147     {
01148         if ((pAddrInf != NULL) && (pAddrInf->ai_family == supportedAddressType1 || pAddrInf->ai_family == supportedAddressType2))
01149         {
01150             result = pal_plat_socketAddressToPalSockAddr((struct sockaddr*)pAddrInf->ai_addr, &localAddress, length);
01151 
01152             if (0 == memcmp(localAddress.addressData, zeroAddress.addressData, PAL_NET_MAX_ADDR_SIZE) ) // invalid 0 address
01153             {
01154                 result = PAL_ERR_SOCKET_DNS_ERROR ;
01155             }
01156             else
01157             {
01158                 *address = localAddress;
01159             }
01160         }
01161         else
01162         {
01163             result = PAL_ERR_SOCKET_INVALID_ADDRESS_FAMILY ;
01164         }
01165 
01166         freeaddrinfo(pAddrInf);
01167     }
01168 
01169     return result;
01170 }
01171 
01172 #endif