/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * Unix implementation of a SPITSocket. * * File: UnixSocket.cpp * Author: Hagi * * Created on 12. April 2019, 15:58 */ #include "SPITSocket.h" #include "Task.hpp" #include "esp/uuid.h" #include "esp_log.h" #include "esp_netif.h" #include #include using namespace std; /** * Creates socket. If there exist some, they will be closed. * @return */ bool SPITSocket::createSocket_UDP() { bool boolSuccess = true; int intResult = -1; int intOptionValue4 = 1; // ip4 if (m_UDPSocketIP4 != INVALID_SOCKET) { close(m_UDPSocketIP4); m_UDPSocketIP4 = INVALID_SOCKET; } m_UDPSocketIP4 = socket(AF_INET, SOCK_DGRAM, 0); if (m_UDPSocketIP4 == INVALID_SOCKET) { boolSuccess = false; } else { intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_REUSEADDR, (void *)&intOptionValue4, sizeof(intOptionValue4)); } if (intResult < 0) { boolSuccess = false; } if (boolSuccess == true) { struct timeval tv; tv.tv_sec = 1; // seconds tv.tv_usec = 0; // microseconds (0.0 sec) // This sets the receive timeout setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); // set the m_UDPSocketIP4 in NON BLOCKING mode because // if the UDPSockets are in blocking mode the receiveMessage does not return in every constellation // int intFlags; // intFlags = fcntl(m_UDPSocketIP4, F_GETFL); // fcntl(m_UDPSocketIP4, F_SETFL, intFlags | O_NONBLOCK); // int intBufferSize = 2046 * 512; // intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_RCVBUF, (void*)&intBufferSize, sizeof(intBufferSize)); // intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_SNDBUF, (void*)&intBufferSize, sizeof(intBufferSize)); } return boolSuccess; } /** * Binds the socket to the client's ip address and port. The socket option SO_REUSEADDR is set to true. * @param p_ClientIP ip address of the client * @param p_ClientPort port of the client. * if p_Port == "0" any free port will be used * @return -1 id bind fails, o if bind is ok * */ int SPITSocket::bindSocket(string p_ServerIP, string p_ClientIP, string p_ClientPort) { addrinfo *clientAI; struct sockaddr_in *ptrIP4SocketAddress; struct sockaddr_in o_IP4SocketAddress; int intSocklen; string stringClientPort; if (p_ClientPort.length() <= 0) stringClientPort = "0"; else stringClientPort = p_ClientPort; // int intResult = SOCKET_ERROR; int intResult = 0; if (getaddrinfo(p_ClientIP.data(), p_ClientPort.data(), NULL, &clientAI) != 0) { return -1; } switch (clientAI->ai_family) { case AF_INET: if (m_UDPSocketIP4 == INVALID_SOCKET) { break; } ptrIP4SocketAddress = reinterpret_cast(clientAI->ai_addr); intSocklen = sizeof(*ptrIP4SocketAddress); // copy the ptrIP4SocketAddress, may be not filled correct by getaddrinfo memset(&o_IP4SocketAddress, 0, intSocklen); o_IP4SocketAddress.sin_addr = ptrIP4SocketAddress->sin_addr; o_IP4SocketAddress.sin_family = ptrIP4SocketAddress->sin_family; // o_IP4SocketAddress.sin_zero = ptrIP4SocketAddress->sin_zero; o_IP4SocketAddress.sin_port = ptrIP4SocketAddress->sin_port; intResult = bind(m_UDPSocketIP4, (const sockaddr *)(ptrIP4SocketAddress), (socklen_t)intSocklen); if (intResult < 0) { break; } setBoundClientFamily(AF_INET); if (intResult == 0) { if (getsockname(m_UDPSocketIP4, (sockaddr *)ptrIP4SocketAddress, (socklen_t *)&intSocklen) != -1) { setBoundClientPort(to_string((int)ptrIP4SocketAddress->sin_port)); } } break; default: setBoundClientFamily(0); intResult = -1; break; } freeaddrinfo(clientAI); if (intResult == -1) { setIsBound(false); } else { setIsBound(true); } return intResult; } /** * Set whether the sockat are brodcast sockets or not. Set the sockopt SO_BROADCAST to 0 or 1 * @param p_Broadcast true SO_BROADCAST is set * false = SO_BROADCAST is not set * @return 0 = ok, -1 = error */ int SPITSocket::setBroadcast(bool p_Broadcast) { int intResult; int intOptionValue = 1; u_char charOptionValue = 0x01; // IP4 if (p_Broadcast) { intOptionValue = 1; } else { intOptionValue = 0; } intResult = setsockopt(m_UDPSocketIP4, SOL_SOCKET, SO_BROADCAST, &intOptionValue, sizeof(int)); // intResult = setsockopt(m_UDPSocketIP4, IPPROTO_IP, IP_MULTICAST_LOOP, (void*)&charOptionValue, sizeof(charOptionValue)); return intResult; } /** * * @param p_InetFamily AF_INET or AF_INET6 * @param p_ServerIP the ip address of the server * @param p_ServerPort the port of the server * @param p_MessageBytes buffer containing the message * @param p_MessageLength the length of the message * @return -1 send fails * 0 send is done */ int SPITSocket::sendMessageTo(int p_InetFamily, string p_ServerIP, string p_ServerPort, const char *p_MessageBytes, int p_MessageLength) { if (m_UDPSocketIP4 == INVALID_SOCKET) return -1; struct addrinfo *ptrAddressInfo; struct sockaddr_in *ptrIP4SocketAddress; struct sockaddr_in o_IP4SocketAddress; int intSocklen; int intResult = -1; // prepare AddressInfo if (getaddrinfo(p_ServerIP.data(), p_ServerPort.data(), NULL, &ptrAddressInfo) != 0) { return -1; } switch (ptrAddressInfo->ai_family) { case AF_INET: ptrIP4SocketAddress = reinterpret_cast(ptrAddressInfo->ai_addr); intSocklen = sizeof(*ptrIP4SocketAddress); if (m_UDPSocketIP4 != INVALID_SOCKET) { // copy the ptrIP4SocketAddress, may be not filled correct by getaddrinfo memset(&o_IP4SocketAddress, 0, intSocklen); o_IP4SocketAddress.sin_addr = ptrIP4SocketAddress->sin_addr; o_IP4SocketAddress.sin_family = ptrIP4SocketAddress->sin_family; o_IP4SocketAddress.sin_port = ptrIP4SocketAddress->sin_port; intResult = sendto(m_UDPSocketIP4, p_MessageBytes, p_MessageLength, 0, (const sockaddr *)&o_IP4SocketAddress, (socklen_t)intSocklen); if (intResult < 0) { printf("UnixSocket::sendMessageTo IP4 sendto %s FAILED %s\n", p_ServerIP.data(), strerror(errno)); printf("UnixSocket::sendMessageTo ret=%d %s / %s / %d\n", intResult, p_ServerPort.data(), p_MessageBytes, p_MessageLength); } freeaddrinfo(ptrAddressInfo); } break; default: intResult = -1; } if (intResult < 0) { return -1; } return 0; } /** * Call this for receiving a message * This will block until a message is received or the underlying socket is closed * @param p_InetFamily either AF_INET or AF_INET6
* The SPITSocket creates two udp sockets, one for IP4 and one for IP6 * This parameter decides from which socket should a message recieved * @param p_Buffer the buffer containing the received message later. * @param p_BufferLength the size of the buffer * @param p_ServerIP a pointer to a string, when a messages is received the string will contain the ip address of the sender/server * if p_ServerIP is NULL - no detection of the server will be done. * @return */ int SPITSocket::receiveMessage(int p_InetFamily, char *p_Buffer, int p_BufferLength, string *p_ServerIP) { int intResult = -1; // ADDRINFO *AI; struct sockaddr_in o_IP4SocketAddress; int intSocklen; switch (p_InetFamily) { case AF_INET: if (m_UDPSocketIP4 == INVALID_SOCKET) { break; } intSocklen = sizeof(o_IP4SocketAddress); memset(&o_IP4SocketAddress, 0, intSocklen); intResult = recvfrom(m_UDPSocketIP4, (void *)p_Buffer, p_BufferLength, 0, (sockaddr *)&o_IP4SocketAddress, (socklen_t *)&intSocklen); if (intResult >= 0) { if (p_ServerIP != NULL) { char bufferIP4[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &(o_IP4SocketAddress.sin_addr), bufferIP4, intSocklen); *p_ServerIP = bufferIP4; } } break; } return intResult; } SPITSocket::IPAddress SPITSocket::getAdaptersInfo() { // iterate over active interfaces, and print out IPs esp_netif_t *netif = NULL; while ((netif = esp_netif_next_unsafe(netif)) != NULL) { ESP_LOGI("SPIT", "Connected to %s", esp_netif_get_desc(netif)); esp_netif_ip_info_t ip; ESP_ERROR_CHECK(esp_netif_get_ip_info(netif, &ip)); ESP_LOGI("SPIT", "- IPv4 address: " IPSTR ",", IP2STR(&ip.ip)); ESP_LOGI("SPIT", "- IPv4 netmask: " IPSTR ",", IP2STR(&ip.netmask)); char buffer[64]; sprintf(buffer, IPSTR, IP2STR(&ip.ip)); string stringIP4 = buffer; sprintf(buffer, IPSTR, IP2STR(&ip.netmask)); string stringSubnet = buffer; return {stringIP4, stringSubnet}; } return {"0.0.0.0", "0.0.0.0"}; } string createGUID() { // uuid_t id; // uuid_generate(id); // char *guid_string = new char[100]; // uuid_unparse(id, guid_string); // string stringGUID = guid_string; // return stringGUID; uuid_t uu; char uu_str[UUID_STR_LEN]; uuid_generate(uu); uuid_unparse(uu, uu_str); string stringGUID = uu_str; return stringGUID; } /** The name of the client's host computer*/ string getClientHostName() { string stringHostName = ""; const char *hostname; esp_netif_get_hostname(esp_netif_get_default_netif(), &hostname); if (hostname != nullptr) { stringHostName = hostname; } return stringHostName; ; }