From b0576980184571384269fcc86c96e3b5786c3340 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Wed, 15 Jul 2020 19:29:16 +0200 Subject: [PATCH] Added api_endpoint API call to give local API endpoint address, added responses to local-only UDP API, added Socket::getSocketName(), added ability to discover current listening interface address and port for serveSocket-style functions --- lib/config.cpp | 5 +++ lib/config.h | 5 +++ lib/socket.cpp | 57 ++++++++++++++++--------------- lib/socket.h | 1 + src/controller/controller_api.cpp | 12 +++++++ 5 files changed, 52 insertions(+), 28 deletions(-) diff --git a/lib/config.cpp b/lib/config.cpp index a0e9c762..0e62df60 100644 --- a/lib/config.cpp +++ b/lib/config.cpp @@ -40,6 +40,9 @@ static Socket::Server *serv_sock_pointer = 0; uint32_t Util::Config::printDebugLevel = DEBUG; // std::string Util::Config::streamName; +std::string Util::listenInterface; +uint32_t Util::listenPort = 0; + Util::Config::Config(){ // global options here vals["debug"]["long"] = "debug"; @@ -341,6 +344,7 @@ int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)){ DEVEL_MSG("Failure to open socket"); return 1; } + Socket::getSocketName(server_socket.getSocket(), Util::listenInterface, Util::listenPort); serv_sock_pointer = &server_socket; activate(); if (server_socket.getSocket()){ @@ -368,6 +372,7 @@ int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection &S)){ DEVEL_MSG("Failure to open socket"); return 1; } + Socket::getSocketName(server_socket.getSocket(), Util::listenInterface, Util::listenPort); serv_sock_pointer = &server_socket; activate(); if (server_socket.getSocket()){ diff --git a/lib/config.h b/lib/config.h index 1ea0c865..18a50096 100644 --- a/lib/config.h +++ b/lib/config.h @@ -49,6 +49,11 @@ namespace Util{ void addConnectorOptions(int port, JSON::Value &capabilities); }; + /// The interface address the current serveSocket function is listening on + extern std::string listenInterface; + /// The port the current serveSocket function is listening on + extern uint32_t listenPort; + /// Gets directory the current executable is stored in. std::string getMyPath(); diff --git a/lib/socket.cpp b/lib/socket.cpp index 6e34365b..cc98322c 100644 --- a/lib/socket.cpp +++ b/lib/socket.cpp @@ -270,6 +270,31 @@ std::string Socket::resolveHostToBestExternalAddrGuess(const std::string &host, return newaddr; } +/// Gets bound host and port for a socket and returns them by reference. +/// Returns true on success and false on failure. +bool Socket::getSocketName(int fd, std::string & host, uint32_t & port){ + struct sockaddr_in6 tmpaddr; + socklen_t len = sizeof(tmpaddr); + if (getsockname(fd, (sockaddr *)&tmpaddr, &len)){ + return false; + } + static char addrconv[INET6_ADDRSTRLEN]; + if (tmpaddr.sin6_family == AF_INET6){ + host = inet_ntop(AF_INET6, &(tmpaddr.sin6_addr), addrconv, INET6_ADDRSTRLEN); + if (host.substr(0, 7) == "::ffff:"){host = host.substr(7);} + port = ntohs(tmpaddr.sin6_port); + HIGH_MSG("Local IPv6 addr [%s:%" PRIu32 "]", host.c_str(), port); + return true; + } + if (tmpaddr.sin6_family == AF_INET){ + host = inet_ntop(AF_INET, &(((sockaddr_in *)&tmpaddr)->sin_addr), addrconv, INET6_ADDRSTRLEN); + port = ntohs(((sockaddr_in *)&tmpaddr)->sin_port); + HIGH_MSG("Local IPv4 addr [%s:%" PRIu32 "]", host.c_str(), port); + return true; + } + return false; +} + std::string uint2string(unsigned int i){ std::stringstream st; st << i; @@ -457,20 +482,8 @@ void Socket::Connection::setBoundAddr(){ return; } //Otherwise, read from socket pointer. Works for both SSL and non-SSL sockets, and real sockets passed as fd's, but not for non-sockets (duh) - struct sockaddr_in6 tmpaddr; - socklen_t len = sizeof(tmpaddr); - if (!getsockname(getSocket(), (sockaddr *)&tmpaddr, &len)){ - static char addrconv[INET6_ADDRSTRLEN]; - if (tmpaddr.sin6_family == AF_INET6){ - boundaddr = inet_ntop(AF_INET6, &(tmpaddr.sin6_addr), addrconv, INET6_ADDRSTRLEN); - if (boundaddr.substr(0, 7) == "::ffff:"){boundaddr = boundaddr.substr(7);} - HIGH_MSG("Local IPv6 addr [%s]", boundaddr.c_str()); - } - if (tmpaddr.sin6_family == AF_INET){ - boundaddr = inet_ntop(AF_INET, &(((sockaddr_in *)&tmpaddr)->sin_addr), addrconv, INET6_ADDRSTRLEN); - HIGH_MSG("Local IPv4 addr [%s]", boundaddr.c_str()); - } - } + uint32_t boundport = 0; + getSocketName(getSocket(), boundaddr, boundport); } // Cleans up the socket by dropping the connection. @@ -1741,21 +1754,9 @@ void Socket::UDPConnection::SendNow(const char *sdata, size_t len){ } std::string Socket::UDPConnection::getBoundAddress(){ - struct sockaddr_in6 tmpaddr; - socklen_t len = sizeof(tmpaddr); std::string boundaddr; - if (!getsockname(sock, (sockaddr *)&tmpaddr, &len)){ - static char addrconv[INET6_ADDRSTRLEN]; - if (tmpaddr.sin6_family == AF_INET6){ - boundaddr = inet_ntop(AF_INET6, &(tmpaddr.sin6_addr), addrconv, INET6_ADDRSTRLEN); - if (boundaddr.substr(0, 7) == "::ffff:"){boundaddr = boundaddr.substr(7);} - HIGH_MSG("Local IPv6 addr [%s]", boundaddr.c_str()); - } - if (tmpaddr.sin6_family == AF_INET){ - boundaddr = inet_ntop(AF_INET, &(((sockaddr_in *)&tmpaddr)->sin_addr), addrconv, INET6_ADDRSTRLEN); - HIGH_MSG("Local IPv4 addr [%s]", boundaddr.c_str()); - } - } + uint32_t boundport; + Socket::getSocketName(sock, boundaddr, boundport); return boundaddr; } diff --git a/lib/socket.h b/lib/socket.h index 786f5455..f652fbc4 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -44,6 +44,7 @@ namespace Socket{ bool checkTrueSocket(int sock); std::string resolveHostToBestExternalAddrGuess(const std::string &host, int family = AF_UNSPEC, const std::string &hint = ""); + bool getSocketName(int fd, std::string & host, uint32_t & port); /// A buffer made out of std::string objects that can be efficiently read from and written to. class Buffer{ diff --git a/src/controller/controller_api.cpp b/src/controller/controller_api.cpp index 6346f037..cfab522a 100644 --- a/src/controller/controller_api.cpp +++ b/src/controller/controller_api.cpp @@ -1,6 +1,7 @@ #include //for browse API call #include //for browse API call #include +#include #include #include #include @@ -368,6 +369,7 @@ void Controller::handleUDPAPI(void * np){ return; } Util::Procs::socketList.insert(uSock.getSock()); + uSock.SetDestination(UDP_API_HOST, UDP_API_PORT); while (Controller::conf.is_active){ if (uSock.Receive()){ MEDIUM_MSG("UDP API: %s", uSock.data); @@ -377,6 +379,7 @@ void Controller::handleUDPAPI(void * np){ if (Request.isObject()){ tthread::lock_guard guard(configMutex); handleAPICommands(Request, Response); + uSock.SendNow(Response.toString()); }else{ WARN_MSG("Invalid API command received over UDP: %s", uSock.data); } @@ -639,6 +642,15 @@ void Controller::handleAPICommands(JSON::Value & Request, JSON::Value & Response if (Request.isMember("stats_streams")){ Controller::fillActive(Request["stats_streams"], Response["stats_streams"]); } + + if (Request.isMember("api_endpoint")){ + HTTP::URL url("http://localhost:4242"); + url.host = Util::listenInterface; + if (url.host == "::"){url.host = "::1";} + if (url.host == "0.0.0.0"){url.host = "127.0.0.1";} + url.port = JSON::Value(Util::listenPort).asString(); + Response["api_endpoint"] = url.getUrl(); + } Controller::configChanged = true; }