diff --git a/source/shared_lib/include/platform/posix/socket.h b/source/shared_lib/include/platform/posix/socket.h index d923b2199..719de2316 100644 --- a/source/shared_lib/include/platform/posix/socket.h +++ b/source/shared_lib/include/platform/posix/socket.h @@ -171,6 +171,8 @@ class Socket { static int getBroadCastPort() { return broadcast_portno; } static void setBroadCastPort(int value) { broadcast_portno = value; } + static int getIpStr(struct addrinfo *ptr, char *buf); + struct addrinfo *getAddrInfo(const int port); static std::vector getLocalIPAddressList(); // Int lookup is socket fd while bool result is whether or not that socket was signalled for reading diff --git a/source/shared_lib/sources/platform/posix/socket.cpp b/source/shared_lib/sources/platform/posix/socket.cpp index 8bc2922f3..ce910a2ae 100644 --- a/source/shared_lib/sources/platform/posix/socket.cpp +++ b/source/shared_lib/sources/platform/posix/socket.cpp @@ -647,7 +647,7 @@ string getNetworkInterfaceBroadcastAddress(string ipAddress) //printf(" Found interface: name=[%s] desc=[%s] address=[%s] netmask=[%s] broadcastAddr=[%s]\n", name, desc?desc:"unavailable", ifaAddrStr, maskAddrStr, dstAddrStr); if(strcmp(ifaAddrStr,ipAddress.c_str()) == 0) { broadCastAddress = dstAddrStr; - } + } } if(pAdapterInfo) free(pAdapterInfo); @@ -661,44 +661,103 @@ string getNetworkInterfaceBroadcastAddress(string ipAddress) return broadCastAddress; } +int Socket::getIpStr(struct addrinfo *ptr, char *buf) { + void *addr; + if (ptr->ai_family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in *) ptr->ai_addr; + addr = &(ipv4->sin_addr); + } + else { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) ptr->ai_addr; + addr = &(ipv6->sin6_addr); + } + + if (inet_ntop(ptr->ai_family, addr, buf, INET6_ADDRSTRLEN) == NULL) { + perror("inet_ntop:"); + return -1; + } + + return 0; +} + uint32 Socket::getConnectedIPAddress(string IP) { - sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); + unsigned char addr[sizeof(struct in6_addr)]; + if(IP == "") { + IP = connectedIpAddress; + } + int r = inet_pton(AF_INET, IP.c_str(), addr); + if (r != 0) { + // handle error + } + return SockAddrToUint32((struct in_addr *)&addr);; +} - addr.sin_family= AF_INET; - if(IP == "") { - IP = connectedIpAddress; - } - addr.sin_addr.s_addr= inet_addr(IP.c_str()); - //addr.sin_port= htons(port); +// TODO: This may be too inefficient because it's called multiple +// times. It may be adequate to store 'result' and reuse it later. Note +// that the 4th argument ('&result) of getaddrinfo() is normally +// malloc'ed and needs to be freed later with freeaddrinfo(). One way to +// work around that may be to declare it statically. +// +// Returns a pointer to a memory-allocated addrinfo struct which must +// be freed later with freeaddrinfo() +struct addrinfo *Socket::getAddrInfo(const int port) { + struct addrinfo hints, *result; + + /* Obtain address(es) matching host/port */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; + hints.ai_protocol = 0; + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + char strPort[BUFSIZ]; + size_t n = snprintf (strPort, sizeof strPort, "%d", port); + if (n > sizeof strPort) { + fprintf (stderr, "strPort truncated. This should not happen."); + throw megaglest_runtime_error(strPort); + } + + char myhostname[HOST_NAME_MAX]=""; + int r=gethostname(myhostname,HOST_NAME_MAX); + if (r != 0) { + fputs("gethostname failed.", stderr); + throw megaglest_runtime_error(myhostname); + } + + int s = getaddrinfo(myhostname, strPort, &hints, &result); + if (s != 0) + { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); + throw megaglest_runtime_error(myhostname); + } - return SockAddrToUint32((struct sockaddr *)&addr); + return result; } -std::vector Socket::getLocalIPAddressList() { +std::vectorSocket::getLocalIPAddressList() { std::vector ipList; - /* get my host name */ - char myhostname[101]=""; - gethostname(myhostname,100); - - struct hostent* myhostent = gethostbyname(myhostname); - if(myhostent) { - // get all host IP addresses (Except for loopback) - char myhostaddr[101] = ""; - for(int ipIdx = 0; myhostent->h_addr_list[ipIdx] != NULL; ++ipIdx) { - Ip::Inet_NtoA(SockAddrToUint32((struct in_addr *)myhostent->h_addr_list[ipIdx]), myhostaddr); - - //printf("ipIdx = %d [%s]\n",ipIdx,myhostaddr); - if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] myhostaddr = [%s]\n",__FILE__,__FUNCTION__,__LINE__,myhostaddr); - - if(strlen(myhostaddr) > 0 && - strncmp(myhostaddr,"127.",4) != 0 && - strncmp(myhostaddr,"0.",2) != 0) { - ipList.push_back(myhostaddr); - } + Socket tmp; + struct addrinfo *result = tmp.getAddrInfo(61357); + char ipStr[INET6_ADDRSTRLEN]; + struct addrinfo *ptr = result; + + for (ptr; ptr != NULL; ptr = ptr->ai_next) + { + if (tmp.getIpStr(ptr, ipStr) != 0) + throw megaglest_runtime_error("getLocalIPAddressList"); + + if(strlen(ipStr) > 0 && + strncmp(ipStr,"127.",4) != 0 && + strncmp(ipStr,"0.",2) != 0) { + ipList.push_back(ipStr); } } + freeaddrinfo(result); + Socket::getLocalIPAddressListForPlatform(ipList); return ipList; } @@ -905,7 +964,7 @@ Socket::Socket() { this->connectedIpAddress = ""; - sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + sock = socket(AF_INET, SOCK_STREAM, 0); if(isSocketValid() == false) { throwException("Error creating socket"); } @@ -1381,7 +1440,7 @@ int Socket::send(const void *data, int dataSize) { int totalBytesSent = bytesSent; int attemptCount = 0; - + time_t tStartTimer = time(NULL); while(((bytesSent > 0 && totalBytesSent < dataSize) || (bytesSent < 0 && lastSocketError == PLATFORM_SOCKET_TRY_AGAIN)) && @@ -2392,49 +2451,45 @@ bool ServerSocket::isBroadCastThreadRunning() { void ServerSocket::bind(int port) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d port = %d, portBound = %d START\n",__FILE__,__FUNCTION__,__LINE__,port,portBound); - boundPort = port; - if(isSocketValid() == false) { - sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if(isSocketValid() == false) { - throwException("Error creating socket"); - } - setBlock(false); - } + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_flowinfo = 0; + addr.sin6_port=htons(boundPort); + addr.sin6_addr = in6addr_any; - //sockaddr structure - sockaddr_in addr; - addr.sin_family= AF_INET; - if(this->bindSpecificAddress != "") { - addr.sin_addr.s_addr= inet_addr(this->bindSpecificAddress.c_str()); + sock = socket(addr.sin6_family, SOCK_STREAM, 0); + if(sock == -1) { + throw megaglest_runtime_error("socket failed"); } - else { - addr.sin_addr.s_addr= INADDR_ANY; - } - addr.sin_port= htons(port); - addr.sin_zero[0] = 0; + setBlock(false); int val = 1; #ifndef WIN32 - int opt_result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); +int opt_result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); #else - int opt_result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); +int opt_result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); #endif - int err= ::bind(sock, reinterpret_cast(&addr), sizeof(addr)); - if(err < 0) { - char szBuf[8096]=""; - snprintf(szBuf, 8096,"In [%s::%s] Error binding socket sock = " PLATFORM_SOCKET_FORMAT_TYPE ", address [%s] port = %d err = %d, error = %s opt_result = %d\n",__FILE__,__FUNCTION__,sock,this->bindSpecificAddress.c_str(),port,err,getLastSocketErrorFormattedText().c_str(),opt_result); - if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"%s",szBuf); + //char ipStr[INET6_ADDRSTRLEN]; + //if (Socket::getIpStr(ptr, ipStr) != 0) { + //throw megaglest_runtime_error(""); + //} + + //printf("Binding to %s:%d...", ipStr, boundPort); - snprintf(szBuf, 8096,"Error binding socket sock = " PLATFORM_SOCKET_FORMAT_TYPE ", address [%s] port = %d err = %d, error = %s\n",sock,this->bindSpecificAddress.c_str(),port,err,getLastSocketErrorFormattedText().c_str()); - throw megaglest_runtime_error(szBuf); + if ((::bind (sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6))) < 0) { + puts("fail"); + perror("bind"); + close(sock); + exit(EXIT_FAILURE); } - portBound = true; + puts("ok"); - if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d port = %d, portBound = %d END\n",__FILE__,__FUNCTION__,__LINE__,port,portBound); + portBound = true; } void ServerSocket::disconnectSocket() { @@ -2449,7 +2504,7 @@ void ServerSocket::listen(int connectionQueueSize) { if(isSocketValid() == false) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + sock = socket(AF_INET, SOCK_STREAM, 0); if(isSocketValid() == false) { throwException("Error creating socket"); }