aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Gabriel <mike.gabriel@das-netzwerkteam.de>2016-07-05 08:09:24 +0200
committerMike Gabriel <mike.gabriel@das-netzwerkteam.de>2016-07-05 08:09:24 +0200
commit854f3fa49351ec72da432f195806162fcf5e5ddc (patch)
tree2366136004c46641fa72b8a717663c7ac08ac440
parente0edae04db6dc189512b3a1eda7fe4516af56512 (diff)
parent5a22f2ec1fc5f40257bb61939f9cad4187e00ab8 (diff)
downloadnx-libs-854f3fa49351ec72da432f195806162fcf5e5ddc.tar.gz
nx-libs-854f3fa49351ec72da432f195806162fcf5e5ddc.tar.bz2
nx-libs-854f3fa49351ec72da432f195806162fcf5e5ddc.zip
Merge branch 'sunweaver-pr/proxy-to-proxy-over-unix-socket' into 3.6.x
Attributes GH PR #142: https://github.com/ArcticaProject/nx-libs/pull/142 Reviewed by: Salvador Fandino <sfandino@yahoo.com> -- Mon, 04 Jul 2016 16:31:00 +0200
-rwxr-xr-xdoc/examples/run-nxagent-over-sockets146
-rwxr-xr-xdoc/examples/run-nxproxy2nxproxy-over-sockets150
-rw-r--r--nxcomp/ChannelEndPoint.cpp143
-rw-r--r--nxcomp/ChannelEndPoint.h11
-rw-r--r--nxcomp/Loop.cpp961
5 files changed, 922 insertions, 489 deletions
diff --git a/doc/examples/run-nxagent-over-sockets b/doc/examples/run-nxagent-over-sockets
new file mode 100755
index 000000000..651e71b83
--- /dev/null
+++ b/doc/examples/run-nxagent-over-sockets
@@ -0,0 +1,146 @@
+#!/bin/bash
+
+#/**************************************************************************/
+#/* */
+#/* Copyright (c) 2001, 2011 NoMachine, http://www.nomachine.com/. */
+#/* Copyright (c) 2015-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
+#/* */
+#/* NXSCRIPTS, NX protocol compression and NX extensions to this software */
+#/* are copyright of NoMachine. Redistribution and use of the present */
+#/* software is allowed according to terms specified in the file LICENSE */
+#/* which comes in the source distribution. */
+#/* */
+#/* Check http://www.nomachine.com/licensing.html for applicability. */
+#/* */
+#/* NX and NoMachine are trademarks of Medialogic S.p.A. */
+#/* */
+#/* All rights reserved. */
+#/* */
+#/**************************************************************************/
+
+#
+# Uncomment this to enable echo.
+#
+#set -x
+#
+
+ulimit -c unlimited
+
+NXPROXYBIN=nxproxy
+NXAGENTBIN=nxagent
+
+
+NX_PORT=7
+
+NX_SYSTEM=${HOME}/.nx
+
+NX_ROOT=${HOME}/.nx
+
+#
+# This should be randlomly generated.
+#
+#NX_COOKIE=`xauth list |grep "${HOSTNAME}/unix:\<${NX_PORT}\>" | grep MIT | cut -f 5 -d ' '`
+NX_COOKIE=123efa980d2cba234ef6f73deac810ff
+
+#
+# Create the directories for the NX session.
+#
+
+rm -rf ${NX_ROOT}/C-${NX_PORT} || exit
+mkdir -p ${NX_ROOT}/C-${NX_PORT} || exit
+
+rm -rf ${HOME}/.nx/S-${NX_PORT} || exit
+mkdir -p ${HOME}/.nx/S-${NX_PORT} || exit
+
+#
+# Set the path to libraries and NX executables.
+#
+
+LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${HOME}/NX/nxcomp:${HOME}/NX/nxcompext:${HOME}/NX/nx-X11/exports/lib"
+export LD_LIBRARY_PATH
+
+PATH="${PATH}:${HOME}/NX/nxclient/nxclient:${HOME}/NX/nx-X11/programs/Xserver/"
+export PATH
+
+#
+# Create the fake cookie for this display.
+#
+
+echo -ne "Creating the X authorization cookie.\n"
+
+xauth add ${HOSTNAME}/unix:${NX_PORT} MIT-MAGIC-COOKIE-1 ${NX_COOKIE}
+xauth add ${HOSTNAME}:${NX_PORT} MIT-MAGIC-COOKIE-1 ${NX_COOKIE}
+
+function urlencode() {
+
+ echo "$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$1")"
+
+}
+
+#
+# Options are written in a file 'options' in the session
+# directory. The agent will use the DISPLAY settings, so
+# we pass in the DISPLAY the name of the options file.
+#
+# cache=8M,images=32M,link=modem,type=unix-kde,cleanup=0,
+# accept=62.98.198.1,cookie=$NX_COOKIE,
+# id=giulietta.nomachine.com-1098-6A4649FD0FCA57FAC275AF3F1C45B10F,
+# media=1:1098
+#
+
+NX_HOST=nx/nx,cache=8192k,link=modem,menu=1,keybd=1,samba=0,cups=0,limit=0,\
+listen=$(urlencode "unix:${NX_SYSTEM}/C-${NX_PORT}/proxy.socket"),cookie=$NX_COOKIE,errors=${NX_ROOT}/C-${NX_PORT}/session
+
+echo "${NX_HOST}:${NX_PORT}" >${NX_ROOT}/C-${NX_PORT}/options
+
+#
+# Run the agent. if you don't have a font server running,
+# remove the argument "-fp unix/:7100"
+#
+
+NX_AGENT=:${NX_PORT}
+
+echo -ne "Running the X client side NX agent.\n"
+
+SAVED_DISPLAY=$DISPLAY
+
+DISPLAY=nx/nx,options=${NX_ROOT}/C-${NX_PORT}/options:${NX_PORT}
+export DISPLAY
+
+#valgrind -v --num-callers=8 --error-limit=no --trace-children=no \
+#valgrind --num-callers=8 --tool=memcheck --leak-check=yes --show-reachable=yes --track-fds=yes \
+#ldd ${NXAGENTBIN}
+${NXAGENTBIN} -name 'NX' -geometry 800x600+100+100 "$@" \
+${NX_AGENT} 2>>${NX_ROOT}/C-${NX_PORT}/session &
+
+#
+# The X server side proxy will forward the connection
+# to the original DISPLAY.
+#
+
+DISPLAY=$SAVED_DISPLAY
+export DISPLAY
+
+#
+# These are the nxproxy options used to run a typical session.
+#
+# cookie=$NX_COOKIE,root=/home/pinzari/.nx,media=32824,
+# session=kde_on_giulietta,id=giulietta.nomachine.com-1098-6A4649FD0FCA57FAC275AF3F1C45B10F,
+# connect=giulietta.nomachine.com:1098
+#
+
+#NX_HOST=nx/nx,keybd=1,samba=1,cups=1,connect=localhost,cookie=$NX_COOKIE,errors=${NX_ROOT}/S-${NX_PORT}/session
+NX_HOST=nx/nx,keybd=1,samba=0,cups=0,connect=$(urlencode "unix:${NX_SYSTEM}/C-${NX_PORT}/proxy.socket"),cookie=$NX_COOKIE,errors=${NX_ROOT}/S-${NX_PORT}/session
+
+echo "${NX_HOST}:${NX_PORT}" >${NX_ROOT}/S-${NX_PORT}/options
+
+echo -ne "Running the X server side NX proxy.\n"
+
+#valgrind -v --num-callers=8 --error-limit=no --trace-children=no \
+#valgrind --num-callers=8 --tool=memcheck --leak-check=yes --show-reachable=yes --track-fds=yes \
+#ldd ${NXPROXYBIN}
+${NXPROXYBIN} -S nx/nx,options=${NX_ROOT}/S-${NX_PORT}/options:${NX_PORT} \
+2>>${HOME}/.nx/S-${NX_PORT}/session &
+
+echo -ne "Session running on display :$NX_PORT.\n"
+
diff --git a/doc/examples/run-nxproxy2nxproxy-over-sockets b/doc/examples/run-nxproxy2nxproxy-over-sockets
new file mode 100755
index 000000000..ae9642681
--- /dev/null
+++ b/doc/examples/run-nxproxy2nxproxy-over-sockets
@@ -0,0 +1,150 @@
+#!/bin/bash
+
+set -ex
+
+#/**************************************************************************/
+#/* */
+#/* Copyright (c) 2001, 2011 NoMachine, http://www.nomachine.com/. */
+#/* Copyright (c) 2015-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
+#/* */
+#/* NXSCRIPTS, NX protocol compression and NX extensions to this software */
+#/* are copyright of NoMachine. Redistribution and use of the present */
+#/* software is allowed according to terms specified in the file LICENSE */
+#/* which comes in the source distribution. */
+#/* */
+#/* Check http://www.nomachine.com/licensing.html for applicability. */
+#/* */
+#/* NX and NoMachine are trademarks of Medialogic S.p.A. */
+#/* */
+#/* All rights reserved. */
+#/* */
+#/**************************************************************************/
+
+#
+# Uncomment this to enable echo.
+#
+# set -x
+#
+
+ulimit -c unlimited
+
+NX_PORT=6
+
+NX_SYSTEM=${HOME}/.nx
+
+NX_ROOT=${HOME}/.nx
+
+mkdir -p "${NX_ROOT}"
+
+#
+# This should be randlomly generated.
+#
+
+NX_COOKIE=`xauth -n list |grep "${HOSTNAME}/unix:${NX_PORT}" | grep MIT | cut -f 5 -d ' ' | head -n1`
+if [ -z "$NX_COOKIE" ]; then
+ NX_COOKIE=`mcookie`
+fi
+
+#
+# Create the directories for the NX session.
+#
+
+rm -rf ${NX_ROOT}/C-${NX_PORT} || exit
+mkdir -p ${NX_ROOT}/C-${NX_PORT} || exit
+
+rm -rf ${HOME}/.nx/S-${NX_PORT} || exit
+mkdir -p ${HOME}/.nx/S-${NX_PORT} || exit
+
+#
+# Set the path to libraries and NX executables.
+#
+
+LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${HOME}/NX/nxcomp:${HOME}/NX/nxcompext:${HOME}/NX/nx-X11/exports/lib"
+export LD_LIBRARY_PATH
+
+PATH="${PATH}:${HOME}/NX/nxclient/nxclient:${HOME}/NX/nx-X11/programs/Xserver/"
+export PATH
+
+#
+# Create the fake cookie for this display.
+#
+
+echo -ne "Creating the X authorization cookie.\n"
+
+xauth add ${HOSTNAME}/unix:${NX_PORT} MIT-MAGIC-COOKIE-1 ${NX_COOKIE}
+xauth add ${HOSTNAME}:${NX_PORT} MIT-MAGIC-COOKIE-1 ${NX_COOKIE}
+
+function urlencode() {
+
+ echo "$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$1")"
+
+}
+
+#
+# Options are written in a file 'options' in the session
+# directory. The agent will use the DISPLAY settings, so
+# we pass in the DISPLAY the name of the options file.
+#
+# cache=8M,images=32M,link=modem,type=unix-kde,cleanup=0,
+# accept=62.98.198.1,cookie=$NX_COOKIE,
+# id=giulietta.nomachine.com-1098-6A4649FD0FCA57FAC275AF3F1C45B10F,
+# media=1:1098
+#
+
+#NX_HOST=nx/nx,link=lan,pack=no-pack,keybd=1,samba=1,cups=1,limit=0,\
+#accept=127.0.0.1,cookie=$NX_COOKIE,errors=${NX_ROOT}/C-${NX_PORT}/session
+
+#NX_HOST=nx/nx,link=lan,pack=16m-jpeg-9,keybd=1,samba=1,cups=1,limit=0,\
+#accept=127.0.0.1,cookie=$NX_COOKIE,errors=${NX_ROOT}/C-${NX_PORT}/session
+
+#NX_HOST=nx/nx,cache=8192k,link=modem,keybd=1,samba=1,cups=1,limit=0,\
+#connect=127.0.0.1,cookie=$NX_COOKIE,errors=${NX_ROOT}/C-${NX_PORT}/session
+
+#NX_HOST=nx/nx,link=lan,pack=16m-jpeg-9,keybd=1,samba=1,cups=1,limit=0,\
+#accept=127.0.0.1,cookie=$NX_COOKIE,errors=${NX_ROOT}/C-${NX_PORT}/session
+
+NX_HOST=nx/nx,link=lan,pack=16m-jpeg-9,keybd=1,samba=1,cups=1,limit=0,\
+listen=$(urlencode "unix:${NX_SYSTEM}/C-${NX_PORT}/proxy.socket"),cookie=$NX_COOKIE,errors=${NX_ROOT}/C-${NX_PORT}/session
+
+echo "${NX_HOST}:${NX_PORT}" >${NX_ROOT}/C-${NX_PORT}/options
+
+#
+# Run the local proxy impersonating the X display.
+#
+
+echo -ne "Running the X client side NX proxy.\n"
+
+#valgrind -v --num-callers=8 --error-limit=no --trace-children=no \
+#valgrind --tool=memcheck --track-fds=yes \
+nxproxy -C nx/nx,options=${NX_ROOT}/C-${NX_PORT}/options:${NX_PORT} \
+2>>${HOME}/.nx/C-${NX_PORT}/session &
+
+#
+# The X server side proxy will forward the connection
+# to the original DISPLAY.
+#
+
+#
+# These are the nxproxy options used to run a typical session.
+#
+# cookie=$NX_COOKIE,root=/home/pinzari/.nx,media=32824,
+# session=kde_on_giulietta,id=giulietta.nomachine.com-1098-6A4649FD0FCA57FAC275AF3F1C45B10F,
+# connect=giulietta.nomachine.com:1098
+#
+
+NX_HOST=nx/nx,keybd=1,samba=1,cups=1,connect=$(urlencode "unix:${NX_SYSTEM}/C-${NX_PORT}/proxy.socket"),cookie=$NX_COOKIE,errors=${NX_ROOT}/S-${NX_PORT}/session
+
+echo "${NX_HOST}:${NX_PORT}" >${NX_ROOT}/S-${NX_PORT}/options
+
+echo -ne "Running the X server side NX proxy.\n"
+
+#cachegrind -v --dumps=100000000 \
+#cachegrind -v \
+#valgrind -v --leak-check=yes --leak-resolution=high --show-reachable=yes \
+# --show-reachable=yes --suppressions=nxproxy/nxproxy.supp \
+# --weird-hacks=lax-ioctls --num-callers=8 --logfile-fd=2 \
+nxproxy -S nx/nx,options=${NX_ROOT}/S-${NX_PORT}/options:${NX_PORT} \
+2>>${HOME}/.nx/S-${NX_PORT}/session &
+
+echo -ne "Session running on display :$NX_PORT.\n"
+
diff --git a/nxcomp/ChannelEndPoint.cpp b/nxcomp/ChannelEndPoint.cpp
index cb35e52d2..3e3053927 100644
--- a/nxcomp/ChannelEndPoint.cpp
+++ b/nxcomp/ChannelEndPoint.cpp
@@ -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;
diff --git a/nxcomp/ChannelEndPoint.h b/nxcomp/ChannelEndPoint.h
index 5b4e75345..901952e37 100644
--- a/nxcomp/ChannelEndPoint.h
+++ b/nxcomp/ChannelEndPoint.h
@@ -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();
};
diff --git a/nxcomp/Loop.cpp b/nxcomp/Loop.cpp
index 5086db012..6bec5e30d 100644
--- a/nxcomp/Loop.cpp
+++ b/nxcomp/Loop.cpp
@@ -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
@@ -524,14 +527,6 @@ static int ParseHostOption(const char *opt, char *host, int &port);
static int ParseFontPath(char *path);
//
-// Determine the interface where to listen for
-// the remote proxy connection or the local
-// forwarder.
-//
-
-static int ParseListenOption(int &interface);
-
-//
// Translate a pack method id in a literal.
//
@@ -952,9 +947,7 @@ 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 listenHost[DEFAULT_STRING_LENGTH] = { 0 };
static char displayHost[DEFAULT_STRING_LENGTH] = { 0 };
static char authCookie[DEFAULT_STRING_LENGTH] = { 0 };
@@ -972,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 int listenPort = -1;
-static int connectPort = -1;
+static ChannelEndPoint listenSocket;
+
+//
+// The TCP host and port or Unix file socket where
+// the remote proxy will be contacted.
+//
+
+static ChannelEndPoint connectSocket;
//
// Helper channels are disabled by default.
@@ -3364,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
@@ -3431,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
@@ -3945,72 +3977,7 @@ int SetupTcpSocket()
// Open TCP socket emulating local display.
//
- tcpFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
-
- if (tcpFD == -1)
- {
- #ifdef PANIC
- *logofs << "Loop: PANIC! Call to socket failed for TCP socket"
- << ". Error is " << EGET() << " '" << ESTR() << "'.\n"
- << logofs_flush;
- #endif
-
- cerr << "Error" << ": Call to socket failed for TCP socket"
- << ". Error is " << EGET() << " '" << ESTR() << "'.\n";
-
- HandleCleanup();
- }
- else if (SetReuseAddress(tcpFD) < 0)
- {
- HandleCleanup();
- }
-
- unsigned int proxyPortTCP = X_TCP_PORT + proxyPort;
-
- sockaddr_in tcpAddr;
-
- tcpAddr.sin_family = AF_INET;
- tcpAddr.sin_port = htons(proxyPortTCP);
- if ( loopbackBind )
- {
- tcpAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- }
- else
- {
- tcpAddr.sin_addr.s_addr = htonl(INADDR_ANY);
- }
-
- if (bind(tcpFD, (sockaddr *) &tcpAddr, sizeof(tcpAddr)) == -1)
- {
- #ifdef PANIC
- *logofs << "Loop: PANIC! Call to bind failed for TCP port "
- << proxyPortTCP << ". Error is " << EGET() << " '" << ESTR()
- << "'.\n" << logofs_flush;
- #endif
-
- cerr << "Error" << ": Call to bind failed for TCP port "
- << proxyPortTCP << ". Error is " << EGET() << " '" << ESTR()
- << "'.\n";
-
- HandleCleanup();
- }
-
- if (listen(tcpFD, 8) == -1)
- {
- #ifdef PANIC
- *logofs << "Loop: PANIC! Call to listen failed for TCP port "
- << proxyPortTCP << ". Error is " << EGET() << " '" << ESTR()
- << "'.\n" << logofs_flush;
- #endif
-
- cerr << "Error" << ": Call to listen failed for TCP port "
- << proxyPortTCP << ". Error is " << EGET() << " '" << ESTR()
- << "'.\n";
-
- HandleCleanup();
- }
-
- return 1;
+ return ListenConnectionTCP((loopbackBind ? "localhost" : "*"), X_TCP_PORT + proxyPort, "X11");
}
int SetupUnixSocket()
@@ -4019,90 +3986,40 @@ int SetupUnixSocket()
// Open UNIX domain socket for display.
//
- unixFD = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC);
-
- if (unixFD == -1)
- {
+ if (!control->TempPath) {
#ifdef PANIC
- *logofs << "Loop: PANIC! Call to socket failed for UNIX domain"
- << ". Error is " << EGET() << " '" << ESTR() << "'.\n"
- << logofs_flush;
+ *logofs << "Loop: PANIC! Temporal path is null.\n" << logofs_flush;
#endif
- cerr << "Error" << ": Call to socket failed for UNIX domain"
- << ". Error is " << EGET() << " '" << ESTR() << "'.\n";
-
+ cerr << "Error" << ": Temporal path is null.\n";
HandleCleanup();
}
- sockaddr_un unixAddr;
- unixAddr.sun_family = AF_UNIX;
-
- char dirName[DEFAULT_STRING_LENGTH];
-
- snprintf(dirName, DEFAULT_STRING_LENGTH - 1, "%s/.X11-unix",
- control -> TempPath);
+ unsigned int required = snprintf(unixSocketName, DEFAULT_STRING_LENGTH, "%s/.X11-unix", control->TempPath);
+ if (required < sizeof(unixSocketName)) {
- *(dirName + DEFAULT_STRING_LENGTH - 1) = '\0';
+ // No need to execute the following actions conditionally
+ mkdir(unixSocketName, (0777 | S_ISVTX));
+ chmod(unixSocketName, (0777 | S_ISVTX));
- struct stat dirStat;
+ required = snprintf(unixSocketName, DEFAULT_STRING_LENGTH, "%s/.X11-unix/X%d", control->TempPath, proxyPort);
+ if (required < sizeof(unixSocketName)) {
- if ((stat(dirName, &dirStat) == -1) && (EGET() == ENOENT))
- {
- mkdir(dirName, (0777 | S_ISVTX));
- chmod(dirName, (0777 | S_ISVTX));
+ unixFD = ListenConnectionUnix(unixSocketName, "x11");
+ if (unixFD >= 0)
+ chmod(unixSocketName, 0777);
+ return unixFD;
+ }
}
- snprintf(unixSocketName, DEFAULT_STRING_LENGTH - 1, "%s/X%d",
- dirName, proxyPort);
-
- strncpy(unixAddr.sun_path, unixSocketName, 108);
+ unixSocketName[0] = '\0'; // Just in case!
- #ifdef TEST
- *logofs << "Loop: Assuming Unix socket with name '"
- << unixAddr.sun_path << "'.\n"
- << logofs_flush;
+ #ifdef PANIC
+ *logofs << "Loop: PANIC! path for unix socket is too long.\n" << logofs_flush;
#endif
- *(unixAddr.sun_path + 107) = '\0';
-
- if (bind(unixFD, (sockaddr *) &unixAddr, sizeof(unixAddr)) == -1)
- {
- #ifdef PANIC
- *logofs << "Loop: PANIC! Call to bind failed for UNIX domain socket "
- << unixSocketName << ". Error is " << EGET() << " '" << ESTR()
- << "'.\n" << logofs_flush;
- #endif
-
- cerr << "Error" << ": Call to bind failed for UNIX domain socket "
- << unixSocketName << ". Error is " << EGET() << " '" << ESTR()
- << "'.\n";
-
- HandleCleanup();
- }
-
- if (listen(unixFD, 8) == -1)
- {
- #ifdef PANIC
- *logofs << "Loop: PANIC! Call to listen failed for UNIX domain socket "
- << unixSocketName << ". Error is " << EGET() << " '" << ESTR()
- << "'.\n" << logofs_flush;
- #endif
-
- cerr << "Error" << ": Call to listen failed for UNIX domain socket "
- << unixSocketName << ". Error is " << EGET() << " '" << ESTR()
- << "'.\n";
-
- HandleCleanup();
- }
-
- //
- // Let any local user to gain access to socket.
- //
-
- chmod(unixSocketName, 0777);
-
- return 1;
+ cerr << "Error" << ": path for Unix socket is too long.\n";
+ HandleCleanup();
}
//
@@ -4528,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)
{
@@ -4551,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";
@@ -5569,9 +5488,7 @@ void CleanupLocal()
*unixSocketName = '\0';
- *connectHost = '\0';
*acceptHost = '\0';
- *listenHost = '\0';
*displayHost = '\0';
*authCookie = '\0';
@@ -5585,8 +5502,8 @@ void CleanupLocal()
xServerAddr = NULL;
- listenPort = -1;
- connectPort = -1;
+ listenSocket.disable();
+ connectSocket.disable();
cupsPort.disable();
auxPort.disable();
@@ -6717,151 +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 listenIPAddr = -1;
int proxyFD = -1;
int newFD = -1;
- //
- // Get IP address of host to be awaited.
- //
-
int acceptIPAddr = 0;
- if (*acceptHost != '\0')
- {
- acceptIPAddr = GetHostAddress(acceptHost);
-
- if (acceptIPAddr == 0)
- {
- #ifdef PANIC
- *logofs << "Loop: PANIC! Cannot accept connections from unknown host '"
- << acceptHost << "'.\n" << logofs_flush;
- #endif
-
- cerr << "Error" << ": Cannot accept connections from unknown host '"
- << acceptHost << "'.\n";
-
- goto WaitForRemoteError;
- }
- }
-
- proxyFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
-
- if (proxyFD == -1)
- {
- #ifdef PANIC
- *logofs << "Loop: PANIC! Call to socket failed for TCP socket. "
- << "Error is " << EGET() << " '" << ESTR() << "'.\n"
- << logofs_flush;
- #endif
-
- cerr << "Error" << ": Call to socket failed for TCP socket. "
- << "Error is " << EGET() << " '" << ESTR() << "'.\n";
-
- goto WaitForRemoteError;
- }
- else if (SetReuseAddress(proxyFD) < 0)
+ if (socketAddress.isTCPSocket())
{
- goto WaitForRemoteError;
- }
- listenIPAddr = 0;
-
- ParseListenOption(listenIPAddr);
+ //
+ // Get IP address of host to be awaited.
+ //
- sockaddr_in tcpAddr;
+ if (*acceptHost != '\0')
+ {
+ acceptIPAddr = GetHostAddress(acceptHost);
- tcpAddr.sin_family = AF_INET;
- tcpAddr.sin_port = htons(portNum);
+ if (acceptIPAddr == 0)
+ {
+ #ifdef PANIC
+ *logofs << "Loop: PANIC! Cannot accept connections from unknown host '"
+ << acceptHost << "'.\n" << logofs_flush;
+ #endif
- //
- // Quick patch to run on MacOS/X where inet_addr("127.0.0.1")
- // alone seems to fail to return a valid interface. It probably
- // just needs a htonl() or something like that.
- //
- // TODO: We have to give another look at inet_addr("127.0.0.1")
- // on the Mac.
- //
+ cerr << "Error" << ": Cannot accept connections from unknown host '"
+ << acceptHost << "'.\n";
- #ifdef __APPLE__
+ goto WaitForRemoteError;
+ }
+ strcpy(hostLabel, "any host");
+ }
+ else
+ {
+ snprintf(hostLabel, sizeof(hostLabel), "'%s'", acceptHost);
+ }
- if ( loopbackBind )
- {
- tcpAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ if (loopbackBind)
+ {
+ long bindPort;
+ if (socketAddress.getTCPHostAndPort(NULL, &bindPort))
+ socketAddress.setSpec("localhost", bindPort);
+ }
}
+ else if (socketAddress.isUnixSocket())
+ strcpy(hostLabel, "this host");
else
- {
- tcpAddr.sin_addr.s_addr = htonl(INADDR_ANY);
- }
+ strcpy(hostLabel, "unknown origin (something went wrong!!!)");
- #else
-
- tcpAddr.sin_addr.s_addr = listenIPAddr;
-
- #endif
- if (bind(proxyFD, (sockaddr *) &tcpAddr, sizeof(tcpAddr)) == -1)
- {
- #ifdef PANIC
- *logofs << "Loop: PANIC! Call to bind failed for TCP port "
- << portNum << ". Error is " << EGET() << " '" << ESTR()
- << "'.\n" << logofs_flush;
- #endif
-
- cerr << "Error" << ": Call to bind failed for TCP port "
- << portNum << ". Error is " << EGET() << " '" << ESTR()
- << "'.\n";
-
- goto WaitForRemoteError;
- }
-
- if (listen(proxyFD, 4) == -1)
- {
- #ifdef PANIC
- *logofs << "Loop: PANIC! Call to listen failed for TCP port "
- << portNum << ". Error is " << EGET() << " '" << ESTR()
- << "'.\n" << logofs_flush;
- #endif
-
- cerr << "Error" << ": Call to listen failed for TCP port "
- << portNum << ". Error is " << EGET() << " '" << ESTR()
- << "'.\n";
-
- goto WaitForRemoteError;
- }
-
- if (*acceptHost != '\0')
- {
- strcat(hostLabel, "'");
- strcat(hostLabel, acceptHost);
- strcat(hostLabel, "'");
- }
- else
- {
- strcpy(hostLabel, "any host");
- }
+ 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
@@ -6916,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
@@ -6936,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)
+ {
- sleep(5);
+ #ifdef TEST
+
+ 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 "
@@ -7018,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;
@@ -7072,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
@@ -7113,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)
{
@@ -7133,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
@@ -7219,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
@@ -8448,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, ",");
@@ -8468,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);
@@ -8529,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)
{
@@ -8556,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;
}
@@ -8597,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)
{
@@ -9056,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;
@@ -9296,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;
@@ -13409,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
@@ -13676,40 +13743,6 @@ ParseFontPathError:
return -1;
}
-int ParseListenOption(int &address)
-{
- if (*listenHost == '\0')
- {
- //
- // On the X client side listen on any address.
- // On the X server side listen to the forwarder
- // on localhost.
- //
-
- if (control -> ProxyMode == proxy_server)
- {
- address = (int) inet_addr("127.0.0.1");
- }
- else
- {
- if ( loopbackBind )
- {
- address = htonl(INADDR_LOOPBACK);
- }
- else
- {
- address = htonl(INADDR_ANY);
- }
- }
- }
- else
- {
- address = inet_addr(listenHost);
- }
-
- return 1;
-}
-
int OpenLogFile(char *name, ostream *&stream)
{
if (name == NULL || *name == '\0')