>From 580a540ecf506415b85a2978ac28c17e48acce51 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Salvador=20Fandi=C3=B1o?= <salvador@qindel.com>
Date: Sat, 18 Apr 2015 10:37:23 +0200
Subject: [PATCH] Add support for using Unix sockets as channel end-points.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Currently, NX channels always terminate on a TCP socket. That has several problems:

- TCP ports are global to the machine and can not be reserved. nx-libs aborts the aplication when
it can not bind to some port because it is already being used by another application.

- Anybody can access them, so they are intrinsically insecure.

- Some applications as for instance PulseAudio do not enable TCP access by default, so they have
to be reconfigured in order to be used with nx-libs.

This patch extends the nx-libs to allow using UNIX sockets as channels end-points, both in
listening and connecting mode.

In order to maintain full backward compatibility with previous versions of the software some parts
of the patch are more convoluted than I would wish.

Until now, in order to configure some channel, as for instance, the media one, one would invoke
nxagent as...

     nxagent -display=nx/nx,media=1:200

"media=1" tells nx-libs to enable and allocate the default listening port.

A custom port can also be requested just passing it as the value after the equal sign (in that
regard, the "1" is just a magic value):

     nxagent -display=nx/nx,media=10222:200

With this patch, now a URL-encoded end-channel specification can *also* be used (%3a is the colon):

     nxagent -display=nx/nx,media=tcp%3alocalhost%3a10222:200
     nxagent -display=nx/nx,media=unix%3a/tmp/media-200:200

The end-channel specification (without being URL-encoded) uses the same format as PulseAudio
configuration file. Both the schemes "tcp" and "unix" are supported.

I plan to add support for a "cmd" scheme too in the future.

The end-point specification works in the same way in the nxproxy side.

Signed-off-by: Salvador Fandi��o <salvador@qindel.com>
---
 nxcomp/ChannelEndPoint.cpp | 245 +++++++++++++++++++++
 nxcomp/ChannelEndPoint.h   |  61 ++++++
 nxcomp/ClientProxy.cpp     |  13 +-
 nxcomp/ClientProxy.h       |   7 +-
 nxcomp/Loop.cpp            | 524 +++++++++++++++++++++------------------------
 nxcomp/Makefile.in         |   3 +-
 nxcomp/Proxy.cpp           |  35 ++-
 nxcomp/Proxy.h             |  17 +-
 nxcomp/ServerProxy.cpp     |  25 ++-
 nxcomp/ServerProxy.h       |  17 +-
 10 files changed, 636 insertions(+), 311 deletions(-)
 create mode 100644 nxcomp/ChannelEndPoint.cpp
 create mode 100644 nxcomp/ChannelEndPoint.h

diff --git a/nxcomp/ChannelEndPoint.cpp b/nxcomp/ChannelEndPoint.cpp
new file mode 100644
index 0000000..cb35e52
--- /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 <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#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;
+}
diff --git a/nxcomp/ChannelEndPoint.h b/nxcomp/ChannelEndPoint.h
new file mode 100644
index 0000000..5b4e753
--- /dev/null
+++ b/nxcomp/ChannelEndPoint.h
@@ -0,0 +1,61 @@
+/**************************************************************************/
+/*                                                                        */
+/* 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.                                                   */
+/*                                                                        */
+/**************************************************************************/
+
+#ifndef ChannelEndPoint_H
+#define ChannelEndPoint_H
+
+#include <iostream>
+#include <sys/un.h>
+
+class ChannelEndPoint
+{
+ private:
+  long defaultTCPPort_;
+  int defaultTCPInterface_; // 0=localhost, otherwise IP of public interface.
+  char *defaultUnixPath_;
+  char *spec_;
+
+  bool specIsPort(long *port = NULL) const;
+
+ public:
+  ChannelEndPoint(const char *spec = NULL);
+  ChannelEndPoint &operator=(const ChannelEndPoint &other);
+
+  bool enabled() const;
+  bool disabled() { return !enabled(); }
+  void disable();
+  void setSpec(const char *spec);
+  void setSpec(int port);
+  void setDefaultTCPPort(long port);
+  void setDefaultTCPInterface(int publicInterface);
+  void setDefaultUnixPath(char *path);
+
+  bool getUnixPath(char **path = NULL) const;
+  bool getTCPHostAndPort(char **hostname = NULL, long *port = NULL) const;
+  long getTCPPort() const;
+
+  bool validateSpec();
+};
+
+std::ostream& operator<<(std::ostream& os, const ChannelEndPoint& endPoint);
+
+#endif
diff --git a/nxcomp/ClientProxy.cpp b/nxcomp/ClientProxy.cpp
index ef63bb0..7dd3dbb 100644
--- a/nxcomp/ClientProxy.cpp
+++ b/nxcomp/ClientProxy.cpp
@@ -68,8 +68,11 @@ void ClientProxy::handleDisplayConfiguration(const char *xServerDisplay, int xSe
   #endif
 }
 
-void ClientProxy::handlePortConfiguration(int cupsServerPort, int smbServerPort, int mediaServerPort,
-                                              int httpServerPort, const char *fontServerPort)
+void ClientProxy::handlePortConfiguration(ChannelEndPoint &cupsServerPort,
+                                          ChannelEndPoint &smbServerPort,
+                                          ChannelEndPoint &mediaServerPort,
+                                          ChannelEndPoint &httpServerPort,
+                                          const char *fontServerPort)
 {
   delete [] fontServerPort_;
 
@@ -141,8 +144,8 @@ int ClientProxy::handleNewConnectionFromProxy(T_channel_type type, int channelId
         // Connect on the TCP port number.
         //
 
-        return handleNewGenericConnectionFromProxy(channelId, channel_font, "localhost",
-                                                       port, "font");
+        return handleNewGenericConnectionFromProxyTCP(channelId, channel_font, "localhost",
+                                                      port, "font");
       }
       else
       {
@@ -150,7 +153,7 @@ int ClientProxy::handleNewConnectionFromProxy(T_channel_type type, int channelId
         // Connect to the Unix path.
         //
 
-        return handleNewGenericConnectionFromProxy(channelId, channel_font, "localhost",
+        return handleNewGenericConnectionFromProxyUnix(channelId, channel_font,
                                                        fontServerPort_, "font");
       }
     }
diff --git a/nxcomp/ClientProxy.h b/nxcomp/ClientProxy.h
index 2b669ba..0a6169f 100644
--- a/nxcomp/ClientProxy.h
+++ b/nxcomp/ClientProxy.h
@@ -38,8 +38,11 @@ class ClientProxy : public Proxy
   virtual void handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily,
                                               sockaddr *xServerAddr, unsigned int xServerAddrLength);
 
-  virtual void handlePortConfiguration(int cupsServerPort, int smbServerPort, int mediaServerPort,
-                                           int httpServerPort, const char *fontServerPort);
+  virtual void handlePortConfiguration(ChannelEndPoint &cupsServerPort,
+                                       ChannelEndPoint &smbServerPort,
+                                       ChannelEndPoint &mediaServerPort,
+                                       ChannelEndPoint &httpServerPort,
+                                       const char *fontServerPort);
 
   protected:
 
diff --git a/nxcomp/Loop.cpp b/nxcomp/Loop.cpp
index 92b6fc2..0ee717e 100644
--- a/nxcomp/Loop.cpp
+++ b/nxcomp/Loop.cpp
@@ -36,7 +36,7 @@
 #include <sys/wait.h>
 #include <sys/resource.h>
 #include <sys/utsname.h>
-
+#include <sys/un.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -89,6 +89,7 @@ typedef int socklen_t;
 #include "ServerProxy.h"
 
 #include "Message.h"
+#include "ChannelEndPoint.h"
 
 //
 // System specific defines.
@@ -437,7 +438,10 @@ static int SetupDisplaySocket(int &xServerAddrFamily, sockaddr *&xServerAddr,
 // a new connection.
 //
 
-static int ListenConnection(int port, const char *label);
+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 ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label);
 static int AcceptConnection(int fd, int domain, const char *label);
 
 //
@@ -475,6 +479,8 @@ static const char *GetArg(int &argi, int argc, const char **argv);
 static int CheckArg(const char *type, const char *name, const char *value);
 static int ParseArg(const char *type, const char *name, const char *value);
 static int ValidateArg(const char *type, const char *name, const char *value);
+static void SetAndValidateChannelEndPointArg(const char *type, const char *name, const char *value,
+                                             ChannelEndPoint &endPoint);
 static int LowercaseArg(const char *type, const char *name, char *value);
 static int CheckSignal(int signal);
 
@@ -977,12 +983,12 @@ static int connectPort = -1;
 // Helper channels are disabled by default.
 //
 
-static int cupsPort  = -1;
-static int auxPort   = -1;
-static int smbPort   = -1;
-static int mediaPort = -1;
-static int httpPort  = -1;
-static int slavePort = -1;
+static ChannelEndPoint cupsPort;
+static ChannelEndPoint auxPort;
+static ChannelEndPoint smbPort;
+static ChannelEndPoint mediaPort;
+static ChannelEndPoint httpPort;
+static ChannelEndPoint slavePort;
 
 //
 // Can be either a port number or a Unix
@@ -4426,7 +4432,7 @@ int SetupServiceSockets()
       {
         int port = atoi(fontPort);
 
-        if ((fontFD = ListenConnection(port, "font")) < 0)
+        if ((fontFD = ListenConnectionTCP("localhost", port, "font")) < 0)
         {
           useFontSocket = 0;
         }
@@ -4483,47 +4489,40 @@ int SetupServiceSockets()
   return 1;
 }
 
-int ListenConnection(int port, const char *label)
+int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label)
 {
-  sockaddr_in tcpAddr;
-
-  unsigned int portTCP = port;
-
-  int newFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
-
+  int newFD = socket(addr->sa_family, SOCK_STREAM, PF_UNSPEC);
   if (newFD == -1)
   {
     #ifdef PANIC
     *logofs << "Loop: PANIC! Call to socket failed for " << label
-            << " TCP socket. Error is " << EGET() << " '"
+            << " socket. Error is " << EGET() << " '"
             << ESTR() << "'.\n" << logofs_flush;
     #endif
 
     cerr << "Error" << ": Call to socket failed for " << label
-         << " TCP socket. Error is " << EGET() << " '"
+         << " socket. Error is " << EGET() << " '"
          << ESTR() << "'.\n";
 
     goto SetupSocketError;
   }
-  else if (SetReuseAddress(newFD) < 0)
+
+  if (SetReuseAddress(newFD) == -1)
   {
+    // SetReuseAddress already warns on error
     goto SetupSocketError;
   }
 
-  tcpAddr.sin_family = AF_INET;
-  tcpAddr.sin_port = htons(portTCP);
-  tcpAddr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-  if (bind(newFD, (sockaddr *) &tcpAddr, sizeof(tcpAddr)) == -1)
+  if (bind(newFD, addr, addrlen) == -1)
   {
     #ifdef PANIC
     *logofs << "Loop: PANIC! Call to bind failed for " << label
-            << " TCP port " << port << ". Error is " << EGET()
+            << ". Error is " << EGET()
             << " '" << ESTR() << "'.\n" << logofs_flush;
     #endif
 
     cerr << "Error" << ": Call to bind failed for " << label
-         << " TCP port " << port << ". Error is " << EGET()
+         << ". Error is " << EGET()
          << " '" << ESTR() << "'.\n";
 
     goto SetupSocketError;
@@ -4533,14 +4532,13 @@ int ListenConnection(int port, const char *label)
   {
     #ifdef PANIC
     *logofs << "Loop: PANIC! Call to bind failed for " << label
-            << " TCP port " << port << ". Error is " << EGET()
+            << ". Error is " << EGET()
             << " '" << ESTR() << "'.\n" << logofs_flush;
     #endif
 
     cerr << "Error" << ": Call to bind failed for " << label
-         << " TCP port " << port << ". Error is " << EGET()
+         << ". Error is " << EGET()
          << " '" << ESTR() << "'.\n";
-
     goto SetupSocketError;
   }
 
@@ -4562,6 +4560,81 @@ SetupSocketError:
   //
 
   HandleCleanup();
+  return -1;
+}
+
+int ListenConnectionUnix(const char *path, const char *label)
+{
+
+  sockaddr_un unixAddr;
+  unixAddr.sun_family = AF_UNIX;
+#ifdef UNIX_PATH_MAX
+  if (strlen(path) >= UNIX_PATH_MAX)
+#else
+  if (strlen(path) >= sizeof(unixAddr.sun_path))
+#endif
+  {
+    #ifdef PANIC
+    *logofs << "Loop: PANIC! Socket path \"" << path << "\" for "
+            << label << " is too long.\n" << logofs_flush;
+    #endif
+
+    cerr << "Error" << ": Socket path \"" << path << "\" for "
+         << label << " is too long.\n";
+
+    HandleCleanup();
+    return -1;
+  }
+
+  strcpy(unixAddr.sun_path, path);
+  return ListenConnectionAny((sockaddr *)&unixAddr, sizeof(unixAddr), label);
+}
+
+int ListenConnectionTCP(const char *host, long port, const char *label)
+{
+  sockaddr_in tcpAddr;
+  tcpAddr.sin_family = AF_INET;
+  tcpAddr.sin_port = htons(port);
+
+  if (!host ||
+      !strcmp(host, "") ||
+      !strcmp(host, "localhost")) {
+    tcpAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  }
+  else if(strcmp(host, "*") == 0) {
+    tcpAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+  }
+  else {
+    int ip = tcpAddr.sin_addr.s_addr = GetHostAddress(host);
+    if (ip == 0)
+    {
+      #ifdef PANIC
+      *logofs << "Loop: PANIC! Unknown " << label << " host '" << host
+              << "'.\n" << logofs_flush;
+      #endif
+
+      cerr << "Error" << ": Unknown " << label << " host '" << host
+           << "'.\n";
+
+      HandleCleanup();
+      return -1;
+    }
+  }
+
+  return ListenConnectionAny((sockaddr *)&tcpAddr, sizeof(tcpAddr), label);
+}
+
+int ListenConnection(ChannelEndPoint &endpoint, const char *label)
+{
+  char *unixPath, *host;
+  long port;
+  if (endpoint.getUnixPath(&unixPath)) {
+    return ListenConnectionUnix(unixPath, label);
+  }
+  else if (endpoint.getTCPHostAndPort(&host, &port)) {
+    return ListenConnectionTCP(host, port, label);
+  }
+  return -1;
 }
 
 static int AcceptConnection(int fd, int domain, const char *label)
@@ -5083,7 +5156,7 @@ void CleanupChildren()
     #endif
 
     KillProcess(control -> KillDaemonOnShutdown[i], "daemon", SIGTERM, 0);
-  }    
+  }
 }
 
 void CleanupGlobal()
@@ -5471,12 +5544,12 @@ void CleanupLocal()
   listenPort  = -1;
   connectPort = -1;
 
-  cupsPort  = -1;
-  auxPort   = -1;
-  smbPort   = -1;
-  mediaPort = -1;
-  httpPort  = -1;
-  slavePort = -1;
+  cupsPort.disable();
+  auxPort.disable();
+  smbPort.disable();
+  mediaPort.disable();
+  httpPort.disable();
+  slavePort.disable();
 
   *fontPort = '\0';
 
@@ -8025,6 +8098,35 @@ int ReadRemoteData(int fd, char *buffer, int size, char stop)
   return -1;
 }
 
+static int
+hexval(char c) {
+  if ((c >= '0') && (c <= '9'))
+    return c - '0';
+  if ((c >= 'a') && (c <= 'f'))
+    return c - 'a' + 10;
+  if ((c >= 'A') && (c <= 'F'))
+    return c - 'A' + 10;
+  return -1;
+}
+
+static void
+URLDecodeInPlace(char *str) {
+  if (str) {
+    char *to = str;
+    while (str[0]) {
+      if ((str[0] == '%') &&
+          (hexval(str[1]) >= 0) &&
+          (hexval(str[2]) >= 0)) {
+        *(to++) = hexval(str[1]) * 16 + hexval(str[2]);
+        str += 3;
+      }
+      else
+        *(to++) = *(str++);
+    }
+    *to = '\0';
+  }
+}
+
 int WriteLocalData(int fd, const char *buffer, int size)
 {
   int position = 0;
@@ -8276,6 +8378,7 @@ int ParseEnvironmentOptions(const char *env, int force)
   while (name)
   {
     value = strtok(NULL, ",");
+    URLDecodeInPlace(value);
 
     if (CheckArg("environment", name, value) < 0)
     {
@@ -8665,7 +8768,7 @@ int ParseEnvironmentOptions(const char *env, int force)
     }
     else if (strcasecmp(name, "cups") == 0)
     {
-      cupsPort = ValidateArg("local", name, value);
+      SetAndValidateChannelEndPointArg("local", name, value, cupsPort);
     }
     else if (strcasecmp(name, "sync") == 0)
     {
@@ -8677,25 +8780,25 @@ int ParseEnvironmentOptions(const char *env, int force)
       cerr << "Warning" << ": No 'sync' channel in current version. "
            << "Assuming 'cups' channel.\n";
 
-      cupsPort = ValidateArg("local", name, value);
+      SetAndValidateChannelEndPointArg("local", name, value, cupsPort);
     }
     else if (strcasecmp(name, "keybd") == 0 ||
                  strcasecmp(name, "aux") == 0)
     {
-      auxPort = ValidateArg("local", name, value);
+      SetAndValidateChannelEndPointArg("local", name, value, auxPort);
     }
     else if (strcasecmp(name, "samba") == 0 ||
                  strcasecmp(name, "smb") == 0)
     {
-      smbPort = ValidateArg("local", name, value);
+      SetAndValidateChannelEndPointArg("local", name, value, smbPort);
     }
     else if (strcasecmp(name, "media") == 0)
     {
-      mediaPort = ValidateArg("local", name, value);
+      SetAndValidateChannelEndPointArg("local", name, value, mediaPort);
     }
     else if (strcasecmp(name, "http") == 0)
     {
-      httpPort = ValidateArg("local", name, value);
+      SetAndValidateChannelEndPointArg("local", name, value, httpPort);
     }
     else if (strcasecmp(name, "font") == 0)
     {
@@ -8703,7 +8806,7 @@ int ParseEnvironmentOptions(const char *env, int force)
     }
     else if (strcasecmp(name, "slave") == 0)
     {
-      slavePort = ValidateArg("local", name, value);
+      SetAndValidateChannelEndPointArg("local", name, value, slavePort);
     }
     else if (strcasecmp(name, "mask") == 0)
     {
@@ -11438,237 +11541,105 @@ int SetPorts()
   // ing, causing a loop.
   //
 
-  if (cupsPort <= 0)
-  {
-    #ifdef TEST
-    *logofs << "Loop: Disabling cups connections.\n"
-            << logofs_flush;
-    #endif
-
-    cupsPort = 0;
-
-    useCupsSocket = 0;
-  }
-  else
-  {
-    if (control -> ProxyMode == proxy_client)
-    {
-      if (cupsPort == 1)
-      {
-        cupsPort = DEFAULT_NX_CUPS_PORT_OFFSET + proxyPort;
-      }
-
+  useCupsSocket = 0;
+  if (cupsPort.enabled()) {
+    if (control -> ProxyMode == proxy_client) {
+      cupsPort.setDefaultTCPPort(DEFAULT_NX_CUPS_PORT_OFFSET + proxyPort);
       useCupsSocket = 1;
     }
     else
-    {
-      if (cupsPort == 1)
-      {
-        //
-        // Use the well-known 631/tcp port of the
-        // Internet Printing Protocol.
-        //
-
-        cupsPort = 631;
-      }
-
-      useCupsSocket = 0;
-    }
-
-    #ifdef TEST
-    *logofs << "Loop: Using cups port '" << cupsPort
-            << "'.\n" << logofs_flush;
-    #endif
+      cupsPort.setDefaultTCPPort(631);
   }
 
-  if (auxPort <= 0)
-  {
-    #ifdef TEST
-    *logofs << "Loop: Disabling auxiliary X11 connections.\n"
+#ifdef TEST
+  *logofs << "Loop: cups port: " << cupsPort->getDebugSpec() << "\n"
             << logofs_flush;
-    #endif
-
-    auxPort = 0;
-
-    useAuxSocket = 0;
-  }
-  else
-  {
-    if (control -> ProxyMode == proxy_client)
-    {
-      if (auxPort == 1)
-      {
-        auxPort = DEFAULT_NX_AUX_PORT_OFFSET + proxyPort;
-      }
+#endif
 
+  useAuxSocket = 0;
+  if (auxPort.enabled()) {
+    if (control -> ProxyMode == proxy_client) {
+      auxPort.setDefaultTCPPort(DEFAULT_NX_AUX_PORT_OFFSET + proxyPort);
       useAuxSocket = 1;
     }
-    else
-    {
-      //
-      // Auxiliary X connections are always forwarded
-      // to the display where the session is running.
-      // The only value accepted is 1.
-      //
+    else {
+      auxPort.setDefaultTCPPort(1);
 
-      if (auxPort != 1)
-      {
-        #ifdef WARNING
+      if (auxPort.getTCPPort() != 1) {
+
+#ifdef WARNING
         *logofs << "Loop: WARNING! Overriding auxiliary X11 "
                 << "port with new value '" << 1 << "'.\n"
                 << logofs_flush;
-        #endif
+#endif
 
         cerr << "Warning" << ": Overriding auxiliary X11 "
              << "port with new value '" << 1 << "'.\n";
 
-        auxPort = 1;
+	auxPort.setSpec("1");
       }
-
-      useAuxSocket = 0;
     }
-
-    #ifdef TEST
-    *logofs << "Loop: Using auxiliary X11 port '" << auxPort
-            << "'.\n" << logofs_flush;
-    #endif
   }
 
-  if (smbPort <= 0)
-  {
-    #ifdef TEST
-    *logofs << "Loop: Disabling SMB connections.\n"
-            << logofs_flush;
-    #endif
-
-    smbPort = 0;
-
-    useSmbSocket = 0;
-  }
-  else
-  {
-    if (control -> ProxyMode == proxy_client)
-    {
-      if (smbPort == 1)
-      {
-        smbPort = DEFAULT_NX_SMB_PORT_OFFSET + proxyPort;
-      }
+#ifdef TEST
+  *logofs << "Loop: aux port: " << auxPort->getDebugSpec() << "\n"
+	  << logofs_flush;
+#endif
 
-      useSmbSocket = 1;
+  useSmbSocket = 0;
+  if (smbPort.enabled()) {
+    if (control -> ProxyMode == proxy_client) {
+      auxPort.setDefaultTCPPort(DEFAULT_NX_SMB_PORT_OFFSET + proxyPort);
+      useAuxSocket = 1;
     }
     else
-    {
-      if (smbPort == 1)
-      {
-        //
-        // Assume the 139/tcp port used for SMB
-        // over NetBIOS over TCP.
-        //
-
-        smbPort = 139;
-      }
-
-      useSmbSocket = 0;
-    }
-
-    #ifdef TEST
-    *logofs << "Loop: Using SMB port '" << smbPort
-            << "'.\n" << logofs_flush;
-    #endif
+      auxPort.setDefaultTCPPort(139);
   }
 
-  if (mediaPort <= 0)
-  {
-    #ifdef TEST
-    *logofs << "Loop: Disabling multimedia connections.\n"
-            << logofs_flush;
-    #endif
-
-    mediaPort = 0;
 
-    useMediaSocket = 0;
-  }
-  else
-  {
-    if (control -> ProxyMode == proxy_client)
-    {
-      if (mediaPort == 1)
-      {
-        mediaPort = DEFAULT_NX_MEDIA_PORT_OFFSET + proxyPort;
-      }
+#ifdef TEST
+  *logofs << "Loop: smb port: " << smbPort->getDebugSpec() << "\n"
+	  << logofs_flush;
+#endif
 
+  useMediaSocket = 0;
+  if (mediaPort.enabled()) {
+    if (control -> ProxyMode == proxy_client) {
+      mediaPort.setDefaultTCPPort(DEFAULT_NX_MEDIA_PORT_OFFSET + proxyPort);
       useMediaSocket = 1;
     }
-    else
-    {
-      if (mediaPort == 1)
-      {
-        //
-        // We don't have a well-known port to
-        // be used for media connections.
-        //
-
-        #ifdef PANIC
-        *logofs << "Loop: PANIC! No port specified for multimedia connections.\n"
-                << logofs_flush;
-        #endif
-
-        cerr << "Error" << ": No port specified for multimedia connections.\n";
+    else if (mediaPort.getTCPPort() == 1) {
+#ifdef PANIC
+      *logofs << "Loop: PANIC! No port specified for multimedia connections.\n"
+              << logofs_flush;
+#endif
 
-        HandleCleanup();
-      }
+      cerr << "Error" << ": No port specified for multimedia connections.\n";
 
-      useMediaSocket = 0;
+      HandleCleanup();
     }
-
-    #ifdef TEST
-    *logofs << "Loop: Using multimedia port '" << mediaPort
-            << "'.\n" << logofs_flush;
-    #endif
   }
 
-  if (httpPort <= 0)
-  {
-    #ifdef TEST
-    *logofs << "Loop: Disabling HTTP connections.\n"
-            << logofs_flush;
-    #endif
-
-    httpPort = 0;
-
-    useHttpSocket = 0;
-  }
-  else
-  {
-    if (control -> ProxyMode == proxy_client)
-    {
-      if (httpPort == 1)
-      {
-        httpPort = DEFAULT_NX_HTTP_PORT_OFFSET + proxyPort;
-      }
+#ifdef TEST
+  *logofs << "Loop: Using multimedia port '" << mediaPort->getDebugSpec()
+	  << "'.\n" << logofs_flush;
+#endif
 
+  useHttpSocket = 0;
+  if (httpPort.enabled()) {
+    if (control -> ProxyMode == proxy_client) {
+      httpPort.setDefaultTCPPort(DEFAULT_NX_HTTP_PORT_OFFSET + proxyPort);
       useHttpSocket = 1;
     }
     else
-    {
-      if (httpPort == 1)
-      {
-        //
-        // Use the well-known 80/tcp port.
-        //
-
-        httpPort = 80;
-      }
-
-      useHttpSocket = 0;
-    }
-
-    #ifdef TEST
-    *logofs << "Loop: Using HTTP port '" << httpPort
-            << "'.\n" << logofs_flush;
-    #endif
+      httpPort.setDefaultTCPPort(80);
   }
 
+#ifdef TEST
+  *logofs << "Loop: Using HTTP port '" << httpPort->getDebugSpec()
+	  << "'.\n" << logofs_flush;
+#endif
+
   if (ParseFontPath(fontPort) <= 0)
   {
     #ifdef TEST
@@ -11704,44 +11675,20 @@ int SetPorts()
     #endif
   }
 
-  if (slavePort <= 0)
-  {
-    #ifdef TEST
-    *logofs << "Loop: Disabling slave connections.\n"
-            << logofs_flush;
-    #endif
-
-    slavePort = 0;
-
-    useSlaveSocket = 0;
-  }
-  else
-  {
-    //
-    // File transfer connections can
-    // be originated by both sides.
-    //
-
-    if (slavePort == 1)
-    {
-      if (control -> ProxyMode == proxy_client)
-      {
-        slavePort = DEFAULT_NX_SLAVE_PORT_CLIENT_OFFSET + proxyPort;
-      }
-      else
-      {
-        slavePort = DEFAULT_NX_SLAVE_PORT_SERVER_OFFSET + proxyPort;
-      }
-    }
-
+  useSlaveSocket = 0;
+  if (slavePort.enabled()) {
     useSlaveSocket = 1;
-
-    #ifdef TEST
-    *logofs << "Loop: Using slave port '" << slavePort
-            << "'.\n" << logofs_flush;
-    #endif
+    if (control -> ProxyMode == proxy_client)
+      slavePort.setDefaultTCPPort(DEFAULT_NX_SLAVE_PORT_CLIENT_OFFSET + proxyPort);
+    else
+      slavePort.setDefaultTCPPort(DEFAULT_NX_SLAVE_PORT_SERVER_OFFSET + proxyPort);
   }
 
+#ifdef TEST
+  *logofs << "Loop: Using slave port '" << slavePort->getDebugSpec()
+	  << "'.\n" << logofs_flush;
+#endif
+
   return 1;
 }
 
@@ -14100,65 +14047,65 @@ void PrintConnectionInfo()
   }
 
   if (control -> ProxyMode == proxy_client &&
-          useCupsSocket > 0 && cupsPort > 0)
+      useCupsSocket > 0 && cupsPort.enabled())
   {
     cerr << "Info" << ": Listening to CUPS connections "
          << "on port '" << cupsPort << "'.\n";
   }
   else if (control -> ProxyMode == proxy_server &&
-               cupsPort > 0)
+           cupsPort.enabled())
   {
     cerr << "Info" << ": Forwarding CUPS connections "
          << "to port '" << cupsPort << "'.\n";
   }
 
   if (control -> ProxyMode == proxy_client &&
-          useAuxSocket > 0 && auxPort > 0)
+      useAuxSocket > 0 && auxPort.enabled())
   {
     cerr << "Info" << ": Listening to auxiliary X11 connections "
          << "on port '" << auxPort << "'.\n";
   }
   else if (control -> ProxyMode == proxy_server &&
-               auxPort > 0)
+           auxPort.enabled())
   {
     cerr << "Info" << ": Forwarding auxiliary X11 connections "
          << "to display '" << displayHost << "'.\n";
   }
 
   if (control -> ProxyMode == proxy_client &&
-          useSmbSocket > 0 && smbPort > 0)
+      useSmbSocket > 0 && smbPort.enabled())
   {
     cerr << "Info" << ": Listening to SMB connections "
          << "on port '" << smbPort << "'.\n";
   }
   else if (control -> ProxyMode == proxy_server &&
-               smbPort > 0)
+           smbPort.enabled())
   {
     cerr << "Info" << ": Forwarding SMB connections "
          << "to port '" << smbPort << "'.\n";
   }
 
   if (control -> ProxyMode == proxy_client &&
-          useMediaSocket > 0 && mediaPort > 0)
+      useMediaSocket > 0 && mediaPort.enabled())
   {
     cerr << "Info" << ": Listening to multimedia connections "
          << "on port '" << mediaPort << "'.\n";
   }
   else if (control -> ProxyMode == proxy_server &&
-               mediaPort > 0)
+           mediaPort.enabled())
   {
     cerr << "Info" << ": Forwarding multimedia connections "
          << "to port '" << mediaPort << "'.\n";
   }
 
   if (control -> ProxyMode == proxy_client &&
-          useHttpSocket > 0 && httpPort > 0)
+      useHttpSocket > 0 && httpPort.enabled())
   {
     cerr << "Info" << ": Listening to HTTP connections "
          << "on port '" << httpPort << "'.\n";
   }
   else if (control -> ProxyMode == proxy_server &&
-               httpPort > 0)
+           httpPort.enabled())
   {
     cerr << "Info" << ": Forwarding HTTP connections "
          << "to port '" << httpPort << "'.\n";
@@ -14177,7 +14124,7 @@ void PrintConnectionInfo()
          << "to port '" << fontPort << "'.\n";
   }
 
-  if (useSlaveSocket > 0 && slavePort > 0)
+  if (useSlaveSocket > 0 && slavePort.enabled())
   {
     cerr << "Info" << ": Listening to slave connections "
          << "on port '" << slavePort << "'.\n";
@@ -14433,6 +14380,25 @@ int ParseArg(const char *type, const char *name, const char *value)
   return (int) result;
 }
 
+void SetAndValidateChannelEndPointArg(const char *type, const char *name, const char *value,
+                                      ChannelEndPoint &endPoint) {
+  endPoint.setSpec(value);
+  if (!endPoint.validateSpec()) {
+    #ifdef PANIC
+    *logofs << "Loop: PANIC! Invalid " << type
+            << " option '" << name << "' with value '"
+            << value << "'.\n" << logofs_flush;
+    #endif
+
+    cerr << "Error" << ": Invalid " << type
+         << " option '" << name << "' with value '"
+         << value << "'.\n";
+
+    HandleCleanup();
+  }
+}
+
+
 int ValidateArg(const char *type, const char *name, const char *value)
 {
   int number = atoi(value);
diff --git a/nxcomp/Makefile.in b/nxcomp/Makefile.in
index 434118b..07eb75e 100644
--- a/nxcomp/Makefile.in
+++ b/nxcomp/Makefile.in
@@ -219,7 +219,8 @@ CXXSRC = Loop.cpp 				\
 	 RenderPictureClipCompat.cpp		\
 	 RenderCreateGlyphSetCompat.cpp		\
 	 RenderCompositeCompat.cpp		\
-	 RenderCompositeGlyphsCompat.cpp
+	 RenderCompositeGlyphsCompat.cpp	\
+	 ChannelEndPoint.cpp
 
 MOBJ   = $(MSRC:.c=.o)
 COBJ   = $(CSRC:.c=.o)
diff --git a/nxcomp/Proxy.cpp b/nxcomp/Proxy.cpp
index 3b4df7e..847bb2c 100644
--- a/nxcomp/Proxy.cpp
+++ b/nxcomp/Proxy.cpp
@@ -57,6 +57,7 @@ struct sockaddr_un
 #include "ClientChannel.h"
 #include "ServerChannel.h"
 #include "GenericChannel.h"
+#include "ChannelEndPoint.h"
 
 //
 // We need to adjust some values related
@@ -6118,8 +6119,36 @@ int Proxy::handleNewSlaveConnection(int clientFd)
   }
 }
 
+
+
 int Proxy::handleNewGenericConnectionFromProxy(int channelId, T_channel_type type,
-                                                   const char *hostname, int port, const char *label)
+                                               ChannelEndPoint &endPoint, const char *label)
+{
+  char *unixPath, *host;
+  long port;
+
+  if (endPoint.getUnixPath(&unixPath)) {
+    return handleNewGenericConnectionFromProxyUnix(channelId, type, unixPath, label);
+  }
+
+  if (endPoint.getTCPHostAndPort(&host, &port)) {
+    return handleNewGenericConnectionFromProxyTCP(channelId, type, host, port, label);
+  }
+
+  #ifdef WARNING
+  *logofs << "Proxy: WARNING! Refusing attempted connection "
+      << "to " << label << " server.\n" << logofs_flush;
+  #endif
+
+  cerr << "Warning" << ": Refusing attempted connection "
+      << "to " << label << " server.\n";
+
+  return -1;
+}
+
+int Proxy::handleNewGenericConnectionFromProxyTCP(int channelId, T_channel_type type,
+                                                  const char *hostname, long port, const char *label)
+
 {
   if (port <= 0)
   {
@@ -6238,8 +6267,8 @@ int Proxy::handleNewGenericConnectionFromProxy(int channelId, T_channel_type typ
   return 1;
 }
 
-int Proxy::handleNewGenericConnectionFromProxy(int channelId, T_channel_type type,
-                                                   const char *hostname, const char *path, const char *label)
+int Proxy::handleNewGenericConnectionFromProxyUnix(int channelId, T_channel_type type,
+                                                   const char *path, const char *label)
 {
   if (path == NULL || *path == '\0' )
   {
diff --git a/nxcomp/Proxy.h b/nxcomp/Proxy.h
index 3d6c62c..d1a2236 100644
--- a/nxcomp/Proxy.h
+++ b/nxcomp/Proxy.h
@@ -32,6 +32,7 @@
 #include "Transport.h"
 #include "EncodeBuffer.h"
 #include "ProxyReadBuffer.h"
+#include "ChannelEndPoint.h"
 
 //
 // Forward declaration as we
@@ -258,8 +259,11 @@ class Proxy
   virtual void handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily,
                                               sockaddr * xServerAddr, unsigned int xServerAddrLength) = 0;
 
-  virtual void handlePortConfiguration(int cupsServerPort, int smbServerPort, int mediaServerPort,
-                                           int httpServerPort, const char *fontServerPort) = 0;
+  virtual void handlePortConfiguration(ChannelEndPoint &cupsServerPort,
+                                       ChannelEndPoint &smbServerPort,
+                                       ChannelEndPoint &mediaServerPort,
+                                       ChannelEndPoint &httpServerPort,
+                                       const char *fontServerPort) = 0;
 
   //
   // Create new tunneled channels.
@@ -278,10 +282,13 @@ class Proxy
   int handleNewGenericConnection(int clientFd, T_channel_type type, const char *label);
 
   int handleNewGenericConnectionFromProxy(int channelId, T_channel_type type,
-                                              const char *hostname, int port, const char *label);
+                                          ChannelEndPoint &endpoint, const char *label);
 
-  int handleNewGenericConnectionFromProxy(int channelId, T_channel_type type,
-                                              const char *hostname, const char *path, const char *label);
+  int handleNewGenericConnectionFromProxyUnix(int channelId, T_channel_type type,
+                                              const char *path, const char *label);
+
+  int handleNewGenericConnectionFromProxyTCP(int channelId, T_channel_type type,
+                                             const char *hostname, long port, const char *label);
 
   int handleNewSlaveConnection(int clientFd);
 
diff --git a/nxcomp/ServerProxy.cpp b/nxcomp/ServerProxy.cpp
index 0a72fc3..3060e82 100644
--- a/nxcomp/ServerProxy.cpp
+++ b/nxcomp/ServerProxy.cpp
@@ -1,6 +1,7 @@
 /**************************************************************************/
 /*                                                                        */
 /* Copyright (c) 2001, 2011 NoMachine, http://www.nomachine.com/.         */
+/* Copyright (c) 2015 Qindel Formacion y Servicios S.L.                   */
 /*                                                                        */
 /* NXCOMP, NX protocol compression and NX extensions to this software     */
 /* are copyright of NoMachine. Redistribution and use of the present      */
@@ -51,10 +52,10 @@ ServerProxy::ServerProxy(int proxyFd) : Proxy(proxyFd)
   xServerAddr_    = NULL;
   xServerDisplay_ = NULL;
 
-  cupsServerPort_  = -1;
-  smbServerPort_   = -1;
-  mediaServerPort_ = -1;
-  httpServerPort_  = -1;
+  cupsServerPort_  = NULL;
+  smbServerPort_   = NULL;
+  mediaServerPort_ = NULL;
+  httpServerPort_  = NULL;
 
   fontServerPort_ = NULL;
 
@@ -101,8 +102,11 @@ void ServerProxy::handleDisplayConfiguration(const char *xServerDisplay, int xSe
   #endif
 }
 
-void ServerProxy::handlePortConfiguration(int cupsServerPort, int smbServerPort, int mediaServerPort,
-                                              int httpServerPort, const char *fontServerPort)
+void ServerProxy::handlePortConfiguration(ChannelEndPoint &cupsServerPort,
+                                          ChannelEndPoint &smbServerPort,
+                                          ChannelEndPoint &mediaServerPort,
+                                          ChannelEndPoint &httpServerPort,
+                                          const char *fontServerPort)
 {
   cupsServerPort_  = cupsServerPort;
   smbServerPort_   = smbServerPort;
@@ -161,22 +165,23 @@ int ServerProxy::handleNewConnectionFromProxy(T_channel_type type, int channelId
     }
     case channel_cups:
     {
-      return handleNewGenericConnectionFromProxy(channelId, channel_cups, "localhost",
+      return handleNewGenericConnectionFromProxy(channelId, channel_cups,
                                                      cupsServerPort_, "CUPS");
     }
     case channel_smb:
     {
-      return handleNewGenericConnectionFromProxy(channelId, channel_smb, getComputerName(),
+      smbServerPort_.setDefaultTCPInterface(1);
+      return handleNewGenericConnectionFromProxy(channelId, channel_smb,
                                                      smbServerPort_, "SMB");
     }
     case channel_media:
     {
-      return handleNewGenericConnectionFromProxy(channelId, channel_media, "localhost",
+      return handleNewGenericConnectionFromProxy(channelId, channel_media,
                                                      mediaServerPort_, "media");
     }
     case channel_http:
     {
-      return handleNewGenericConnectionFromProxy(channelId, channel_http, getComputerName(),
+      return handleNewGenericConnectionFromProxy(channelId, channel_http,
                                                      httpServerPort_, "HTTP");
     }
     case channel_slave:
diff --git a/nxcomp/ServerProxy.h b/nxcomp/ServerProxy.h
index 8c4a884..57f455e 100644
--- a/nxcomp/ServerProxy.h
+++ b/nxcomp/ServerProxy.h
@@ -24,6 +24,7 @@
 #include "Proxy.h"
 
 #include "Misc.h"
+#include "ChannelEndPoint.h"
 
 //
 // Set the verbosity level.
@@ -43,8 +44,11 @@ class ServerProxy : public Proxy
   virtual void handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily,
                                               sockaddr *xServerAddr, unsigned int xServerAddrLength);
 
-  virtual void handlePortConfiguration(int cupsServerPort, int smbServerPort, int mediaServerPort,
-                                           int httpServerPort, const char *fontServerPort);
+  virtual void handlePortConfiguration(ChannelEndPoint &cupsServerPort,
+                                       ChannelEndPoint &smbServerPort,
+                                       ChannelEndPoint &mediaServerPort,
+                                       ChannelEndPoint &httpServerPort,
+                                       const char *fontServerPort);
 
   protected:
 
@@ -114,6 +118,7 @@ class ServerProxy : public Proxy
 
   private:
 
+  // FIXME: Use a ChannelEndPoint object also for the X server!
   int xServerAddrFamily_;
   sockaddr *xServerAddr_;
   unsigned int xServerAddrLength_;
@@ -130,10 +135,10 @@ class ServerProxy : public Proxy
   // TCP connections.
   //
 
-  int cupsServerPort_;
-  int smbServerPort_;
-  int mediaServerPort_;
-  int httpServerPort_;
+  ChannelEndPoint cupsServerPort_;
+  ChannelEndPoint smbServerPort_;
+  ChannelEndPoint mediaServerPort_;
+  ChannelEndPoint httpServerPort_;
 
   //
   // It will have to be passed to the channel
-- 
1.9.1

