// // UDPSocket.cpp // interface // // Created by Stephen Birarda on 1/28/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // #include #include #include #include #include #ifdef _WIN32 #include "Syssocket.h" #else #include #include #include #include #endif #include #include "Logging.h" #include "UDPSocket.h" sockaddr_in destSockaddr, senderAddress; bool socketMatch(const sockaddr* first, const sockaddr* second) { if (first != NULL && second != NULL) { // utility function that indicates if two sockets are equivalent // currently only compares two IPv4 addresses // expandable to IPv6 by adding else if for AF_INET6 if (first->sa_family != second->sa_family) { // not the same family, can't be equal return false; } else if (first->sa_family == AF_INET) { const sockaddr_in *firstIn = (const sockaddr_in *) first; const sockaddr_in *secondIn = (const sockaddr_in *) second; return firstIn->sin_addr.s_addr == secondIn->sin_addr.s_addr && firstIn->sin_port == secondIn->sin_port; } else { return false; } } else { return false; } } int packSocket(unsigned char* packStore, in_addr_t inAddress, in_port_t networkOrderPort) { packStore[0] = inAddress >> 24; packStore[1] = inAddress >> 16; packStore[2] = inAddress >> 8; packStore[3] = inAddress; packStore[4] = networkOrderPort >> 8; packStore[5] = networkOrderPort; return 6; // could be dynamically more if we need IPv6 } int packSocket(unsigned char* packStore, sockaddr* socketToPack) { return packSocket(packStore, ((sockaddr_in*) socketToPack)->sin_addr.s_addr, ((sockaddr_in*) socketToPack)->sin_port); } int unpackSocket(const unsigned char* packedData, sockaddr* unpackDestSocket) { sockaddr_in* destinationSocket = (sockaddr_in*) unpackDestSocket; destinationSocket->sin_family = AF_INET; destinationSocket->sin_addr.s_addr = (packedData[0] << 24) + (packedData[1] << 16) + (packedData[2] << 8) + packedData[3]; destinationSocket->sin_port = (packedData[4] << 8) + packedData[5]; return 6; // this could be more if we ever need IPv6 } void copySocketToEmptySocketPointer(sockaddr** destination, const sockaddr* source) { // create a new sockaddr or sockaddr_in depending on what type of address this is if (source->sa_family == AF_INET) { *destination = (sockaddr*) new sockaddr_in; memcpy(*destination, source, sizeof(sockaddr_in)); } else { *destination = (sockaddr*) new sockaddr_in6; memcpy(*destination, source, sizeof(sockaddr_in6)); } } int getLocalAddress() { // get this node's local address so we can pass that to DS struct ifaddrs* ifAddrStruct = NULL; struct ifaddrs* ifa = NULL; int family; int localAddress = 0; #ifndef _WIN32 getifaddrs(&ifAddrStruct); for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { family = ifa->ifa_addr->sa_family; if (family == AF_INET) { localAddress = ((sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; } } freeifaddrs(ifAddrStruct); #else // Get the local hostname char szHostName[255]; gethostname(szHostName, 255); struct hostent *host_entry; host_entry = gethostbyname(szHostName); char * szLocalIP; szLocalIP = inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list); localAddress = inet_addr(szLocalIP); #endif return localAddress; } unsigned short loadBufferWithSocketInfo(char* addressBuffer, sockaddr* socket) { if (socket != NULL) { char* copyBuffer = inet_ntoa(((sockaddr_in*) socket)->sin_addr); memcpy(addressBuffer, copyBuffer, strlen(copyBuffer)); return htons(((sockaddr_in*) socket)->sin_port); } else { const char* unknownAddress = "Unknown"; memcpy(addressBuffer, unknownAddress, strlen(unknownAddress)); return 0; } } sockaddr_in socketForHostnameAndHostOrderPort(const char* hostname, unsigned short port) { struct hostent* pHostInfo; sockaddr_in newSocket = {}; if ((pHostInfo = gethostbyname(hostname))) { memcpy(&newSocket.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length); } if (port != 0) { newSocket.sin_port = htons(port); } return newSocket; } UDPSocket::UDPSocket(unsigned short int listeningPort) : _listeningPort(listeningPort), blocking(true) { init(); // create the socket handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (handle <= 0) { qDebug("Failed to create socket.\n"); return; } destSockaddr.sin_family = AF_INET; // bind the socket to the passed listeningPort sockaddr_in bind_address; bind_address.sin_family = AF_INET; bind_address.sin_addr.s_addr = INADDR_ANY; bind_address.sin_port = htons((uint16_t) _listeningPort); if (bind(handle, (const sockaddr*) &bind_address, sizeof(sockaddr_in)) < 0) { qDebug("Failed to bind socket to port %hu.\n", _listeningPort); return; } // if we requested an ephemeral port, get the actual port if (listeningPort == 0) { socklen_t addressLength = sizeof(sockaddr_in); getsockname(handle, (sockaddr*) &bind_address, &addressLength); _listeningPort = ntohs(bind_address.sin_port); } const int DEFAULT_BLOCKING_SOCKET_TIMEOUT_USECS = 0.5 * 1000000; setBlockingReceiveTimeoutInUsecs(DEFAULT_BLOCKING_SOCKET_TIMEOUT_USECS); qDebug("Created UDP Socket listening on %hd\n", _listeningPort); } UDPSocket::~UDPSocket() { #ifdef _WIN32 closesocket(handle); #else close(handle); #endif } bool UDPSocket::init() { #ifdef _WIN32 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ return false; } /* Confirm that the WinSock DLL supports 2.2.*/ /* Note that if the DLL supports versions later */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ WSACleanup(); return false; } #endif return true; } void UDPSocket::setBlocking(bool blocking) { this->blocking = blocking; #ifdef _WIN32 u_long mode = blocking ? 0 : 1; ioctlsocket(handle, FIONBIO, &mode); #else int flags = fcntl(handle, F_GETFL, 0); fcntl(handle, F_SETFL, blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK)); #endif } void UDPSocket::setBlockingReceiveTimeoutInUsecs(int timeoutUsecs) { struct timeval tv = {timeoutUsecs / 1000000, timeoutUsecs % 1000000}; setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); } // Receive data on this socket with retrieving address of sender bool UDPSocket::receive(void* receivedData, ssize_t* receivedBytes) const { return receive((sockaddr*) &senderAddress, receivedData, receivedBytes); } // Receive data on this socket with the address of the sender bool UDPSocket::receive(sockaddr* recvAddress, void* receivedData, ssize_t* receivedBytes) const { #ifdef _WIN32 int addressSize = sizeof(*recvAddress); #else socklen_t addressSize = sizeof(&recvAddress); #endif *receivedBytes = recvfrom(handle, static_cast(receivedData), MAX_BUFFER_LENGTH_BYTES, 0, recvAddress, &addressSize); return (*receivedBytes > 0); } int UDPSocket::send(sockaddr* destAddress, const void* data, size_t byteLength) const { // send data via UDP int sent_bytes = sendto(handle, (const char*)data, byteLength, 0, (sockaddr *) destAddress, sizeof(sockaddr_in)); if (sent_bytes != byteLength) { qDebug("Failed to send packet: %s\n", strerror(errno)); return false; } return sent_bytes; } int UDPSocket::send(char* destAddress, int destPort, const void* data, size_t byteLength) const { // change address and port on reusable global to passed variables destSockaddr.sin_addr.s_addr = inet_addr(destAddress); destSockaddr.sin_port = htons((uint16_t)destPort); return send((sockaddr *)&destSockaddr, data, byteLength); }