Commit c6e95651 authored by Mike Gabriel's avatar Mike Gabriel

nxcomp/Loop.cpp: Add Unix file socket support for proxy <-> proxy connection.

parent b23dcd10
......@@ -24,6 +24,7 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include "ChannelEndPoint.h"
......@@ -31,8 +32,21 @@
ChannelEndPoint::ChannelEndPoint(const char *spec)
: defaultTCPPort_(0), defaultTCPInterface_(0),
defaultUnixPath_(NULL) {
spec_ = (spec ? strdup(spec) : NULL);
defaultUnixPath_(NULL), spec_(NULL) {
setSpec(spec);
}
ChannelEndPoint::~ChannelEndPoint()
{
char *unixPath = NULL;
if (getUnixPath(&unixPath))
{
struct stat st;
lstat(unixPath, &st);
if(S_ISSOCK(st.st_mode))
unlink(unixPath);
}
}
void
......@@ -40,21 +54,92 @@ ChannelEndPoint::setSpec(const char *spec) {
if (spec_) free(spec_);
if (spec && strlen(spec))
{
spec_ = strdup(spec);
isUnix_ = getUnixPath();
isTCP_ = getTCPHostAndPort();
}
else
{
spec_ = NULL;
isUnix_ = false;
isTCP_ = false;
}
}
void
ChannelEndPoint::setSpec(int port) {
ChannelEndPoint::setSpec(long port) {
if (port >= 0) {
char tmp[20];
sprintf(tmp, "%d", port);
sprintf(tmp, "%ld", port);
setSpec(tmp);
}
else {
disable();
}
}
void
ChannelEndPoint::setSpec(const char *hostName, long port) {
int length;
if (spec_) free(spec_);
isUnix_ = false;
isTCP_ = false;
if (hostName && strlen(hostName) && port >= 1)
{
length = snprintf(NULL, 0, "tcp:%s:%ld", hostName, port);
spec_ = (char *)calloc(length + 1, sizeof(char));
snprintf(spec_, length+1, "tcp:%s:%ld", hostName, port);
isTCP_ = true;
}
else setSpec((char*)NULL);
}
bool
ChannelEndPoint::getSpec(char **socketUri) const {
if (socketUri) *socketUri = NULL;
char *unixPath = NULL;
char *hostName = NULL;
long port = -1;
char *newSocketUri = NULL;
int length = -1;
if (getUnixPath(&unixPath))
{
length = snprintf(NULL, 0, "unix:%s", unixPath);
}
else if (getTCPHostAndPort(&hostName, &port))
{
length = snprintf(NULL, 0, "tcp:%s:%ld", hostName, port);
}
if (length > 0)
{
newSocketUri = (char *)calloc(length + 1, sizeof(char));
if (isUnixSocket())
snprintf(newSocketUri, length+1, "unix:%s", unixPath);
else
snprintf(newSocketUri, length+1, "tcp:%s:%ld", hostName, port);
if (socketUri)
*socketUri = strdup(newSocketUri);
}
free(newSocketUri);
free(unixPath);
free(hostName);
if (*socketUri != '\0')
return true;
return false;
}
void
ChannelEndPoint::setDefaultTCPPort(long port) {
defaultTCPPort_ = port;
......@@ -76,10 +161,12 @@ ChannelEndPoint::setDefaultUnixPath(char *path) {
}
void
ChannelEndPoint::disable() { setSpec("0"); }
ChannelEndPoint::disable() {
setSpec("0");
}
bool
ChannelEndPoint::specIsPort(long *port) const {
ChannelEndPoint::getPort(long *port) const {
if (port) *port = 0;
long p = -1;
if (spec_) {
......@@ -101,7 +188,7 @@ ChannelEndPoint::getUnixPath(char **unixPath) const {
long p;
char *path = NULL;
if (specIsPort(&p)) {
if (getPort(&p)) {
if (p != 1) return false;
}
else if (spec_ && (strncmp("unix:", spec_, 5) == 0)) {
......@@ -122,6 +209,11 @@ ChannelEndPoint::getUnixPath(char **unixPath) const {
return true;
}
bool
ChannelEndPoint::isUnixSocket() const {
return isUnix_;
}
// FIXME!!!
static const char *
getComputerName() {
......@@ -158,7 +250,7 @@ ChannelEndPoint::getTCPHostAndPort(char **host, long *port) const {
if (host) *host = NULL;
if (port) *port = 0;
if (specIsPort(&p)) {
if (getPort(&p)) {
h_len = 0;
}
else if (spec_ && (strncmp("tcp:", spec_, 4) == 0)) {
......@@ -194,8 +286,8 @@ ChannelEndPoint::getTCPHostAndPort(char **host, long *port) const {
}
bool
ChannelEndPoint::enabled() const {
return (getUnixPath() || getTCPHostAndPort());
ChannelEndPoint::isTCPSocket() const {
return isTCP_;
}
long ChannelEndPoint::getTCPPort() const {
......@@ -205,8 +297,15 @@ long ChannelEndPoint::getTCPPort() const {
}
bool
ChannelEndPoint::enabled() const {
return (isUnixSocket() || isTCPSocket());
}
bool
ChannelEndPoint::validateSpec() {
return (specIsPort() || getUnixPath() || getTCPHostAndPort());
isTCP_ = getTCPHostAndPort();
isUnix_ = getUnixPath();
return ( getPort() || isUnix_ || isTCP_ );
}
ChannelEndPoint &ChannelEndPoint::operator=(const ChannelEndPoint &other) {
......@@ -219,26 +318,24 @@ ChannelEndPoint &ChannelEndPoint::operator=(const ChannelEndPoint &other) {
old = spec_;
spec_ = (other.spec_ ? strdup(other.spec_) : NULL);
free(old);
isUnix_ = getUnixPath();
isTCP_ = getTCPHostAndPort();
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);
char* endPointSpec = NULL;
if (endPoint.getSpec(&endPointSpec))
{
os << endPointSpec;
free(endPointSpec);
}
else if (endPoint.getTCPHostAndPort(&host, &port)) {
os << "tcp:" << host << ":" << port;
free(host);
}
else {
else
os << "(invalid)";
}
}
else {
else
{
os << "(disabled)";
}
return os;
......
......@@ -33,25 +33,32 @@ class ChannelEndPoint
int defaultTCPInterface_; // 0=localhost, otherwise IP of public interface.
char *defaultUnixPath_;
char *spec_;
bool isUnix_;
bool isTCP_;
bool specIsPort(long *port = NULL) const;
bool getPort(long *port = NULL) const;
public:
ChannelEndPoint(const char *spec = NULL);
~ChannelEndPoint();
ChannelEndPoint &operator=(const ChannelEndPoint &other);
bool enabled() const;
bool disabled() { return !enabled(); }
void disable();
void setSpec(const char *spec);
void setSpec(int port);
void setSpec(long port);
void setSpec(const char *hostName, long port);
bool getSpec(char **socketUri) const;
void setDefaultTCPPort(long port);
void setDefaultTCPInterface(int publicInterface);
void setDefaultUnixPath(char *path);
bool getUnixPath(char **path = NULL) const;
bool isUnixSocket() const;
bool getTCPHostAndPort(char **hostname = NULL, long *port = NULL) const;
long getTCPPort() const;
bool isTCPSocket() const;
bool validateSpec();
};
......
......@@ -239,7 +239,7 @@ struct sockaddr_un
// should connect to remote.
//
#define WE_INITIATE_CONNECTION (*connectHost != '\0')
#define WE_INITIATE_CONNECTION (connectSocket.enabled())
//
// Is true if we must provide our credentials
......@@ -255,7 +255,7 @@ struct sockaddr_un
//
#define WE_LISTEN_FORWARDER (control -> ProxyMode == proxy_server && \
listenPort != -1)
listenSocket.enabled())
//
// You must define FLUSH in Misc.h if
......@@ -440,7 +440,7 @@ static int SetupDisplaySocket(int &xServerAddrFamily, sockaddr *&xServerAddr,
static int ListenConnection(ChannelEndPoint &endPoint, const char *label);
static int ListenConnectionTCP(const char *host, long port, const char *label);
static int ListenConnectionUnix(const char *unixPath, const char *label);
static int ListenConnectionUnix(const char *path, const char *label);
static int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label);
static int AcceptConnection(int fd, int domain, const char *label);
......@@ -448,8 +448,11 @@ static int AcceptConnection(int fd, int domain, const char *label);
// Other convenience functions.
//
static int WaitForRemote(int portNum);
static int ConnectToRemote(const char *const hostName, int portNum);
static int PrepareProxyConnectionTCP(char** hostName, long int* portNum, int* timeout, int* proxyFD, int* reason);
static int PrepareProxyConnectionUnix(char** path, int* timeout, int* proxyFD, int* reason);
static int WaitForRemote(ChannelEndPoint &socketAddress);
static int ConnectToRemote(ChannelEndPoint &socketAddress);
static int SendProxyOptions(int fd);
static int SendProxyCaches(int fd);
......@@ -514,7 +517,7 @@ static int ParsePackOption(const char *opt);
// given on the command line.
//
static int ParseHostOption(const char *opt, char *host, int &port);
static int ParseHostOption(const char *opt, char *host, long &port);
//
// Translate a font server port specification
......@@ -944,7 +947,6 @@ static char unixSocketName[DEFAULT_STRING_LENGTH] = { 0 };
// Other parameters.
//
static char connectHost[DEFAULT_STRING_LENGTH] = { 0 };
static char acceptHost[DEFAULT_STRING_LENGTH] = { 0 };
static char displayHost[DEFAULT_STRING_LENGTH] = { 0 };
static char authCookie[DEFAULT_STRING_LENGTH] = { 0 };
......@@ -963,13 +965,19 @@ static sockaddr *xServerAddr = NULL;
static unsigned int xServerAddrLength = 0;
//
// The port where the local proxy will await
// the peer connection or where the remote
// proxy will be contacted.
// The representation of a Unix socket path or
// a bind address, denoting where the local proxy
// will await the peer connection.
//
static ChannelEndPoint listenSocket;
//
// The TCP host and port or Unix file socket where
// the remote proxy will be contacted.
//
static int listenPort = -1;
static int connectPort = -1;
static ChannelEndPoint connectSocket;
//
// Helper channels are disabled by default.
......@@ -3355,58 +3363,88 @@ int InitBeforeNegotiation()
int SetupProxyConnection()
{
if (proxyFD == -1)
{
char *socketUri = NULL;
// Let's make sure, the default value for listenSocket is properly set. Doing this
// here, because we have to make sure that we call it after the connectSocket
// declaration is really really complete.
if (listenSocket.disabled() && connectSocket.disabled())
{
char listenPortValue[20] = { 0 };
sprintf(listenPortValue, "%ld", (long)(proxyPort + DEFAULT_NX_PROXY_PORT_OFFSET));
SetAndValidateChannelEndPointArg("local", "listen", listenPortValue, listenSocket);
}
#ifdef TEST
connectSocket.getSpec(&socketUri);
*logofs << "Loop: connectSocket is "<< ( connectSocket.enabled() ? "enabled" : "disabled") << ". "
<< "The socket URI is '"<< ( socketUri != NULL ? socketUri : "<unset>") << "'.\n" << logofs_flush;
listenSocket.getSpec(&socketUri);
*logofs << "Loop: listenSocket is "<< ( listenSocket.enabled() ? "enabled" : "disabled") << ". "
<< "The socket URI is '"<< ( socketUri != NULL ? socketUri : "<unset>") << "'.\n" << logofs_flush;
free(socketUri);
socketUri = NULL;
#endif
if (WE_INITIATE_CONNECTION)
{
if (connectPort < 0)
if (connectSocket.getSpec(&socketUri))
{
connectPort = DEFAULT_NX_PROXY_PORT_OFFSET + proxyPort;
}
#ifdef TEST
*logofs << "Loop: Going to connect to " << connectHost
<< ":" << connectPort << ".\n" << logofs_flush;
#endif
#ifdef TEST
*logofs << "Loop: Going to connect to '" << socketUri
<< "'.\n" << logofs_flush;
#endif
free(socketUri);
proxyFD = ConnectToRemote(connectHost, connectPort);
proxyFD = ConnectToRemote(connectSocket);
#ifdef TEST
*logofs << "Loop: Connected to remote proxy on FD#"
<< proxyFD << ".\n" << logofs_flush;
#endif
#ifdef TEST
*logofs << "Loop: Connected to remote proxy on FD#"
<< proxyFD << ".\n" << logofs_flush;
#endif
cerr << "Info" << ": Connection to remote proxy '" << connectHost
<< ":" << connectPort << "' established.\n";
cerr << "Info" << ": Connected to remote proxy on FD#"
<< proxyFD << ".\n";
}
}
else
{
if (listenPort < 0)
if (listenSocket.isTCPSocket() && (listenSocket.getTCPPort() < 0))
{
listenPort = DEFAULT_NX_PROXY_PORT_OFFSET + proxyPort;
listenSocket.setSpec(DEFAULT_NX_PROXY_PORT_OFFSET + proxyPort);
}
#ifdef TEST
*logofs << "Loop: Going to wait for connection on port "
<< listenPort << ".\n" << logofs_flush;
#endif
if (listenSocket.getSpec(&socketUri))
{
#ifdef TEST
*logofs << "Loop: Going to wait for connection at '"
<< socketUri << "'.\n" << logofs_flush;
#endif
free(socketUri);
proxyFD = WaitForRemote(listenPort);
proxyFD = WaitForRemote(listenSocket);
#ifdef TEST
#ifdef TEST
if (WE_LISTEN_FORWARDER)
{
*logofs << "Loop: Connected to remote forwarder on FD#"
<< proxyFD << ".\n" << logofs_flush;
}
else
{
*logofs << "Loop: Connected to remote proxy on FD#"
<< proxyFD << ".\n" << logofs_flush;
}
#endif
if (WE_LISTEN_FORWARDER)
{
*logofs << "Loop: Connected to remote forwarder on FD#"
<< proxyFD << ".\n" << logofs_flush;
}
else
{
*logofs << "Loop: Connected to remote proxy on FD#"
<< proxyFD << ".\n" << logofs_flush;
}
#endif
}
}
#ifdef TEST
......@@ -3422,8 +3460,11 @@ int SetupProxyConnection()
// to reduce startup time. Option will
// later be disabled if needed.
//
// either listenSocket or connectSocket is used here...
if(listenSocket.isTCPSocket() || connectSocket.isTCPSocket())
SetNoDelay(proxyFD, 1);
SetNoDelay(proxyFD, 1);
//
// We need non-blocking input since the
......@@ -4404,11 +4445,13 @@ int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label)
goto SetupSocketError;
}
if (SetReuseAddress(newFD) < 0)
{
// SetReuseAddress already warns with an error
goto SetupSocketError;
}
if (addr->sa_family == AF_INET)
if (SetReuseAddress(newFD) < 0)
{
// SetReuseAddress already warns with an error
goto SetupSocketError;
}
if (bind(newFD, addr, addrlen) == -1)
{
......@@ -4427,12 +4470,12 @@ int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label)
if (listen(newFD, 8) == -1)
{
#ifdef PANIC
*logofs << "Loop: PANIC! Call to bind failed for " << label
*logofs << "Loop: PANIC! Call to listen failed for " << label
<< ". Error is " << EGET()
<< " '" << ESTR() << "'.\n" << logofs_flush;
#endif
cerr << "Error" << ": Call to bind failed for " << label
cerr << "Error" << ": Call to listen failed for " << label
<< ". Error is " << EGET()
<< " '" << ESTR() << "'.\n";
......@@ -5445,7 +5488,6 @@ void CleanupLocal()
*unixSocketName = '\0';
*connectHost = '\0';
*acceptHost = '\0';
*displayHost = '\0';
*authCookie = '\0';
......@@ -5460,8 +5502,8 @@ void CleanupLocal()
xServerAddr = NULL;
listenPort = -1;
connectPort = -1;
listenSocket.disable();
connectSocket.disable();
cupsPort.disable();
auxPort.disable();
......@@ -6592,62 +6634,79 @@ void ResetTimer()
}
//
// Open TCP socket to listen for remote proxy and
// block until remote connects. If successful close
// the listening socket and return FD on which the
// other party is connected.
// Open TCP or UNIX file socket to listen for remote proxy
// and block until remote connects. If successful close
// the listening socket and return FD on which the other
// party is connected.
//
int WaitForRemote(int portNum)
int WaitForRemote(ChannelEndPoint &socketAddress)
{
char hostLabel[DEFAULT_STRING_LENGTH] = { 0 };
char *socketUri = NULL;
int retryAccept = -1;
int proxyFD = -1;
int newFD = -1;
//
// Get IP address of host to be awaited.
//
int acceptIPAddr = 0;
if (*acceptHost != '\0')
if (socketAddress.isTCPSocket())
{
acceptIPAddr = GetHostAddress(acceptHost);
if (acceptIPAddr == 0)
//
// Get IP address of host to be awaited.
//
if (*acceptHost != '\0')
{
#ifdef PANIC
*logofs << "Loop: PANIC! Cannot accept connections from unknown host '"
<< acceptHost << "'.\n" << logofs_flush;
#endif
acceptIPAddr = GetHostAddress(acceptHost);
cerr << "Error" << ": Cannot accept connections from unknown host '"
<< acceptHost << "'.\n";
if (acceptIPAddr == 0)
{
#ifdef PANIC
*logofs << "Loop: PANIC! Cannot accept connections from unknown host '"
<< acceptHost << "'.\n" << logofs_flush;
#endif
goto WaitForRemoteError;
cerr << "Error" << ": Cannot accept connections from unknown host '"
<< acceptHost << "'.\n";
goto WaitForRemoteError;
}
strcpy(hostLabel, "any host");
}
else
{
snprintf(hostLabel, sizeof(hostLabel), "'%s'", acceptHost);
}
if (loopbackBind)
{
long bindPort;
if (socketAddress.getTCPHostAndPort(NULL, &bindPort))
socketAddress.setSpec("localhost", bindPort);
}
strcpy(hostLabel, "any host");
}
else if (socketAddress.isUnixSocket())
strcpy(hostLabel, "this host");
else
{
snprintf(hostLabel, sizeof(hostLabel), "'%s'", acceptHost);
}
strcpy(hostLabel, "unknown origin (something went wrong!!!)");
proxyFD = ListenConnectionTCP(((loopbackBind || (control->ProxyMode == proxy_server)) ? "localhost" : "*"),
portNum, "NX");
proxyFD = ListenConnection(socketAddress, "NX");
socketAddress.getSpec(&socketUri);
#ifdef TEST
*logofs << "Loop: Waiting for connection from "
<< hostLabel << " on port '" << portNum
<< hostLabel << " on socket '" << socketUri
<< "'.\n" << logofs_flush;
#endif
cerr << "Info" << ": Waiting for connection from "
<< hostLabel << " on port '" << portNum
<< hostLabel << " on socket '" << socketUri
<< "'.\n";
free(socketUri);
//
// How many times to loop waiting for connections
......@@ -6702,12 +6761,19 @@ int WaitForRemote(int portNum)
}
else if (result > 0 && FD_ISSET(proxyFD, &readSet))
{
sockaddr_in newAddr;
socklen_t addrLen = sizeof(sockaddr_in);
newFD = accept(proxyFD, (sockaddr *) &newAddr, &addrLen);
sockaddr_in newAddrINET;
if (socketAddress.isUnixSocket())
{
socklen_t addrLen = sizeof(sockaddr_un);
newFD = accept(proxyFD, NULL, &addrLen);
}
else if (socketAddress.isTCPSocket())
{
socklen_t addrLen = sizeof(sockaddr_in);
newFD = accept(proxyFD, (sockaddr *) &newAddrINET, &addrLen);
}
if (newFD == -1)
{
#ifdef PANIC
......@@ -6722,47 +6788,82 @@ int WaitForRemote(int portNum)
goto WaitForRemoteError;
}
char *connectedHost = inet_ntoa(newAddr.sin_addr);
if (*acceptHost == '\0' || (int) newAddr.sin_addr.s_addr == acceptIPAddr)
if (socketAddress.isUnixSocket())
{
#ifdef TEST
unsigned int connectedPort = ntohs(newAddr.sin_port);
*logofs << "Loop: Accepted connection from '" << connectedHost
<< "' with port '" << connectedPort << "'.\n"
char * unixPath = NULL;
socketAddress.getUnixPath(&unixPath);
#ifdef TEST
*logofs << "Loop: Accepted connection from this host on Unix file socket '"
<< unixPath << "'.\n"
<< logofs_flush;
#endif
cerr << "Info" << ": Accepted connection from '"
<< connectedHost << "'.\n";
cerr << "Info" << ": Accepted connection from this host on Unix file socket '"
<< unixPath << "'.\n";
free(unixPath);
break;
}
else
else if (socketAddress.isTCPSocket())
{
#ifdef PANIC
*logofs << "Loop: WARNING! Refusing connection from '" << connectedHost
<< "' on port '" << portNum << "'.\n" << logofs_flush;
#endif
cerr << "Warning" << ": Refusing connection from '"
<< connectedHost << "'.\n";
}
char *connectedHost = inet_ntoa(newAddrINET.sin_addr);
//
// Not the best way to elude a DOS attack...
//
if (*acceptHost == '\0' || (int) newAddrINET.sin_addr.s_addr == acceptIPAddr)
{
#ifdef TEST
sleep(5);
unsigned int connectedPort = ntohs(newAddrINET.sin_port);
*logofs << "Loop: Accepted connection from '" << connectedHost
<< "' with port '" << connectedPort << "'.\n"
<< logofs_flush;
#endif
cerr << "Info" << ": Accepted connection from '"
<< connectedHost << "'.\n";
break;
}
else
{
#ifdef PANIC
*logofs << "Loop: WARNING! Refusing connection from '" << connectedHost
<< "' on port '" << socketAddress.getTCPPort() << "'.\n" << logofs_flush;
#endif
cerr << "Warning" << ": Refusing connection from '"
<< connectedHost << "'.\n";
}
//
// Not the best way to elude a DOS attack...
//
sleep(5);
close(newFD);
}
close(newFD);
}
if (--retryAccept == 0)
{
if (*acceptHost == '\0')
if (socketAddress.isUnixSocket())
{
#ifdef PANIC
*logofs << "Loop: PANIC! Connection via Unix file socket from this host "
<< "could not be established.\n"
<< logofs_flush;
#endif
cerr << "Error" << ": Connection via Unix file socket from this host "
<< "could not be established.\n";
}
else if (*acceptHost == '\0')
{
#ifdef PANIC
*logofs << "Loop: PANIC! Connection with remote host "
......@@ -6804,43 +6905,194 @@ WaitForRemoteError:
HandleCleanup();
}
//
// Connect to remote proxy. If successful
// return FD of connection, else return -1.
//
int ConnectToRemote(const char *const hostName, int portNum)
int PrepareProxyConnectionTCP(char** hostName, long int* portNum, int* timeout, int* proxyFD, int* reason)
{
int proxyFD = -1;
int remoteIPAddr = GetHostAddress(hostName);
if (!proxyFD)
{
#ifdef PANIC
*logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionTCP). "
<< "'proxyFD' must not be a NULL pointer.\n" << logofs_flush;
#endif
cerr << "Error" << ": Implementation error (PrepareProxyConnectionTCP). "
<< "'proxyFD' must not be a NULL pointer.\n";
return -1;
}
if (!reason)
{
#ifdef PANIC
*logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionTCP). "
<< "'reason' must not be a NULL pointer.\n" << logofs_flush;
#endif
cerr << "Error" << ": Implementation error (PrepareProxyConnectionTCP). "
<< "'reason' must not be a NULL pointer.\n";
return -1;
}
int remoteIPAddr = GetHostAddress(*hostName);
if (remoteIPAddr == 0)
{
#ifdef PANIC
*logofs << "Loop: PANIC! Unknown remote host '"
<< hostName << "'.\n" << logofs_flush;
<< *hostName << "'.\n" << logofs_flush;
#endif
cerr << "Error" << ": Unknown remote host '"
<< hostName << "'.\n";
cerr << "Error" << ": Unknown remote host '"
<< *hostName << "'.\n";
HandleCleanup();
}
#ifdef TEST
*logofs << "Loop: Connecting to remote host '"
<< hostName << ":" << portNum << "'.\n"
<< *hostName << ":" << *portNum << "'.\n"
<< logofs_flush;
#endif
cerr << "Info" << ": Connecting to remote host '"
<< hostName << ":" << portNum << "'.\n"
<< *hostName << ":" << *portNum << "'.\n"
<< logofs_flush;
*proxyFD = -1;
*reason = -1;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(*portNum);
addr.sin_addr.s_addr = remoteIPAddr;
*proxyFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
*reason = EGET();
if (*proxyFD == -1)
{
#ifdef PANIC
*logofs << "Loop: PANIC! Call to socket failed. "
<< "Error is " << *reason << " '" << ESTR()
<< "'.\n" << logofs_flush;
#endif
cerr << "Error" << ": Call to socket failed. "
<< "Error is " << *reason << " '" << ESTR()
<< "'.\n";
return -1;
}
else if (SetReuseAddress(*proxyFD) < 0)
{
return -1;
}
//
// Ensure operation is timed out
// if there is a network problem.
//
if (timeout)
SetTimer(*timeout);
else
SetTimer(20000);
int result = connect(*proxyFD, (sockaddr *) &addr, sizeof(sockaddr_in));
*reason = EGET();
ResetTimer();
return result;
}
int PrepareProxyConnectionUnix(char** path, int* timeout, int* proxyFD, int* reason)
{
if (!proxyFD)
{
#ifdef PANIC
*logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionUnix). "
<< "proxyFD must not be a NULL pointer.\n" << logofs_flush;
#endif
cerr << "Error" << ": Implementation error (PrepareProxyConnectionUnix). "
<< "proxyFD must not be a NULL pointer.\n";
return -1;
}
if (!reason)
{
#ifdef PANIC
*logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionUnix). "
<< "'reason' must not be a NULL pointer.\n" << logofs_flush;
#endif
cerr << "Error" << ": Implementation error (PrepareProxyConnectionUnix). "
<< "'reason' must not be a NULL pointer.\n";
return -1;
}
/* FIXME: Add socket file existence and permission checks */
*proxyFD = -1;
*reason = -1;
sockaddr_un addr;
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, *path, 108 - 1);
*proxyFD = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC);
*reason = EGET();
if (*proxyFD == -1)
{
#ifdef PANIC
*logofs << "Loop: PANIC! Call to socket failed. "
<< "Error is " << *reason << " '" << ESTR()
<< "'.\n" << logofs_flush;
#endif
cerr << "Error" << ": Call to socket failed. "
<< "Error is " << *reason << " '" << ESTR()
<< "'.\n";
return -1;
}
//
// Ensure operation is timed out
// if there is a network problem.
//
if (timeout)
SetTimer(*timeout);
else
SetTimer(20000);
int result = connect(*proxyFD, (sockaddr *) &addr, sizeof(sockaddr_un));
*reason = EGET();
ResetTimer();
return result;
}
//
// Connect to remote proxy. If successful
// return FD of connection, else return -1.
//
int ConnectToRemote(ChannelEndPoint &socketAddress)
{
//
// How many times we retry to connect to remote
// host in case of failure?
// host / Unix domain socket in case of failure?
//
int retryConnect = control -> OptionProxyRetryConnect;
......@@ -6858,39 +7110,16 @@ int ConnectToRemote(const char *const hostName, int portNum)
T_timestamp lastRetry = getNewTimestamp();
sockaddr_in addr;
int result = -1;
int reason = -1;
int proxyFD = -1;
addr.sin_family = AF_INET;
addr.sin_port = htons(portNum);
addr.sin_addr.s_addr = remoteIPAddr;
char *hostName = NULL;
long int portNum = -1;
char *unixPath = NULL;
for (;;)
{
proxyFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
if (proxyFD == -1)
{
#ifdef PANIC
*logofs << "Loop: PANIC! Call to socket failed. "
<< "Error is " << EGET() << " '" << ESTR()
<< "'.\n" << logofs_flush;
#endif
cerr << "Error" << ": Call to socket failed. "
<< "Error is " << EGET() << " '" << ESTR()
<< "'.\n";
goto ConnectToRemoteError;
}
else if (SetReuseAddress(proxyFD) < 0)
{
goto ConnectToRemoteError;
}
//
// Ensure operation is timed out
// if there is a network problem.
//
#ifdef DEBUG
*logofs << "Loop: Timer set to " << connectTimeout / 1000
......@@ -6899,13 +7128,10 @@ int ConnectToRemote(const char *const hostName, int portNum)
<< "'.\n" << logofs_flush;
#endif
SetTimer(connectTimeout);
int result = connect(proxyFD, (sockaddr *) &addr, sizeof(sockaddr_in));
int reason = EGET();
ResetTimer();
if (socketAddress.getUnixPath(&unixPath))
result = PrepareProxyConnectionUnix(&unixPath, &connectTimeout, &proxyFD, &reason);
else if (socketAddress.getTCPHostAndPort(&hostName, &portNum))
result = PrepareProxyConnectionTCP(&hostName, &portNum, &connectTimeout, &proxyFD, &reason);
if (result < 0)
{
......@@ -6919,24 +7145,40 @@ int ConnectToRemote(const char *const hostName, int portNum)
{
ESET(reason);
#ifdef PANIC
*logofs << "Loop: PANIC! Connection to '" << hostName
<< ":" << portNum << "' failed. Error is "
<< EGET() << " '" << ESTR() << "'.\n"
<< logofs_flush;
#endif
if (socketAddress.isUnixSocket())
{
#ifdef PANIC
*logofs << "Loop: PANIC! Connection to Unix file socket '"
<< unixPath << "' failed. Error is "
<< EGET() << " '" << ESTR() << "'.\n"
<< logofs_flush;
#endif
cerr << "Error" << ": Connection to '" << hostName
<< ":" << portNum << "' failed. Error is "
<< EGET() << " '" << ESTR() << "'.\n";
cerr << "Error" << ": Connection to Unix file socket '"
<< unixPath << "' failed. Error is "
<< EGET() << " '" << ESTR() << "'.\n";
}
else
{
#ifdef PANIC
*logofs << "Loop: PANIC! Connection to '" << hostName
<< ":" << portNum << "' failed. Error is "
<< EGET() << " '" << ESTR() << "'.\n"
<< logofs_flush;
#endif
cerr << "Error" << ": Connection to '" << hostName
<< ":" << portNum << "' failed. Error is "
<< EGET() << " '" << ESTR() << "'.\n";
}
goto ConnectToRemoteError;
}
else
{
#ifdef TEST
*logofs << "Loop: Sleeping " << retryTimeout
<< " Ms before retrying.\n"
*logofs << "Loop: Sleeping " << retryTimeout
<< " ms before retrying.\n"
<< logofs_flush;
#endif
......@@ -7005,10 +7247,20 @@ int ConnectToRemote(const char *const hostName, int portNum)
ESET(reason);
#ifdef TEST
*logofs << "Loop: Connection to '" << hostName
<< ":" << portNum << "' failed with error '"
<< ESTR() << "'. Retrying.\n"
<< logofs_flush;
if (unixPath[0] != '\0' )
{
*logofs << "Loop: Connection to Unix socket file '"
<< unixPath << "' failed with error '"
<< ESTR() << "'. Retrying.\n"
<< logofs_flush;
}
else
{
*logofs << "Loop: Connection to '" << hostName
<< ":" << portNum << "' failed with error '"
<< ESTR() << "'. Retrying.\n"
<< logofs_flush;
}
#endif
}
else
......@@ -8234,6 +8486,9 @@ int ParseEnvironmentOptions(const char *env, int force)
name = strtok(nextOpts, "=");
char connectHost[DEFAULT_STRING_LENGTH] = { 0 };
long connectPort = -1;
while (name)
{
value = strtok(NULL, ",");
......@@ -8254,6 +8509,7 @@ int ParseEnvironmentOptions(const char *env, int force)
}
else if (strcasecmp(name, "link") == 0)
{
if (control -> ProxyMode == proxy_server)
{
PrintOptionIgnored("local", name, value);
......@@ -8315,26 +8571,29 @@ int ParseEnvironmentOptions(const char *env, int force)
}
else if (strcasecmp(name, "listen") == 0)
{
if (*connectHost != '\0')
char *socketUri = NULL;
if (connectSocket.getSpec(&socketUri))
{
#ifdef PANIC
*logofs << "Loop: PANIC! Can't handle 'listen' and 'connect' parameters "
<< "at the same time.\n" << logofs_flush;
*logofs << "Loop: PANIC! Refusing 'listen' parameter with 'connect' being '"
<< connectHost << "'.\n" << logofs_flush;
<< socketUri << "'.\n" << logofs_flush;
#endif
cerr << "Error" << ": Can't handle 'listen' and 'connect' parameters "
<< "at the same time.\n";
cerr << "Error" << ": Refusing 'listen' parameter with 'connect' being '"
<< connectHost << "'.\n";
<< socketUri << "'.\n";
free(socketUri);
return -1;
}
listenPort = ValidateArg("local", name, value);
SetAndValidateChannelEndPointArg("local", name, value, listenSocket);
}
else if (strcasecmp(name, "loopback") == 0)
{
......@@ -8342,22 +8601,24 @@ int ParseEnvironmentOptions(const char *env, int force)
}
else if (strcasecmp(name, "accept") == 0)
{
if (*connectHost != '\0')
char *socketUri = NULL;
if (connectSocket.getSpec(&socketUri))
{
#ifdef PANIC
*logofs << "Loop: PANIC! Can't handle 'accept' and 'connect' parameters "
<< "at the same time.\n" << logofs_flush;
*logofs << "Loop: PANIC! Refusing 'accept' parameter with 'connect' being '"
<< connectHost << "'.\n" << logofs_flush;
<< socketUri << "'.\n" << logofs_flush;
#endif
cerr << "Error" << ": Can't handle 'accept' and 'connect' parameters "
<< "at the same time.\n";
cerr << "Error" << ": Refusing 'accept' parameter with 'connect' being '"
<< connectHost << "'.\n";
<< socketUri << "'.\n";
free(socketUri);
return -1;
}
......@@ -8383,8 +8644,12 @@ int ParseEnvironmentOptions(const char *env, int force)
return -1;
}
strncpy(connectHost, value, DEFAULT_STRING_LENGTH - 1);
if ((strncmp(value, "tcp:", 4) == 0) || (strncmp(value, "unix:", 5) == 0))
SetAndValidateChannelEndPointArg("local", name, value, connectSocket);
else
// if the "connect" parameter does not start with "unix:" or "tcp:" assume
// old parameter usage style (providing hostname string only).
strcpy(connectHost, value);
}
else if (strcasecmp(name, "port") == 0)
{
......@@ -8842,6 +9107,17 @@ int ParseEnvironmentOptions(const char *env, int force)
} // End of while (name) ...
// Assemble the connectSocket channel end point if parameter values have been old-school...
if (connectSocket.disabled() && (connectHost[0] != '\0') && (proxyPort > 0 || connectPort > 0))
{
if (connectPort < 0)
connectPort = proxyPort + DEFAULT_NX_PROXY_PORT_OFFSET;
char tcpHostAndPort[DEFAULT_STRING_LENGTH] = { 0 };
sprintf(tcpHostAndPort, "tcp:%s:%ld", connectHost, connectPort);
SetAndValidateChannelEndPointArg("local", name, tcpHostAndPort, connectSocket);
}
#ifdef TEST
*logofs << "Loop: Completed parsing of string '"
<< env << "'.\n" << logofs_flush;
......@@ -9082,16 +9358,21 @@ int ParseCommandLineOptions(int argc, const char **argv)
// command line at the connecting side.
//
if (ParseHostOption(nextArg, connectHost, connectPort) > 0)
{
//
// Assume port is at a proxied display offset.
//
char *cHost;
long cPort;
proxyPort = connectPort;
if (connectSocket.getTCPHostAndPort(&cHost, &cPort) && (ParseHostOption(nextArg, cHost, cPort) > 0))
{
//
// Assume port is at a proxied display offset.
//
connectPort += DEFAULT_NX_PROXY_PORT_OFFSET;
}
proxyPort = cPort;
cPort += DEFAULT_NX_PROXY_PORT_OFFSET;
connectSocket.setSpec(cHost, cPort);
}
else if (ParseEnvironmentOptions(nextArg, 1) < 0)
{
return -1;
......@@ -13195,7 +13476,7 @@ int ParseBitrateOption(const char *opt)
return 1;
}
int ParseHostOption(const char *opt, char *host, int &port)
int ParseHostOption(const char *opt, char *host, long &port)
{
#ifdef TEST
*logofs << "Loop: Trying to parse options string '" << opt
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment