Vault
4.1
|
00001 /* 00002 Copyright c1997-2014 Trygve Isaacson. All rights reserved. 00003 This file is part of the Code Vault version 4.1 00004 http://www.bombaydigital.com/ 00005 License: MIT. See LICENSE.md in the Vault top level directory. 00006 */ 00007 00010 #include "vsocket.h" 00011 00012 #include "vexception.h" 00013 00014 #include <signal.h> 00015 00016 #ifdef sun 00017 #include <sys/proc.h> 00018 #endif 00019 00020 #include <sys/ioctl.h> 00021 #include <ifaddrs.h> 00022 00023 // static 00024 bool VSocket::_platform_staticInit() { 00025 //lint -e421 -e923 " Caution -- function 'signal(int, void (*)(int))' is considered dangerous [MISRA Rule 123]" 00026 ::signal(SIGPIPE, SIG_IGN); 00027 00028 // Should log the error if the call failed. 00029 00030 return true; 00031 } 00032 00033 // static 00034 VNetworkInterfaceList VSocket::_platform_enumerateNetworkInterfaces() { 00035 VNetworkInterfaceList interfaces; 00036 struct ifaddrs* interfacesDataPtr = NULL; 00037 int result = ::getifaddrs(&interfacesDataPtr); 00038 if (result != 0) { 00039 throw VStackTraceException(VSystemError::getSocketError(), VSTRING_FORMAT("VSocket::enumerateNetworkInterfaces: getifaddrs() failed with result %d.", result)); 00040 } 00041 00042 struct ifaddrs* intfPtr = interfacesDataPtr; 00043 while (intfPtr != NULL) { 00044 if (intfPtr->ifa_addr != NULL) { 00045 VNetworkInterfaceInfo info; 00046 info.mFamily = intfPtr->ifa_addr->sa_family; 00047 info.mName.copyFromCString(intfPtr->ifa_name); 00048 // AF_INET6 will work just fine here, too. But hold off until we can verify callers can successfully use IPV6 address strings to listen, connect, etc. 00049 if ((info.mFamily == AF_INET) && (info.mName != "lo0")) { // Internet interfaces only, and skip the loopback address. 00050 info.mAddress.preflight(255); 00051 char* buffer = info.mAddress.buffer(); 00052 ::inet_ntop(intfPtr->ifa_addr->sa_family, &((struct sockaddr_in*) intfPtr->ifa_addr)->sin_addr, buffer, 255); 00053 info.mAddress.postflight((int) ::strlen(buffer)); 00054 00055 // Check for "lo0" above should filter out 127.x.x.x (loopback addresses), but in case it doesn't, check it. 00056 if (! info.mAddress.startsWith("127.")) { 00057 interfaces.push_back(info); 00058 } 00059 } 00060 } 00061 00062 intfPtr = intfPtr->ifa_next; 00063 } 00064 00065 ::freeifaddrs(interfacesDataPtr); 00066 return interfaces; 00067 } 00068 00069 static const int MAX_ADDRSTRLEN = V_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN); 00070 // static 00071 VString VSocket::_platform_addrinfoToIPAddressString(const VString& hostName, const struct addrinfo* info) { 00072 void* addr; 00073 if (info->ai_family == AF_INET) { 00074 addr = (void*) &(((struct sockaddr_in*)info->ai_addr)->sin_addr); 00075 } else if (info->ai_family == AF_INET6) { 00076 addr = (void*) &(((struct sockaddr_in6*)info->ai_addr)->sin6_addr); 00077 } else { 00078 // We don't know how to access the addr for other family types. They could conceivably be added. 00079 throw VException(VSTRING_FORMAT("VSocket::_platform_addrinfoToIPAddressString(%s): An invalid family (%d) other than AF_INET or AF_INET6 was specified.", hostName.chars(), info->ai_family)); 00080 } 00081 00082 VString result; 00083 result.preflight(MAX_ADDRSTRLEN); 00084 const char* buf = ::inet_ntop(info->ai_family, addr, result.buffer(), MAX_ADDRSTRLEN); 00085 if (buf == NULL) { 00086 throw VException(VSystemError::getSocketError(), VSTRING_FORMAT("VSocket::_platform_addrinfoToIPAddressString(%s): inet_ntop() failed.", hostName.chars())); 00087 } 00088 result.postflight((int) ::strlen(buf)); 00089 00090 return result; 00091 } 00092 00093 // static 00094 bool VSocket::_platform_isSocketIDValid(VSocketID socketID) { 00095 // On Unix: 00096 // -1 is typical error return value from ::socket() 00097 // Also, FD_SETSIZE is max num open sockets, sockid over that is sign of a big problem, and would cause FD_SET() during read() to fail. 00098 return (socketID >= 0) && (socketID <= FD_SETSIZE); 00099 } 00100 00101 int VSocket::_platform_available() { 00102 int numBytesAvailable = 0; 00103 00104 int result = ::v_ioctlsocket(mSocketID, FIONREAD, &numBytesAvailable); 00105 00106 if (result == -1) { 00107 throw VStackTraceException(VSystemError::getSocketError(), VSTRING_FORMAT("VSocket[%s] available: v_ioctlsocket() failed.", mSocketName.chars())); 00108 } 00109 00110 return numBytesAvailable; 00111 } 00112