Toyomasa Watarai
/
Mbed-example-WS-W27
Mbed Cloud example program for workshop in W27 2018.
Embed:
(wiki syntax)
Show/hide line numbers
pal_plat_network.c
00001 /* 00002 * Copyright (c) 2016 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * 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, WITHOUT 00012 * 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; 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 00131 // The below function is the signal handler API, doing nothing. 00132 // The idea is to signal the asyncSocketManager thread with pthread_kill(s_pollThread, SIGUSR1) command 00133 // which make the ppoll API to be interrupted. 00134 00135 static uint64_t s_palUSR1Counter =0; 00136 static void sigusr2(int signo) { 00137 (void)signo; 00138 s_palUSR1Counter++; 00139 pal_osSemaphoreRelease(s_socketCallbackSignalSemaphore); 00140 } 00141 00142 static uint64_t s_palIOCounter =0; 00143 00144 static void sig_io_handler(int signo) { 00145 (void)signo; 00146 00147 s_palIOCounter++; 00148 pal_osSemaphoreRelease(s_socketCallbackSignalSemaphore); 00149 } 00150 00151 00152 static const unsigned int PAL_SOCKETS_TERMINATE = 10000; 00153 00154 00155 PAL_PRIVATE void clearSocketFilter( int socketFD) 00156 { 00157 palStatus_t result = PAL_SUCCESS; 00158 int i = 0; 00159 result = pal_osMutexWait(s_mutexSocketEventFilter, PAL_RTOS_WAIT_FOREVER); 00160 if (PAL_SUCCESS != result) 00161 { 00162 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. 00163 } 00164 for (i = 0; i < PAL_NET_TEST_MAX_ASYNC_SOCKETS; i++) 00165 { 00166 00167 if (s_fds[i].fd == socketFD) 00168 { 00169 s_callbackFilter[i] = 0; 00170 break; 00171 } 00172 } 00173 result = pal_osMutexRelease(s_mutexSocketEventFilter); 00174 if (PAL_SUCCESS != result) 00175 { 00176 PAL_LOG(ERR, "error releasing mutex"); 00177 } 00178 } 00179 00180 00181 // Thread function. 00182 static void* asyncSocketManager(void *arg) 00183 { 00184 PAL_UNUSED_ARG(arg); // unused 00185 int res; 00186 palAsyncSocketCallback_t callbacks[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {0}; 00187 void* callbackArgs[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {0}; 00188 struct pollfd fds[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {{0,0,0}}; 00189 nfds_t nfds = 0; 00190 struct sigaction s; 00191 palStatus_t result = PAL_SUCCESS; 00192 uint64_t lastIOCounter=0; 00193 uint64_t lastUSRCounter=0; 00194 00195 const struct timespec timeout_zero = {0, 0}; 00196 00197 // Initialize the signal handler. SIG_IGN and SIG_DFL do not work 00198 s.sa_handler = sigusr2; 00199 sigemptyset(&s.sa_mask); 00200 s.sa_flags = 0; 00201 sigaction(SIGUSR1, &s, NULL); 00202 00203 s.sa_handler = sig_io_handler; 00204 sigemptyset(&s.sa_mask); 00205 s.sa_flags = SA_RESTART ; 00206 sigaction(SIGIO, &s, NULL); 00207 00208 // Tell the calling thread that we have finished initialization 00209 result = pal_osSemaphoreRelease(s_socketCallbackSemaphore); 00210 if (result != PAL_SUCCESS) 00211 { 00212 PAL_LOG(ERR, "Error in async socket manager on semaphore release"); 00213 } 00214 00215 00216 while (result == PAL_SUCCESS) //As long as all goes well loop forever 00217 { 00218 // block until a SIGIO signal is received 00219 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 00220 { 00221 pal_osSemaphoreWait(s_socketCallbackSignalSemaphore, PAL_RTOS_WAIT_FOREVER, NULL); 00222 } 00223 00224 // Critical section to update globals 00225 result = pal_osMutexWait(s_mutexSocketCallbacks, PAL_RTOS_WAIT_FOREVER); 00226 if (PAL_SUCCESS != result) 00227 { 00228 PAL_LOG(ERR, "Error in async socket manager on mutex wait"); 00229 break; 00230 } 00231 00232 // Check for thread termination request 00233 if(s_nfds == PAL_SOCKETS_TERMINATE) 00234 { 00235 result = pal_osMutexRelease(s_mutexSocketCallbacks); 00236 if (result != PAL_SUCCESS) 00237 { 00238 PAL_LOG(ERR, "Error in async socket manager on mutex release during termination"); 00239 } 00240 s_nfds = 0; // Reset s_ndfs 00241 // Break out of while(1) 00242 break; 00243 } 00244 // Update the list of sockets to watch from the global list 00245 nfds = s_nfds; 00246 if(nfds) 00247 { 00248 memcpy(callbacks, s_callbacks, nfds*sizeof(callbacks[0])); 00249 memcpy(callbackArgs, s_callbackArgs, nfds * sizeof(void*)); 00250 memcpy(fds, s_fds, nfds*sizeof(fds[0])); 00251 00252 for (int i=0; i < nfds; i++) 00253 { 00254 fds[i].events = POLLIN|POLLOUT|POLLRDHUP|POLLERR; 00255 fds[i].revents = 0; 00256 s_callbackFilter[i] = 0; 00257 } 00258 } 00259 result = pal_osMutexRelease(s_mutexSocketCallbacks); 00260 if (result != PAL_SUCCESS) 00261 { 00262 PAL_LOG(ERR, "Error in async socket manager on mutex release"); 00263 break; 00264 } 00265 00266 // Wait for a socket event or pthread_kill(s_pollThread, SIGUSR1) event 00267 lastUSRCounter = s_palUSR1Counter; 00268 res = ppoll(&fds[0], nfds, &timeout_zero, &s.sa_mask); 00269 00270 00271 // Notes: 00272 // If a POLLIN event occurred and recv from the socket results in 0 bytes being read, it means that 00273 // the remote socket was closed. Unless this is dealt with in the callback (for example by closing the 00274 // socket) the next call to ppoll will also immediately return with the same result. 00275 if(res >0 || errno == EINTR) 00276 { 00277 unsigned int i; 00278 errno = 0; 00279 // Some event was triggered, so iterate over all watched fds's and call the relevant callbacks. 00280 if (lastIOCounter< s_palIOCounter) 00281 { 00282 lastIOCounter = s_palIOCounter; 00283 for( i = 0; i < nfds; i++) 00284 { 00285 if(fds[i].revents) 00286 { 00287 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. 00288 00289 00290 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. 00291 { 00292 callbacks[i](callbackArgs[i]); 00293 } 00294 result = pal_osMutexWait(s_mutexSocketEventFilter, PAL_RTOS_WAIT_FOREVER); 00295 if (PAL_SUCCESS != result) 00296 { 00297 PAL_LOG(ERR, "error waiting for mutex"); 00298 } 00299 else 00300 { 00301 s_callbackFilter[i] = fds[i].revents; 00302 result = pal_osMutexRelease(s_mutexSocketEventFilter); 00303 if (PAL_SUCCESS != result) 00304 { 00305 PAL_LOG(ERR, "error releasing mutex"); 00306 } 00307 } 00308 00309 00310 } 00311 } 00312 } 00313 00314 00315 } 00316 else if (res == 0) 00317 { 00318 // Timeout 00319 } 00320 else 00321 { 00322 PAL_LOG(ERR, "Error in async socket manager"); 00323 } 00324 } // while 00325 00326 return NULL; 00327 } 00328 #endif // PAL_NET_ASYNCHRONOUS_SOCKET_API 00329 00330 PAL_PRIVATE palStatus_t pal_plat_SockAddrToSocketAddress(const palSocketAddress_t* palAddr, struct sockaddr* output) 00331 { 00332 palStatus_t result = PAL_SUCCESS; 00333 uint16_t port = 0; 00334 00335 result = pal_getSockAddrPort(palAddr, &port); 00336 if (result != PAL_SUCCESS) 00337 { 00338 return result; 00339 } 00340 00341 if (PAL_AF_INET == palAddr->addressType) 00342 { 00343 palIpV4Addr_t ipV4Addr = {0}; 00344 struct sockaddr_in* ip4addr = (struct sockaddr_in*)output; 00345 ip4addr->sin_family = AF_INET; 00346 ip4addr->sin_port = PAL_HTONS(port); 00347 result = pal_getSockAddrIPV4Addr(palAddr, ipV4Addr); 00348 if (result == PAL_SUCCESS) 00349 { 00350 memcpy(&ip4addr->sin_addr, ipV4Addr, sizeof(ip4addr->sin_addr)); 00351 } 00352 } 00353 else if (PAL_AF_INET6 == palAddr->addressType) 00354 { 00355 palIpV6Addr_t ipV6Addr = {0}; 00356 struct sockaddr_in6* ip6addr = (struct sockaddr_in6*)output; 00357 ip6addr->sin6_family = AF_INET6; 00358 ip6addr->sin6_scope_id = 0; // we assume there will not be several interfaces with the same IP. 00359 ip6addr->sin6_flowinfo = 0; 00360 ip6addr->sin6_port = PAL_HTONS(port); 00361 result = pal_getSockAddrIPV6Addr(palAddr, ipV6Addr); 00362 if (result == PAL_SUCCESS) 00363 { 00364 memcpy(&ip6addr->sin6_addr, ipV6Addr, sizeof(ip6addr->sin6_addr)); 00365 } 00366 } 00367 00368 return result; 00369 } 00370 00371 PAL_PRIVATE palStatus_t pal_plat_socketAddressToPalSockAddr(struct sockaddr* input, palSocketAddress_t* out, palSocketLength_t* length) 00372 { 00373 palStatus_t result = PAL_SUCCESS; 00374 00375 if (input->sa_family == AF_INET) 00376 { 00377 palIpV4Addr_t ipV4Addr; 00378 struct sockaddr_in* ip4addr = (struct sockaddr_in*)input; 00379 00380 memcpy(ipV4Addr, &ip4addr->sin_addr, PAL_IPV4_ADDRESS_SIZE); 00381 result = pal_setSockAddrIPV4Addr(out, ipV4Addr); 00382 if (result == PAL_SUCCESS) 00383 { 00384 result = pal_setSockAddrPort(out, PAL_NTOHS(ip4addr->sin_port)); 00385 } 00386 *length = sizeof(struct sockaddr_in); 00387 } 00388 else if (input->sa_family == AF_INET6) 00389 { 00390 palIpV6Addr_t ipV6Addr; 00391 struct sockaddr_in6* ip6addr = (struct sockaddr_in6*)input; 00392 memcpy(ipV6Addr, &ip6addr->sin6_addr, PAL_IPV6_ADDRESS_SIZE); 00393 result = pal_setSockAddrIPV6Addr(out, ipV6Addr); 00394 if (result == PAL_SUCCESS) 00395 { 00396 result = pal_setSockAddrPort(out, PAL_NTOHS(ip6addr->sin6_port)); 00397 } 00398 *length = sizeof(struct sockaddr_in6); 00399 } 00400 else 00401 { // we got unspeicified in one of the tests, so Don't fail , but don't translate address. 00402 //result = PAL_ERR_SOCKET_INVALID_ADDRESS_FAMILY; 00403 } 00404 00405 return result; 00406 } 00407 00408 palStatus_t pal_plat_socketsInit(void* context) 00409 { 00410 PAL_UNUSED_ARG(context); 00411 palStatus_t result = PAL_SUCCESS; 00412 00413 if (s_pal_network_initialized == 1) 00414 { 00415 return PAL_SUCCESS; // already initialized. 00416 } 00417 00418 00419 #if PAL_NET_ASYNCHRONOUS_SOCKET_API 00420 pthread_attr_t attr; 00421 int res; 00422 00423 result = pal_osMutexCreate(&s_mutexSocketCallbacks); 00424 if (result != PAL_SUCCESS) 00425 { 00426 return result; 00427 } 00428 00429 result = pal_osMutexCreate(&s_mutexSocketEventFilter); 00430 if (PAL_SUCCESS != result) 00431 { 00432 return result; 00433 } 00434 00435 00436 result = pal_osSemaphoreCreate(0, &s_socketCallbackSignalSemaphore); 00437 if (result != PAL_SUCCESS) 00438 { 00439 // todo: clean up the mess created so far 00440 return result; 00441 } 00442 00443 // Sleep at first wait 00444 result = pal_osSemaphoreCreate(0, &s_socketCallbackSemaphore); 00445 if (result != PAL_SUCCESS) 00446 { 00447 if (pal_osMutexDelete(&s_mutexSocketCallbacks) != PAL_SUCCESS) //cleanup allocated resources 00448 { 00449 // TODO print error using logging mechanism when available. 00450 } 00451 return result; 00452 } 00453 // prepare thread attributes 00454 pthread_attr_init(&attr); 00455 pthread_attr_setstacksize (&attr, PAL_NET_TEST_ASYNC_SOCKET_MANAGER_THREAD_STACK_SIZE); //sets the minimum stack size 00456 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 00457 00458 // create the thread 00459 res = pthread_create(&s_pollThread, &attr, &asyncSocketManager, 0); 00460 if (res < 0) 00461 { 00462 result = translateErrorToPALError(res); 00463 } 00464 else 00465 { 00466 // Wait here for the thread to be initialized. 00467 result = pal_osSemaphoreWait(s_socketCallbackSemaphore, PAL_RTOS_WAIT_FOREVER, NULL); 00468 if (PAL_SUCCESS != result) 00469 { 00470 goto end; 00471 } 00472 result = pal_osSemaphoreDelete(&s_socketCallbackSemaphore); 00473 if (PAL_SUCCESS != result) 00474 { 00475 goto end; 00476 } 00477 } 00478 #endif 00479 00480 end: 00481 if (PAL_SUCCESS == result) 00482 { 00483 s_pal_network_initialized = 1; 00484 } 00485 00486 #if PAL_NET_ASYNCHRONOUS_SOCKET_API 00487 pthread_attr_destroy(&attr); 00488 #endif 00489 00490 return result; 00491 } 00492 00493 palStatus_t pal_plat_registerNetworkInterface (void* context, uint32_t* interfaceIndex) 00494 { 00495 palStatus_t result = PAL_SUCCESS; 00496 uint32_t index = 0; 00497 bool found = false; 00498 00499 for (index = 0; index < s_palNumOfInterfaces; index++) // if specific context already registered return existing index instead of registering again. 00500 { 00501 if (memcmp(s_palNetworkInterfacesSupported[index].interfaceName, (const char *)context, strlen(s_palNetworkInterfacesSupported[index].interfaceName)) == 0) 00502 { 00503 found = true; 00504 *interfaceIndex = index; 00505 break; 00506 } 00507 } 00508 if (false == found) 00509 { 00510 if (s_palNumOfInterfaces < PAL_MAX_SUPORTED_NET_INTERFACES) 00511 { 00512 strncpy(s_palNetworkInterfacesSupported[s_palNumOfInterfaces].interfaceName, (const char *)context, PAL_NET_MAX_IF_NAME_LENGTH-1); 00513 s_palNetworkInterfacesSupported[s_palNumOfInterfaces].interfaceName[PAL_NET_MAX_IF_NAME_LENGTH-1] = '\0'; 00514 *interfaceIndex = s_palNumOfInterfaces; 00515 ++s_palNumOfInterfaces; 00516 } 00517 else 00518 { 00519 result = PAL_ERR_SOCKET_MAX_NUMBER_OF_INTERFACES_REACHED ; 00520 } 00521 } 00522 00523 return result; 00524 } 00525 00526 palStatus_t pal_plat_socketsTerminate (void* context) 00527 { 00528 PAL_UNUSED_ARG(context); 00529 palStatus_t result = PAL_SUCCESS; 00530 palStatus_t firstError = PAL_SUCCESS; 00531 00532 #if PAL_NET_ASYNCHRONOUS_SOCKET_API 00533 // Critical section to update globals 00534 result = pal_osMutexWait(s_mutexSocketCallbacks, PAL_RTOS_WAIT_FOREVER); 00535 if (result != PAL_SUCCESS) 00536 { 00537 // TODO print error using logging mechanism when available. 00538 firstError = result; 00539 } 00540 00541 s_nfds = PAL_SOCKETS_TERMINATE; 00542 result = pal_osSemaphoreRelease(s_socketCallbackSignalSemaphore); 00543 if ((PAL_SUCCESS != result) && (PAL_SUCCESS == firstError)) 00544 { 00545 // TODO print error using logging mechanism when available. 00546 firstError = result; 00547 } 00548 // Tell the poll thread to interrupt so that it can check for termination. 00549 pthread_kill(s_pollThread, SIGUSR1); 00550 result = pal_osMutexRelease(s_mutexSocketCallbacks); 00551 if ((PAL_SUCCESS != result) && (PAL_SUCCESS == firstError)) 00552 { 00553 // TODO print error using logging mechanism when available. 00554 firstError = result; 00555 } 00556 00557 pthread_join(s_pollThread, NULL); 00558 00559 result = pal_osSemaphoreDelete(&s_socketCallbackSignalSemaphore); 00560 if ((PAL_SUCCESS != result) && (PAL_SUCCESS == firstError)) 00561 { 00562 // TODO print error using logging mechanism when available. 00563 firstError = result; 00564 } 00565 00566 result = pal_osMutexDelete(&s_mutexSocketEventFilter); 00567 if ((PAL_SUCCESS != result) && (PAL_SUCCESS == firstError)) 00568 { 00569 // TODO print error using logging mechanism when available. 00570 firstError = result; 00571 } 00572 00573 result = pal_osMutexDelete(&s_mutexSocketCallbacks); 00574 if ((PAL_SUCCESS != result ) && (PAL_SUCCESS == firstError)) 00575 { 00576 // TODO print error using logging mechanism when available. 00577 firstError = result; 00578 } 00579 #endif // PAL_NET_ASYNCHRONOUS_SOCKET_API 00580 00581 s_pal_network_initialized = 0; 00582 00583 return firstError; 00584 } 00585 00586 /* 00587 * NOTE!!!! 00588 * When creating socket in Linux, we ignore interfaceNum provided. 00589 * The socket should be bound to interface pal_plat_bind API (bind to address reflects the bound between 00590 * socket and interface). 00591 */ 00592 palStatus_t pal_plat_socket (palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palSocket_t* sockt) 00593 { 00594 int result = PAL_SUCCESS; 00595 int sockfd; 00596 int sockBehavior = 0; 00597 00598 if (interfaceNum >= s_palNumOfInterfaces && PAL_NET_DEFAULT_INTERFACE != interfaceNum) 00599 { 00600 return PAL_ERR_INVALID_ARGUMENT ; 00601 } 00602 00603 // These are the same in Linux 00604 if(type == PAL_SOCK_STREAM_SERVER ) 00605 { 00606 type = PAL_SOCK_STREAM; 00607 } 00608 00609 // Compile time check that PAL values are the same as Linux values 00610 PAL_ASSERT_STATIC(AF_INET == PAL_AF_INET); 00611 PAL_ASSERT_STATIC(AF_INET6 == PAL_AF_INET6 ); 00612 PAL_ASSERT_STATIC(AF_UNSPEC == PAL_AF_UNSPEC); 00613 PAL_ASSERT_STATIC(SOCK_DGRAM == (unsigned int)PAL_SOCK_DGRAM ); 00614 PAL_ASSERT_STATIC(SOCK_STREAM == (unsigned int)PAL_SOCK_STREAM); 00615 00616 if (nonBlockingSocket) 00617 { 00618 sockBehavior = SOCK_NONBLOCK; 00619 } 00620 00621 // SOCK_NONBLOCK since Linux 2.6.27 00622 sockfd = socket(domain, type | sockBehavior , 0); 00623 // Note - though it is not an error, if we get sockfd == 0 then we probably (accidentally closed fd 0 somewhere else) 00624 if (sockfd == PAL_LINUX_INVALID_SOCKET) 00625 { 00626 result = translateErrorToPALError(errno); 00627 } 00628 else 00629 { 00630 *sockt = (palSocket_t )sockfd; 00631 } 00632 return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) 00633 } 00634 00635 00636 palStatus_t pal_plat_getSocketOptions (palSocket_t socket, palSocketOptionName_t optionName, void* optionValue, palSocketLength_t* optionLength) 00637 { 00638 int result = PAL_SUCCESS; 00639 int linuxName; 00640 00641 // TODO moved to shared function 00642 switch ((palSocketOptionName_t )optionName) 00643 { 00644 case PAL_SO_SNDTIMEO : 00645 linuxName = SO_SNDTIMEO ; 00646 break; 00647 case PAL_SO_RCVTIMEO : 00648 linuxName = SO_RCVTIMEO ; 00649 break; 00650 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT 00651 case PAL_SO_KEEPALIVE : 00652 linuxName = SO_KEEPALIVE; 00653 break; 00654 case PAL_SO_KEEPIDLE : 00655 linuxName = TCP_KEEPIDLE; 00656 break; 00657 case PAL_SO_KEEPINTVL : 00658 linuxName = TCP_KEEPINTVL; 00659 break; 00660 #endif 00661 case PAL_SO_REUSEADDR: 00662 linuxName = SO_REUSEADDR; 00663 break; 00664 default: 00665 // Unsupported option 00666 result = PAL_ERR_SOCKET_OPTION_NOT_SUPPORTED ; 00667 } 00668 00669 if (result == PAL_SUCCESS) 00670 { 00671 if (PAL_SO_REUSEADDR == optionName || 00672 PAL_SO_SNDTIMEO == optionName || 00673 PAL_SO_RCVTIMEO == optionName) 00674 { 00675 result = getsockopt ((int)socket, SOL_SOCKET, linuxName, optionValue, optionLength); 00676 } 00677 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT 00678 else if (PAL_SO_KEEPALIVE == optionName) 00679 { 00680 result = getsockopt((int)socket, SOL_SOCKET, linuxName, optionValue, optionLength); 00681 } 00682 else 00683 { 00684 result = getsockopt((int)socket, SOL_TCP, linuxName, optionValue, optionLength); 00685 } 00686 #endif 00687 00688 if(result == -1) 00689 { 00690 result = translateErrorToPALError(errno); 00691 } 00692 } 00693 00694 return result; 00695 } 00696 00697 // Assume input timeout value is in milliseconds. 00698 palStatus_t pal_plat_setSocketOptions (palSocket_t socket, int optionName, const void* optionValue, palSocketLength_t optionLength) 00699 { 00700 int result = PAL_SUCCESS; 00701 int linuxName; 00702 PAL_UNUSED_ARG(optionLength); 00703 00704 00705 struct timeval timeout; 00706 timeout.tv_sec = 0; 00707 timeout.tv_usec = 0; 00708 00709 switch (optionName) 00710 { 00711 case PAL_SO_SNDTIMEO : 00712 linuxName = SO_SNDTIMEO; 00713 timeout.tv_sec = (*(int *)optionValue)/1000 ; 00714 timeout.tv_usec = ((*(int *)optionValue)%1000)*1000 ; 00715 break; 00716 case PAL_SO_RCVTIMEO : 00717 linuxName = SO_RCVTIMEO; 00718 timeout.tv_sec = (*(int *)optionValue)/1000 ; 00719 timeout.tv_usec = ((*(int *)optionValue)%1000)*1000 ; 00720 break; 00721 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT 00722 case PAL_SO_KEEPALIVE : 00723 linuxName = SO_KEEPALIVE; 00724 break; 00725 case PAL_SO_KEEPIDLE : 00726 linuxName = TCP_KEEPIDLE; 00727 break; 00728 case PAL_SO_KEEPINTVL : 00729 linuxName = TCP_KEEPINTVL; 00730 break; 00731 #endif 00732 case PAL_SO_REUSEADDR: 00733 linuxName = SO_REUSEADDR; 00734 break; 00735 default: 00736 // Unsupported option 00737 result = PAL_ERR_SOCKET_OPTION_NOT_SUPPORTED ; 00738 } 00739 00740 if (PAL_SUCCESS == result) 00741 { 00742 if (PAL_SO_SNDTIMEO == optionName || PAL_SO_RCVTIMEO == optionName) 00743 { 00744 result = setsockopt ((int)socket, SOL_SOCKET, linuxName, &timeout, sizeof(timeout)); 00745 } 00746 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT 00747 else if (PAL_SO_KEEPIDLE == optionName || PAL_SO_KEEPINTVL == optionName) 00748 { 00749 result = setsockopt ((int)socket, SOL_TCP, linuxName, (int *)optionValue, optionLength); 00750 } 00751 #endif 00752 else 00753 { 00754 result = setsockopt ((int)socket, SOL_SOCKET, linuxName, (int *)optionValue, optionLength); 00755 } 00756 00757 if(-1 == result) 00758 { 00759 result = translateErrorToPALError(errno); 00760 } 00761 } 00762 00763 return result; 00764 } 00765 00766 palStatus_t pal_plat_isNonBlocking (palSocket_t socket, bool* isNonBlocking) 00767 { 00768 int flags = fcntl((int)socket, F_GETFL); 00769 00770 if (0 != (flags & O_NONBLOCK)) 00771 { 00772 *isNonBlocking = true; 00773 } 00774 else 00775 { 00776 *isNonBlocking = false; 00777 } 00778 return PAL_SUCCESS; 00779 } 00780 00781 00782 palStatus_t pal_plat_bind (palSocket_t socket, palSocketAddress_t* myAddress, palSocketLength_t addressLength) 00783 { 00784 int result = PAL_SUCCESS; 00785 int res = 0; 00786 struct sockaddr_storage internalAddr = {0} ; 00787 00788 result = pal_plat_SockAddrToSocketAddress(myAddress, (struct sockaddr *)&internalAddr); 00789 if (result == PAL_SUCCESS) 00790 { 00791 res = bind((int)socket, (struct sockaddr *)&internalAddr, addressLength); 00792 if (res == -1) 00793 { 00794 result = translateErrorToPALError(errno); 00795 } 00796 } 00797 00798 return result; 00799 } 00800 00801 00802 palStatus_t pal_plat_receiveFrom (palSocket_t socket, void* buffer, size_t length, palSocketAddress_t* from, palSocketLength_t* fromLength, size_t* bytesReceived) 00803 { 00804 palStatus_t result = PAL_SUCCESS; 00805 ssize_t res; 00806 struct sockaddr_storage internalAddr; 00807 socklen_t addrlen; 00808 00809 clearSocketFilter((int)socket); 00810 addrlen = sizeof(struct sockaddr_storage); 00811 res = recvfrom((int)socket, buffer, length, 0 ,(struct sockaddr *)&internalAddr, &addrlen); 00812 if(res == -1) 00813 { 00814 result = translateErrorToPALError(errno); 00815 } 00816 else // only return address / bytesReceived in case of success 00817 { 00818 if ((NULL != from) && (NULL != fromLength)) 00819 { 00820 result = pal_plat_socketAddressToPalSockAddr((struct sockaddr *)&internalAddr, from, fromLength); 00821 } 00822 *bytesReceived = res; 00823 } 00824 00825 return result; 00826 } 00827 00828 palStatus_t pal_plat_sendTo (palSocket_t socket, const void* buffer, size_t length, const palSocketAddress_t* to, palSocketLength_t toLength, size_t* bytesSent) 00829 { 00830 palStatus_t result = PAL_SUCCESS; 00831 ssize_t res; 00832 00833 clearSocketFilter((int)socket); 00834 res = sendto((int)socket, buffer, length, 0, (struct sockaddr *)to, toLength); 00835 if(res == -1) 00836 { 00837 result = translateErrorToPALError(errno); 00838 } 00839 else 00840 { 00841 *bytesSent = res; 00842 } 00843 00844 return result; 00845 } 00846 00847 palStatus_t pal_plat_close (palSocket_t* socket) 00848 { 00849 palStatus_t result = PAL_SUCCESS; 00850 int res; 00851 unsigned int i,j; 00852 00853 if (*socket == (void *)PAL_LINUX_INVALID_SOCKET) // socket already closed - return success. 00854 { 00855 PAL_LOG(DBG, "socket close called on socket which was already closed"); 00856 return result; 00857 } 00858 #if PAL_NET_ASYNCHRONOUS_SOCKET_API 00859 // Critical section to update globals 00860 result = pal_osMutexWait(s_mutexSocketCallbacks, PAL_RTOS_WAIT_FOREVER); 00861 if (result != PAL_SUCCESS) 00862 { 00863 // TODO print error using logging mechanism when available. 00864 return result; 00865 } 00866 00867 for(i= 0 ; i < s_nfds; i++) 00868 { 00869 // check if we have we found the socket being closed 00870 if (s_fds[i].fd == (int)*socket) 00871 { 00872 // Remove from async socket list 00873 // Close the gap in the socket data structures. 00874 for(j = i; j < s_nfds - 1; j++) 00875 { 00876 s_fds[j].fd = s_fds[j+1].fd; 00877 s_fds[j].events = s_fds[j+1].events; 00878 s_callbacks[j] = s_callbacks[j+1]; 00879 s_callbackArgs[j] = s_callbackArgs[j+1]; 00880 } 00881 // Blank out the last one 00882 s_fds[j].fd = 0; 00883 s_callbacks[j] = 0; 00884 s_callbackArgs[j] = 0; 00885 s_nfds--; 00886 // Tell the poll thread to remove the socket 00887 pthread_kill(s_pollThread, SIGUSR1); 00888 break; 00889 } 00890 } 00891 result = pal_osMutexRelease(s_mutexSocketCallbacks); 00892 if (result != PAL_SUCCESS) 00893 { 00894 // TODO print error using logging mechanism when available. 00895 return result; 00896 } 00897 #endif // PAL_NET_ASYNCHRONOUS_SOCKET_API 00898 // In Linux it is ok to close a socket while it is being polled, but may not be on other os's 00899 res = close((int) *socket); 00900 if(res == -1) 00901 result = translateErrorToPALError(errno); 00902 else 00903 { 00904 *socket = (void *)PAL_LINUX_INVALID_SOCKET; 00905 } 00906 return result; 00907 } 00908 00909 palStatus_t pal_plat_getNumberOfNetInterfaces ( uint32_t* numInterfaces) 00910 { 00911 *numInterfaces = s_palNumOfInterfaces; 00912 return PAL_SUCCESS; 00913 } 00914 00915 palStatus_t pal_plat_getNetInterfaceInfo (uint32_t interfaceNum, palNetInterfaceInfo_t * interfaceInfo) 00916 { 00917 palStatus_t result = PAL_SUCCESS; 00918 struct ifaddrs *ifap,*ifa; 00919 int res,n; 00920 uint32_t found = 0; 00921 00922 if (interfaceNum >= s_palNumOfInterfaces) 00923 { 00924 return PAL_ERR_INVALID_ARGUMENT ; 00925 } 00926 00927 res = getifaddrs(&ifap); 00928 if(res < 0) 00929 { 00930 result = translateErrorToPALError(errno); 00931 } 00932 else 00933 { 00934 for (ifa = ifap, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) 00935 { 00936 if (ifa->ifa_addr == NULL) 00937 continue; 00938 int family = ifa->ifa_addr->sa_family; 00939 if (strcmp(s_palNetworkInterfacesSupported[interfaceNum].interfaceName, ifa->ifa_name) == 0) 00940 { 00941 if (family == AF_INET || family == AF_INET6) 00942 { 00943 found = 1; 00944 if (family == AF_INET) 00945 { 00946 interfaceInfo->addressSize = sizeof(struct sockaddr_in); 00947 } 00948 else 00949 { 00950 interfaceInfo->addressSize = sizeof(struct sockaddr_in6); 00951 } 00952 00953 strncpy(interfaceInfo->interfaceName, s_palNetworkInterfacesSupported[interfaceNum].interfaceName, strlen(s_palNetworkInterfacesSupported[interfaceNum].interfaceName)); 00954 00955 result = pal_plat_socketAddressToPalSockAddr(ifa->ifa_addr, &interfaceInfo->address, &interfaceInfo->addressSize); 00956 00957 break; 00958 } 00959 } 00960 } 00961 // free what was allocated by getifaddrs 00962 freeifaddrs(ifap); 00963 } 00964 00965 //interface not found error 00966 if (found != 1 && result == PAL_SUCCESS) 00967 { 00968 PAL_LOG(ERR, "Network failed reading interface info"); 00969 result = PAL_ERR_GENERIC_FAILURE; 00970 } 00971 00972 return result; 00973 } 00974 00975 00976 palStatus_t pal_plat_socketMiniSelect (const palSocket_t socketsToCheck[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t numberOfSockets, pal_timeVal_t* timeout, 00977 uint8_t palSocketStatus[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t * numberOfSocketsSet) 00978 { 00979 uint32_t index = 0; 00980 palStatus_t result = PAL_SUCCESS; 00981 fd_set readset, writeset, exset; 00982 // Keep a local copy because select in Linux will modify it. 00983 struct timeval tmpTimeout; 00984 int res; 00985 int fd; 00986 int maxfd = 0; 00987 00988 if ((NULL == socketsToCheck) || (NULL == numberOfSocketsSet) || (NULL == timeout)) 00989 { 00990 return PAL_ERR_INVALID_ARGUMENT ; 00991 } 00992 00993 // Copy the values manually as the struct variables may have different sizes. 00994 tmpTimeout.tv_sec = timeout->pal_tv_sec; 00995 tmpTimeout.tv_usec = timeout->pal_tv_usec; 00996 00997 *numberOfSocketsSet = 0; 00998 00999 FD_ZERO(&readset); 01000 FD_ZERO(&writeset); 01001 FD_ZERO(&exset); 01002 01003 for(index = 0; index < numberOfSockets; index++) 01004 { 01005 fd = (int)socketsToCheck[index]; 01006 FD_SET(fd, &readset); 01007 // Do not detect writes because they will not block unless something is in the process of being written(Nir) 01008 // XXX: Actually for a nonblocking connect() we need to detect readiness for write 01009 // to find out if the socket is ready. 01010 FD_SET(fd, &writeset); 01011 FD_SET(fd, &exset); 01012 if (fd > maxfd) 01013 { 01014 maxfd = fd; 01015 } 01016 } 01017 01018 res = select(maxfd + 1, &readset, &writeset, &exset, &tmpTimeout); 01019 if(res == -1) 01020 { 01021 result = translateErrorToPALError(errno); 01022 } 01023 else if (res > 0) // select returns 0 in case timeout expire 01024 { 01025 for(index = 0; index < numberOfSockets; index++) 01026 { 01027 uint8_t socketStatus = 0; 01028 fd = (int)socketsToCheck[index]; 01029 01030 if(FD_ISSET(fd, &readset)) 01031 { 01032 socketStatus |= PAL_NET_SOCKET_SELECT_RX_BIT; 01033 } 01034 if(FD_ISSET(fd, &writeset)) 01035 { 01036 socketStatus |= PAL_NET_SOCKET_SELECT_TX_BIT; 01037 } 01038 if(FD_ISSET(fd, &exset)) 01039 { 01040 socketStatus |= PAL_NET_SOCKET_SELECT_ERR_BIT; 01041 } 01042 01043 palSocketStatus[index] = socketStatus; 01044 } 01045 *numberOfSocketsSet = res; 01046 } 01047 01048 return result ; 01049 } 01050 01051 #if PAL_NET_TCP_AND_TLS_SUPPORT // functionality below supported only in case TCP is supported. 01052 palStatus_t pal_plat_listen (palSocket_t socket, int backlog) 01053 { 01054 palStatus_t result = PAL_SUCCESS; 01055 int res; 01056 01057 res = listen((int)socket,backlog); 01058 if(res == -1) 01059 { 01060 result = translateErrorToPALError(errno); 01061 } 01062 return result; 01063 } 01064 01065 01066 palStatus_t pal_plat_accept (palSocket_t socket, palSocketAddress_t * address, palSocketLength_t* addressLen, palSocket_t* acceptedSocket) 01067 { 01068 int res = 0; 01069 palStatus_t result = PAL_SUCCESS; 01070 struct sockaddr_storage internalAddr = {0} ; 01071 01072 res = accept((int)socket,(struct sockaddr *)&internalAddr, addressLen); 01073 if(res == -1) 01074 { 01075 result = translateErrorToPALError(errno); 01076 } 01077 else 01078 { 01079 *acceptedSocket = (palSocket_t*)res; 01080 result = pal_plat_socketAddressToPalSockAddr((struct sockaddr *)&internalAddr, address, addressLen); 01081 } 01082 01083 return result; 01084 } 01085 01086 01087 palStatus_t pal_plat_connect (palSocket_t socket, const palSocketAddress_t* address, palSocketLength_t addressLen) 01088 { 01089 int result = PAL_SUCCESS; 01090 int res; 01091 struct sockaddr_storage internalAddr = {0} ; 01092 01093 result = pal_plat_SockAddrToSocketAddress(address, (struct sockaddr *)&internalAddr); 01094 if (result == PAL_SUCCESS) 01095 { 01096 res = connect((int)socket,(struct sockaddr *)&internalAddr, addressLen); 01097 if(res == -1) 01098 { 01099 result = translateErrorToPALError(errno); 01100 } 01101 } 01102 01103 return result; 01104 } 01105 01106 palStatus_t pal_plat_recv (palSocket_t socket, void *buffer, size_t len, size_t* recievedDataSize) 01107 { 01108 palStatus_t result = PAL_SUCCESS; 01109 ssize_t res; 01110 01111 clearSocketFilter((int)socket); 01112 res = recv((int)socket, buffer, len, 0); 01113 if(res == -1) 01114 { 01115 result = translateErrorToPALError(errno); 01116 } 01117 else 01118 { 01119 if (0 == res) 01120 { 01121 result = PAL_ERR_SOCKET_CONNECTION_CLOSED ; 01122 } 01123 *recievedDataSize = res; 01124 } 01125 return result; 01126 } 01127 01128 palStatus_t pal_plat_send (palSocket_t socket, const void *buf, size_t len, size_t *sentDataSize) 01129 { 01130 palStatus_t result = PAL_SUCCESS; 01131 ssize_t res; 01132 01133 clearSocketFilter((int)socket); 01134 01135 res = send((int)socket, buf, len, 0); 01136 if(res == -1) 01137 { 01138 result = translateErrorToPALError(errno); 01139 } 01140 else 01141 { 01142 *sentDataSize = res; 01143 } 01144 01145 return result; 01146 } 01147 01148 #endif //PAL_NET_TCP_AND_TLS_SUPPORT 01149 01150 01151 01152 01153 01154 01155 01156 #if PAL_NET_ASYNCHRONOUS_SOCKET_API 01157 palStatus_t pal_plat_asynchronousSocket (palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palAsyncSocketCallback_t callback, void* callbackArgument, palSocket_t* socket) 01158 { 01159 01160 int err; 01161 int flags; 01162 palStatus_t result = pal_plat_socket (domain, type, nonBlockingSocket, interfaceNum, socket); 01163 01164 01165 01166 // initialize the socket to be ASYNC so we get SIGIO's for it 01167 // XXX: this needs to be conditionalized as the blocking IO might have some use also. 01168 err = fcntl((int)*socket, F_SETOWN, getpid()); 01169 assert(err != -1); 01170 01171 flags = fcntl((int)*socket, F_GETFL, 0); 01172 assert(flags >= 0); 01173 01174 flags |= O_ASYNC; 01175 01176 err = fcntl((int)*socket, F_SETFL, flags); 01177 01178 if (err == -1) 01179 { 01180 result = translateErrorToPALError(errno); 01181 } 01182 01183 01184 if (result == PAL_SUCCESS) 01185 { 01186 // Critical section to update globals 01187 result = pal_osMutexWait(s_mutexSocketCallbacks, PAL_RTOS_WAIT_FOREVER); 01188 if (result != PAL_SUCCESS) 01189 { 01190 // TODO print error using logging mechanism when available. 01191 return result; 01192 } 01193 s_fds[s_nfds].fd = (int)*socket; 01194 s_fds[s_nfds].events = POLLIN|POLLERR; //TODO POLLOUT missing is not documented 01195 s_callbacks[s_nfds] = callback; 01196 s_callbackArgs[s_nfds] = callbackArgument; 01197 s_nfds++; 01198 result = pal_osMutexRelease(s_mutexSocketCallbacks); 01199 if (result != PAL_SUCCESS) 01200 { 01201 // TODO print error using logging mechanism when available. 01202 return result; 01203 } 01204 // Tell the poll thread to add the new socket 01205 pthread_kill(s_pollThread, SIGUSR1); 01206 } 01207 01208 return result; 01209 01210 } 01211 01212 #endif 01213 01214 #if PAL_NET_DNS_SUPPORT 01215 01216 palStatus_t pal_plat_getAddressInfo (const char *url, palSocketAddress_t *address, palSocketLength_t* length) 01217 { 01218 palStatus_t result = PAL_SUCCESS; 01219 palSocketAddress_t localAddress = {0}; 01220 palSocketAddress_t zeroAddress = {0}; 01221 struct addrinfo *pAddrInf = NULL; 01222 struct addrinfo hints = {0}; 01223 int res; 01224 int supportedAddressType1 = 0; 01225 int supportedAddressType2 = 0; 01226 hints.ai_family = AF_UNSPEC; 01227 01228 #if PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_ANY 01229 supportedAddressType1 = AF_INET; 01230 supportedAddressType2 = AF_INET6; 01231 hints.ai_family = AF_UNSPEC; 01232 #elif PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_IPV4_ONLY 01233 supportedAddressType1 = AF_INET; 01234 supportedAddressType2 = AF_INET; 01235 hints.ai_family = AF_INET; 01236 #elif PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_IPV6_ONLY 01237 supportedAddressType1 = AF_INET6; 01238 supportedAddressType2 = AF_INET6; 01239 hints.ai_family = AF_INET6; 01240 #else 01241 #error PAL_NET_DNS_IP_SUPPORT is not defined to a valid value. 01242 #endif 01243 01244 res = getaddrinfo(url, NULL, &hints, &pAddrInf); 01245 if(res < 0) 01246 { 01247 result = translateErrorToPALError(errno); 01248 } 01249 else 01250 { 01251 if ((pAddrInf != NULL) && (pAddrInf->ai_family == supportedAddressType1 || pAddrInf->ai_family == supportedAddressType2)) 01252 { 01253 result = pal_plat_socketAddressToPalSockAddr((struct sockaddr*)pAddrInf->ai_addr, &localAddress, length); 01254 01255 if (0 == memcmp(localAddress.addressData, zeroAddress.addressData, PAL_NET_MAX_ADDR_SIZE) ) // invalid 0 address 01256 { 01257 result = PAL_ERR_SOCKET_DNS_ERROR ; 01258 } 01259 else 01260 { 01261 *address = localAddress; 01262 } 01263 } 01264 else 01265 { 01266 result = PAL_ERR_SOCKET_INVALID_ADDRESS_FAMILY ; 01267 } 01268 01269 freeaddrinfo(pAddrInf); 01270 } 01271 01272 return result; 01273 } 01274 01275 #endif
Generated on Tue Jul 12 2022 16:22:09 by 1.7.2