From 3713346f3959782c5e5d1ddd0252f25fb319d732 Mon Sep 17 00:00:00 2001 From: Salvador Fandino Date: Wed, 20 Apr 2016 16:22:56 +0200 Subject: Provide support for channel endpoints being UNIX file sockets in addition to being TCP/IP sockets. --- nxcomp/ChannelEndPoint.cpp | 245 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 nxcomp/ChannelEndPoint.cpp (limited to 'nxcomp/ChannelEndPoint.cpp') diff --git a/nxcomp/ChannelEndPoint.cpp b/nxcomp/ChannelEndPoint.cpp new file mode 100644 index 000000000..cb35e52d2 --- /dev/null +++ b/nxcomp/ChannelEndPoint.cpp @@ -0,0 +1,245 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2015 Qindel Formacion y Servicios SL. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License Version 2, as */ +/* published by the Free Software Foundation. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTA- */ +/* BILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, you can request a copy to Qindel */ +/* or write to the Free Software Foundation, Inc., 59 Temple Place, Suite */ +/* 330, Boston, MA 02111-1307 USA */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +#include +#include +#include +#include + +#include "ChannelEndPoint.h" + +#include "NXalert.h" + +ChannelEndPoint::ChannelEndPoint(const char *spec) + : defaultTCPPort_(0), defaultTCPInterface_(0), + defaultUnixPath_(NULL) { + spec_ = (spec ? strdup(spec) : NULL); +} + +void +ChannelEndPoint::setSpec(const char *spec) { + if (spec_) free(spec_); + + if (spec && strlen(spec)) + spec_ = strdup(spec); + else + spec_ = NULL; +} + +void +ChannelEndPoint::setSpec(int port) { + if (port >= 0) { + char tmp[20]; + sprintf(tmp, "%d", port); + setSpec(tmp); + } + else setSpec((char*)NULL); +} + +void +ChannelEndPoint::setDefaultTCPPort(long port) { + defaultTCPPort_ = port; +} + +void +ChannelEndPoint::setDefaultTCPInterface(int publicInterface) { + defaultTCPInterface_ = publicInterface; +} + +void +ChannelEndPoint::setDefaultUnixPath(char *path) { + if (defaultUnixPath_) free(defaultUnixPath_); + + if (path && strlen(path)) + defaultUnixPath_ = strdup(path); + else + defaultUnixPath_ = NULL; +} + +void +ChannelEndPoint::disable() { setSpec("0"); } + +bool +ChannelEndPoint::specIsPort(long *port) const { + if (port) *port = 0; + long p = -1; + if (spec_) { + char *end; + p = strtol(spec_, &end, 10); + if ((end == spec_) || (*end != '\0')) + return false; + } + + if (port) *port = p; + return true; +} + +bool +ChannelEndPoint::getUnixPath(char **unixPath) const { + + if (unixPath) *unixPath = 0; + + long p; + char *path = NULL; + + if (specIsPort(&p)) { + if (p != 1) return false; + } + else if (spec_ && (strncmp("unix:", spec_, 5) == 0)) { + path = spec_ + 5; + } + else + return false; + + if (!path || (*path == '\0')) { + path = defaultUnixPath_; + if (!path) + return false; + } + + if (unixPath) + *unixPath = strdup(path); + + return true; +} + +// FIXME!!! +static const char * +getComputerName() { + // + // Strangely enough, under some Windows OSes SMB + // service doesn't bind to localhost. Fall back + // to localhost if can't find computer name in + // the environment. In future we should try to + // bind to localhost and then try the other IPs. + // + + const char *hostname = NULL; + + #ifdef __CYGWIN32__ + + hostname = getenv("COMPUTERNAME"); + + #endif + + if (hostname == NULL) + { + hostname = "localhost"; + } + + return hostname; +} + +bool +ChannelEndPoint::getTCPHostAndPort(char **host, long *port) const { + long p; + char *h = NULL; + ssize_t h_len; + + if (host) *host = NULL; + if (port) *port = 0; + + if (specIsPort(&p)) { + h_len = 0; + } + else if (spec_ && (strncmp("tcp:", spec_, 4) == 0)) { + h = spec_ + 4; + char *colon = strrchr(h, ':'); + if (colon) { + char *end; + h_len = colon++ - h; + p = strtol(colon, &end, 10); + if ((end == colon) || (*end != '\0')) + return false; + } + else { + h_len = strlen(h); + p = 1; + } + } + else + return false; + + if (p == 1) p = defaultTCPPort_; + if (p < 1) return false; + + if (port) + *port = p; + + if (host) + *host = ( h_len + ? strndup(h, h_len) + : strdup(defaultTCPInterface_ ? getComputerName() : "localhost")); + + return true; +} + +bool +ChannelEndPoint::enabled() const { + return (getUnixPath() || getTCPHostAndPort()); +} + +long ChannelEndPoint::getTCPPort() const { + long port; + if (getTCPHostAndPort(NULL, &port)) return port; + return -1; +} + +bool +ChannelEndPoint::validateSpec() { + return (specIsPort() || getUnixPath() || getTCPHostAndPort()); +} + +ChannelEndPoint &ChannelEndPoint::operator=(const ChannelEndPoint &other) { + char *old; + defaultTCPPort_ = other.defaultTCPPort_; + defaultTCPInterface_ = other.defaultTCPInterface_; + old = defaultUnixPath_; + defaultUnixPath_ = (other.defaultUnixPath_ ? strdup(other.defaultUnixPath_) : NULL); + free(old); + old = spec_; + spec_ = (other.spec_ ? strdup(other.spec_) : NULL); + free(old); + return *this; +} + +std::ostream& operator<<(std::ostream& os, const ChannelEndPoint& endPoint) { + if (endPoint.enabled()) { + char *unixPath, *host; + long port; + if (endPoint.getUnixPath(&unixPath)) { + os << "unix:" << unixPath; + free(unixPath); + } + else if (endPoint.getTCPHostAndPort(&host, &port)) { + os << "tcp:" << host << ":" << port; + free(host); + } + else { + os << "(invalid)"; + } + } + else { + os << "(disabled)"; + } + return os; +} -- cgit v1.2.3