diff options
author | Mike Gabriel <mike.gabriel@das-netzwerkteam.de> | 2017-06-30 20:13:51 +0200 |
---|---|---|
committer | Mike Gabriel <mike.gabriel@das-netzwerkteam.de> | 2017-07-26 10:12:43 +0200 |
commit | f76c82403888bb498973ec974dbfd20e4edb02fe (patch) | |
tree | be0cb6c112d9d9fb46387fbd114727510197ddec /nxcomp/Loop.cpp | |
parent | 9193d11eeeea933e293acd5e0f03fa4e9887186b (diff) | |
download | nx-libs-f76c82403888bb498973ec974dbfd20e4edb02fe.tar.gz nx-libs-f76c82403888bb498973ec974dbfd20e4edb02fe.tar.bz2 nx-libs-f76c82403888bb498973ec974dbfd20e4edb02fe.zip |
nxcomp: Switch to autoreconf.
Diffstat (limited to 'nxcomp/Loop.cpp')
-rw-r--r-- | nxcomp/Loop.cpp | 16689 |
1 files changed, 0 insertions, 16689 deletions
diff --git a/nxcomp/Loop.cpp b/nxcomp/Loop.cpp deleted file mode 100644 index 4592121de..000000000 --- a/nxcomp/Loop.cpp +++ /dev/null @@ -1,16689 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ -/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ -/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ -/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <errno.h> -#include <signal.h> -#include <setjmp.h> - -#include <math.h> -#include <ctype.h> -#include <string.h> -#include <dirent.h> -#include <pwd.h> - -#include <fcntl.h> - -#include <sys/types.h> -#include <sys/stat.h> -#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> - -#include "Misc.h" - -#ifdef __sun -#include <strings.h> -#endif - -// -// MacOSX 10.4 defines socklen_t. This is -// intended to ensure compatibility with -// older versions. -// - -#ifdef __APPLE__ -#include <AvailabilityMacros.h> -#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_3 -typedef int socklen_t; -#endif -#endif - -#ifdef _AIX -#include <strings.h> -#include <sys/select.h> -#endif - -#ifndef __CYGWIN32__ -#include <netinet/tcp.h> -#endif - -// -// NX include files. -// - -#include "NX.h" -#include "NXalert.h" - -#include "Misc.h" -#include "Control.h" -#include "Socket.h" -#include "Statistics.h" -#include "Auth.h" -#include "Keeper.h" -#include "Agent.h" - -#include "ClientProxy.h" -#include "ServerProxy.h" - -#include "Message.h" -#include "ChannelEndPoint.h" - -// -// System specific defines. -// - - -// -// HP-UX hides this define. -// - -#if defined(hpux) && !defined(RLIM_INFINITY) - -#define RLIM_INFINITY 0x7fffffff - -#endif - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Enable log output in signal handler. -// This is likely to hang the proxy at -// random, at least on Linux. -// - -#undef UNSAFE - -// -// Let all logs go to the standard error. -// This is useful to interleave the Xlib -// log output with the proxy output in a -// single file. -// - -#undef MIXED - -// -// Define this to check if the client and -// server caches match at shutdown. This -// is a test facility as it requires that -// both proxies are running on the same -// host. -// - -#undef MATCH - -// -// If defined, reduce the size of the log -// file and be sure it never exceeds the -// limit. -// - -#undef QUOTA - -// -// If defined, force very strict limits for -// the proxy tokens and force the proxy to -// enter often in congestion state. -// - -#undef STRICT - -// -// Print a line in the log if the time we -// spent inside the select or handling the -// messages exceeded a given time value. -// - -#undef TIME - -// -// This can be useful when testing the forwarding -// of the SSHD connection by nxssh to the agent. -// The debug output will go to a well known file -// that will be opened also by nxssh when BINDER -// is enabled there. -// - -#undef BINDER - -// -// Define this to override the limits on -// the core dump size. -// - -#define COREDUMPS - -// -// Upper limit of pre-allocated buffers -// for string parameters. -// - -#define DEFAULT_STRING_LENGTH 256 - -// -// Maximum length of remote options data -// passed by peer proxy at startup. -// - -#define DEFAULT_REMOTE_OPTIONS_LENGTH 512 - -// -// Maximum length of NX display string. -// - -#define DEFAULT_DISPLAY_OPTIONS_LENGTH 1024 - -// -// Maximum number of cache file names to -// send to the server side. -// - -#define DEFAULT_REMOTE_CACHE_ENTRIES 100 - -// -// Maximum length of remote options string -// that can be received from the peer proxy. -// - -#define MAXIMUM_REMOTE_OPTIONS_LENGTH 4096 - -// -// Macro is true if we determined our proxy -// mode. -// - -#define WE_SET_PROXY_MODE (control -> ProxyMode != proxy_undefined) - -// -// Macro is true if our side is the one that -// should connect to remote. -// - -#define WE_INITIATE_CONNECTION (connectSocket.enabled()) - -// -// Is true if we must provide our credentials -// to the remote peer. -// - -#define WE_PROVIDE_CREDENTIALS (control -> ProxyMode == proxy_server) - -// -// Is true if we listen for a local forwarder -// that will tunnel the traffic through a SSH -// or HTTP link. -// - -#define WE_LISTEN_FORWARDER (control -> ProxyMode == proxy_server && \ - listenSocket.enabled()) - -// -// You must define FLUSH in Misc.h if -// you want an immediate flush of the -// log output. -// - -ostream *logofs = NULL; - -// -// Other stream destriptors used for -// logging. -// - -ostream *statofs = NULL; -ostream *errofs = NULL; - -// -// Save standard error's rdbuf here -// and restore it when exiting. -// - -static streambuf *errsbuf = NULL; - -// -// Allow faults to be recovered by -// jumping back into the main loop. -// - -jmp_buf context; - -// -// Provide operational parameters. -// - -Control *control = NULL; - -// -// Collect and print statistics. -// - -Statistics *statistics = NULL; - -// -// Keep data for X11 authentication. -// - -Auth *auth = NULL; - -// -// This class makes the hard work. -// - -Proxy *proxy = NULL; - -// -// Used to handle memory-to-memory -// transport to the X agent. -// - -Agent *agent = NULL; - -// -// The image cache house-keeping class. -// - -Keeper *keeper = NULL; - -// -// Callback set by the child process -// to be notified about signals. -// - -int (*handler)(int) = NULL; - -// -// Signal handling functions. -// - -void DisableSignals(); -void EnableSignals(); -void InstallSignals(); - -static void RestoreSignals(); -static void HandleSignal(int signal); - -// -// Signal handling utilities. -// - -static void InstallSignal(int signal, int action); -static void RestoreSignal(int signal); - -static int HandleChildren(); - -int HandleChild(int child); -static int CheckChild(int pid, int status); -static int WaitChild(int child, const char *label, int force); - -int CheckParent(const char *name, const char *type, int parent); - -void RegisterChild(int child); - -static int CheckAbort(); - -// -// Timer handling utilities. -// - -void SetTimer(int timeout); -void ResetTimer(); - -static void HandleTimer(int signal); - -// -// Kill or check a running child. -// - -static int KillProcess(int pid, const char *label, int signal, int wait); -static int CheckProcess(int pid, const char *label); - -// -// Macros used to test the pid of a child. -// - -#define IsFailed(pid) ((pid) < 0) -#define IsRunning(pid) ((pid) > 1) -#define IsNotRunning(pid) ((pid) == 0) -#define IsRestarting(pid) ((pid) == 1) - -#define SetNotRunning(pid) ((pid) = 0) -#define SetRestarting(pid) ((pid) = 1) - -// -// Start or restart the house-keeper process. -// - -static int StartKeeper(); - -// -// Cleanup functions. -// - -void CleanupConnections(); -void CleanupListeners(); -void CleanupSockets(); -void CleanupGlobal(); - -static void CleanupChildren(); -static void CleanupLocal(); -static void CleanupKeeper(); -static void CleanupStreams(); - -// -// Loop forever until the connections -// to the peer proxy is dropped. -// - -static void WaitCleanup(); - -// -// Initialization functions. -// - -static int InitBeforeNegotiation(); -static int SetupProxyConnection(); -static int InitAfterNegotiation(); -static int SetupProxyInstance(); -static int SetupAuthInstance(); -static int SetupAgentInstance(); - -static int SetupTcpSocket(); -static int SetupUnixSocket(); -static int SetupServiceSockets(); -static int SetupDisplaySocket(int &xServerAddrFamily, sockaddr *&xServerAddr, - unsigned int &xServerAddrLength); - -// -// Setup a listening socket and accept -// a new connection. -// - -static int ListenConnection(ChannelEndPoint &endPoint, const char *label); -static int ListenConnectionTCP(const char *host, long port, 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); - -// -// Other convenience functions. -// - -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); -static int ReadProxyVersion(int fd); -static int ReadProxyOptions(int fd); -static int ReadProxyCaches(int fd); -static int ReadForwarderVersion(int fd); -static int ReadForwarderOptions(int fd); - -static int ReadRemoteData(int fd, char *buffer, int size, char stop); -static int WriteLocalData(int fd, const char *buffer, int size); - -static void PrintVersionInfo(); -static void PrintProcessInfo(); -static void PrintConnectionInfo(); -static void PrintUsageInfo(const char *option, const int error); -static void PrintOptionIgnored(const char *type, const char *name, const char *value); - -// -// This is not static to avoid a warning. -// - -void PrintCopyrightInfo(); - -static const char *GetOptions(const char *options); -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); - -extern "C" -{ - int ParseCommandLineOptions(int argc, const char **argv); - int ParseEnvironmentOptions(const char *env, int force); - int ParseBindOptions(char **host, int *port); -} - -static int ParseFileOptions(const char *file); -static int ParseRemoteOptions(char *opts); -static int ParseForwarderOptions(char *opts); - -// -// These functions are used to parse literal -// values provided by the user and set the -// control parameters accordingly. -// - -static int ParseLinkOption(const char *opt); -static int ParseBitrateOption(const char *opt); -static int ParseCacheOption(const char *opt); -static int ParseShmemOption(const char *opt); -static int ParseImagesOption(const char *opt); -static int ParsePackOption(const char *opt); - -// -// Set host and port where NX proxy is supposed -// to be listening in case such parameters are -// given on the command line. -// - -static int ParseHostOption(const char *opt, char *host, long &port); - -// -// Translate a font server port specification -// to the corresponding Unix socket path. -// - -static int ParseFontPath(char *path); - -// -// Translate a pack method id in a literal. -// - -static int ParsePackMethod(const int method, const int quality); - -// -// Try to increase the size of the allowed -// core dumps. -// - -static int SetCore(); - -// -// Set the proxy mode to either client or -// server. -// - -static int SetMode(int mode); - -// -// Determine the path of the NX_* directories -// from the environment. -// - -static int SetDirectories(); - -// -// Set the defaults used for the log file and -// statistics. -// - -static int SetLogs(); - -// -// Check if local and remote protocol versions -// are compatible and, eventually, downgrade -// local version to the minimum level that is -// known to work. -// - -static int SetVersion(); - -// -// Setup the listening TCP ports used for the -// additional channels according to user's -// wishes. -// - -static int SetPorts(); - -// -// Set the maximum number of open descriptors. -// - -static int SetDescriptors(); - -// -// Set the path used for choosing the cache. -// It must be selected after determining the -// session type. -// - -static int SetCaches(); - -// -// Initialize, one after the other, all the -// configuration parameters. -// - -static int SetParameters(); - -// -// Set the specific configuration parameter. -// - -static int SetSession(); -static int SetStorage(); -static int SetShmem(); -static int SetPack(); -static int SetImages(); -static int SetLimits(); - -// -// Set up the control parameters based on -// the link speed negotiated between the -// proxies. -// - -static int SetLink(); - -static int SetLinkModem(); -static int SetLinkIsdn(); -static int SetLinkAdsl(); -static int SetLinkWan(); -static int SetLinkLan(); - -// -// Adjust the compression parameters. -// - -static int SetCompression(); - -static int SetCompressionModem(); -static int SetCompressionIsdn(); -static int SetCompressionAdsl(); -static int SetCompressionWan(); -static int SetCompressionLan(); - -// -// Determine the NX paths based on the -// user's parameters or the environment. -// - -char *GetClientPath(); - -static char *GetSystemPath(); -static char *GetHomePath(); -static char *GetTempPath(); -static char *GetRootPath(); -static char *GetCachePath(); -static char *GetImagesPath(); -static char *GetSessionPath(); -static char *GetLastCache(char *list, const char *path); - -static int OpenLogFile(char *name, ostream *&stream); -static int ReopenLogFile(char *name, ostream *&stream, int limit); - -// -// Perform operations on the managed -// descriptors in the main loop. -// - -static void handleCheckSessionInLoop(); -static void handleCheckBitrateInLoop(); - -#if defined(TEST) || defined(INFO) -static void handleCheckSelectInLoop(int &setFDs, fd_set &readSet, - fd_set &writeSet, T_timestamp selectTs); -static void handleCheckResultInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs, - struct timeval &startTs); -static void handleCheckStateInLoop(int &setFDs); -#endif - -static void handleCheckSessionInConnect(); - -static inline void handleSetReadInLoop(fd_set &readSet, int &setFDs, struct timeval &selectTs); -static inline void handleSetWriteInLoop(fd_set &writeSet, int &setFDs, struct timeval &selectTs); -static inline void handleSetListenersInLoop(fd_set &writeSet, int &setFDs); -static inline void handleSetAgentInLoop(int &setFDs, fd_set &readSet, fd_set &writeSet, - struct timeval &selectTs); - -static void handleAlertInLoop(); -static void handleStatisticsInLoop(); - -static inline void handleAgentInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs); -static inline void handleAgentLateInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs); - -static inline void handleReadableInLoop(int &resultFDs, fd_set &readSet); -static inline void handleWritableInLoop(int &resultFDs, fd_set &writeSet); - -static inline void handleRotateInLoop(); -static inline void handleEventsInLoop(); -static inline void handleFlushInLoop(); - -// -// Manage the proxy link during the negotiation -// phase. -// - -static void handleNegotiationInLoop(int &setFDs, fd_set &readSet, - fd_set &writeSet, T_timestamp &selectTs); - -// -// Print the 'terminating' messages in the -// session log. -// - -static inline void handleTerminatingInLoop(); -static inline void handleTerminatedInLoop(); - -// -// Monitor the size of the log file. -// - -static void handleLogReopenInLoop(T_timestamp &logsTs, T_timestamp &nowTs); - -// -// Directory where the NX binaries and libraries reside. -// - -static char systemDir[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Directory used for temporary files. -// - -static char tempDir[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Actually the full path to the client. -// - -static char clientDir[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// User's home directory. -// - -static char homeDir[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Root of directory structure to be created by proxy. -// - -static char rootDir[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Root of statistics and log files to be created by proxy. -// - -static char sessionDir[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Log files for errors and statistics. Error log is -// the place where we print also debug informations. -// Both files are closed, deleted and reopened as -// their size exceed the limit set in control class. -// The session log is not reopened, as it is used by -// the NX client and server to track the advance of -// the session. -// - -static char errorsFileName[DEFAULT_STRING_LENGTH] = { 0 }; -static char statsFileName[DEFAULT_STRING_LENGTH] = { 0 }; -static char sessionFileName[DEFAULT_STRING_LENGTH] = { 0 }; -static char optionsFileName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// String literal representing selected link speed -// parameter. Value is translated in control values -// used by proxies to stay synchronized. -// - -static char linkSpeedName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// String literal representing selected -// cache size. -// - -static char cacheSizeName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// String literal representing selected -// shared memory segment size. -// - -static char shsegSizeName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// String literal of images cache size. -// - -static char imagesSizeName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// String literal for bandwidth limit. -// - -static char bitrateLimitName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// String literal for image packing method. -// - -static char packMethodName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Product name provided by the server or client. -// - -static char productName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Its corresponding value from NXpack.h. -// - -static int packMethod = -1; -static int packQuality = -1; - -// -// String literal for session type. Persistent caches -// are searched in directory whose name matches this -// parameter. -// - -static char sessionType[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Unique id assigned to session. It is used as -// name of directory where all files are placed. -// - -static char sessionId[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Set if we already parsed the options. -// - -static int parsedOptions = 0; -static int parsedCommand = 0; - -// -// Buffer data received from the remote proxy at -// session negotiation. -// - -static char remoteData[MAXIMUM_REMOTE_OPTIONS_LENGTH] = { 0 }; -static int remotePosition = 0; - -// -// Main loop file descriptors. -// - -static int tcpFD = -1; -static int unixFD = -1; -static int cupsFD = -1; -static int auxFD = -1; -static int smbFD = -1; -static int mediaFD = -1; -static int httpFD = -1; -static int fontFD = -1; -static int slaveFD = -1; -static int proxyFD = -1; - -// -// Used for internal communication -// with the X agent. -// - -static int agentFD[2] = { -1, -1 }; - -// -// Flags determining which protocols and -// ports are forwarded. -// - -int useUnixSocket = 1; - -static int useTcpSocket = 1; -static int useCupsSocket = 0; -static int useAuxSocket = 0; -static int useSmbSocket = 0; -static int useMediaSocket = 0; -static int useHttpSocket = 0; -static int useFontSocket = 0; -static int useSlaveSocket = 0; -static int useAgentSocket = 0; - -// -// Set if the launchd service is running -// and its socket must be used as X socket. -// - -static int useLaunchdSocket = 0; - -// -// Set by user if he/she wants to modify -// the default TCP_NODELAY option as set -// in control. -// - -static int useNoDelay = -1; - -// -// Set if user wants to override default -// flush timeout set according to link. -// - -static int usePolicy = -1; - -// -// Set if user wants to hide the RENDER -// extension or wants to short-circuit -// some simple replies at client side. -// - -static int useRender = -1; -static int useTaint = -1; - -// -// Set if the user wants to reduce the -// nominal size of the token messages -// exchanged between the proxies. -// - -static int useStrict = -1; - -// -// Set if the proxy is running as part -// of SSH on the client. -// - -static int useEncryption = -1; - -// -// Name of Unix socket created by the client proxy to -// accept client connections. File must be unlinked -// by cleanup function. -// - -static char unixSocketName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Other parameters. -// - -static char acceptHost[DEFAULT_STRING_LENGTH] = { 0 }; -static char displayHost[DEFAULT_STRING_LENGTH] = { 0 }; -static char authCookie[DEFAULT_STRING_LENGTH] = { 0 }; - -static int loopbackBind = DEFAULT_LOOPBACK_BIND; -static int proxyPort = DEFAULT_NX_PROXY_PORT; -static int xPort = DEFAULT_NX_X_PORT; - -// -// Used to setup the connection the real -// X display socket. -// - -static int xServerAddrFamily = -1; -static sockaddr *xServerAddr = NULL; -static unsigned int xServerAddrLength = 0; - -// -// The representation of a Unix socket path or -// a bind address, denoting where the local proxy -// will await the peer connection. -// - -static ChannelEndPoint listenSocket; - -// -// The TCP host and port or Unix file socket where -// the remote proxy will be contacted. -// - -static ChannelEndPoint connectSocket; - -// -// Helper channels are disabled by default. -// - -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 -// socket. -// - -static char fontPort[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Host and port where the existing proxy -// is running. -// - -static char bindHost[DEFAULT_STRING_LENGTH] = { 0 }; -static int bindPort = -1; - -// -// Pointers to the callback functions and -// parameter set by the agent -// - -static void (*flushCallback)(void *, int) = NULL; -static void *flushParameter = NULL; - -static void (*statisticsCallback)(void *, int) = NULL; -static void *statisticsParameter = NULL; - -// -// State variables shared between the init -// function and the main loop. -// - -T_timestamp initTs; -T_timestamp startTs; -T_timestamp logsTs; -T_timestamp nowTs; - -int diffTs; - -// -// This is set to the main proxy process id. -// - -int lastProxy = 0; - -// -// Set to last dialog process launched by proxy. -// - -int lastDialog = 0; - -// -// Set to watchdog process launched by proxy. -// - -int lastWatchdog = 0; - -// -// Set if a cache house-keeper process is running. -// - -int lastKeeper = 0; - -// -// Let an inner routine register the pid of a slave -// process. -// - -static int lastChild = 0; - -// -// Exit code of the last child process exited. -// - -static int lastStatus = 0; - -// -// Set if shutdown was requested through a signal. -// - -static int lastKill = 0; - -// -// Set if the agent confirmed the destruction of -// the NX transport. -// - -static int lastDestroy = 0; - -// -// This is set to the code and local flag of the -// last requested alert. -// - -static struct -{ - int code; - int local; - -} lastAlert; - -// -// Manage the current signal masks. -// - -static struct -{ - sigset_t saved; - - int blocked; - int installed; - - int enabled[32]; - int forward[32]; - - struct sigaction action[32]; - -} lastMasks; - -// -// Manage the current timer. -// - -static struct -{ - struct sigaction action; - struct itimerval value; - struct timeval start; - struct timeval next; - -} lastTimer; - -// -// This is set to last signal received in handler. -// - -static int lastSignal = 0; - -// -// Set to the last time bytes readable were queried -// by the agent. -// - -static T_timestamp lastReadableTs = nullTimestamp(); - -// -// Here are interfaces declared in NX.h. -// - -int NXTransProxy(int fd, int mode, const char* options) -{ - // - // Let the log temporarily go to the standard - // error. Be also sure we have a jump context, - // in the case any subsequent operation will - // cause a cleanup. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - if (setjmp(context) == 1) - { - #ifdef TEST - *logofs << "NXTransProxy: Out of the long jump with pid '" - << lastProxy << "'.\n" << logofs_flush; - #endif - - return -1; - } - - // - // Check if have already performed a parsing of - // parameters, as in the case we are running as - // a stand-alone process. If needed create the - // parameters repository - // - - if (control == NULL) - { - control = new Control(); - } - - lastProxy = getpid(); - - #ifdef TEST - *logofs << "NXTransProxy: Main process started with pid '" - << lastProxy << "'.\n" << logofs_flush; - #endif - - SetMode(mode); - - if (mode == NX_MODE_CLIENT) - { - if (fd != NX_FD_ANY) - { - #ifdef TEST - - *logofs << "NXTransProxy: Agent descriptor for X client connections is FD#" - << fd << ".\n" << logofs_flush; - - *logofs << "NXTransProxy: Disabling listening on further X client connections.\n" - << logofs_flush; - - #endif - - useTcpSocket = 0; - useUnixSocket = 0; - useAgentSocket = 1; - - agentFD[1] = fd; - } - } - else if (mode == NX_MODE_SERVER) - { - if (fd != NX_FD_ANY) - { - #ifdef TEST - *logofs << "NXTransProxy: PANIC! Agent descriptor for X server connections " - << "not supported yet.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Agent descriptor for X server connections " - << "not supported yet.\n"; - - return -1; - } - } - - const char *env = GetOptions(options); - - if (ParseEnvironmentOptions(env, 0) < 0) - { - cerr << "Error" << ": Parsing of NX transport options failed.\n"; - - return -1; - } - - // - // Set the path of the NX directories. - // - - SetDirectories(); - - // - // Open the log files. - // - - SetLogs(); - - #ifdef TEST - *logofs << "NXTransProxy: Going to run the NX transport loop.\n" - << logofs_flush; - #endif - - WaitCleanup(); - - // - // This function should never return. - // - - exit(0); -} - -void NXTransExit(int code) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - static int recurse; - - if (++recurse > 1) - { - #ifdef TEST - *logofs << "NXTransExit: Aborting process with pid '" - << getpid() << "' due to recursion through " - << "exit.\n" << logofs_flush; - #endif - - abort(); - } - - #ifdef TEST - *logofs << "NXTransExit: Process with pid '" - << getpid() << "' called exit with code '" - << code << "'.\n" << logofs_flush; - #endif - - if (control != NULL) - { - // - // Be sure that there we can detect the - // termination of the watchdog. - // - - EnableSignals(); - - // - // Close the NX transport if it was not - // shut down already. - // - - NXTransDestroy(NX_FD_ANY); - } - - exit(code); -} - -int NXTransParseCommandLine(int argc, const char **argv) -{ - return ParseCommandLineOptions(argc, argv); -} - -int NXTransParseEnvironment(const char *env, int force) -{ - return ParseEnvironmentOptions(env, force); -} - -void NXTransCleanup() -{ - HandleCleanup(); -} - -void NXTransCleanupForReconnect() -{ - HandleCleanupForReconnect(); -} - -// -// Check the parameters for subsequent -// initialization of the NX transport. -// - -int NXTransCreate(int fd, int mode, const char* options) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - // - // Be sure we have a jump context, in the - // case a subsequent operation will cause - // a cleanup. - // - - if (setjmp(context) == 1) - { - return -1; - } - - // - // Create the parameters repository - // - - if (control != NULL) - { - #ifdef PANIC - *logofs << "NXTransCreate: PANIC! The NX transport seems " - << "to be already running.\n" << logofs_flush; - #endif - - cerr << "Error" << ": The NX transport seems " - << "to be already running.\n"; - - return -1; - } - - control = new Control(); - - if (control == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating the NX transport.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error creating the NX transport.\n"; - - return -1; - } - - lastProxy = getpid(); - - #ifdef TEST - *logofs << "NXTransCreate: Caller process running with pid '" - << lastProxy << "'.\n" << logofs_flush; - #endif - - // - // Set the local proxy mode an parse the - // display NX options. - // - - SetMode(mode); - - const char *env = GetOptions(options); - - if (ParseEnvironmentOptions(env, 0) < 0) - { - cerr << "Error" << ": Parsing of NX transport options failed.\n"; - - return -1; - } - - // - // Set the path of the NX directories. - // - - SetDirectories(); - - // - // Open the log files. - // - - SetLogs(); - - // - // Use the provided descriptor. - // - - proxyFD = fd; - - #ifdef TEST - *logofs << "NXTransCreate: Called with NX proxy descriptor '" - << proxyFD << "'.\n" << logofs_flush; - #endif - - #ifdef TEST - *logofs << "NXTransCreate: Creation of the NX transport completed.\n" - << logofs_flush; - #endif - - return 1; -} - -// -// Tell the proxy to use the descriptor as the internal -// connection to the X client side NX agent. This will -// have the side effect of disabling listening for add- -// itional X client connections. -// - -int NXTransAgent(int fd[2]) -{ - // - // Be sure we have a jump context, in the - // case a subsequent operation will cause - // a cleanup. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - if (setjmp(context) == 1) - { - return -1; - } - - if (control == NULL) - { - cerr << "Error" << ": Can't set the NX agent without a NX transport.\n"; - - return -1; - } - else if (control -> ProxyMode != proxy_client) - { - #ifdef PANIC - *logofs << "NXTransAgent: Invalid mode while setting the NX agent.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid mode while setting the NX agent.\n\n"; - - return -1; - } - - useTcpSocket = 0; - useUnixSocket = 0; - useAgentSocket = 1; - - agentFD[0] = fd[0]; - agentFD[1] = fd[1]; - - #ifdef TEST - - *logofs << "NXTransAgent: Internal descriptors for agent are FD#" - << agentFD[0] << " and FD#" << agentFD[1] << ".\n" - << logofs_flush; - - *logofs << "NXTransAgent: Disabling listening for further X client " - << "connections.\n" << logofs_flush; - - #endif - - agent = new Agent(agentFD); - - if (agent == NULL || agent -> isValid() != 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating the NX memory transport .\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error creating the NX memory transport.\n"; - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "NXTransAgent: Enabling memory-to-memory transport.\n" - << logofs_flush; - #endif - - return 1; -} - -int NXTransClose(int fd) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - /* - * Only handle the proxy connection. The X - * transport will take care of closing its - * end of the socket pair. - */ - - if (control != NULL && ((agent != NULL && - (fd == agentFD[0] || fd == NX_FD_ANY)) || - (fd == proxyFD || fd == NX_FD_ANY))) - { - if (proxy != NULL) - { - #ifdef TEST - *logofs << "NXTransClose: Closing down all the X connections.\n" - << logofs_flush; - #endif - - CleanupConnections(); - } - } - #ifdef TEST - else - { - *logofs << "NXTransClose: The NX transport is not running.\n" - << logofs_flush; - } - #endif - - return 1; -} - -// -// Close down the transport and free the -// allocated NX resources. -// - -int NXTransDestroy(int fd) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - if (control != NULL && ((agent != NULL && - (fd == agentFD[0] || fd == NX_FD_ANY)) || - (fd == proxyFD || fd == NX_FD_ANY))) - { - // - // Shut down the X connections and - // wait the cleanup to complete. - // - - if (proxy != NULL) - { - #ifdef TEST - *logofs << "NXTransDestroy: Closing down all the X connections.\n" - << logofs_flush; - #endif - - CleanupConnections(); - } - - #ifdef TEST - *logofs << "NXTransDestroy: Waiting for the NX transport to terminate.\n" - << logofs_flush; - #endif - - lastDestroy = 1; - - WaitCleanup(); - } - #ifdef TEST - else - { - *logofs << "NXTransDestroy: The NX transport is not running.\n" - << logofs_flush; - } - #endif - - return 1; -} - -// -// Assume that the NX transport is valid -// as long as the control class has not -// been destroyed. -// - -int NXTransRunning(int fd) -{ - return (control != NULL); -} - -int NXTransContinue(struct timeval *selectTs) -{ - if (control != NULL) - { - // - // If no timeout is provided use - // the default. - // - - T_timestamp newTs; - - if (selectTs == NULL) - { - setTimestamp(newTs, control -> PingTimeout); - - selectTs = &newTs; - } - - // - // Use empty masks and only get the - // descriptors set by the proxy. - // - - fd_set readSet; - fd_set writeSet; - - int setFDs; - int errorFDs; - int resultFDs; - - setFDs = 0; - - FD_ZERO(&readSet); - FD_ZERO(&writeSet); - - // - // Run a new loop. If the transport - // is gone avoid sleeping until the - // timeout. - // - - if (NXTransPrepare(&setFDs, &readSet, &writeSet, selectTs) != 0) - { - NXTransSelect(&resultFDs, &errorFDs, &setFDs, &readSet, &writeSet, selectTs); - - NXTransExecute(&resultFDs, &errorFDs, &setFDs, &readSet, &writeSet, selectTs); - } - } - - return (control != NULL); -} - -int NXTransSignal(int signal, int action) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - if (control == NULL) - { - return 0; - } - - if (action == NX_SIGNAL_RAISE) - { - #ifdef TEST - *logofs << "NXTransSignal: Raising signal '" << DumpSignal(signal) - << "' in the proxy handler.\n" << logofs_flush; - #endif - - HandleSignal(signal); - - return 1; - } - else if (signal == NX_SIGNAL_ANY) - { - #ifdef TEST - *logofs << "NXTransSignal: Setting action of all signals to '" - << action << "'.\n" << logofs_flush; - #endif - - for (int i = 0; i < 32; i++) - { - if (CheckSignal(i) == 1) - { - NXTransSignal(i, action); - } - } - - return 1; - } - else if (CheckSignal(signal) == 1) - { - #ifdef TEST - *logofs << "NXTransSignal: Setting action of signal '" - << DumpSignal(signal) << "' to '" << action - << "'.\n" << logofs_flush; - #endif - - if (action == NX_SIGNAL_ENABLE || - action == NX_SIGNAL_FORWARD) - { - InstallSignal(signal, action); - - return 1; - } - else if (action == NX_SIGNAL_DISABLE) - { - RestoreSignal(signal); - - return 1; - } - } - - #ifdef WARNING - *logofs << "NXTransSignal: WARNING! Unable to perform action '" - << action << "' on signal '" << DumpSignal(signal) - << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Unable to perform action '" << action - << "' on signal '" << DumpSignal(signal) - << "'.\n"; - - return -1; -} - -int NXTransCongestion(int fd) -{ - if (control != NULL && proxy != NULL) - { - #ifdef DUMP - - int congestion = proxy -> getCongestion(proxyFD); - - *logofs << "NXTransCongestion: Returning " << congestion - << " as current congestion level.\n" << logofs_flush; - - return congestion; - - #endif - - return (proxy -> getCongestion(proxyFD)); - } - - return 0; -} - -int NXTransHandler(int fd, int type, void (*handler)(void *parameter, - int reason), void *parameter) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - switch (type) - { - case NX_HANDLER_FLUSH: - { - flushCallback = handler; - flushParameter = parameter; - - break; - } - case NX_HANDLER_STATISTICS: - { - // - // Reporting of statistics by the agent - // still needs to be implemented. - // - - statisticsCallback = handler; - statisticsParameter = parameter; - - break; - } - default: - { - #ifdef TEST - *logofs << "NXTransHandler: WARNING! Failed to set " - << "the NX callback for event '" << type << "' to '" - << (void *) handler << "' and parameter '" - << parameter << "'.\n" << logofs_flush; - #endif - - return 0; - } - } - - #ifdef TEST - *logofs << "NXTransHandler: Set the NX " - << "callback for event '" << type << "' to '" - << (void *) handler << "' and parameter '" - << parameter << "'.\n" << logofs_flush; - #endif - - return 1; -} - -int NXTransRead(int fd, char *data, int size) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - if (control != NULL && agent != NULL && - fd == agentFD[0]) - { - #ifdef DUMP - *logofs << "NXTransRead: Dequeuing " << size << " bytes " - << "from FD#" << agentFD[0] << ".\n" << logofs_flush; - #endif - - int result = agent -> dequeueData(data, size); - - #ifdef DUMP - - if (result < 0 && EGET() == EAGAIN) - { - *logofs << "NXTransRead: WARNING! Dequeuing from FD#" - << agentFD[0] << " would block.\n" << logofs_flush; - } - else - { - *logofs << "NXTransRead: Dequeued " << result << " bytes " - << "to FD#" << agentFD[0] << ".\n" << logofs_flush; - } - - #endif - - return result; - } - else - { - #ifdef DUMP - *logofs << "NXTransRead: Reading " << size << " bytes " - << "from FD#" << fd << ".\n" << logofs_flush; - #endif - - return read(fd, data, size); - } -} - -int NXTransReadVector(int fd, struct iovec *iovdata, int iovsize) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - if (control != NULL && agent != NULL && - fd == agentFD[0]) - { - #if defined(DUMP) - - if (control -> ProxyStage >= stage_operational && - agent -> localReadable() > 0) - { - *logofs << "NXTransReadVector: WARNING! Agent has data readable.\n" - << logofs_flush; - } - - #endif - - char *base; - - int length; - int result; - - struct iovec *vector = iovdata; - int count = iovsize; - - ESET(0); - - int i = 0; - int total = 0; - - for (; i < count; i++, vector++) - { - length = vector -> iov_len; - base = (char *) vector -> iov_base; - - while (length > 0) - { - #ifdef DUMP - *logofs << "NXTransReadVector: Dequeuing " << length - << " bytes " << "from FD#" << agentFD[0] << ".\n" - << logofs_flush; - #endif - - result = agent -> dequeueData(base, length); - - #ifdef DUMP - - if (result < 0 && EGET() == EAGAIN) - { - *logofs << "NXTransReadVector: WARNING! Dequeuing from FD#" - << agentFD[0] << " would block.\n" << logofs_flush; - } - else - { - *logofs << "NXTransReadVector: Dequeued " << result - << " bytes " << "from FD#" << agentFD[0] << ".\n" - << logofs_flush; - } - - #endif - - if (result < 0 && total == 0) - { - return result; - } - else if (result <= 0) - { - return total; - } - - ESET(0); - - length -= result; - total += result; - base += result; - } - } - - return total; - } - else - { - #ifdef DUMP - *logofs << "NXTransReadVector: Reading vector with " - << iovsize << " elements from FD#" << fd << ".\n" - << logofs_flush; - #endif - - return readv(fd, iovdata, iovsize); - } -} - -int NXTransReadable(int fd, int *readable) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - if (control == NULL || agent == NULL || - fd != agentFD[0]) - { - #ifdef DUMP - - int result = GetBytesReadable(fd, readable); - - if (result == -1) - { - *logofs << "NXTransReadable: Error detected on FD#" - << fd << ".\n" << logofs_flush; - } - else - { - *logofs << "NXTransReadable: Returning " << *readable - << " bytes as readable from FD#" << fd - << ".\n" << logofs_flush; - } - - return result; - - #else - - return GetBytesReadable(fd, readable); - - #endif - } - - int result = agent -> dequeuableData(); - - switch (result) - { - case 0: - { - // - // The client might have enqueued data to our side - // and is now checking for the available events. As - // _XEventsQueued() may omit to call _XSelect(), we - // handle here the new data that is coming from the - // proxy to avoid spinning through this function - // again. - // - - if (proxy != NULL && proxy -> canRead() == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "NXTransReadable: WARNING! Trying to " - << "read to generate new agent data.\n" - << logofs_flush; - #endif - - // - // Set the context as the function - // can cause a cleanup. - // - - if (setjmp(context) == 1) - { - return -1; - } - - if (proxy -> handleRead() < 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "NXTransReadable: Failure reading " - << "messages from proxy FD#" << proxyFD - << ".\n" << logofs_flush; - #endif - - HandleShutdown(); - } - - // - // Call again the routine. By reading - // new control messages from the proxy - // the agent channel may be gone. - // - - return NXTransReadable(fd, readable); - } - - #ifdef DUMP - *logofs << "NXTransReadable: Returning " << 0 - << " bytes as readable from FD#" << fd - << " with result 0.\n" << logofs_flush; - #endif - - *readable = 0; - - return 0; - } - case -1: - { - #ifdef DUMP - *logofs << "NXTransReadable: Returning " << 0 - << " bytes as readable from FD#" << fd - << " with result -1.\n" << logofs_flush; - #endif - - *readable = 0; - - return -1; - } - default: - { - #ifdef DUMP - *logofs << "NXTransReadable: Returning " << result - << " bytes as readable from FD#" << fd - << " with result 0.\n" << logofs_flush; - #endif - - *readable = result; - - return 0; - } - } -} - -int NXTransWrite(int fd, char *data, int size) -{ - // - // Be sure we have a valid log file. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - if (control != NULL && agent != NULL && - fd == agentFD[0]) - { - int result; - - if (proxy != NULL) - { - if (proxy -> canRead(agentFD[1]) == 0) - { - #if defined(DUMP) || defined(TEST) - *logofs << "NXTransWrite: WARNING! Delayed enqueuing to FD#" - << agentFD[0] << " with proxy unable to read.\n" - << logofs_flush; - #endif - - ESET(EAGAIN); - - return -1; - } - - // - // Set the context as the function - // can cause a cleanup. - // - - if (setjmp(context) == 1) - { - return -1; - } - - // - // Don't enqueue the data to the transport - // but let the channel borrow the buffer. - // - - #ifdef DUMP - *logofs << "NXTransWrite: Letting the channel borrow " - << size << " bytes from FD#" << agentFD[0] - << ".\n" << logofs_flush; - #endif - - result = proxy -> handleRead(agentFD[1], data, size); - - if (result == 1) - { - result = size; - } - else - { - if (result == 0) - { - ESET(EAGAIN); - } - else - { - ESET(EPIPE); - } - - result = -1; - } - } - else - { - // - // We don't have a proxy connection, yet. - // Enqueue the data to the agent transport. - // - - #ifdef DUMP - *logofs << "NXTransWrite: Enqueuing " << size << " bytes " - << "to FD#" << agentFD[0] << ".\n" << logofs_flush; - #endif - - result = agent -> enqueueData(data, size); - } - - #ifdef DUMP - - if (result < 0) - { - if (EGET() == EAGAIN) - { - *logofs << "NXTransWrite: WARNING! Enqueuing to FD#" - << agentFD[0] << " would block.\n" - << logofs_flush; - } - else - { - *logofs << "NXTransWrite: WARNING! Error enqueuing to FD#" - << agentFD[0] << ".\n" << logofs_flush; - } - } - else - { - *logofs << "NXTransWrite: Enqueued " << result << " bytes " - << "to FD#" << agentFD[0] << ".\n" << logofs_flush; - } - - #endif - - return result; - } - else - { - #ifdef DUMP - *logofs << "NXTransWrite: Writing " << size << " bytes " - << "to FD#" << fd << ".\n" << logofs_flush; - #endif - - return write(fd, data, size); - } -} - -int NXTransWriteVector(int fd, struct iovec *iovdata, int iovsize) -{ - // - // Be sure we have a valid log file and a - // jump context because we will later call - // functions that can perform a cleanup. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - int result = 0; - - if (control != NULL && agent != NULL && - fd == agentFD[0]) - { - // - // See the comment in NXTransWrite(). - // - - if (proxy != NULL) - { - if (proxy -> canRead(agentFD[1]) == 0) - { - #if defined(DUMP) || defined(TEST) - *logofs << "NXTransWriteVector: WARNING! Delayed enqueuing to FD#" - << agentFD[0] << " with proxy unable to read.\n" - << logofs_flush; - #endif - - ESET(EAGAIN); - - return -1; - } - } - - // - // Set the context as the function - // can cause a cleanup. - // - - if (setjmp(context) == 1) - { - return -1; - } - - char *base; - - int length; - - struct iovec *vector = iovdata; - int count = iovsize; - - ESET(0); - - int i = 0; - int total = 0; - - for (; i < count; i++, vector++) - { - length = vector -> iov_len; - base = (char *) vector -> iov_base; - - while (length > 0) - { - if (proxy != NULL) - { - // - // Don't enqueue the data to the transport - // but let the channel borrow the buffer. - // - - #ifdef DUMP - *logofs << "NXTransWriteVector: Letting the channel borrow " - << length << " bytes from FD#" << agentFD[0] - << ".\n" << logofs_flush; - #endif - - result = proxy -> handleRead(agentFD[1], base, length); - - if (result == 1) - { - result = length; - } - else - { - if (result == 0) - { - ESET(EAGAIN); - } - else - { - ESET(EPIPE); - } - - result = -1; - } - } - else - { - // - // We don't have a proxy connection, yet. - // Enqueue the data to the agent transport. - // - - #ifdef DUMP - *logofs << "NXTransWriteVector: Enqueuing " << length - << " bytes " << "to FD#" << agentFD[0] << ".\n" - << logofs_flush; - #endif - - result = agent -> enqueueData(base, length); - } - - #ifdef DUMP - - if (result < 0) - { - if (EGET() == EAGAIN) - { - *logofs << "NXTransWriteVector: WARNING! Enqueuing to FD#" - << agentFD[0] << " would block.\n" - << logofs_flush; - } - else - { - *logofs << "NXTransWriteVector: WARNING! Error enqueuing to FD#" - << agentFD[0] << ".\n" << logofs_flush; - } - } - else - { - *logofs << "NXTransWriteVector: Enqueued " << result - << " bytes " << "to FD#" << agentFD[0] << ".\n" - << logofs_flush; - } - - #endif - - if (result < 0 && total == 0) - { - return result; - } - else if (result <= 0) - { - return total; - } - - ESET(0); - - length -= result; - total += result; - base += result; - } - } - - return total; - } - else - { - #ifdef DUMP - *logofs << "NXTransWriteVector: Writing vector with " - << iovsize << " elements to FD#" << fd << ".\n" - << logofs_flush; - #endif - - return writev(fd, iovdata, iovsize); - } -} - -int NXTransPolicy(int fd, int type) -{ - if (control != NULL) - { - if (usePolicy == -1) - { - #if defined(TEST) || defined(INFO) - *logofs << "NXTransPolicy: Setting flush policy on " - << "proxy FD#" << proxyFD << " to '" - << DumpPolicy(type == NX_POLICY_DEFERRED ? - policy_deferred : policy_immediate) - << "'.\n" << logofs_flush; - #endif - - control -> FlushPolicy = (type == NX_POLICY_DEFERRED ? - policy_deferred : policy_immediate); - - if (proxy != NULL) - { - proxy -> handleFlush(); - } - - return 1; - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "NXTransPolicy: Ignoring the agent " - << "setting with user policy set to '" - << DumpPolicy(control -> FlushPolicy) - << "'.\n" << logofs_flush; - #endif - - return 0; - } - } - - return 0; -} - -int NXTransFlushable(int fd) -{ - if (proxy == NULL || agent == NULL || - fd != agentFD[0]) - { - #ifdef DUMP - *logofs << "NXTransFlushable: Returning 0 bytes as " - << "flushable for unrecognized FD#" << fd - << ".\n" << logofs_flush; - #endif - - return 0; - } - else - { - #if defined(DUMP) || defined(INFO) - *logofs << "NXTransFlushable: Returning " << proxy -> - getFlushable(proxyFD) << " as bytes flushable on " - << "proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - return proxy -> getFlushable(proxyFD); - } -} - -int NXTransFlush(int fd) -{ - if (proxy != NULL) - { - #if defined(TEST) || defined(INFO) - *logofs << "NXTransFlush: Requesting an immediate flush of " - << "proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - return proxy -> handleFlush(); - } - - return 0; -} - -int NXTransChannel(int fd, int channelFd, int type) -{ - if (proxy != NULL) - { - // - // Set the context as the function - // can cause a cleanup. - // - - if (setjmp(context) == 1) - { - return -1; - } - - #if defined(TEST) || defined(INFO) - *logofs << "NXTransChannel: Going to create a new channel " - << "with type '" << type << "' on FD#" << channelFd - << ".\n" << logofs_flush; - #endif - - int result = -1; - - switch (type) - { - case NX_CHANNEL_X11: - { - if (useUnixSocket == 1 || useTcpSocket == 1 || - useAgentSocket == 1 || useAuxSocket == 1) - { - result = proxy -> handleNewConnection(channel_x11, channelFd); - } - - break; - } - case NX_CHANNEL_CUPS: - { - if (useCupsSocket == 1) - { - result = proxy -> handleNewConnection(channel_cups, channelFd); - } - - break; - } - case NX_CHANNEL_SMB: - { - if (useSmbSocket == 1) - { - result = proxy -> handleNewConnection(channel_smb, channelFd); - } - - break; - } - case NX_CHANNEL_MEDIA: - { - if (useMediaSocket == 1) - { - result = proxy -> handleNewConnection(channel_media, channelFd); - } - - break; - } - case NX_CHANNEL_HTTP: - { - if (useHttpSocket == 1) - { - result = proxy -> handleNewConnection(channel_http, channelFd); - } - - break; - } - case NX_CHANNEL_FONT: - { - if (useFontSocket == 1) - { - result = proxy -> handleNewConnection(channel_font, channelFd); - } - - break; - } - case NX_CHANNEL_SLAVE: - { - if (useSlaveSocket == 1) - { - result = proxy -> handleNewConnection(channel_slave, channelFd); - } - - break; - } - default: - { - #ifdef WARNING - *logofs << "NXTransChannel: WARNING! Unrecognized channel " - << "type '" << type << "'.\n" << logofs_flush; - #endif - - break; - } - } - - #ifdef WARNING - - if (result != 1) - { - *logofs << "NXTransChannel: WARNING! Could not create the " - << "new channel with type '" << type << "' on FD#" - << channelFd << ".\n" << logofs_flush; - } - - #endif - - return result; - } - - return 0; -} - -const char *NXTransFile(int type) -{ - char *name = NULL; - - switch (type) - { - case NX_FILE_SESSION: - { - name = sessionFileName; - - break; - } - case NX_FILE_ERRORS: - { - name = errorsFileName; - - break; - } - case NX_FILE_OPTIONS: - { - name = optionsFileName; - - break; - } - case NX_FILE_STATS: - { - name = statsFileName; - - break; - } - } - - if (name != NULL && *name != '\0') - { - return name; - } - - return NULL; -} - -long NXTransTime() -{ - static T_timestamp last = getTimestamp(); - - T_timestamp now = getTimestamp(); - - long diff = diffTimestamp(last, now); - - last = now; - - return diff; -} - -int NXTransAlert(int code, int local) -{ - if (proxy != NULL) - { - #if defined(DUMP) || defined(INFO) - *logofs << "NXTransAlert: Requesting a NX dialog with code " - << code << " and local " << local << ".\n" - << logofs_flush; - #endif - - if (local == 0) - { - // - // Set the context as the function - // can cause a cleanup. - // - - if (setjmp(context) == 1) - { - return -1; - } - - proxy -> handleAlert(code); - } - else - { - // - // Show the alert at the next loop. - // - - HandleAlert(code, local); - } - - return 1; - } - #if defined(DUMP) || defined(INFO) - else - { - if (logofs == NULL) - { - logofs = &cerr; - } - - *logofs << "NXTransAlert: Can't request an alert without " - << "a valid NX transport.\n" << logofs_flush; - } - #endif - - return 0; -} - -// -// Prepare the file sets and the timeout -// for a later execution of the select(). -// - -int NXTransPrepare(int *setFDs, fd_set *readSet, - fd_set *writeSet, struct timeval *selectTs) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - // - // Control is NULL if the NX transport was - // reset or was never created. If control - // is valid then prepare to jump back when - // the transport is destroyed. - // - - if (control == NULL || setjmp(context) == 1) - { - return 0; - } - - #if defined(TEST) || defined(INFO) - *logofs << "\nNXTransPrepare: Going to prepare the NX transport.\n" - << logofs_flush; - #endif - - if (control -> ProxyStage < stage_operational) - { - handleNegotiationInLoop(*setFDs, *readSet, *writeSet, *selectTs); - } - else - { - #if defined(TEST) || defined(INFO) - - if (isTimestamp(*selectTs) == 0) - { - *logofs << "Loop: WARNING! Preparing the select with requested " - << "timeout of " << selectTs -> tv_sec << " S and " - << (double) selectTs -> tv_usec / 1000 << " Ms.\n" - << logofs_flush; - } - else - { - *logofs << "Loop: Preparing the select with requested " - << "timeout of " << selectTs -> tv_sec << " S and " - << (double) selectTs -> tv_usec / 1000 << " Ms.\n" - << logofs_flush; - } - - #endif - - // - // Set descriptors of listening sockets. - // - - handleSetListenersInLoop(*readSet, *setFDs); - - // - // Set descriptors of both proxy and X - // connections. - // - - handleSetReadInLoop(*readSet, *setFDs, *selectTs); - - // - // Find out which file descriptors have - // data to write. - // - - handleSetWriteInLoop(*writeSet, *setFDs, *selectTs); - } - - // - // Prepare the masks for handling the memory- - // to-memory transport. This is required even - // during session negotiation. - // - - if (agent != NULL) - { - handleSetAgentInLoop(*setFDs, *readSet, *writeSet, *selectTs); - } - - // - // Register time spent handling messages. - // - - nowTs = getNewTimestamp(); - - diffTs = diffTimestamp(startTs, nowTs); - - #ifdef TEST - *logofs << "Loop: Mark - 0 - at " << strMsTimestamp() - << " with " << diffTs << " Ms elapsed.\n" - << logofs_flush; - #endif - - // - // TODO: Should add the read time in two - // parts otherwise the limits are checked - // before the counters are updated with - // time spent in the last loop. - // - - if (control -> ProxyStage >= stage_operational) - { - statistics -> addReadTime(diffTs); - } - - startTs = nowTs; - - #ifdef DEBUG - *logofs << "Loop: New timestamp is " << strMsTimestamp(startTs) - << ".\n" << logofs_flush; - #endif - - return 1; -} - -// -// Let's say that we call select() to find out -// if any of the handled descriptors has data, -// but actually things are a bit more complex -// than that. -// - -int NXTransSelect(int *resultFDs, int *errorFDs, int *setFDs, fd_set *readSet, - fd_set *writeSet, struct timeval *selectTs) -{ - #ifdef TIME - - static T_timestamp lastTs; - - #endif - - if (logofs == NULL) - { - logofs = &cerr; - } - - // - // Control is NULL if the NX transport was - // reset or never created. If control is - // valid then prepare for jumping back in - // the case of an error. - // - - if (control == NULL || setjmp(context) == 1) - { - *resultFDs = select(*setFDs, readSet, writeSet, NULL, selectTs); - - *errorFDs = errno; - - return 0; - } - - #if defined(TEST) || defined(INFO) - *logofs << "\nNXTransSelect: Going to select the NX descriptors.\n" - << logofs_flush; - #endif - - #if defined(TEST) || defined(INFO) - - handleCheckSelectInLoop(*setFDs, *readSet, *writeSet, *selectTs); - - #endif - - #ifdef TIME - - diffTs = diffTimestamp(lastTs, getNewTimestamp()); - - if (diffTs > 20) - { - *logofs << "Loop: TIME! Spent " << diffTs - << " Ms handling messages for proxy FD#" - << proxyFD << ".\n" << logofs_flush; - } - - lastTs = getNewTimestamp(); - - #endif - - #if defined(TEST) || defined(INFO) - - if (isTimestamp(*selectTs) == 0) - { - *logofs << "Loop: WARNING! Executing the select with requested " - << "timeout of " << selectTs -> tv_sec << " S and " - << (double) selectTs -> tv_usec / 1000 << " Ms.\n" - << logofs_flush; - } - else if (proxy != NULL && proxy -> getFlushable(proxyFD) > 0) - { - *logofs << "Loop: WARNING! Proxy FD#" << proxyFD - << " has " << proxy -> getFlushable(proxyFD) - << " bytes to write but timeout is " - << selectTs -> tv_sec << " S and " - << selectTs -> tv_usec / 1000 << " Ms.\n" - << logofs_flush; - } - - #endif - - // - // Wait for the selected sockets - // or the timeout. - // - - ESET(0); - - *resultFDs = select(*setFDs, readSet, writeSet, NULL, selectTs); - - *errorFDs = EGET(); - - #ifdef TIME - - diffTs = diffTimestamp(lastTs, getNewTimestamp()); - - if (diffTs > 100) - { - *logofs << "Loop: TIME! Spent " << diffTs - << " Ms waiting for new data for proxy FD#" - << proxyFD << ".\n" << logofs_flush; - } - - lastTs = getNewTimestamp(); - - #endif - - // - // Check the result of the select. - // - - #if defined(TEST) || defined(INFO) - - handleCheckResultInLoop(*resultFDs, *errorFDs, *setFDs, *readSet, *writeSet, *selectTs, startTs); - - #endif - - // - // Get time spent in select. The accouting is done - // in milliseconds. This is a real problem on fast - // machines where each loop is unlikely to take - // more than 500 us, so consider that the results - // can be inaccurate. - // - - nowTs = getNewTimestamp(); - - diffTs = diffTimestamp(startTs, nowTs); - - #ifdef TEST - *logofs << "Loop: Out of select after " << diffTs << " Ms " - << "at " << strMsTimestamp(nowTs) << " with result " - << *resultFDs << ".\n" << logofs_flush; - #endif - - startTs = nowTs; - - #ifdef DEBUG - *logofs << "Loop: New timestamp is " << strMsTimestamp(startTs) - << ".\n" << logofs_flush; - #endif - - if (control -> ProxyStage >= stage_operational) - { - statistics -> addIdleTime(diffTs); - } - - if (*resultFDs < 0) - { - // - // Check if the call was interrupted or if any of the - // managed descriptors has become invalid. This can - // happen to the X11 code, before the descriptor is - // removed from the managed set. - // - - #ifdef __sun - - if (*errorFDs == EINTR || *errorFDs == EBADF || - *errorFDs == EINVAL) - - #else - - if (*errorFDs == EINTR || *errorFDs == EBADF) - - #endif - - { - #ifdef TEST - - if (*errorFDs == EINTR) - { - *logofs << "Loop: Select failed due to EINTR error.\n" - << logofs_flush; - } - else - { - *logofs << "Loop: WARNING! Call to select failed. Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - } - - #endif - } - else - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to select failed. Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Call to select failed. Error is " - << EGET() << " '" << ESTR() << "'.\n"; - - HandleCleanup(); - } - } - - return 1; -} - -// -// Perform the required actions on all -// the descriptors having I/O pending. -// - -int NXTransExecute(int *resultFDs, int *errorFDs, int *setFDs, fd_set *readSet, - fd_set *writeSet, struct timeval *selectTs) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - // - // Control is NULL if the NX transport was - // reset or never created. If control is - // valid then prepare for jumping back in - // the case of an error. - // - - if (control == NULL || setjmp(context) == 1) - { - return 0; - } - - #if defined(TEST) || defined(INFO) - *logofs << "\nNXTransExecute: Going to execute I/O on the NX descriptors.\n" - << logofs_flush; - #endif - - if (control -> ProxyStage >= stage_operational) - { - // - // Check if I/O is possible on the proxy and - // local agent descriptors. - // - - if (agent != NULL) - { - handleAgentInLoop(*resultFDs, *errorFDs, *setFDs, *readSet, *writeSet, *selectTs); - } - - #ifdef TEST - *logofs << "Loop: Mark - 1 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - - // - // Rotate the channel that will be handled - // first. - // - - handleRotateInLoop(); - - // - // Flush any data on newly writable sockets. - // - - handleWritableInLoop(*resultFDs, *writeSet); - - #ifdef TEST - *logofs << "Loop: Mark - 2 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - - // - // Check if any socket has become readable. - // - - handleReadableInLoop(*resultFDs, *readSet); - - #ifdef TEST - *logofs << "Loop: Mark - 3 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - - // - // Handle the scheduled events on channels. - // - // - Restart, if possible, any client that was - // put to sleep. - // - // - Check if there are pointer motion events to - // flush. This applies only to X server side. - // - // - Check if any channel has exited the conges- - // tion state. - // - // - Check if there are images that are currently - // being streamed. - // - - handleEventsInLoop(); - - #ifdef TEST - *logofs << "Loop: Mark - 4 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - - // - // Check if user sent a signal to produce - // statistics. - // - - handleStatisticsInLoop(); - - // - // We may have flushed the proxy link or - // handled data coming from the remote. - // Post-process the masks and set the - // selected agent descriptors as ready. - // - - if (agent != NULL) - { - handleAgentLateInLoop(*resultFDs, *errorFDs, *setFDs, *readSet, *writeSet, *selectTs); - } - - #ifdef TEST - *logofs << "Loop: Mark - 5 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - - // - // Check if there is any data to flush. - // Agents should flush the proxy link - // explicitly. - // - - handleFlushInLoop(); - - #ifdef TEST - *logofs << "Loop: Mark - 6 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - } - - // - // Check if we have an alert to show. - // - - handleAlertInLoop(); - - if (control -> ProxyStage >= stage_operational) - { - // - // Check if it's time to give up. - // - - handleCheckSessionInLoop(); - - // - // Check if local proxy is consuming - // too many resources. - // - - handleCheckBitrateInLoop(); - - // - // Check coherency of internal state. - // - - #if defined(TEST) || defined(INFO) - - handleCheckStateInLoop(*setFDs); - - #endif - - #ifdef TEST - *logofs << "Loop: Mark - 7 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - } - - // - // Truncate the logs if needed. - // - - handleLogReopenInLoop(logsTs, nowTs); - - return 1; -} - -// -// Initialize the connection parameters and -// prepare for negotiating the link with the -// remote proxy. -// - -int InitBeforeNegotiation() -{ - // - // Disable limits on core dumps. - // - - SetCore(); - - // - // Install the signal handlers. - // - - InstallSignals(); - - // - // Track how much time we spent in initialization. - // - - nowTs = getNewTimestamp(); - - startTs = nowTs; - initTs = nowTs; - - #ifdef TEST - *logofs << "Loop: INIT! Taking mark for initialization at " - << strMsTimestamp(initTs) << ".\n" - << logofs_flush; - #endif - - // - // If not explicitly specified, determine if local - // mode is client or server according to parameters - // provided so far. - // - - if (WE_SET_PROXY_MODE == 0) - { - cerr << "Error" << ": Please specify either the -C or -S option.\n"; - - HandleCleanup(); - } - - // - // Start a watchdog. If initialization cannot - // be completed before timeout, then clean up - // everything and exit. - // - - if (control -> ProxyMode == proxy_client) - { - #ifdef TEST - *logofs << "Loop: Starting watchdog process with timeout of " - << control -> InitTimeout / 1000 << " seconds.\n" - << logofs_flush; - #endif - - lastWatchdog = NXTransWatchdog(control -> InitTimeout); - - if (IsFailed(lastWatchdog)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't start the NX watchdog process.\n" - << logofs_flush; - #endif - - SetNotRunning(lastWatchdog); - } - #ifdef TEST - else - { - *logofs << "Loop: Watchdog started with pid '" - << lastWatchdog << "'.\n" << logofs_flush; - } - #endif - } - - // - // Print preliminary info. - // - - PrintProcessInfo(); - - // - // Set cups, multimedia and other - // auxiliary ports. - // - - SetPorts(); - - // - // Increase the number of maximum open - // file descriptors for this process. - // - - SetDescriptors(); - - // - // Set local endianess. - // - - unsigned int test = 1; - - setHostBigEndian(*((unsigned char *) (&test)) == 0); - - #ifdef TEST - *logofs << "Loop: Local host is " - << (hostBigEndian() ? "big endian" : "little endian") - << ".\n" << logofs_flush; - #endif - - if (control -> ProxyMode == proxy_client) - { - // - // Listen on sockets that mimic an X display to - // which X clients will be able to connect (e.g. - // unix:8 and/or localhost:8). - // - - if (useTcpSocket == 1) - { - SetupTcpSocket(); - } - - if (useUnixSocket == 1) - { - SetupUnixSocket(); - } - } - else - { - // - // Don't listen for X connections. - // - - useUnixSocket = 0; - useTcpSocket = 0; - useAgentSocket = 0; - - // - // Get ready to open the local display. - // - - SetupDisplaySocket(xServerAddrFamily, xServerAddr, xServerAddrLength); - } - - // - // If we are the NX server-side proxy we need to - // complete our initializazion. We will mandate - // our parameters at the time the NX client will - // connect. - // - - if (control -> ProxyMode == proxy_client) - { - SetParameters(); - } - - return 1; -} - -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 (connectSocket.getSpec(&socketUri)) - { - #ifdef TEST - *logofs << "Loop: Going to connect to '" << socketUri - << "'.\n" << logofs_flush; - #endif - free(socketUri); - - proxyFD = ConnectToRemote(connectSocket); - - #ifdef TEST - *logofs << "Loop: Connected to remote proxy on FD#" - << proxyFD << ".\n" << logofs_flush; - #endif - - cerr << "Info" << ": Connected to remote proxy on FD#" - << proxyFD << ".\n"; - } - } - else - { - - if (listenSocket.isTCPSocket() && (listenSocket.getTCPPort() < 0)) - { - listenSocket.setSpec(DEFAULT_NX_PROXY_PORT_OFFSET + proxyPort); - } - - if (listenSocket.getSpec(&socketUri)) - { - #ifdef TEST - *logofs << "Loop: Going to wait for connection at '" - << socketUri << "'.\n" << logofs_flush; - #endif - free(socketUri); - - proxyFD = WaitForRemote(listenSocket); - - #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 - - } - } - } - #ifdef TEST - else - { - *logofs << "Loop: Using the inherited connection on FD#" - << proxyFD << ".\n" << logofs_flush; - } - #endif - - // - // Set TCP_NODELAY on proxy descriptor - // 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); - - // - // We need non-blocking input since the - // negotiation phase. - // - - SetNonBlocking(proxyFD, 1); - - return 1; -} - -// -// Create the required proxy and channel classes -// and get ready for handling the encoded traffic. -// - -int InitAfterNegotiation() -{ - #ifdef TEST - *logofs << "Loop: Connection with remote proxy completed.\n" - << logofs_flush; - #endif - - cerr << "Info" << ": Connection with remote proxy completed.\n" - << logofs_flush; - - // - // If we are the server proxy we completed - // our initializazion phase according to - // the values provided by the client side. - // - - if (control -> ProxyMode == proxy_server) - { - SetParameters(); - } - - // - // Set up the listeners for the additional - // services. - // - - SetupServiceSockets(); - - // - // Create the proxy class and the statistics - // repository and pass all the configuration - // data we negotiated with the remote peer. - // - - SetupProxyInstance(); - - // - // We completed both parsing of user's parameters - // and handlshaking with remote proxy. Now print - // a brief summary including the most significant - // control values. - // - - PrintConnectionInfo(); - - // - // Cancel the initialization watchdog. - // - - if (IsRunning(lastWatchdog)) - { - KillProcess(lastWatchdog, "watchdog", SIGTERM, 1); - - SetNotRunning(lastWatchdog); - - lastSignal = 0; - } - - // - // Start the house-keeper process. It will - // remove the oldest persistent caches, if - // the amount of storage exceed the limits - // set by the user. - // - - StartKeeper(); - - // - // Set the log size check timestamp. - // - - nowTs = getNewTimestamp(); - - logsTs = nowTs; - - // - // TODO: Due to the way the new NX transport is working, - // the accounting of time spent handling messages must - // be rewritten. In particular, at the moment it only - // shows the time spent encoding and decoding messages - // in the main loop, after executing a select. It doesn't - // take into account the time spent in the NXTrans* calls - // where messages can be encoded and decoded implicitly, - // on demand of the agent. When the agent transport is - // in use, these calls constitute the vast majority of - // the encoding activity. The result is that the number - // of KB encoded per second shown by the proxy statistics - // is actually much lower than the real throughput gene- - // rated by the proxy. - // - - #ifdef TEST - *logofs << "Loop: INIT! Completed initialization at " - << strMsTimestamp(nowTs) << " with " - << diffTimestamp(initTs, nowTs) << " Ms " - << "since the init mark.\n" << logofs_flush; - #endif - - initTs = getNewTimestamp(); - - // - // We can now start handling binary data from - // our peer proxy. - // - - if (agent == NULL) - { - cerr << "Session" << ": Session started at '" - << strTimestamp() << "'.\n"; - } - - return 1; -} - -int SetMode(int mode) -{ - // - // Set the local proxy mode. - // - - if (control -> ProxyMode == proxy_undefined) - { - if (mode == NX_MODE_CLIENT) - { - #ifdef TEST - *logofs << "Loop: INIT! Initializing with mode " - << "NX_MODE_CLIENT at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - control -> ProxyMode = proxy_client; - } - else if (mode == NX_MODE_SERVER) - { - #ifdef TEST - *logofs << "Loop: INIT! Initializing with mode " - << "NX_MODE_SERVER at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - control -> ProxyMode = proxy_server; - } - else - { - cerr << "Error" << ": Please specify either " - << "the -C or -S option.\n"; - - HandleCleanup(); - } - } - - return 1; -} - -int SetupProxyInstance() -{ - if (control -> ProxyMode == proxy_client) - { - proxy = new ClientProxy(proxyFD); - } - else - { - proxy = new ServerProxy(proxyFD); - } - - if (proxy == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating the NX proxy.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error creating the NX proxy.\n"; - - HandleCleanup(); - } - - // - // Create the statistics repository. - // - - statistics = new Statistics(proxy); - - if (statistics == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating the NX statistics.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error creating the NX statistics.\n"; - - HandleCleanup(); - } - - // - // If user gave us a proxy cookie than create the - // X11 authorization repository and find the real - // cookie to be used for our X display. - // - - SetupAuthInstance(); - - // - // Reset the static members in channels. - // - - proxy -> handleChannelConfiguration(); - - // - // Inform the proxies about the ports where they - // will have to forward the network connections. - // - - proxy -> handleDisplayConfiguration(displayHost, xServerAddrFamily, - xServerAddr, xServerAddrLength); - - proxy -> handlePortConfiguration(cupsPort, smbPort, mediaPort, - httpPort, fontPort); - - // - // We handed over the sockaddr structure we - // created when we set up the display socket - // to the proxy. - // - - xServerAddr = NULL; - - // - // Set socket options on proxy link, then propagate link - // configuration to proxy. This includes translating some - // control parameters in 'local' and 'remote'. Finally - // adjust cache parameters according to pack method and - // session type selected by user. - // - - if (proxy -> handleSocketConfiguration() < 0 || - proxy -> handleLinkConfiguration() < 0 || - proxy -> handleCacheConfiguration() < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error configuring the NX transport.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error configuring the NX transport.\n"; - - HandleCleanup(); - } - - // - // Load the message stores from the persistent - // cache. - // - - proxy -> handleLoad(load_if_first); - - // - // Inform the proxy that from now on it can - // start handling the encoded data. - // - - proxy -> setOperational(); - - // - // Are we going to use an internal IPC connection - // with an agent? In this case create the channel - // by using the socket descriptor provided by the - // caller at the proxy initialization. - // - - SetupAgentInstance(); - - // - // Check if we need to verify the existence of - // a matching client cache at shutdown. - // - - #ifdef MATCH - - control -> PersistentCacheCheckOnShutdown = 1; - - #endif - - // - // Flush any data produced so far. - // - - proxy -> handleFlush(); - - #if defined(TEST) || defined(INFO) - - if (proxy -> getFlushable(proxyFD) > 0) - { - *logofs << "Loop: WARNING! Proxy FD#" << proxyFD << " has data " - << "to flush after setup of the NX transport.\n" - << logofs_flush; - } - - #endif - - return 1; -} - -int SetupAuthInstance() -{ - // - // If user gave us a proxy cookie, then create the - // X11 authorization repository and find the real - // cookie to be used for our X display. - // - - if (control -> ProxyMode == proxy_server) - { - if (authCookie != NULL && *authCookie != '\0') - { - if (useLaunchdSocket == 1) - { - // - // If we are going to retrieve the X11 autho- - // rization through the launchd service, make - // a connection to its socket to trigger the - // X server starting. - // - - sockaddr_un launchdAddrUnix; - - unsigned int launchdAddrLength = sizeof(sockaddr_un); - - int launchdAddrFamily = AF_UNIX; - - launchdAddrUnix.sun_family = AF_UNIX; - - const int launchdAddrNameLength = 108; - - int success = -1; - - strncpy(launchdAddrUnix.sun_path, displayHost, launchdAddrNameLength); - - *(launchdAddrUnix.sun_path + launchdAddrNameLength - 1) = '\0'; - - #ifdef TEST - *logofs << "Loop: Connecting to launchd service " - << "on Unix port '" << displayHost << "'.\n" << logofs_flush; - #endif - - int launchdFd = socket(launchdAddrFamily, SOCK_STREAM, PF_UNSPEC); - - if (launchdFd < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to socket failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - } - else if ((success = connect(launchdFd, (sockaddr *) &launchdAddrUnix, launchdAddrLength)) < 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Connection to launchd service " - << "on Unix port '" << displayHost << "' failed " - << "with error " << EGET() << ", '" << ESTR() << "'.\n" - << logofs_flush; - #endif - } - - if (launchdFd >= 0) - { - close(launchdFd); - } - - // - // The real cookie will not be available - // until the X server starts. Query for the - // cookie in a loop, unless the connection - // to the launchd service failed. - // - - int attempts = (success < 0 ? 1 : 10); - - for (int i = 0; i < attempts; i++) - { - delete auth; - - auth = new Auth(displayHost, authCookie); - - if (auth != NULL && auth -> isFake() == 1) - { - usleep(200000); - - continue; - } - - break; - } - } - else - { - auth = new Auth(displayHost, authCookie); - } - - if (auth == NULL || auth -> isValid() != 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating the X authorization.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error creating the X authorization.\n"; - - HandleCleanup(); - } - else if (auth -> isFake() == 1) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Could not retrieve the X server " - << "authentication cookie.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Failed to read data from the X " - << "auth command.\n"; - - cerr << "Warning" << ": Generated a fake cookie for X " - << "authentication.\n"; - } - } - else - { - #ifdef TEST - *logofs << "Loop: No proxy cookie was provided for " - << "authentication.\n" << logofs_flush; - #endif - - cerr << "Info" << ": No proxy cookie was provided for " - << "authentication.\n"; - - #ifdef TEST - *logofs << "Loop: Forwarding the real X authorization " - << "cookie.\n" << logofs_flush; - #endif - - cerr << "Info" << ": Forwarding the real X authorization " - << "cookie.\n"; - } - } - - return 1; -} - -int SetupAgentInstance() -{ - if (control -> ProxyMode == proxy_client && - useAgentSocket == 1) - { - // - // This will temporarily disable signals to safely - // load the cache, then will send a control packet - // to the remote end, telling that cache has to be - // loaded, so it's important that proxy is already - // set in operational state. - // - - int result; - - if (agent != NULL) - { - result = proxy -> handleNewAgentConnection(agent); - } - else - { - result = proxy -> handleNewConnection(channel_x11, agentFD[1]); - } - - if (result < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating the NX agent connection.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error creating the NX agent connection.\n"; - - HandleCleanup(); - } - } - - return 1; -} - -int SetupTcpSocket() -{ - // - // Open TCP socket emulating local display. - // - - return ListenConnectionTCP((loopbackBind ? "localhost" : "*"), X_TCP_PORT + proxyPort, "X11"); -} - -int SetupUnixSocket() -{ - // - // Open UNIX domain socket for display. - // - - if (!control->TempPath) { - #ifdef PANIC - *logofs << "Loop: PANIC! Temporal path is null.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Temporal path is null.\n"; - HandleCleanup(); - } - - unsigned int required = snprintf(unixSocketName, DEFAULT_STRING_LENGTH, "%s/.X11-unix", control->TempPath); - if (required < sizeof(unixSocketName)) { - - // No need to execute the following actions conditionally - mkdir(unixSocketName, (0777 | S_ISVTX)); - chmod(unixSocketName, (0777 | S_ISVTX)); - - required = snprintf(unixSocketName, DEFAULT_STRING_LENGTH, "%s/.X11-unix/X%d", control->TempPath, proxyPort); - if (required < sizeof(unixSocketName)) { - - unixFD = ListenConnectionUnix(unixSocketName, "x11"); - if (unixFD >= 0) - chmod(unixSocketName, 0777); - return unixFD; - } - } - - unixSocketName[0] = '\0'; // Just in case! - - #ifdef PANIC - *logofs << "Loop: PANIC! path for unix socket is too long.\n" << logofs_flush; - #endif - - cerr << "Error" << ": path for Unix socket is too long.\n"; - HandleCleanup(); -} - -// -// The following is a dumb copy-paste. The -// nxcompsh library should offer a better -// implementation. -// - -int SetupDisplaySocket(int &xServerAddrFamily, sockaddr *&xServerAddr, - unsigned int &xServerAddrLength) -{ - xServerAddrFamily = AF_INET; - xServerAddr = NULL; - xServerAddrLength = 0; - - char *display; - - if (*displayHost == '\0') - { - // - // Assume DISPLAY as the X server to which - // we will forward the proxied connections. - // This means that NX parameters have been - // passed through other means. - // - - display = getenv("DISPLAY"); - - if (display == NULL || *display == '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! Host X server DISPLAY is not set.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Host X server DISPLAY is not set.\n"; - - HandleCleanup(); - } - else if (strncasecmp(display, "nx/nx,", 6) == 0 || - strncasecmp(display, "nx,", 3) == 0 || - strncasecmp(display, "nx/nx:", 6) == 0 || - strncasecmp(display, "nx:", 3) == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! NX transport on host X server '" - << display << "' not supported.\n" << logofs_flush; - #endif - - cerr << "Error" << ": NX transport on host X server '" - << display << "' not supported.\n"; - - cerr << "Error" << ": Please run the local proxy specifying " - << "the host X server to connect to.\n"; - - HandleCleanup(); - } - else if (strlen(display) >= DEFAULT_STRING_LENGTH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Host X server DISPLAY cannot exceed " - << DEFAULT_STRING_LENGTH << " characters.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Host X server DISPLAY cannot exceed " - << DEFAULT_STRING_LENGTH << " characters.\n"; - - HandleCleanup(); - } - - strcpy(displayHost, display); - } - - display = new char[strlen(displayHost) + 1]; - - if (display == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Out of memory handling DISPLAY variable.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Out of memory handling DISPLAY variable.\n"; - - HandleCleanup(); - } - - strcpy(display, displayHost); - - #ifdef __APPLE__ - - if ((strncasecmp(display, "/tmp/launch", 11) == 0) || (strncasecmp(display, "/private/tmp/com.apple.launchd", 30) == 0)) - { - #ifdef TEST - *logofs << "Loop: Using launchd service on socket '" - << display << "'.\n" << logofs_flush; - #endif - - useLaunchdSocket = 1; - } - - #endif - - char *separator = strrchr(display, ':'); - - if ((separator == NULL) || !isdigit(*(separator + 1))) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid display '" << display << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid display '" << display << "'.\n"; - - HandleCleanup(); - } - - *separator = '\0'; - - xPort = atoi(separator + 1); - - #ifdef TEST - *logofs << "Loop: Using local X display '" << displayHost - << "' with host '" << display << "' and port '" - << xPort << "'.\n" << logofs_flush; - #endif - - #ifdef __APPLE__ - - if (separator == display || strcmp(display, "unix") == 0 || - useLaunchdSocket == 1) - - #else - - if (separator == display || strcmp(display, "unix") == 0) - - #endif - { - // - // UNIX domain port. - // - - #ifdef TEST - *logofs << "Loop: Using real X server on UNIX domain socket.\n" - << logofs_flush; - #endif - - sockaddr_un *xServerAddrUNIX = new sockaddr_un; - - xServerAddrFamily = AF_UNIX; - xServerAddrUNIX -> sun_family = AF_UNIX; - - // - // The scope of this function is to fill either the sockaddr_un - // (when the display is set to the Unix Domain socket) or the - // sockaddr_in structure (when connecting by TCP) only once, so - // that the structure will be later used at the time the server - // proxy will try to forward the connection to the X server. We - // don't need to verify that the socket does exist at the pre- - // sent moment. The method that forwards the connection will - // perform the required checks and will retry, if needed. Anyway - // we need to select the name of the socket, so we check if the - // well-known directory exists and take that as an indication of - // where the socket will be created. - // - - // Try abstract X11 socket first (via a test connect), if that fails - // fall back to Unix domain socket file. - - #ifdef __linux__ - int testSocketFD; - testSocketFD = socket(xServerAddrFamily, SOCK_STREAM, PF_UNSPEC); - - int len = sprintf(unixSocketName + 1, "/tmp/.X11-unix/X%d", xPort); - unixSocketName[0] = '\0'; - - sockaddr_un *xServerAddrABSTRACT = new sockaddr_un; - memset(xServerAddrABSTRACT, 0, xServerAddrLength); - xServerAddrABSTRACT -> sun_family = AF_UNIX; - memcpy(xServerAddrABSTRACT -> sun_path, unixSocketName, len+1); - xServerAddrLength = len +3; - - int ret = connect(testSocketFD, (struct sockaddr *) xServerAddrABSTRACT, xServerAddrLength); - if (ret == 0) { - - cerr << "Info" << ": Using abstract X11 socket in kernel namespace " - << "for accessing DISPLAY=:" << xPort << ".\n"; - - close(testSocketFD); - xServerAddr = (sockaddr *) xServerAddrABSTRACT; - return 1; - - } else { - - cerr << "Info" << ": Falling back to file system X11 socket " - << "for accessing DISPLAY=:" << xPort << ".\n"; - - #endif - - struct stat statInfo; - - char unixSocketDir[DEFAULT_STRING_LENGTH]; - - snprintf(unixSocketDir, DEFAULT_STRING_LENGTH - 1, "%s/.X11-unix", - control -> TempPath); - - #ifdef __APPLE__ - - if (useLaunchdSocket == 1) - { - char *slash = rindex(display, '/'); - - if (slash != NULL) - { - *slash = '\0'; - } - - snprintf(unixSocketDir, DEFAULT_STRING_LENGTH - 1, "%s", display); - } - - #endif - - *(unixSocketDir + DEFAULT_STRING_LENGTH - 1) = '\0'; - - #ifdef TEST - *logofs << "Loop: Assuming X socket in directory '" - << unixSocketDir << "'.\n" << logofs_flush; - #endif - - if (stat(unixSocketDir, &statInfo) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't determine the location of " - << "the X display socket.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't determine the location of " - << "the X display socket.\n"; - - #ifdef PANIC - *logofs << "Loop: PANIC! Error " << EGET() << " '" << ESTR() - << "' checking '" << unixSocketDir << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error " << EGET() << " '" << ESTR() - << "' checking '" << unixSocketDir << "'.\n"; - - HandleCleanup(); - } - - sprintf(unixSocketName, "%s/X%d", unixSocketDir, xPort); - - #ifdef __APPLE__ - - if (useLaunchdSocket == 1) - { - strncpy(unixSocketName, displayHost, DEFAULT_STRING_LENGTH - 1); - } - - #endif - - #ifdef TEST - *logofs << "Loop: Assuming X socket name '" << unixSocketName - << "'.\n" << logofs_flush; - #endif - - strcpy(xServerAddrUNIX -> sun_path, unixSocketName); - - xServerAddr = (sockaddr *) xServerAddrUNIX; - xServerAddrLength = sizeof(sockaddr_un); - - #ifdef __linux__ - - } - #endif - } - else - { - // - // TCP port. - // - - #ifdef TEST - *logofs << "Loop: Using real X server on TCP port.\n" - << logofs_flush; - #endif - - xServerAddrFamily = AF_INET; - - int xServerIPAddr = GetHostAddress(display); - - if (xServerIPAddr == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Unknown display host '" << display - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unknown display host '" << display - << "'.\n"; - - HandleCleanup(); - } - - sockaddr_in *xServerAddrTCP = new sockaddr_in; - - xServerAddrTCP -> sin_family = AF_INET; - xServerAddrTCP -> sin_port = htons(X_TCP_PORT + xPort); - xServerAddrTCP -> sin_addr.s_addr = xServerIPAddr; - - xServerAddr = (sockaddr *) xServerAddrTCP; - xServerAddrLength = sizeof(sockaddr_in); - } - - delete [] display; - - return 1; -} - -int SetupServiceSockets() -{ - if (control -> ProxyMode == proxy_client) - { - if (useCupsSocket) - { - if ((cupsFD = ListenConnection(cupsPort, "CUPS")) < 0) - { - useCupsSocket = 0; - } - } - - if (useAuxSocket) - { - if ((auxFD = ListenConnection(auxPort, "auxiliary X11")) < 0) - { - useAuxSocket = 0; - } - } - - if (useSmbSocket) - { - if ((smbFD = ListenConnection(smbPort, "SMB")) < 0) - { - useSmbSocket = 0; - } - } - - if (useMediaSocket) - { - if ((mediaFD = ListenConnection(mediaPort, "media")) < 0) - { - useMediaSocket = 0; - } - } - - if (useHttpSocket) - { - if ((httpFD = ListenConnection(httpPort, "http")) < 0) - { - useHttpSocket = 0; - } - } - - useFontSocket = 0; - } - else - { - // - // Get ready to listen for the font server connections - // - - if (useFontSocket) - { - // Since ProtoStep7 (#issue 108) - int port = atoi(fontPort); - - if ((fontFD = ListenConnectionTCP("localhost", port, "font")) < 0) - { - useFontSocket = 0; - } - } - - useCupsSocket = 0; - useAuxSocket = 0; - useSmbSocket = 0; - useMediaSocket = 0; - useHttpSocket = 0; - } - - // - // Slave channels can be originated - // by both sides. - // - - if (useSlaveSocket) - { - // Since ProtoStep7 (#issue 108) - if ((slaveFD = ListenConnection(slavePort, "slave")) < 0) - { - useSlaveSocket = 0; - } - } - - return 1; -} - -int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label) -{ - int newFD = socket(addr->sa_family, SOCK_STREAM, PF_UNSPEC); - - if (newFD == -1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to socket failed for " << label - << " socket. Error is " << EGET() << " '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to socket failed for " << label - << " socket. Error is " << EGET() << " '" - << ESTR() << "'.\n"; - - 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) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to bind failed for " << label - << ". Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to bind failed for " << label - << ". Error is " << EGET() - << " '" << ESTR() << "'.\n"; - goto SetupSocketError; - } - - if (listen(newFD, 8) == -1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to listen failed for " << label - << ". Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to listen failed for " << label - << ". Error is " << EGET() - << " '" << ESTR() << "'.\n"; - - goto SetupSocketError; - } - - return newFD; - -SetupSocketError: - - if (newFD != -1) - { - close(newFD); - } - - // - // May optionally return. The session would - // continue without the service. The problem - // with this approach is that it would make - // harder to track problems with allocation - // of ports in clients and server. - // - - 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 (loopbackBind || - !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) -{ - struct sockaddr newAddr; - - socklen_t addrLen = sizeof(newAddr); - - #ifdef TEST - - if (domain == AF_UNIX) - { - *logofs << "Loop: Going to accept new Unix " << label - << " connection on FD#" << fd << ".\n" - << logofs_flush; - } - else - { - *logofs << "Loop: Going to accept new TCP " << label - << " connection on FD#" << fd << ".\n" - << logofs_flush; - } - - #endif - - int newFD = accept(fd, &newAddr, &addrLen); - - if (newFD < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to accept failed for " - << label << " connection. Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to accept failed for " - << label << " connection. Error is " << EGET() - << " '" << ESTR() << "'.\n"; - } - - return newFD; -} - -void HandleShutdown() -{ - if (proxy -> getShutdown() == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! No shutdown of proxy link " - << "performed by remote proxy.\n" - << logofs_flush; - #endif - - // - // Close the socket before showing the alert. - // It seems that the closure of the socket can - // sometimes take several seconds, even after - // the connection is broken. The result is that - // the dialog can be shown long after the user - // has gone after the failed session. Note that - // disabling the linger timeout does not seem - // to make any difference. - // - - CleanupSockets(); - - cerr << "Error" << ": Connection with remote peer broken.\n"; - - #ifdef TEST - *logofs << "Loop: Bytes received so far are " - << (unsigned long long) statistics -> getBytesIn() - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Please check the state of your " - << "network and retry.\n"; - - handleTerminatingInLoop(); - - if (control -> ProxyMode == proxy_server) - { - #ifdef TEST - *logofs << "Loop: Showing the proxy abort dialog.\n" - << logofs_flush; - #endif - - HandleAlert(ABORT_PROXY_CONNECTION_ALERT, 1); - - handleAlertInLoop(); - } - } - #ifdef TEST - else - { - *logofs << "Loop: Finalized the remote proxy shutdown.\n" - << logofs_flush; - } - #endif - - HandleCleanup(); -} - - -void WaitCleanup() -{ - T_timestamp selectTs; - - while (NXTransRunning(NX_FD_ANY)) - { - setTimestamp(selectTs, control -> PingTimeout); - - NXTransContinue(&selectTs); - } -} - -int KillProcess(int pid, const char *label, int signal, int wait) -{ - if (pid > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Killing the " << label << " process '" - << pid << "' from process with pid '" << getpid() - << "' with signal '" << DumpSignal(signal) - << "'.\n" << logofs_flush; - #endif - - signal = (signal == 0 ? SIGTERM : signal); - - if (kill(pid, signal) < 0 && EGET() != ESRCH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Couldn't kill the " << label - << " process with pid '" << pid << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Couldn't kill the " << label - << " process with pid '" << pid << "'.\n"; - } - - if (wait == 1) - { - WaitChild(pid, label, 1); - } - - return 1; - } - else - { - #ifdef TEST - *logofs << "Loop: No " << label << " process " - << "to kill with pid '" << pid - << "'.\n" << logofs_flush; - #endif - - return 0; - } -} - -int CheckProcess(int pid, const char *label) -{ - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Checking the " << label << " process '" - << pid << "' from process with pid '" << getpid() - << "'.\n" << logofs_flush; - #endif - - if (kill(pid, SIGCONT) < 0 && EGET() == ESRCH) - { - #ifdef WARNING - *logofs << "Loop: WARNING! The " << label << " process " - << "with pid '" << pid << "' has exited.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": The " << label << " process " - << "with pid '" << pid << "' has exited.\n"; - - return 0; - } - - return 1; -} - -int StartKeeper() -{ - #if defined(TEST) || defined(INFO) - - if (IsRunning(lastKeeper) == 1 || - IsRestarting(lastKeeper) == 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! The house-keeping process is " - << "alreay running with pid '" << lastKeeper - << "'.\n" << logofs_flush; - #endif - - HandleCleanup(); - } - - #endif - - // - // Don't care harvesting the persistent caches if - // the memory cache is not enabled. If the memory - // cache is not enabled neither we produced per- - // sistent caches. The user can still delete any - // persistent cache produced by the previous runs - // by using the client GUI. - // - // TODO: At the moment the user doesn't have a way - // to specify the amount of disk space to use for - // the persistent caches, but only the amount of - // space to use for images. - // - - if (control -> LocalTotalStorageSize > 0) - { - #ifdef TEST - *logofs << "Loop: Starting the house-keeping process with " - << "storage size " << control -> PersistentCacheDiskLimit - << ".\n" << logofs_flush; - #endif - - lastKeeper = NXTransKeeper(control -> PersistentCacheDiskLimit, - 0, control -> RootPath); - - if (IsFailed(lastKeeper)) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Failed to start the NX keeper process.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Failed to start the NX keeper process.\n"; - - SetNotRunning(lastKeeper); - } - #ifdef TEST - else - { - *logofs << "Loop: Keeper started with pid '" - << lastKeeper << "'.\n" << logofs_flush; - } - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Nothing to do for the keeper process " - << "with persistent cache not enabled.\n" - << logofs_flush; - } - #endif - - return 1; -} - -void HandleCleanupForReconnect() -{ - #ifdef TEST - *logofs << "Loop: Going to clean up system resources for Reconnect " - << "in process '" << getpid() << "'.\n" - << logofs_flush; - #endif - handleTerminatedInLoop(); - DisableSignals(); - if (control) - CleanupChildren(); - CleanupListeners(); - CleanupSockets(); - CleanupKeeper(); - CleanupStreams(); - CleanupLocal(); - CleanupGlobal(); - RestoreSignals(); - ServerCache::lastInitReply.set(0,NULL); - ServerCache::lastKeymap.set(0,NULL); - ServerCache::getKeyboardMappingLastMap.set(0,NULL); -} -void HandleCleanup(int code) -{ - #ifdef TEST - *logofs << "Loop: Going to clean up system resources " - << "in process '" << getpid() << "'.\n" - << logofs_flush; - #endif - - handleTerminatedInLoop(); - - // - // Suspend any signal while cleaning up. - // - - DisableSignals(); - - if (getpid() == lastProxy) - { - // - // Terminate all the children. - // - - CleanupChildren(); - - // - // Close all listeners. - // - - CleanupListeners(); - - // - // Close all sockets. - // - - CleanupSockets(); - - // - // Release the global objects. - // - - CleanupGlobal(); - - // - // Restore the original signal handlers. - // - - RestoreSignals(); - } - - // - // This is our last chance to print a message. If this - // is the process which created the transport we will - // jump back into the loop, letting the caller find out - // that the connection is broken, otherwise we assume - // that this is a child of the proxy and so we will - // safely exit. - // - - #ifdef TEST - - if (getpid() == lastProxy) - { - *logofs << "Loop: Reverting to loop context in process with " - << "pid '" << getpid() << "' at " << strMsTimestamp() - << ".\n" << logofs_flush; - } - else - { - *logofs << "Loop: Exiting from child process with pid '" - << getpid() << "' at " << strMsTimestamp() - << ".\n" << logofs_flush; - } - - #endif - - if (getpid() == lastProxy) - { - // - // Reset all values to their default. - // - - CleanupLocal(); - - CleanupStreams(); - - longjmp(context, 1); - } - else - { - // - // Give a last chance to the process - // to cleanup the ancillary classes. - // - - CleanupKeeper(); - - CleanupStreams(); - - exit(code); - } -} - -void CleanupKeeper() -{ - if (keeper != NULL) - { - #ifdef TEST - *logofs << "Loop: Freeing up keeper in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - delete keeper; - - keeper = NULL; - } -} - -void CleanupStreams() -{ - // - // TODO: The cleanup procedure skips deletion of - // the I/O streams under Windows. This is intended - // to avoid a strange segfault occurring randomly, - // at the time the proxy is being shut down. - // - - #ifndef __CYGWIN32__ - - #ifdef TEST - *logofs << "Loop: Freeing up streams in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - if (logofs != NULL && logofs != &cerr && - *errorsFileName != '\0') - { - *logofs << flush; - - delete logofs; - - // - // Let the log go again to the standard - // error. - // - - logofs = &cerr; - } - - if (statofs != NULL && statofs != &cerr && - *statsFileName != '\0') - { - *statofs << flush; - - delete statofs; - - statofs = NULL; - } - - if (errofs != NULL) - { - *errofs << flush; - - if (errofs == &cerr) - { - errofs = NULL; - } - else if (errsbuf != NULL) - { - cerr.rdbuf(errsbuf); - - errsbuf = NULL; - - delete errofs; - } - - errofs = NULL; - } - - #endif /* #ifndef __CYGWIN32__ */ - - // - // Reset these as they can't be reset - // in CleanupLocal(). - // - - *sessionFileName = '\0'; - *errorsFileName = '\0'; - *optionsFileName = '\0'; - *statsFileName = '\0'; -} - -void CleanupChildren() -{ - // - // Remove any watchdog. - // - - if (IsRunning(lastWatchdog)) - { - KillProcess(lastWatchdog, "watchdog", SIGTERM, 1); - - SetNotRunning(lastWatchdog); - - lastSignal = 0; - } - - // - // Kill the cache house-keeping process. - // - - if (IsRunning(lastKeeper)) - { - KillProcess(lastKeeper, "house-keeping", SIGTERM, 1); - - SetNotRunning(lastKeeper); - } - - // - // Let any running dialog to continue until it is - // closed by the user. In general this is the exp- - // ected behaviour, as for example when we are - // exiting because the link was abrouptedly shut - // down. - // - - if (IsRunning(lastDialog)) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: WARNING! Leaving the dialog process '" - << lastDialog << "' running in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - SetNotRunning(lastDialog); - } - - // - // Give user a chance to start a new session. - // - - if (control -> EnableRestartOnShutdown == 1) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Respawning the NX client " - << "on display '" << displayHost << "'.\n" - << logofs_flush; - #endif - - NXTransClient(displayHost); - } - - for (int i = 0; i < control -> KillDaemonOnShutdownNumber; i++) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Killing the NX daemon with " - << "pid '" << control -> KillDaemonOnShutdown[i] - << "'.\n" << logofs_flush; - #endif - - KillProcess(control -> KillDaemonOnShutdown[i], "daemon", SIGTERM, 0); - } -} - -void CleanupGlobal() -{ - if (proxy != NULL) - { - #ifdef TEST - *logofs << "Loop: Freeing up proxy in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - delete proxy; - - proxy = NULL; - } - - if (agent != NULL) - { - #ifdef TEST - *logofs << "Loop: Freeing up agent in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - delete agent; - - agent = NULL; - } - - if (auth != NULL) - { - #ifdef TEST - *logofs << "Loop: Freeing up auth data in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - delete auth; - - auth = NULL; - } - - if (statistics != NULL) - { - #ifdef TEST - *logofs << "Loop: Freeing up statistics in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - delete statistics; - - statistics = NULL; - } - - if (control != NULL) - { - #ifdef TEST - *logofs << "Loop: Freeing up control in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - delete control; - - control = NULL; - } -} - -void CleanupConnections() -{ - if (proxy -> getChannels(channel_x11) != 0) - { - #ifdef TEST - *logofs << "Loop: Closing any remaining X connections.\n" - << logofs_flush; - #endif - - proxy -> handleCloseAllXConnections(); - - #ifdef TEST - *logofs << "Loop: Closing any remaining listener.\n" - << logofs_flush; - #endif - - proxy -> handleCloseAllListeners(); - } - - proxy -> handleFinish(); -} - -void CleanupListeners() -{ - if (useTcpSocket == 1) - { - if (tcpFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing TCP listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(tcpFD); - - tcpFD = -1; - } - - useTcpSocket = 0; - } - - if (useUnixSocket == 1) - { - if (unixFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing UNIX listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(unixFD); - - unixFD = -1; - } - - if (*unixSocketName != '\0') - { - #ifdef TEST - *logofs << "Loop: Going to remove the Unix domain socket '" - << unixSocketName << "' in process " << "with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - unlink(unixSocketName); - } - - useUnixSocket = 0; - } - - if (useAgentSocket == 1) - { - // - // There is no listener for the - // agent descriptor. - // - - useAgentSocket = 0; - } - - if (useCupsSocket == 1) - { - if (cupsFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing CUPS listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(cupsFD); - - cupsFD = -1; - } - - useCupsSocket = 0; - } - - if (useAuxSocket == 1) - { - if (auxFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing auxiliary X11 listener " - << "in process " << "with pid '" << getpid() - << "'.\n" << logofs_flush; - #endif - - close(auxFD); - - auxFD = -1; - } - - useAuxSocket = 0; - } - - if (useSmbSocket == 1) - { - if (smbFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing SMB listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(smbFD); - - smbFD = -1; - } - - useSmbSocket = 0; - } - - if (useMediaSocket == 1) - { - if (mediaFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing multimedia listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(mediaFD); - - mediaFD = -1; - } - - useMediaSocket = 0; - } - - if (useHttpSocket == 1) - { - if (httpFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing http listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(httpFD); - - httpFD = -1; - } - - useHttpSocket = 0; - } - - if (useFontSocket == 1) - { - if (fontFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing font server listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(fontFD); - - fontFD = -1; - } - - useFontSocket = 0; - } - - if (useSlaveSocket == 1) - { - if (slaveFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing slave listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(slaveFD); - - slaveFD = -1; - } - - useSlaveSocket = 0; - } -} - -void CleanupSockets() -{ - if (proxyFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing proxy FD in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(proxyFD); - - proxyFD = -1; - } - - if (agentFD[1] != -1) - { - #ifdef TEST - *logofs << "Loop: Closing agent FD in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(agentFD[1]); - - agentFD[0] = -1; - agentFD[1] = -1; - } -} - -void CleanupLocal() -{ - *homeDir = '\0'; - *rootDir = '\0'; - *tempDir = '\0'; - *systemDir = '\0'; - *sessionDir = '\0'; - - *linkSpeedName = '\0'; - *cacheSizeName = '\0'; - *shsegSizeName = '\0'; - *imagesSizeName = '\0'; - *bitrateLimitName = '\0'; - *packMethodName = '\0'; - *productName = '\0'; - - packMethod = -1; - packQuality = -1; - - *sessionType = '\0'; - *sessionId = '\0'; - - parsedOptions = 0; - parsedCommand = 0; - - *remoteData = '\0'; - remotePosition = 0; - - tcpFD = -1; - unixFD = -1; - cupsFD = -1; - auxFD = -1; - smbFD = -1; - mediaFD = -1; - httpFD = -1; - fontFD = -1; - slaveFD = -1; - proxyFD = -1; - - agentFD[0] = -1; - agentFD[1] = -1; - - useUnixSocket = 1; - useTcpSocket = 1; - useCupsSocket = 0; - useAuxSocket = 0; - useSmbSocket = 0; - useMediaSocket = 0; - useHttpSocket = 0; - useFontSocket = 0; - useSlaveSocket = 0; - useAgentSocket = 0; - - useNoDelay = -1; - usePolicy = -1; - useRender = -1; - useTaint = -1; - - *unixSocketName = '\0'; - - *acceptHost = '\0'; - *displayHost = '\0'; - *authCookie = '\0'; - - proxyPort = DEFAULT_NX_PROXY_PORT; - xPort = DEFAULT_NX_X_PORT; - - xServerAddrFamily = -1; - xServerAddrLength = 0; - - delete xServerAddr; - - xServerAddr = NULL; - - listenSocket.disable(); - connectSocket.disable(); - - cupsPort.disable(); - auxPort.disable(); - smbPort.disable(); - mediaPort.disable(); - httpPort.disable(); - slavePort.disable(); - - *fontPort = '\0'; - - *bindHost = '\0'; - bindPort = -1; - - initTs = nullTimestamp(); - startTs = nullTimestamp(); - logsTs = nullTimestamp(); - nowTs = nullTimestamp(); - - diffTs = 0; - - lastProxy = 0; - lastDialog = 0; - lastWatchdog = 0; - lastKeeper = 0; - lastStatus = 0; - lastKill = 0; - lastDestroy = 0; - - lastReadableTs = nullTimestamp(); - - lastAlert.code = 0; - lastAlert.local = 0; - - lastMasks.blocked = 0; - lastMasks.installed = 0; - - memset(&lastMasks.saved, 0, sizeof(sigset_t)); - - for (int i = 0; i < 32; i++) - { - lastMasks.enabled[i] = 0; - lastMasks.forward[i] = 0; - - memset(&lastMasks.action[i], 0, sizeof(struct sigaction)); - } - - lastSignal = 0; - - memset(&lastTimer.action, 0, sizeof(struct sigaction)); - memset(&lastTimer.value, 0, sizeof(struct itimerval)); - - lastTimer.start = nullTimestamp(); - lastTimer.next = nullTimestamp(); -} - -int CheckAbort() -{ - if (lastSignal != 0) - { - #ifdef TEST - *logofs << "Loop: Aborting the procedure due to signal '" - << lastSignal << "', '" << DumpSignal(lastSignal) - << "'.\n" << logofs_flush; - #endif - - cerr << "Info" << ": Aborting the procedure due to signal '" - << lastSignal << "'.\n"; - - lastSignal = 0; - - return 1; - } - - return 0; -} - -void HandleAbort() -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - *logofs << flush; - - handleTerminatingInLoop(); - - if (lastSignal == SIGHUP) - { - lastSignal = 0; - } - - // - // The current default is to just quit the program. - // Code has not been updated to deal with the new - // NX transport loop. - // - - if (control -> EnableCoreDumpOnAbort == 1) - { - if (agent != NULL) - { - cerr << "Session" << ": Terminating session at '" - << strTimestamp() << "'.\n"; - } - - cerr << "Error" << ": Generating a core file to help " - << "the investigations.\n"; - - cerr << "Session" << ": Session terminated at '" - << strTimestamp() << "'.\n"; - - cerr << flush; - - signal(SIGABRT, SIG_DFL); - - raise(SIGABRT); - } - - #ifdef TEST - *logofs << "Loop: Showing the proxy abort dialog.\n" - << logofs_flush; - #endif - - if (control -> ProxyMode == proxy_server) - { - // - // Close the socket before showing the alert. - // It seems that the closure of the socket can - // sometimes take several seconds, even after - // the connection is broken. - // - - CleanupSockets(); - - if (lastKill == 0) - { - HandleAlert(ABORT_PROXY_CONNECTION_ALERT, 1); - } - else - { - HandleAlert(ABORT_PROXY_SHUTDOWN_ALERT, 1); - } - - handleAlertInLoop(); - } - - HandleCleanup(); -} - -void HandleAlert(int code, int local) -{ - if (lastAlert.code == 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Requesting an alert dialog with code " - << code << " and local " << local << ".\n" - << logofs_flush; - #endif - - lastAlert.code = code; - lastAlert.local = local; - } - #if defined(TEST) || defined(INFO) - else - { - *logofs << "Loop: WARNING! Alert dialog already requested " - << "with code " << lastAlert.code << ".\n" - << logofs_flush; - } - #endif - - return; -} - -void FlushCallback(int length) -{ - if (flushCallback != NULL) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Reporting a flush request at " - << strMsTimestamp() << " with " << length - << " bytes written.\n" << logofs_flush; - #endif - - (*flushCallback)(flushParameter, length); - } - #if defined(TEST) || defined(INFO) - else if (control -> ProxyMode == proxy_client) - { - *logofs << "Loop: WARNING! Can't find a flush " - << "callback in process with pid '" << getpid() - << "'.\n" << logofs_flush; - } - #endif -} - -void KeeperCallback() -{ - if (IsRunning(lastKeeper) == 0) - { - // - // Let the house-keeping process take care - // of the persistent image cache. - // - - if (control -> ImageCacheEnableLoad == 1 || - control -> ImageCacheEnableSave == 1) - { - #ifdef TEST - *logofs << "Loop: Starting the house-keeping process with " - << "image storage size " << control -> ImageCacheDiskLimit - << ".\n" << logofs_flush; - #endif - - lastKeeper = NXTransKeeper(0, control -> ImageCacheDiskLimit, - control -> RootPath); - - if (IsFailed(lastKeeper)) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Can't start the NX keeper process.\n" - << logofs_flush; - #endif - - SetNotRunning(lastKeeper); - } - #ifdef TEST - else - { - *logofs << "Loop: Keeper started with pid '" - << lastKeeper << "'.\n" << logofs_flush; - } - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Nothing to do for the keeper process " - << "with image cache not enabled.\n" - << logofs_flush; - } - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Nothing to do with the keeper process " - << "already running.\n" << logofs_flush; - } - #endif -} - -void InstallSignals() -{ - #ifdef TEST - *logofs << "Loop: Installing signals in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - for (int i = 0; i < 32; i++) - { - if (CheckSignal(i) == 1 && - lastMasks.enabled[i] == 0) - { - InstallSignal(i, NX_SIGNAL_ENABLE); - } - } - - lastMasks.installed = 1; -} - -void RestoreSignals() -{ - #ifdef TEST - *logofs << "Loop: Restoring signals in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - if (lastMasks.installed == 1) - { - // - // Need to keep monitoring the children. - // - - for (int i = 0; i < 32; i++) - { - if (lastMasks.enabled[i] == 1) - { - RestoreSignal(i); - } - } - } - - lastMasks.installed = 0; - - if (lastMasks.blocked == 1) - { - EnableSignals(); - } -} - -void DisableSignals() -{ - if (lastMasks.blocked == 0) - { - sigset_t newMask; - - sigemptyset(&newMask); - - // - // Block also the other signals that may be - // installed by the agent, that are those - // signals for which the function returns 2. - // - - for (int i = 0; i < 32; i++) - { - if (CheckSignal(i) > 0) - { - #ifdef DUMP - *logofs << "Loop: Disabling signal " << i << " '" - << DumpSignal(i) << "' in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - sigaddset(&newMask, i); - } - } - - sigprocmask(SIG_BLOCK, &newMask, &lastMasks.saved); - - lastMasks.blocked++; - } - #ifdef TEST - else - { - *logofs << "Loop: WARNING! Signals were already blocked in " - << "process with pid '" << getpid() << "'.\n" - << logofs_flush; - } - #endif -} - -void EnableSignals() -{ - if (lastMasks.blocked == 1) - { - #ifdef TEST - *logofs << "Loop: Enabling signals in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - sigprocmask(SIG_SETMASK, &lastMasks.saved, NULL); - - lastMasks.blocked = 0; - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Signals were not blocked in " - << "process with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Signals were not blocked in " - << "process with pid '" << getpid() << "'.\n"; - } -} - -void InstallSignal(int signal, int action) -{ - if (lastMasks.enabled[signal] == 1) - { - if (action == NX_SIGNAL_FORWARD) - { - #ifdef TEST - *logofs << "Loop: Forwarding handler for signal " << signal - << " '" << DumpSignal(signal) << "' in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - lastMasks.forward[signal] = 1; - - return; - } - #ifdef TEST - else - { - *logofs << "Loop: Reinstalling handler for signal " << signal - << " '" << DumpSignal(signal) << "' in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - } - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Installing handler for signal " << signal - << " '" << DumpSignal(signal) << "' in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - } - #endif - - if (signal == SIGALRM && isTimestamp(lastTimer.start)) - { - ResetTimer(); - } - - struct sigaction newAction; - - memset(&newAction, 0, sizeof(newAction)); - - newAction.sa_handler = HandleSignal; - - sigemptyset(&(newAction.sa_mask)); - - if (signal == SIGCHLD) - { - newAction.sa_flags = SA_NOCLDSTOP; - } - else - { - newAction.sa_flags = 0; - } - - sigaction(signal, &newAction, &lastMasks.action[signal]); - - lastMasks.enabled[signal] = 1; - - if (action == NX_SIGNAL_FORWARD) - { - lastMasks.forward[signal] = 1; - } -} - -void RestoreSignal(int signal) -{ - if (lastMasks.enabled[signal] == 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Signal '" << DumpSignal(signal) - << " not installed in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Signal '" << DumpSignal(signal) - << " not installed in process with pid '" - << getpid() << "'.\n"; - - return; - } - - #ifdef TEST - *logofs << "Loop: Restoring handler for signal " << signal - << " '" << DumpSignal(signal) << "' in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - if (signal == SIGALRM && isTimestamp(lastTimer.start)) - { - ResetTimer(); - } - - sigaction(signal, &lastMasks.action[signal], NULL); - - lastMasks.enabled[signal] = 0; - lastMasks.forward[signal] = 0; -} - -void HandleSignal(int signal) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - #if defined(UNSAFE) && (defined(TEST) || defined(INFO)) - - if (lastSignal != 0) - { - *logofs << "Loop: WARNING! Last signal is '" << lastSignal - << "', '" << DumpSignal(signal) << "' and not zero " - << "in process with pid '" << getpid() << "'.\n" - << logofs_flush; - } - - *logofs << "Loop: Signal '" << signal << "', '" - << DumpSignal(signal) << "' received in process " - << "with pid '" << getpid() << "'.\n" << logofs_flush; - - #endif - - if (getpid() != lastProxy && handler != NULL) - { - #if defined(UNSAFE) && (defined(TEST) || defined(INFO)) - *logofs << "Loop: Calling slave handler in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - if ((*handler)(signal) == 0) - { - return; - } - } - - switch (signal) - { - case SIGUSR1: - { - if (proxy != NULL && lastSignal == 0) - { - lastSignal = SIGUSR1; - } - - break; - } - case SIGUSR2: - { - if (proxy != NULL && lastSignal == 0) - { - lastSignal = SIGUSR2; - } - - break; - } - case SIGPIPE: - { - // - // It can happen that SIGPIPE is delivered - // to the proxy even in the case some other - // descriptor is unexpectedly closed. - // - // if (agentFD[1] != -1) - // { - // cerr << "Info" << ": Received signal 'SIGPIPE'. " - // << "Closing agent conection.\n"; - // - // shutdown(agentFD[1], SHUT_RDWR); - // } - // - - break; - } - case SIGALRM: - { - // - // Nothing to do. Just wake up the - // process on blocking operations. - // - - break; - } - case SIGCHLD: - { - // - // Check if any of our children has exited. - // - - if (HandleChildren() != 0) - { - signal = 0; - } - - // - // Don't save this signal or it will override - // any previous signal sent by child before - // exiting. - // - - break; - } - - #ifdef __CYGWIN32__ - - case 12: - { - // - // Nothing to do. This signal is what is delivered - // by the Cygwin library when trying use a shared - // memory function if the daemon is not running. - // - - #ifdef TEST - *logofs << "Loop: WARNING! Received signal '12' in " - << "process with pid '" << getpid() << "'.\n" - << logofs_flush; - - *logofs << "Loop: WARNING! Please check that the " - << "cygserver daemon is running.\n" - << logofs_flush; - #endif - - break; - } - - #endif - - default: - { - // - // Register the signal so we can handle it - // inside the main loop. We will probably - // dispose any resource and exit. - // - - if (getpid() == lastProxy) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Registering end of session request " - << "due to signal '" << signal << "', '" - << DumpSignal(signal) << "'.\n" - << logofs_flush; - #endif - - lastSignal = signal; - } - else - { - // - // This is a child, so exit immediately. - // - - HandleCleanup(); - } - } - } - - if (signal != 0 && lastMasks.forward[signal] == 1) - { - if (lastMasks.action[signal].sa_handler != NULL && - lastMasks.action[signal].sa_handler != HandleSignal) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Forwarding signal '" << signal << "', '" - << DumpSignal(signal) << "' to previous handler.\n" - << logofs_flush; - #endif - - lastMasks.action[signal].sa_handler(signal); - } - #ifdef WARNING - else if (lastMasks.action[signal].sa_handler == NULL) - { - *logofs << "Loop: WARNING! Parent requested to forward " - << "signal '" << signal << "', '" << DumpSignal(signal) - << "' but didn't set a handler.\n" << logofs_flush; - } - #endif - } -} - -int HandleChildren() -{ - // - // Try to waitpid() for each child because the - // call might have return ECHILD and so we may - // have lost any of the processes. - // - - if (IsRunning(lastDialog) && HandleChild(lastDialog) == 1) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Resetting pid of last dialog process " - << "in handler.\n" << logofs_flush; - #endif - - SetNotRunning(lastDialog); - - if (proxy != NULL) - { - proxy -> handleResetAlert(); - } - - return 1; - } - - if (IsRunning(lastWatchdog) && HandleChild(lastWatchdog) == 1) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Watchdog is gone. Setting the last " - << "signal to SIGHUP.\n" << logofs_flush; - #endif - - lastSignal = SIGHUP; - - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Resetting pid of last watchdog process " - << "in handler.\n" << logofs_flush; - #endif - - SetNotRunning(lastWatchdog); - - return 1; - } - - // - // The house-keeping process exits after a - // number of iterations to keep the memory - // pollution low. It is restarted on demand - // by the lower layers, using the callback - // function. - // - - if (IsRunning(lastKeeper) && HandleChild(lastKeeper) == 1) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Resetting pid of last house-keeping " - << "process in handler.\n" << logofs_flush; - #endif - - SetNotRunning(lastKeeper); - - return 1; - } - - // - // The pid will be checked by the code - // that registered the child. - // - - if (IsRunning(lastChild)) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Resetting pid of last child process " - << "in handler.\n" << logofs_flush; - #endif - - SetNotRunning(lastChild); - - return 1; - } - - proxy->checkSlaves(); - - // - // This can actually happen either because we - // reset the pid of the child process as soon - // as we kill it, or because of a child process - // of our parent. - // - - #if defined(UNSAFE) && (defined(TEST) || defined(INFO)) - *logofs << "Loop: Ignoring signal received for the " - << "unregistered child.\n" << logofs_flush; - #endif - - return 0; -} - -int HandleChild(int child) -{ - int pid; - - int status = 0; - int options = WNOHANG | WUNTRACED; - - while ((pid = waitpid(child, &status, options)) && - pid == -1 && EGET() == EINTR); - - return CheckChild(pid, status); -} - -int WaitChild(int child, const char* label, int force) -{ - int pid; - - int status = 0; - int options = WUNTRACED; - - for (;;) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Waiting for the " << label - << " process '" << child << "' to die.\n" - << logofs_flush; - #endif - - pid = waitpid(child, &status, options); - - if (pid == -1 && EGET() == EINTR) - { - if (force == 0) - { - return 0; - } - - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring signal while " - << "waiting for the " << label << " process '" - << child << "' to die.\n" - << logofs_flush; - #endif - - continue; - } - - break; - } - - return (EGET() == ECHILD ? 1 : CheckChild(pid, status)); -} - -int CheckChild(int pid, int status) -{ - lastStatus = 0; - - if (pid > 0) - { - if (WIFSTOPPED(status)) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Child process '" << pid << "' was stopped " - << "with signal " << (WSTOPSIG(status)) << ".\n" - << logofs_flush; - #endif - - return 0; - } - else - { - if (WIFEXITED(status)) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Child process '" << pid << "' exited " - << "with status '" << (WEXITSTATUS(status)) - << "'.\n" << logofs_flush; - #endif - - lastStatus = WEXITSTATUS(status); - } - else if (WIFSIGNALED(status)) - { - if (CheckSignal(WTERMSIG(status)) != 1) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Child process '" << pid - << "' died because of signal " << (WTERMSIG(status)) - << ", '" << DumpSignal(WTERMSIG(status)) << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Child process '" << pid - << "' died because of signal " << (WTERMSIG(status)) - << ", '" << DumpSignal(WTERMSIG(status)) << "'.\n"; - } - #if defined(UNSAFE) && defined(TEST) - else - { - *logofs << "Loop: Child process '" << pid - << "' died because of signal " << (WTERMSIG(status)) - << ", '" << DumpSignal(WTERMSIG(status)) << "'.\n" - << logofs_flush; - } - #endif - - lastStatus = 1; - } - - return 1; - } - } - else if (pid < 0) - { - if (EGET() != ECHILD) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to waitpid failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to waitpid failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - HandleCleanup(); - } - - // - // This can happen when the waitpid() is - // blocking, as the SIGCHLD is received - // within the call. - // - - #ifdef TEST - *logofs << "Loop: No more children processes running.\n" - << logofs_flush; - #endif - - return 1; - } - - return 0; -} - -void RegisterChild(int child) -{ - #if defined(TEST) || defined(INFO) - - if (IsNotRunning(lastChild)) - { - *logofs << "Loop: Registering child process '" << child - << "' in process with pid '" << getpid() - << "'.\n" << logofs_flush; - } - else - { - *logofs << "Loop: WARNING! Overriding registered child '" - << lastChild << "' with new child '" << child - << "' in process with pid '" << getpid() - << "'.\n" << logofs_flush; - } - - #endif - - lastChild = child; -} - -int CheckParent(const char *name, const char *type, int parent) -{ - if (parent != getppid() || parent == 1) - { - #ifdef WARNING - *logofs << name << ": WARNING! Parent process appears " - << "to be dead. Exiting " << type << ".\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Parent process appears " - << "to be dead. Exiting " << type << ".\n"; - - return 0; - } - - return 1; -} - -void HandleTimer(int signal) -{ - if (signal == SIGALRM) - { - if (isTimestamp(lastTimer.start)) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Timer expired at " << strMsTimestamp() - << " in process with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - if (proxy != NULL) - { - proxy -> handleTimer(); - } - - ResetTimer(); - } - else - { - #ifdef PANIC - *logofs << "Loop: PANIC! Inconsistent timer state " - << " in process with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Inconsistent timer state " - << " in process with pid '" << getpid() << "'.\n"; - } - } - else - { - #ifdef PANIC - *logofs << "Loop: PANIC! Inconsistent signal '" - << signal << "', '" << DumpSignal(signal) - << "' received in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Inconsistent signal '" - << signal << "', '" << DumpSignal(signal) - << "' received in process with pid '" - << getpid() << "'.\n"; - } -} - -void SetTimer(int value) -{ - getNewTimestamp(); - - if (isTimestamp(lastTimer.start)) - { - int diffTs = diffTimestamp(lastTimer.start, getTimestamp()); - - if (diffTs > lastTimer.next.tv_usec / 1000 * 2) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Timer missed to expire at " - << strMsTimestamp() << " in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Timer missed to expire at " - << strMsTimestamp() << " in process with pid '" - << getpid() << "'.\n"; - - HandleTimer(SIGALRM); - } - else - { - #ifdef TEST - *logofs << "Loop: Timer already running at " - << strMsTimestamp() << " in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - return; - } - } - - // - // Save the former handler. - // - - struct sigaction action; - - memset(&action, 0, sizeof(action)); - - action.sa_handler = HandleTimer; - - sigemptyset(&action.sa_mask); - - action.sa_flags = 0; - - sigaction(SIGALRM, &action, &lastTimer.action); - - // - // Start the timer. - // - - lastTimer.next = getTimestamp(value); - - struct itimerval timer; - - timer.it_interval = lastTimer.next; - timer.it_value = lastTimer.next; - - #ifdef TEST - *logofs << "Loop: Timer set to " << lastTimer.next.tv_sec - << " S and " << lastTimer.next.tv_usec / 1000 - << " Ms at " << strMsTimestamp() << " in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - if (setitimer(ITIMER_REAL, &timer, &lastTimer.value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to setitimer failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to setitimer failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - lastTimer.next = nullTimestamp(); - - return; - } - - lastTimer.start = getTimestamp(); -} - -void ResetTimer() -{ - if (isTimestamp(lastTimer.start) == 0) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Timer not running in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - return; - } - - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Timer reset at " << strMsTimestamp() - << " in process with pid '" << getpid() - << "'.\n" << logofs_flush; - #endif - - // - // Restore the old signal mask and timer. - // - - if (setitimer(ITIMER_REAL, &lastTimer.value, NULL) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to setitimer failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to setitimer failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - } - - if (sigaction(SIGALRM, &lastTimer.action, NULL) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to sigaction failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to sigaction failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - } - - lastTimer.start = lastTimer.next = nullTimestamp(); -} - -// -// 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(ChannelEndPoint &socketAddress) -{ - char hostLabel[DEFAULT_STRING_LENGTH] = { 0 }; - char *socketUri = NULL; - - int retryAccept = -1; - - int proxyFD = -1; - int newFD = -1; - - int acceptIPAddr = 0; - - if (socketAddress.isTCPSocket()) - { - - // - // Get IP address of host to be awaited. - // - - 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; - } - snprintf(hostLabel, sizeof(hostLabel), "'%s'", acceptHost); - } - else - { - strcpy(hostLabel, "any host"); - } - - long bindPort; - if (socketAddress.getTCPHostAndPort(NULL, &bindPort)) - { - socketAddress.setSpec(loopbackBind ? "localhost" : "*", bindPort); - } - else - { - // This should never happen - cerr << "Error" << ": Unable to change bind host\n"; - } - } - else if (socketAddress.isUnixSocket()) - strcpy(hostLabel, "this host"); - else - strcpy(hostLabel, "unknown origin (something went wrong!!!)"); - - - proxyFD = ListenConnection(socketAddress, "NX"); - - socketAddress.getSpec(&socketUri); - #ifdef TEST - *logofs << "Loop: Waiting for connection from " - << hostLabel << " on socket '" << socketUri - << "'.\n" << logofs_flush; - #endif - cerr << "Info" << ": Waiting for connection from " - << hostLabel << " on socket '" << socketUri - << "'.\n"; - free(socketUri); - - // - // How many times to loop waiting for connections - // from the selected host? Each loop wait for at - // most 20 seconds so a default value of 3 gives - // a timeout of 1 minute. - // - // TODO: Handling of timeouts and retry attempts - // must be rewritten. - // - - retryAccept = control -> OptionProxyRetryAccept; - - for (;;) - { - fd_set readSet; - - FD_ZERO(&readSet); - FD_SET(proxyFD, &readSet); - - T_timestamp selectTs; - - selectTs.tv_sec = 20; - selectTs.tv_usec = 0; - - int result = select(proxyFD + 1, &readSet, NULL, NULL, &selectTs); - - getNewTimestamp(); - - if (result == -1) - { - if (EGET() == EINTR) - { - if (CheckAbort() != 0) - { - goto WaitForRemoteError; - } - - continue; - } - - #ifdef PANIC - *logofs << "Loop: PANIC! Call to select failed. Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Call to select failed. Error is " - << EGET() << " '" << ESTR() << "'.\n"; - - goto WaitForRemoteError; - } - else if (result > 0 && FD_ISSET(proxyFD, &readSet)) - { - - 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 - *logofs << "Loop: PANIC! Call to accept failed. Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Call to accept failed. Error is " - << EGET() << " '" << ESTR() << "'.\n"; - - goto WaitForRemoteError; - } - - if (socketAddress.isUnixSocket()) - { - - 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 this host on Unix file socket '" - << unixPath << "'.\n"; - free(unixPath); - - break; - } - else if (socketAddress.isTCPSocket()) - { - - char *connectedHost = inet_ntoa(newAddrINET.sin_addr); - - if (*acceptHost == '\0' || (int) newAddrINET.sin_addr.s_addr == acceptIPAddr) - { - - #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); - - } - - } - - if (--retryAccept == 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 " - << "could not be established.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Connection with remote host " - << "could not be established.\n"; - } - else - { - #ifdef PANIC - *logofs << "Loop: PANIC! Connection with remote host '" - << acceptHost << "' could not be established.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Connection with remote host '" - << acceptHost << "' could not be established.\n"; - } - - goto WaitForRemoteError; - } - else - { - handleCheckSessionInConnect(); - } - } - - close(proxyFD); - - return newFD; - -WaitForRemoteError: - - close(proxyFD); - - HandleCleanup(); -} - -int PrepareProxyConnectionTCP(char** hostName, long int* portNum, int* timeout, int* proxyFD, int* reason) -{ - - 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; - #endif - cerr << "Error" << ": Unknown remote host '" - << *hostName << "'.\n"; - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "Loop: Connecting to remote host '" - << *hostName << ":" << *portNum << "'.\n" - << logofs_flush; - #endif - - cerr << "Info" << ": Connecting to remote host '" - << *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 / Unix domain socket in case of failure? - // - - int retryConnect = control -> OptionProxyRetryConnect; - - // - // Show an alert after 20 seconds and use the - // same timeout to interrupt the connect. The - // retry timeout is incremental, starting from - // 100 miliseconds up to 1 second. - // - - int alertTimeout = 20000; - int connectTimeout = 20000; - int retryTimeout = 100; - - T_timestamp lastRetry = getNewTimestamp(); - - int result = -1; - int reason = -1; - int proxyFD = -1; - - char *hostName = NULL; - long int portNum = -1; - char *unixPath = NULL; - - for (;;) - { - - #ifdef DEBUG - *logofs << "Loop: Timer set to " << connectTimeout / 1000 - << " S " << "with retry set to " << retryConnect - << " in process with pid '" << getpid() - << "'.\n" << logofs_flush; - #endif - - 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) - { - close(proxyFD); - - if (CheckAbort() != 0) - { - goto ConnectToRemoteError; - } - else if (--retryConnect == 0) - { - ESET(reason); - - 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 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_flush; - #endif - - usleep(retryTimeout * 1000); - - retryTimeout <<= 1; - - if (retryTimeout > 1000 * 1000) - { - retryTimeout = 1000 * 1000; - } - } - - // - // Check if it is time to show an alert dialog. - // - - if (diffTimestamp(lastRetry, getNewTimestamp()) >= - (alertTimeout - control -> LatencyTimeout)) - { - if (IsNotRunning(lastDialog)) - { - handleCheckSessionInConnect(); - - // - // Wait for the dialog process to die - // unless a signal is received. - // - - while (IsRunning(lastDialog)) - { - WaitChild(lastDialog, "dialog", 0); - - if (CheckAbort() != 0) - { - // - // The client ignores the TERM signal - // on Windows. - // - - #ifdef __CYGWIN32__ - - KillProcess(lastDialog, "dialog", SIGKILL, 1); - - #else - - KillProcess(lastDialog, "dialog", SIGTERM, 1); - - #endif - - goto ConnectToRemoteError; - } - } - - lastRetry = getTimestamp(); - } - } - #ifdef TEST - { - *logofs << "Loop: Not showing the dialog with " - << (diffTimestamp(lastRetry, getTimestamp()) / 1000) - << " seconds elapsed.\n" << logofs_flush; - } - #endif - - ESET(reason); - - #ifdef TEST - if (unixPath && 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 - { - // - // Connection was successful. - // - - break; - } - } - - return proxyFD; - -ConnectToRemoteError: - - if (proxyFD != -1) - { - close(proxyFD); - } - - HandleCleanup(); -} - -// -// Make a string of options for the remote -// proxy and write it to the descriptor. -// The string includes the local version. -// - -int SendProxyOptions(int fd) -{ - char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; - - // - // Send the "compatibility" version first, then our - // actual version. Old proxies will take the first - // value and ignore the second. - // - - sprintf(options, "NXPROXY-%s-%i.%i.%i", - control -> NXPROXY_COMPATIBILITY_VERSION, - control -> LocalVersionMajor, - control -> LocalVersionMinor, - control -> LocalVersionPatch); - - // - // If you want to send options from proxy - // initiating the connection use something - // like this: - // - // if (WE_PROVIDE_CREDENTIALS) - // { - // sprintf(options + strlen(options), "%s=%s", option, value); - // } - // - // If you want to send options according to - // local proxy mode use something like this: - // - // if (control -> ProxyMode == proxy_client) - // { - // sprintf(options + strlen(options), "%s=%s", option, value); - // } - // - - // - // Send the authorization cookie if any. We assume - // user can choose to not provide any auth cookie - // and allow any connection to be accepted. - // - - if (WE_PROVIDE_CREDENTIALS && *authCookie != '\0') - { - sprintf(options + strlen(options), " cookie=%s,", authCookie); - } - else - { - sprintf(options + strlen(options), " "); - } - - // - // Now link characteristics and compression - // options. Delta compression, as well as - // preferred pack method, are imposed by - // client proxy. - // - - if (control -> ProxyMode == proxy_client) - { - sprintf(options + strlen(options), "link=%s,pack=%s,cache=%s,", - linkSpeedName, packMethodName, cacheSizeName); - - if (*bitrateLimitName != '\0') - { - sprintf(options + strlen(options), "limit=%s,", - bitrateLimitName); - } - - // - // Let the user disable the render extension - // and let the X client proxy know if it can - // short-circuit the X replies. Also pass - // along the session type to ensure that the - // remote proxy gets the right value. - // - - sprintf(options + strlen(options), "render=%d,taint=%d,", - (control -> HideRender == 0), - control -> TaintReplies); - - if (*sessionType != '\0') - { - sprintf(options + strlen(options), "type=%s,", sessionType); - } - else - { - sprintf(options + strlen(options), "type=default,"); - } - - // - // Add the 'strict' option, if needed. - // - - // Since ProtoStep7 (#issue 108) - if (useStrict != -1) - { - sprintf(options + strlen(options), "strict=%d,", useStrict); - } - - // - // Tell the remote the size of the shared - // memory segment. - // - - // Since ProtoStep7 (#issue 108) - if (*shsegSizeName != '\0') - { - sprintf(options + strlen(options), "shseg=%s,", shsegSizeName); - } - - // - // Send image cache parameters. - // - - sprintf(options + strlen(options), "images=%s,", imagesSizeName); - - sprintf(options + strlen(options), "delta=%d,stream=%d,data=%d ", - control -> LocalDeltaCompression, - control -> LocalStreamCompressionLevel, - control -> LocalDataCompressionLevel); - } - else - { - // - // If no special compression level was selected, - // server side will use compression levels set - // by client. - // - - if (control -> LocalStreamCompressionLevel < 0) - { - sprintf(options + strlen(options), "stream=default,"); - } - else - { - sprintf(options + strlen(options), "stream=%d,", - control -> LocalStreamCompressionLevel); - } - - if (control -> LocalDataCompressionLevel < 0) - { - sprintf(options + strlen(options), "data=default "); - } - else - { - sprintf(options + strlen(options), "data=%d ", - control -> LocalDataCompressionLevel); - } - } - - #ifdef TEST - *logofs << "Loop: Sending remote options '" - << options << "'.\n" << logofs_flush; - #endif - - return WriteLocalData(fd, options, strlen(options)); -} - -int ReadProxyVersion(int fd) -{ - #ifdef TEST - *logofs << "Loop: Going to read the remote proxy version " - << "from FD#" << fd << ".\n" << logofs_flush; - #endif - - // - // Read until the first space in string. - // We expect the remote version number. - // - - char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; - - int result = ReadRemoteData(fd, options, sizeof(options), ' '); - - if (result <= 0) - { - if (result < 0) - { - if (control -> ProxyMode == proxy_server) - { - HandleAlert(ABORT_PROXY_NEGOTIATION_ALERT, 1); - } - - handleAlertInLoop(); - } - - return result; - } - - #ifdef TEST - *logofs << "Loop: Received remote version string '" - << options << "' from FD#" << fd << ".\n" - << logofs_flush; - #endif - - if (strncmp(options, "NXPROXY-", strlen("NXPROXY-")) != 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Parse error in remote options string '" - << options << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Parse error in remote options string '" - << options << "'.\n"; - - return -1; - } - - // - // Try to determine if this is a pre-2.0.0 - // version advertising itself as compatible - // with the 1.2.2. - // - - int major = -1; - int minor = -1; - int patch = -1; - - sscanf(options, "NXPROXY-%i.%i.%i-%i.%i.%i", &(control -> RemoteVersionMajor), - &(control -> RemoteVersionMinor), &(control -> RemoteVersionPatch), - &major, &minor, &patch); - - if (control -> RemoteVersionMajor == 1 && - control -> RemoteVersionMinor == 2 && - control -> RemoteVersionPatch == 2 && - major != -1 && minor != -1 && patch != -1) - { - #ifdef TEST - *logofs << "Loop: Read trailing remote version '" << major - << "." << minor << "." << patch << "'.\n" - << logofs_flush; - #endif - - control -> CompatVersionMajor = major; - control -> CompatVersionMinor = minor; - control -> CompatVersionPatch = patch; - - control -> RemoteVersionMajor = major; - control -> RemoteVersionMinor = minor; - control -> RemoteVersionPatch = patch; - } - else - { - // - // We read the remote version at the first - // round. If the second version is missing, - // we will retain the values read before. - // - - sscanf(options, "NXPROXY-%i.%i.%i-%i.%i.%i", &(control -> CompatVersionMajor), - &(control -> CompatVersionMinor), &(control -> CompatVersionPatch), - &(control -> RemoteVersionMajor), &(control -> RemoteVersionMinor), - &(control -> RemoteVersionPatch)); - } - - *logofs << "Loop: Identified remote version '" << control -> RemoteVersionMajor - << "." << control -> RemoteVersionMinor << "." << control -> RemoteVersionPatch - << "'.\n" << logofs_flush; - - *logofs << "Loop: Remote compatibility version '" << control -> CompatVersionMajor - << "." << control -> CompatVersionMinor << "." << control -> CompatVersionPatch - << "'.\n" << logofs_flush; - - *logofs << "Loop: Local version '" << control -> LocalVersionMajor - << "." << control -> LocalVersionMinor << "." << control -> LocalVersionPatch - << "'.\n" << logofs_flush; - - if (SetVersion() < 0) - { - if (control -> ProxyMode == proxy_server) - { - HandleAlert(WRONG_PROXY_VERSION_ALERT, 1); - } - - handleAlertInLoop(); - - return -1; - } - - return 1; -} - -int ReadProxyOptions(int fd) -{ - #ifdef TEST - *logofs << "Loop: Going to read the remote proxy options " - << "from FD#" << fd << ".\n" << logofs_flush; - #endif - - char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; - - int result = ReadRemoteData(fd, options, sizeof(options), ' '); - - if (result <= 0) - { - return result; - } - - #ifdef TEST - *logofs << "Loop: Received remote options string '" - << options << "' from FD#" << fd << ".\n" - << logofs_flush; - #endif - - // - // Get the remote options, delimited by a space character. - // Note that there will be a further initialization phase - // at the time proxies negotiate cache file to restore. - // - - if (ParseRemoteOptions(options) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Couldn't negotiate a valid " - << "session with remote NX proxy.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Couldn't negotiate a valid " - << "session with remote NX proxy.\n"; - - return -1; - } - - return 1; -} - -int SendProxyCaches(int fd) -{ - #ifdef TEST - *logofs << "Loop: Synchronizing local and remote caches.\n" - << logofs_flush; - #endif - - if (control -> ProxyMode == proxy_client) - { - // - // Prepare a list of caches matching this - // session type and send it to the remote. - // - - #ifdef TEST - *logofs << "Loop: Going to send the list of local caches.\n" - << logofs_flush; - #endif - - SetCaches(); - - int entries = DEFAULT_REMOTE_CACHE_ENTRIES; - - const char prefix = 'C'; - - if (control -> LocalDeltaCompression == 0 || - control -> PersistentCacheEnableLoad == 0) - { - #ifdef TEST - *logofs << "Loop: Writing an empty list to FD#" << fd - << ".\n" << logofs_flush; - #endif - - return WriteLocalData(fd, "cachelist=none ", strlen("cachelist=none ")); - } - - int count = 0; - - #ifdef TEST - *logofs << "Loop: Looking for cache files in directory '" - << control -> PersistentCachePath << "'.\n" << logofs_flush; - #endif - - DIR *cacheDir = opendir(control -> PersistentCachePath); - - if (cacheDir != NULL) - { - dirent *dirEntry; - - int prologue = 0; - - while (((dirEntry = readdir(cacheDir)) != NULL) && (count < entries)) - { - if (*dirEntry -> d_name == prefix && - strlen(dirEntry -> d_name) == (MD5_LENGTH * 2 + 2)) - { - if (prologue == 0) - { - WriteLocalData(fd, "cachelist=", strlen("cachelist=")); - - prologue = 1; - } - else - { - WriteLocalData(fd, ",", strlen(",")); - } - - #ifdef TEST - *logofs << "Loop: Writing entry '" << control -> PersistentCachePath - << "/" << dirEntry -> d_name << "' to FD#" << fd - << ".\n" << logofs_flush; - #endif - - // - // Write cache file name to the socket, - // including leading 'C-' or 'S-'. - // - - WriteLocalData(fd, dirEntry -> d_name, MD5_LENGTH * 2 + 2); - - count++; - } - } - - closedir(cacheDir); - } - - if (count == 0) - { - #ifdef TEST - *logofs << "Loop: Writing an empty list to FD#" << fd - << ".\n" << logofs_flush; - #endif - - return WriteLocalData(fd, "cachelist=none ", strlen("cachelist=none ")); - } - else - { - return WriteLocalData(fd, " ", 1); - } - } - else - { - // - // Send back the selected cache name. - // - - #ifdef TEST - *logofs << "Loop: Going to send the selected cache.\n" - << logofs_flush; - #endif - - char buffer[DEFAULT_STRING_LENGTH]; - - if (control -> PersistentCacheName != NULL) - { - #ifdef TEST - *logofs << "Loop: Name of selected cache file is '" - << control -> PersistentCacheName << "'.\n" - << logofs_flush; - #endif - - sprintf(buffer, "cachefile=%s%s ", - *(control -> PersistentCacheName) == 'C' ? "S-" : "C-", - control -> PersistentCacheName + 2); - } - else - { - #ifdef TEST - *logofs << "Loop: No valid cache file was selected.\n" - << logofs_flush; - #endif - - sprintf(buffer, "cachefile=none "); - } - - #ifdef TEST - *logofs << "Loop: Sending string '" << buffer - << "' as selected cache file.\n" - << logofs_flush; - #endif - - return WriteLocalData(fd, buffer, strlen(buffer)); - } -} - -int ReadProxyCaches(int fd) -{ - if (control -> ProxyMode == proxy_client) - { - #ifdef TEST - *logofs << "Loop: Going to receive the selected proxy cache.\n" - << logofs_flush; - #endif - - // - // We will read the name of cache plus the stop character. - // - - char buffer[DEFAULT_STRING_LENGTH]; - - // - // Leave space for a trailing null. - // - - int result = ReadRemoteData(fd, buffer, sizeof("cachefile=") + MD5_LENGTH * 2 + 3, ' '); - - if (result <= 0) - { - return result; - } - - char *cacheName = strstr(buffer, "cachefile="); - - if (cacheName == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid cache file option '" - << buffer << "' provided by remote proxy.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid cache file option '" - << buffer << "' provided by remote proxy.\n"; - - HandleCleanup(); - } - - cacheName += strlen("cachefile="); - - if (control -> PersistentCacheName != NULL) - { - delete [] control -> PersistentCacheName; - } - - control -> PersistentCacheName = NULL; - - if (strncasecmp(cacheName, "none", strlen("none")) == 0) - { - #ifdef TEST - *logofs << "Loop: No cache file selected by remote proxy.\n" - << logofs_flush; - #endif - } - else if (strlen(cacheName) != MD5_LENGTH * 2 + 3 || - *(cacheName + MD5_LENGTH * 2 + 2) != ' ') - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid cache file name '" - << cacheName << "' provided by remote proxy.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid cache file name '" - << cacheName << "' provided by remote proxy.\n"; - - HandleCleanup(); - } - else - { - // - // It is "C-" + 32 + "\0". - // - - control -> PersistentCacheName = new char[MD5_LENGTH * 2 + 3]; - - *(cacheName + MD5_LENGTH * 2 + 2) = '\0'; - - strcpy(control -> PersistentCacheName, cacheName); - - #ifdef TEST - *logofs << "Loop: Cache file '" << control -> PersistentCacheName - << "' selected by remote proxy.\n" << logofs_flush; - #endif - } - } - else - { - #ifdef TEST - *logofs << "Loop: Going to receive the list of remote caches.\n" - << logofs_flush; - #endif - - SetCaches(); - - int size = ((MD5_LENGTH * 2 + 2) + strlen(",")) * DEFAULT_REMOTE_CACHE_ENTRIES + - strlen("cachelist=") + strlen(" ") + 1; - - char *buffer = new char[size]; - - int result = ReadRemoteData(fd, buffer, size - 1, ' '); - - if (result <= 0) - { - delete [] buffer; - - return result; - } - - #ifdef TEST - *logofs << "Loop: Read list of caches from remote side as '" - << buffer << "'.\n" << logofs_flush; - #endif - - // - // Prepare the buffer. What we want is a list - // like "cache1,cache2,cache2" terminated by - // null. - // - - *(buffer + strlen(buffer) - 1) = '\0'; - - if (strncasecmp(buffer, "cachelist=", strlen("cachelist=")) != 0) - { - #ifdef PANIC - *logofs << "Loop: Wrong format for list of cache files " - << "read from FD#" << fd << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Wrong format for list of cache files.\n"; - - delete [] buffer; - - return -1; - } - - control -> PersistentCacheName = GetLastCache(buffer, control -> PersistentCachePath); - - // - // Get rid of list of caches. - // - - delete [] buffer; - } - - return 1; -} - -int ReadForwarderVersion(int fd) -{ - #ifdef TEST - *logofs << "Loop: Going to negotiate the forwarder version.\n" - << logofs_flush; - #endif - - // - // Check if we actually expect the session cookie. - // - - if (*authCookie == '\0') - { - #ifdef TEST - *logofs << "Loop: No authentication cookie required " - << "from FD#" << fd << ".\n" << logofs_flush; - #endif - - return 1; - } - - char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; - - int result = ReadRemoteData(fd, options, sizeof(options), ' '); - - if (result <= 0) - { - return result; - } - - #ifdef TEST - *logofs << "Loop: Received forwarder version string '" << options - << "' from FD#" << fd << ".\n" << logofs_flush; - #endif - - if (strncmp(options, "NXSSH-", strlen("NXSSH-")) != 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Parse error in forwarder options string '" - << options << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Parse error in forwarder options string '" - << options << "'.\n"; - - return -1; - } - - // - // Accept whatever forwarder version. - // - - sscanf(options, "NXSSH-%i.%i.%i", &(control -> RemoteVersionMajor), - &(control -> RemoteVersionMinor), &(control -> RemoteVersionPatch)); - - #ifdef TEST - *logofs << "Loop: Read forwarder version '" << control -> RemoteVersionMajor - << "." << control -> RemoteVersionMinor << "." << control -> RemoteVersionPatch - << "'.\n" << logofs_flush; - #endif - - return 1; -} - -int ReadForwarderOptions(int fd) -{ - // - // Get the forwarder cookie. - // - - if (*authCookie == '\0') - { - #ifdef TEST - *logofs << "Loop: No authentication cookie required " - << "from FD#" << fd << ".\n" << logofs_flush; - #endif - - return 1; - } - - char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; - - int result = ReadRemoteData(fd, options, sizeof(options), ' '); - - if (result <= 0) - { - return result; - } - - #ifdef TEST - *logofs << "Loop: Received forwarder options string '" - << options << "' from FD#" << fd << ".\n" - << logofs_flush; - #endif - - if (ParseForwarderOptions(options) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Couldn't negotiate a valid " - << "cookie with the NX forwarder.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Couldn't negotiate a valid " - << "cookie with the NX forwarder.\n"; - - return -1; - } - - return 1; -} - -int ReadRemoteData(int fd, char *buffer, int size, char stop) -{ - #ifdef TEST - *logofs << "Loop: Going to read remote data from FD#" - << fd << ".\n" << logofs_flush; - #endif - - if (size >= MAXIMUM_REMOTE_OPTIONS_LENGTH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Maximum remote options buffer " - << "limit exceeded.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Maximum remote options buffer " - << "limit exceeded.\n"; - - HandleCleanup(); - } - - while (remotePosition < (size - 1)) - { - int result = read(fd, remoteData + remotePosition, 1); - - getNewTimestamp(); - - if (result <= 0) - { - if (result == -1) - { - if (EGET() == EAGAIN) - { - #ifdef TEST - *logofs << "Loop: Reading data from FD#" << fd - << " would block.\n" << logofs_flush; - #endif - - return 0; - } - else if (EGET() == EINTR) - { - if (CheckAbort() != 0) - { - return -1; - } - - continue; - } - } - - #ifdef PANIC - *logofs << "Loop: PANIC! The remote NX proxy closed " - << "the connection.\n" << logofs_flush; - #endif - - cerr << "Error" << ": The remote NX proxy closed " - << "the connection.\n"; - - return -1; - } - else if (*(remoteData + remotePosition) == stop) - { - #ifdef TEST - *logofs << "Loop: Read stop character from FD#" - << fd << ".\n" << logofs_flush; - #endif - - remotePosition++; - - // - // Copy the fake terminating null - // in the buffer. - // - - *(remoteData + remotePosition) = '\0'; - - memcpy(buffer, remoteData, remotePosition + 1); - - #ifdef TEST - *logofs << "Loop: Remote string '" << remoteData - << "' read from FD#" << fd << ".\n" - << logofs_flush; - #endif - - int t = remotePosition; - - remotePosition = 0; - - return t; - } - else - { - // - // Make sure string received - // from far end is printable. - // - - if (isgraph(*(remoteData + remotePosition)) == 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Non printable character decimal '" - << (unsigned int) *(remoteData + remotePosition) - << "' received in remote data from FD#" - << fd << ".\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Non printable character decimal '" - << (unsigned int) *(remoteData + remotePosition) - << "' received in remote data from FD#" - << fd << ".\n" << logofs_flush; - - *(remoteData + remotePosition) = ' '; - } - - #ifdef DEBUG - *logofs << "Loop: Read a further character " - << "from FD#" << fd << ".\n" - << logofs_flush; - #endif - - remotePosition++; - } - } - - *(remoteData + remotePosition) = '\0'; - - #ifdef PANIC - *logofs << "Loop: PANIC! Stop character missing " - << "from FD#" << fd << " after " << remotePosition - << " characters read in string '" << remoteData - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Stop character missing " - << "from FD#" << fd << " after " << remotePosition - << " characters read in string '" << remoteData - << "'.\n"; - - memcpy(buffer, remoteData, remotePosition); - - remotePosition = 0; - - 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; - int ret = 0; - fd_set writeSet; - struct timeval selectTs = {30, 0}; - - while (position < size) - { - - // A write to a non-blocking socket may fail with EAGAIN. The problem is - // that cache data is done in several writes, and there's no easy way - // to handle failure without rewriting a significant amount of code. - // - // Bailing out of the outer loop would result in restarting the sending - // of the entire cache list, which would confuse the other side. - - FD_ZERO(&writeSet); - FD_SET(fd, &writeSet); - - ret = select(fd+1, NULL, &writeSet, NULL, &selectTs); - - #ifdef DEBUG - *logofs << "Loop: WriteLocalData: select() returned with a code of " << ret << " and remaining timeout of " - << selectTs.tv_sec << " sec, " << selectTs.tv_usec << "usec\n" << logofs_flush; - #endif - - if ( ret < 0 ) - { - *logofs << "Loop: Error in select() when writing data to FD#" << fd << ": " << strerror(EGET()) << "\n" << logofs_flush; - - if ( EGET() == EINTR ) - continue; - - return -1; - } - else if ( ret == 0 ) - { - *logofs << "Loop: Timeout expired in select() when writing data to FD#" << fd << ": " << strerror(EGET()) << "\n" << logofs_flush; - return -1; - } - - int result = write(fd, buffer + position, size - position); - - getNewTimestamp(); - - if (result <= 0) - { - if (result < 0 && (EGET() == EINTR || EGET() == EAGAIN || EGET() == EWOULDBLOCK)) - { - continue; - } - - #ifdef TEST - *logofs << "Loop: Error writing data to FD#" - << fd << ".\n" << logofs_flush; - #endif - - return -1; - } - - position += result; - } - - return position; -} - -// -// Parse the string passed by calling process in -// the environment. This is not necessarily the -// content of DISPLAY variable, but can be the -// parameters passed when creating the process -// or thread. -// - -int ParseEnvironmentOptions(const char *env, int force) -{ - // - // Be sure log file is valid. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - // - // Be sure we have a parameters repository - // and a context to jump into because this - // can be called before creating the proxy. - // - - if (control == NULL) - { - control = new Control(); - } - - if (setjmp(context) == 1) - { - #ifdef TEST - *logofs << "Loop: Out of the long jump while parsing " - << "the environment options.\n" - << logofs_flush; - #endif - - return -1; - } - - if (force == 0 && parsedOptions == 1) - { - #ifdef TEST - *logofs << "Loop: Skipping a further parse of environment " - << "options string '" << (env != NULL ? env : "") - << "'.\n" << logofs_flush; - #endif - - return 1; - } - - if (env == NULL || *env == '\0') - { - #ifdef TEST - *logofs << "Loop: Nothing to do with empty environment " - << "options string '" << (env != NULL ? env : "") - << "'.\n" << logofs_flush; - #endif - - return 0; - } - - #ifdef TEST - *logofs << "Loop: Going to parse the environment options " - << "string '" << env << "'.\n" - << logofs_flush; - #endif - - parsedOptions = 1; - - // - // Copy the string passed as parameter - // because we need to modify it. - // - - char opts[DEFAULT_DISPLAY_OPTIONS_LENGTH]; - - #ifdef VALGRIND - - memset(opts, '\0', DEFAULT_DISPLAY_OPTIONS_LENGTH); - - #endif - - if (strlen(env) >= DEFAULT_DISPLAY_OPTIONS_LENGTH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Environment options string '" << env - << "' exceeds length of " << DEFAULT_DISPLAY_OPTIONS_LENGTH - << " characters.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Environment options string '" << env - << "' exceeds length of " << DEFAULT_DISPLAY_OPTIONS_LENGTH - << " characters.\n"; - - return -1; - } - - strcpy(opts, env); - - char *nextOpts = opts; - - // - // Ensure that DISPLAY environment variable - // (roughly) follows the X convention for - // transport notation. - // - - if (strncasecmp(opts, "nx/nx,:", 7) == 0 || - strncasecmp(opts, "nx,:", 4) == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Parse error in options string '" - << opts << "' at 'nx,:'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Parse error in options string '" - << opts << "' at 'nx,:'.\n"; - - return -1; - } - else if (strncasecmp(opts, "nx/nx,", 6) == 0) - { - nextOpts += 6; - } - else if (strncasecmp(opts, "nx,", 3) == 0) - { - nextOpts += 3; - } - else if (strncasecmp(opts, "nx:", 3) == 0) - { - nextOpts += 3; - } - else if (force == 0) - { - #ifdef TEST - *logofs << "Loop: Ignoring host X server display string '" - << opts << "'.\n" << logofs_flush; - #endif - - return 0; - } - - // - // Save here the name of the options file and - // parse it after all the other options. - // - - char fileOptions[DEFAULT_STRING_LENGTH] = { 0 }; - - // - // The options string is intended to be a series - // of name/value tuples in the form name=value - // separated by the ',' character ended by a ':' - // followed by remote NX proxy port. - // - - char *name; - char *value; - - value = strrchr(nextOpts, ':'); - - if (value != NULL) - { - char *check = value + 1; - - if (*check == '\0' || isdigit(*check) == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify NX port in string '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify NX port in string '" - << value << "'.\n"; - - return -1; - } - - proxyPort = atoi(check); - - // - // Get rid of the port specification. - // - - *value = '\0'; - } - else if (proxyPort == DEFAULT_NX_PROXY_PORT && force == 0) - { - // - // Complain only if user didn't specify - // the port on the command line. - // - - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify NX port in string '" - << opts << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify NX port in string '" - << opts << "'.\n"; - - return -1; - } - - #ifdef TEST - *logofs << "Loop: Parsing options string '" - << nextOpts << "'.\n" << logofs_flush; - #endif - - // - // Now all the other optional parameters. - // - - name = strtok(nextOpts, "="); - - char connectHost[DEFAULT_STRING_LENGTH] = { 0 }; - long connectPort = -1; - - while (name) - { - value = strtok(NULL, ","); - URLDecodeInPlace(value); - - if (CheckArg("environment", name, value) < 0) - { - return -1; - } - - if (strcasecmp(name, "options") == 0) - { - strncpy(fileOptions, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "display") == 0) - { - strncpy(displayHost, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "link") == 0) - { - - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else if (ParseLinkOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify 'link' option in string '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify 'link' option in string '" - << value << "'.\n"; - if (ParseLinkOption("adsl") < 0) - return -1; - } - } - else if (strcasecmp(name, "limit") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else if (ParseBitrateOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify option 'limit' in string '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify option 'limit' in string '" - << value << "'.\n"; - - return -1; - } - } - else if (strcasecmp(name, "type") == 0) - { - // - // Type of session, for example "desktop", - // "application", "windows", etc. - // - - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - if (strcasecmp(value, "default") == 0) - { - *sessionType = '\0'; - } - else - { - strncpy(sessionType, value, DEFAULT_STRING_LENGTH - 1); - } - } - } - else if (strcasecmp(name, "listen") == 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 '" - << 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 '" - << socketUri << "'.\n"; - - free(socketUri); - return -1; - } - - SetAndValidateChannelEndPointArg("local", name, value, listenSocket); - - } - else if (strcasecmp(name, "loopback") == 0) - { - loopbackBind = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "accept") == 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 '" - << 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 '" - << socketUri << "'.\n"; - - free(socketUri); - return -1; - } - - strncpy(acceptHost, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "connect") == 0) - { - if (*acceptHost != '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't handle 'connect' and 'accept' parameters " - << "at the same time.\n" << logofs_flush; - - *logofs << "Loop: PANIC! Refusing 'connect' parameter with 'accept' being '" - << acceptHost << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't handle 'connect' and 'accept' parameters " - << "at the same time.\n"; - - cerr << "Error" << ": Refusing 'connect' parameter with 'accept' being '" - << acceptHost << "'.\n"; - - return -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) - { - connectPort = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "retry") == 0) - { - control -> OptionProxyRetryConnect = ValidateArg("local", name, value); - control -> OptionServerRetryConnect = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "session") == 0) - { - strncpy(sessionFileName, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "errors") == 0) - { - // - // The old name of the parameter was 'log' - // but the default name for the file is - // 'errors' so it is more logical to use - // the same name. - // - - strncpy(errorsFileName, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "root") == 0) - { - strncpy(rootDir, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "id") == 0) - { - strncpy(sessionId, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "stats") == 0) - { - control -> EnableStatistics = 1; - - strncpy(statsFileName, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "cookie") == 0) - { - LowercaseArg("local", name, value); - - strncpy(authCookie, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "nodelay") == 0) - { - useNoDelay = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "policy") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - usePolicy = ValidateArg("local", name, value); - } - } - else if (strcasecmp(name, "render") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - useRender = ValidateArg("local", name, value); - } - } - else if (strcasecmp(name, "taint") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - useTaint = ValidateArg("local", name, value); - } - } - else if (strcasecmp(name, "delta") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - control -> LocalDeltaCompression = ValidateArg("local", name, value); - } - } - else if (strcasecmp(name, "data") == 0) - { - control -> LocalDataCompressionLevel = ValidateArg("local", name, value); - - if (control -> LocalDataCompressionLevel == 0) - { - control -> LocalDataCompression = 0; - } - else - { - control -> LocalDataCompression = 1; - } - } - else if (strcasecmp(name, "stream") == 0) - { - control -> LocalStreamCompressionLevel = ValidateArg("local", name, value); - - if (control -> LocalStreamCompressionLevel == 0) - { - control -> LocalStreamCompression = 0; - } - else - { - control -> LocalStreamCompression = 1; - } - } - else if (strcasecmp(name, "memory") == 0) - { - control -> LocalMemoryLevel = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "cache") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else if (ParseCacheOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify cache size for string '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify cache size for string '" - << value << "'.\n"; - - return -1; - } - } - else if (strcasecmp(name, "images") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else if (ParseImagesOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify images cache size for string '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify images cache size for string '" - << value << "'.\n"; - - return -1; - } - } - else if (strcasecmp(name, "shseg") == 0) - { - // - // The 'shmem' option is used by the agent, together - // with 'shpix' literal. We make the 'shseg' option - // specific to the proxy and use it to determine the - // size of the shared memory segment, or otherwise 0, - // if the use of the shared memory extension should - // not be enabled on the real X server. - // - - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else if (ParseShmemOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify size of shared memory " - << "segment in string '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify size of shared memory " - << "segment in string '" << value << "'.\n"; - - return -1; - } - } - else if (strcasecmp(name, "load") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - control -> PersistentCacheEnableLoad = ValidateArg("local", name, value); - - if (control -> PersistentCacheEnableLoad > 0) - { - control -> PersistentCacheEnableLoad = 1; - } - else - { - if (control -> PersistentCacheName != NULL) - { - delete [] control -> PersistentCacheName; - } - - control -> PersistentCacheName = NULL; - - control -> PersistentCacheEnableLoad = 0; - } - } - } - else if (strcasecmp(name, "save") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - control -> PersistentCacheEnableSave = ValidateArg("local", name, value); - - if (control -> PersistentCacheEnableSave > 0) - { - control -> PersistentCacheEnableSave = 1; - } - else - { - if (control -> PersistentCacheName != NULL) - { - delete [] control -> PersistentCacheName; - } - - control -> PersistentCacheName = NULL; - - control -> PersistentCacheEnableSave = 0; - } - } - } - else if (strcasecmp(name, "cups") == 0) - { - SetAndValidateChannelEndPointArg("local", name, value, cupsPort); - } - else if (strcasecmp(name, "sync") == 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! No 'sync' channel in current version. " - << "Assuming 'cups' channel.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": No 'sync' channel in current version. " - << "Assuming 'cups' channel.\n"; - - SetAndValidateChannelEndPointArg("local", name, value, cupsPort); - } - else if (strcasecmp(name, "keybd") == 0 || - strcasecmp(name, "aux") == 0) - { - SetAndValidateChannelEndPointArg("local", name, value, auxPort); - } - else if (strcasecmp(name, "samba") == 0 || - strcasecmp(name, "smb") == 0) - { - SetAndValidateChannelEndPointArg("local", name, value, smbPort); - } - else if (strcasecmp(name, "media") == 0) - { - SetAndValidateChannelEndPointArg("local", name, value, mediaPort); - } - else if (strcasecmp(name, "http") == 0) - { - SetAndValidateChannelEndPointArg("local", name, value, httpPort); - } - else if (strcasecmp(name, "font") == 0) - { - strncpy(fontPort, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "slave") == 0) - { - SetAndValidateChannelEndPointArg("local", name, value, slavePort); - } - else if (strcasecmp(name, "mask") == 0) - { - control -> ChannelMask = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "timeout") == 0) - { - int timeout = ValidateArg("local", name, value); - - if (timeout == 0) - { - #ifdef TEST - *logofs << "Loop: Disabling timeout on broken " - << "proxy connection.\n" << logofs_flush; - #endif - - control -> ProxyTimeout = 0; - } - else - { - control -> ProxyTimeout = timeout * 1000; - } - } - else if (strcasecmp(name, "cleanup") == 0) - { - int cleanup = ValidateArg("local", name, value); - - if (cleanup == 0) - { - #ifdef TEST - *logofs << "Loop: Disabling grace timeout on " - << "proxy shutdown.\n" << logofs_flush; - #endif - - control -> CleanupTimeout = 0; - } - else - { - control -> CleanupTimeout = cleanup * 1000; - } - } - else if (strcasecmp(name, "pack") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else if (ParsePackOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify pack method for string '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify pack method for string '" - << value << "'.\n"; - if (ParsePackOption("nopack")<0) - return -1; - } - } - else if (strcasecmp(name, "core") == 0) - { - control -> EnableCoreDumpOnAbort = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "kill") == 0) - { - if (control -> KillDaemonOnShutdownNumber < - control -> KillDaemonOnShutdownLimit) - { - #ifdef TEST - *logofs << "Loop: WARNING! Adding process with pid '" - << ValidateArg("local", name, value) << " to the " - << "daemons to kill at shutdown.\n" - << logofs_flush; - #endif - - control -> KillDaemonOnShutdown[control -> - KillDaemonOnShutdownNumber] = - ValidateArg("local", name, value); - - control -> KillDaemonOnShutdownNumber++; - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Number of daemons to kill " - << "at shutdown exceeded.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Number of daemons to kill " - << "at shutdown exceeded.\n"; - } - } - else if (strcasecmp(name, "strict") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - useStrict = ValidateArg("local", name, value); - } - } - else if (strcasecmp(name, "encryption") == 0) - { - useEncryption = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "product") == 0) - { - strncpy(productName, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "rootless") == 0 || - strcasecmp(name, "geometry") == 0 || - strcasecmp(name, "resize") == 0 || - strcasecmp(name, "fullscreen") == 0 || - strcasecmp(name, "keyboard") == 0 || - strcasecmp(name, "clipboard") == 0 || - strcasecmp(name, "streaming") == 0 || - strcasecmp(name, "backingstore") == 0 || - strcasecmp(name, "sleep") == 0 || - strcasecmp(name, "tolerancechecks") == 0) - { - #ifdef DEBUG - *logofs << "Loop: Ignoring agent option '" << name - << "' with value '" << value << "'.\n" - << logofs_flush; - #endif - } - else if (strcasecmp(name, "composite") == 0 || - strcasecmp(name, "shmem") == 0 || - strcasecmp(name, "shpix") == 0 || - strcasecmp(name, "kbtype") == 0 || - strcasecmp(name, "client") == 0 || - strcasecmp(name, "shadow") == 0 || - strcasecmp(name, "shadowuid") == 0 || - strcasecmp(name, "shadowmode") == 0 || - strcasecmp(name, "clients") == 0 || - strcasecmp(name, "xinerama") == 0) - { - #ifdef DEBUG - *logofs << "Loop: Ignoring agent option '" << name - << "' with value '" << value << "'.\n" - << logofs_flush; - #endif - } - else if (strcasecmp(name, "defer") == 0 || - strcasecmp(name, "tile") == 0 || - strcasecmp(name, "menu") == 0 || - strcasecmp(name, "state") == 0 ) - { - #ifdef DEBUG - *logofs << "Loop: Ignoring agent option '" << name - << "' with value '" << value << "'.\n" - << logofs_flush; - #endif - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring unknown option '" - << name << "' with value '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Ignoring unknown option '" - << name << "' with value '" << value << "'.\n"; - } - - name = strtok(NULL, "="); - - } // 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; - #endif - - if ((*fileOptions != '\0') && (strncmp(fileOptions, "/dev/", 5) != 0) && (strncmp(fileOptions, "/proc/", 6) != 0) && (strncmp(fileOptions, "/sys/", 5) != 0)) - { - if (strcmp(fileOptions, optionsFileName) != 0) - { - #ifdef TEST - *logofs << "Loop: Reading options from '" << fileOptions - << "'.\n" << logofs_flush; - #endif - - if (ParseFileOptions(fileOptions) < 0) - { - return -1; - } - } - #ifdef WARNING - else - { - *logofs << "Loop: WARNING! Name of the options file " - << "specified multiple times. Not parsing " - << "again.\n" << logofs_flush; - } - #endif - - if (*optionsFileName == '\0') - { - strncpy(optionsFileName, value, DEFAULT_STRING_LENGTH - 1); - - #ifdef TEST - *logofs << "Loop: Assuming name of options file '" - << optionsFileName << "'.\n" - << logofs_flush; - #endif - } - } - - // - // If port where proxy is acting as an X server - // was not specified assume the same port where - // proxy is listening for the remote peer. - // - - if (xPort == DEFAULT_NX_X_PORT) - { - xPort = proxyPort; - } - - return 1; -} - -// -// Parse the command line options passed by user when -// running proxy in stand alone mode. Note that passing -// parameters this way is strongly discouraged. These -// command line switch can change (and they do often). -// Please, use the form "option=value" instead and set -// the DISPLAY environment variable. -// - -int ParseCommandLineOptions(int argc, const char **argv) -{ - // - // Be sure log file is valid. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - if (setjmp(context) == 1) - { - #ifdef TEST - *logofs << "Loop: Out of the long jump while parsing " - << "the command line options.\n" - << logofs_flush; - #endif - - return -1; - } - - // - // Be sure we have a parameters repository - // - - if (control == NULL) - { - control = new Control(); - } - - if (parsedCommand == 1) - { - #ifdef TEST - *logofs << "Loop: Skipping a further parse of command line options.\n" - << logofs_flush; - #endif - - return 1; - } - - #ifdef TEST - *logofs << "Loop: Going to parse the command line options.\n" - << logofs_flush; - #endif - - parsedCommand = 1; - - // - // Print out arguments. - // - - #ifdef TEST - - *logofs << "Loop: Argc is " << argc << ".\n" << logofs_flush; - - for (int argi = 0; argi < argc; argi++) - { - *logofs << "Loop: Argv[" << argi << "] is " << argv[argi] - << ".\n" << logofs_flush; - } - - #endif - - // - // Shall use getopt here. - // - - for (int argi = 1; argi < argc; argi++) - { - const char *nextArg = argv[argi]; - - if (*nextArg == '-') - { - switch (*(nextArg + 1)) - { - case 'h': - { - PrintUsageInfo(nextArg, 0); - - return -1; - } - case 'C': - { - // - // Start proxy in CLIENT mode. - // - - if (WE_SET_PROXY_MODE == 0) - { - #ifdef TEST - *logofs << "Loop: Setting local proxy mode to proxy_client.\n" - << logofs_flush; - #endif - - control -> ProxyMode = proxy_client; - } - else if (control -> ProxyMode != proxy_client) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't redefine local proxy to " - << "client mode.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't redefine local proxy to " - << "client mode.\n"; - - return -1; - } - - break; - } - case 'S': - { - // - // Start proxy in SERVER mode. - // - - if (WE_SET_PROXY_MODE == 0) - { - #ifdef TEST - *logofs << "Loop: Setting local proxy mode to proxy_server.\n" - << logofs_flush; - #endif - - control -> ProxyMode = proxy_server; - } - else if (control -> ProxyMode != proxy_server) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't redefine local proxy to " - << "server mode.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't redefine local proxy to " - << "server mode.\n"; - - return -1; - } - - break; - } - case 'v': - { - PrintVersionInfo(); - - return -1; - } - default: - { - PrintUsageInfo(nextArg, 1); - - // - // Function GetArg() is not used anymore. - // Add a dummy call to avoid the warning. - // - - if (0) - { - GetArg(argi, argc, argv); - } - - return -1; - } - } - } - else - { - if (nextArg) - { - // - // Try to parse the option as a remote host:port - // specification as in 'localhost:8'. Such a - // parameter can be specified at the end of the - // command line at the connecting side. - // - - char cHost[DEFAULT_STRING_LENGTH] = { '\0' }; - long cPort = 0; - - if (ParseHostOption(nextArg, cHost, cPort) > 0) - { - // - // Assume port is at a proxied display offset. - // - - proxyPort = cPort; - - cPort += DEFAULT_NX_PROXY_PORT_OFFSET; - connectSocket.setSpec(cHost, cPort); - - } - else if (ParseEnvironmentOptions(nextArg, 1) < 0) - { - return -1; - } - } - } - } - - return 1; -} - -// -// Set the variable to the values of host and -// port where this proxy is going to hook to -// an existing proxy. -// - -int ParseBindOptions(char **host, int *port) -{ - if (*bindHost != '\0') - { - *host = bindHost; - *port = bindPort; - - return 1; - } - else - { - return 0; - } -} - -// -// Read options from file and merge with environment. -// - -int ParseFileOptions(const char *file) -{ - char *fileName; - - if (*file != '/' && *file != '.') - { - char *filePath = GetSessionPath(); - - if (filePath == NULL) - { - cerr << "Error" << ": Cannot determine directory for NX option file.\n"; - - HandleCleanup(); - } - - fileName = new char[strlen(filePath) + strlen("/") + - strlen(file) + 1]; - - strcpy(fileName, filePath); - - strcat(fileName, "/"); - strcat(fileName, file); - - delete [] filePath; - } - else - { - fileName = new char[strlen(file) + 1]; - - strcpy(fileName, file); - } - - #ifdef TEST - *logofs << "Loop: Going to read options from file '" - << fileName << "'.\n" << logofs_flush; - #endif - - FILE *filePtr = fopen(fileName, "r"); - - if (filePtr == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't open options file '" << fileName - << "'. Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't open options file '" << fileName - << "'. Error is " << EGET() << " '" << ESTR() << "'.\n"; - - delete [] fileName; - - return -1; - } - - char options[DEFAULT_DISPLAY_OPTIONS_LENGTH]; - - #ifdef VALGRIND - - memset(options, '\0', DEFAULT_DISPLAY_OPTIONS_LENGTH); - - #endif - - if (fgets(options, DEFAULT_DISPLAY_OPTIONS_LENGTH, filePtr) == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't read options from file '" << fileName - << "'. Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't read options from file '" << fileName - << "'. Error is " << EGET() << " '" << ESTR() << "'.\n"; - - fclose(filePtr); - - delete [] fileName; - - return -1; - } - - fclose(filePtr); - - // - // Purge the newline and the other non- - // printable characters in the string. - // - - char *next = options; - - while (*next != '\0') - { - if (isprint(*next) == 0) - { - *next = '\0'; - } - - next++; - } - - #ifdef TEST - *logofs << "Loop: Read options '" << options << "' from file '" - << fileName << "'.\n" << logofs_flush; - #endif - - if (ParseEnvironmentOptions(options, 1) < 0) - { - delete [] fileName; - - return -1; - } - - delete [] fileName; - - return 1; -} - -// -// Parse the option string passed from the -// remote proxy at startup. -// - -int ParseRemoteOptions(char *opts) -{ - #ifdef TEST - *logofs << "Loop: Going to parse the remote options " - << "string '" << opts << "'.\n" - << logofs_flush; - #endif - - char *name; - char *value; - - // - // The options string is intended to be a series - // of name/value tuples in the form name=value - // separated by the ',' character. - // - - int hasCookie = 0; - int hasLink = 0; - int hasPack = 0; - int hasCache = 0; - int hasImages = 0; - int hasDelta = 0; - int hasStream = 0; - int hasData = 0; - int hasType = 0; - - // - // Get rid of the terminating space. - // - - if (*(opts + strlen(opts) - 1) == ' ') - { - *(opts + strlen(opts) - 1) = '\0'; - } - - name = strtok(opts, "="); - - while (name) - { - value = strtok(NULL, ","); - - if (CheckArg("remote", name, value) < 0) - { - return -1; - } - - if (strcasecmp(name, "cookie") == 0) - { - if (WE_PROVIDE_CREDENTIALS) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring remote option 'cookie' " - << "with value '" << value << "' when initiating " - << "connection.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Ignoring remote option 'cookie' " - << "with value '" << value << "' when initiating " - << "connection.\n"; - } - else if (strncasecmp(authCookie, value, strlen(authCookie)) != 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Authentication cookie '" << value - << "' doesn't match '" << authCookie << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Authentication cookie '" << value - << "' doesn't match '" << authCookie << "'.\n"; - - return -1; - } - - hasCookie = 1; - } - else if (strcasecmp(name, "link") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - if (*linkSpeedName != '\0' && strcasecmp(linkSpeedName, value) != 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Overriding option 'link' " - << "with new value '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Overriding option 'link' " - << "with new value '" << value << "'.\n"; - } - - if (ParseLinkOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify remote 'link' " - << "option in string '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify remote 'link' " - << "option in string '" << value << "'.\n"; - - return -1; - } - } - - hasLink = 1; - } - else if (strcasecmp(name, "pack") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - if (*packMethodName != '\0' && strcasecmp(packMethodName, value) != 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Overriding option 'pack' " - << "with remote value '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Overriding option 'pack' " - << "with remote value '" << value << "'.\n"; - } - - if (ParsePackOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid pack option '" - << value << "' requested by remote.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid pack option '" - << value << "' requested by remote.\n"; - - return -1; - } - } - - hasPack = 1; - } - else if (strcasecmp(name, "cache") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - // - // Cache size is sent as a hint of how much memory - // the remote proxy is going to consume. A very low - // powered thin client could choose to refuse the - // connection. - // - - if (ParseCacheOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify remote 'cache' " - << "option in string '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify remote 'cache' " - << "option in string '" << value << "'.\n"; - - return -1; - } - } - - hasCache = 1; - } - else if (strcasecmp(name, "images") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - // - // Images cache size is sent as a hint. - // There is no obbligation for the local - // proxy to use the persistent cache. - // - - if (ParseImagesOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify remote 'images' " - << "option in string '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify remote 'images' " - << "option in string '" << value << "'.\n"; - - return -1; - } - } - - hasImages = 1; - } - else if (strcasecmp(name, "limit") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - if (*bitrateLimitName != '\0' && - strcasecmp(bitrateLimitName, value) != 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Overriding option 'limit' " - << "with new value '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Overriding option 'limit' " - << "with new value '" << value << "'.\n"; - } - - if (ParseBitrateOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify 'limit' " - << "option in string '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify 'limit' " - << "option in string '" << value << "'.\n"; - - return -1; - } - } - - } - else if (strcasecmp(name, "render") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - useRender = ValidateArg("remote", name, value); - } - - } - else if (strcasecmp(name, "taint") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - useTaint = ValidateArg("remote", name, value); - } - - } - else if (strcasecmp(name, "type") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - if (strcasecmp(value, "default") == 0) - { - *sessionType = '\0'; - } - else - { - strncpy(sessionType, value, DEFAULT_STRING_LENGTH - 1); - } - } - - hasType = 1; - } - else if (strcasecmp(name, "strict") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - useStrict = ValidateArg("remote", name, value); - } - - } - else if (strcasecmp(name, "shseg") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else if (ParseShmemOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify size of shared memory " - << "segment in string '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify size of shared memory " - << "segment in string '" << value << "'.\n"; - - return -1; - } - - } - else if (strcasecmp(name, "delta") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - control -> RemoteDeltaCompression = ValidateArg("remote", name, value); - - // - // Follow for delta compression the - // same settings as the client proxy. - // - - control -> LocalDeltaCompression = control -> RemoteDeltaCompression; - } - - hasDelta = 1; - } - else if (strcasecmp(name, "stream") == 0) - { - // - // If remote side didn't choose its own - // stream compression level then assume - // local settings. - // - - if (strcasecmp(value, "default") == 0) - { - // - // This applies only at client side. - // - - control -> RemoteStreamCompression = - control -> LocalStreamCompression; - - control -> RemoteStreamCompressionLevel = - control -> LocalStreamCompressionLevel; - } - else - { - control -> RemoteStreamCompressionLevel = ValidateArg("remote", name, value); - - if (control -> RemoteStreamCompressionLevel > 0) - { - control -> RemoteStreamCompression = 1; - } - else - { - control -> RemoteStreamCompression = 0; - } - - if (control -> LocalStreamCompressionLevel < 0) - { - control -> LocalStreamCompressionLevel = ValidateArg("remote", name, value); - - if (control -> LocalStreamCompressionLevel > 0) - { - control -> LocalStreamCompression = 1; - } - else - { - control -> LocalStreamCompression = 0; - } - } - } - - hasStream = 1; - } - else if (strcasecmp(name, "data") == 0) - { - // - // Apply the same to data compression level. - // - - if (strcasecmp(value, "default") == 0) - { - control -> RemoteDataCompression = - control -> LocalDataCompression; - - control -> RemoteDataCompressionLevel = - control -> LocalDataCompressionLevel; - } - else - { - control -> RemoteDataCompressionLevel = ValidateArg("remote", name, value); - - if (control -> RemoteDataCompressionLevel > 0) - { - control -> RemoteDataCompression = 1; - } - else - { - control -> RemoteDataCompression = 0; - } - - if (control -> LocalDataCompressionLevel < 0) - { - control -> LocalDataCompressionLevel = ValidateArg("remote", name, value); - - if (control -> LocalDataCompressionLevel > 0) - { - control -> LocalDataCompression = 1; - } - else - { - control -> LocalDataCompression = 0; - } - } - } - - hasData = 1; - } - else if (strcasecmp(name, "flush") == 0) - { - // - // This option has no effect in recent - // versions. - // - - #ifdef DEBUG - *logofs << "Loop: Ignoring obsolete remote option '" - << name << "' with value '" << value - << "'.\n" << logofs_flush; - #endif - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring unknown remote option '" - << name << "' with value '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Ignoring unknown remote option '" - << name << "' with value '" << value << "'.\n"; - } - - name = strtok(NULL, "="); - - } // End of while (name) ... - - // - // If we are client side, we need remote 'stream' - // and 'data' options. If we are server, we need - // all the above plus 'link' and some others. - // - - char missing[DEFAULT_STRING_LENGTH]; - - *missing = '\0'; - - if (control -> ProxyMode == proxy_client) - { - if (hasStream == 0) - { - strcpy(missing, "stream"); - } - else if (hasData == 0) - { - strcpy(missing, "data"); - } - } - else - { - // - // Don't complain if the optional 'flush', - // 'render' and 'taint' options are not - // provided. - // - - if (hasLink == 0) - { - strcpy(missing, "link"); - } - else if (hasCache == 0) - { - strcpy(missing, "cache"); - } - else if (hasPack == 0) - { - strcpy(missing, "pack"); - } - else if (hasDelta == 0) - { - strcpy(missing, "delta"); - } - else if (hasStream == 0) - { - strcpy(missing, "stream"); - } - else if (hasData == 0) - { - strcpy(missing, "data"); - } - else if (hasType == 0) - { - strcpy(missing, "type"); - } - else if (hasImages == 0) - { - strcpy(missing, "images"); - } - } - - if (WE_PROVIDE_CREDENTIALS == 0) - { - // - // Can be that user doesn't have requested to - // check the authorization cookie provided by - // the connecting peer. - // - - if (hasCookie == 0 && *authCookie != '\0') - { - strcpy(missing, "cookie"); - } - } - - if (*missing != '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! The remote peer didn't specify the option '" - << missing << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": The remote peer didn't specify the option '" - << missing << "'.\n"; - - return -1; - } - - return 1; -} - -// -// Parse the cookie provided by the NX proxy -// connection forwarder. -// - -int ParseForwarderOptions(char *opts) -{ - #ifdef TEST - *logofs << "Loop: Going to parse the forwarder options " - << "string '" << opts << "'.\n" - << logofs_flush; - #endif - - char *name; - char *value; - - int hasCookie = 0; - - // - // Get rid of the terminating space. - // - - if (*(opts + strlen(opts) - 1) == ' ') - { - *(opts + strlen(opts) - 1) = '\0'; - } - - name = strtok(opts, "="); - - while (name) - { - value = strtok(NULL, ","); - - if (CheckArg("forwarder", name, value) < 0) - { - return -1; - } - - if (strcasecmp(name, "cookie") == 0) - { - if (strncasecmp(authCookie, value, strlen(authCookie)) != 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! The NX forwarder cookie '" << value - << "' doesn't match '" << authCookie << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": The NX forwarder cookie '" << value - << "' doesn't match '" << authCookie << "'.\n"; - - return -1; - } - - hasCookie = 1; - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring unknown forwarder option '" - << name << "' with value '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Ignoring unknown forwarder option '" - << name << "' with value '" << value << "'.\n"; - } - - name = strtok(NULL, "="); - - } // End of while (name) ... - - if (hasCookie == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! The NX forwarder didn't provide " - << "the authentication cookie.\n" << logofs_flush; - #endif - - cerr << "Error" << ": The NX forwarder didn't provide " - << "the authentication cookie.\n"; - - return -1; - } - - return 1; -} - -int SetCore() -{ - #ifdef COREDUMPS - - rlimit rlim; - - if (getrlimit(RLIMIT_CORE, &rlim)) - { - #ifdef TEST - *logofs << "Loop: Cannot read RLIMIT_CORE. Error is '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - return -1; - } - - if (rlim.rlim_cur < rlim.rlim_max) - { - rlim.rlim_cur = rlim.rlim_max; - - if (setrlimit(RLIMIT_CORE, &rlim)) - { - #ifdef TEST - *logofs << "Loop: Cannot set RLIMIT_CORE. Error is '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - return -2; - } - } - - #ifdef TEST - *logofs << "Loop: RLIMIT_CORE is "<< rlim.rlim_max - << ".\n" << logofs_flush; - #endif - - #endif // #ifdef COREDUMPS - - return 1; -} - -char *GetLastCache(char *listBuffer, const char *searchPath) -{ - if (listBuffer == NULL || searchPath == NULL || - strncmp(listBuffer, "cachelist=", strlen("cachelist=")) != 0) - { - #ifdef TEST - *logofs << "Loop: Invalid parameters '" << listBuffer << "' and '" - << (searchPath != NULL ? searchPath : "") - << "'. Can't select any cache.\n" << logofs_flush; - #endif - - return NULL; - } - - char *selectedName = new char[MD5_LENGTH * 2 + 3]; - - *selectedName = '\0'; - - const char *localPrefix; - const char *remotePrefix; - - if (control -> ProxyMode == proxy_client) - { - localPrefix = "C-"; - remotePrefix = "S-"; - } - else - { - localPrefix = "S-"; - remotePrefix = "C-"; - } - - // - // Get rid of prefix. - // - - listBuffer += strlen("cachelist="); - - char *fileName; - - fileName = strtok(listBuffer, ","); - - // - // It is "/path/to/file" + "/" + "C-" + 32 + "\0". - // - - char fullPath[strlen(searchPath) + MD5_LENGTH * 2 + 4]; - - time_t selectedTime = 0; - - struct stat fileStat; - - while (fileName) - { - if (strncmp(fileName, "none", strlen("none")) == 0) - { - #ifdef TEST - *logofs << "Loop: No cache files seem to be available.\n" - << logofs_flush; - #endif - - delete [] selectedName; - - return NULL; - } - else if (strlen(fileName) != MD5_LENGTH * 2 + 2 || - strncmp(fileName, remotePrefix, 2) != 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Bad cache file name '" - << fileName << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Bad cache file name '" - << fileName << "'.\n"; - - delete [] selectedName; - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "Loop: Parsing remote cache name '" - << fileName << "'.\n" << logofs_flush; - #endif - - // - // Prefix, received as "S-", becomes - // "C-" and viceversa. - // - - *fileName = *localPrefix; - - strcpy(fullPath, searchPath); - strcat(fullPath, "/"); - strcat(fullPath, fileName); - - if (stat(fullPath, &fileStat) == 0) - { - #ifdef TEST - *logofs << "Loop: Found a matching cache '" - << fullPath << "'.\n" << logofs_flush; - #endif - - if (fileStat.st_mtime >= selectedTime) - { - strcpy(selectedName, fileName); - - selectedTime = fileStat.st_mtime; - } - } - #ifdef TEST - else - { - *logofs << "Loop: Can't get stats of file '" - << fullPath << "'.\n" << logofs_flush; - } - #endif - - fileName = strtok(NULL, ","); - } - - if (*selectedName != '\0') - { - return selectedName; - } - else - { - delete [] selectedName; - - return NULL; - } -} - -char *GetTempPath() -{ - if (*tempDir == '\0') - { - // - // Check the NX_TEMP environment, first, - // then the TEMP variable. - // - - const char *tempEnv = getenv("NX_TEMP"); - - if (tempEnv == NULL || *tempEnv == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No environment for NX_TEMP.\n" - << logofs_flush; - #endif - - tempEnv = getenv("TEMP"); - - if (tempEnv == NULL || *tempEnv == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No environment for TEMP.\n" - << logofs_flush; - #endif - - tempEnv = "/tmp"; - } - } - - if (strlen(tempEnv) > DEFAULT_STRING_LENGTH - 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value for the NX " - << "temporary directory '" << tempEnv - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value for the NX " - << "temporary directory '" << tempEnv - << "'.\n"; - - HandleCleanup(); - } - - strcpy(tempDir, tempEnv); - - #ifdef TEST - *logofs << "Loop: Assuming temporary NX directory '" - << tempDir << "'.\n" << logofs_flush; - #endif - } - - char *tempPath = new char[strlen(tempDir) + 1]; - - if (tempPath == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't allocate memory " - << "for the temp path.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory " - << "for the temp path.\n"; - - HandleCleanup(); - } - - strcpy(tempPath, tempDir); - - return tempPath; -} - -char *GetClientPath() -{ - if (*clientDir == '\0') - { - // - // Check the NX_CLIENT environment. - // - - const char *clientEnv = getenv("NX_CLIENT"); - - if (clientEnv == NULL || *clientEnv == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No environment for NX_CLIENT.\n" - << logofs_flush; - #endif - - // - // Try to guess the location of the client. - // - - clientEnv = "/usr/NX/bin/nxclient"; - - #ifdef __APPLE__ - - clientEnv = "/Applications/NX Client for OSX.app/Contents/MacOS/nxclient"; - - #endif - - #ifdef __CYGWIN32__ - - clientEnv = "C:\\Program Files\\NX Client for Windows\\nxclient"; - - #endif - } - - if (strlen(clientEnv) > DEFAULT_STRING_LENGTH - 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value for the NX " - << "client directory '" << clientEnv - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value for the NX " - << "client directory '" << clientEnv - << "'.\n"; - - HandleCleanup(); - } - - strcpy(clientDir, clientEnv); - - #ifdef TEST - *logofs << "Loop: Assuming NX client location '" - << clientDir << "'.\n" << logofs_flush; - #endif - } - - char *clientPath = new char[strlen(clientDir) + 1]; - - if (clientPath == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't allocate memory " - << "for the client path.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory " - << "for the client path.\n"; - - HandleCleanup(); - } - - strcpy(clientPath, clientDir); - - return clientPath; -} - -char *GetSystemPath() -{ - if (*systemDir == '\0') - { - // - // Check the NX_SYSTEM environment. - // - - const char *systemEnv = getenv("NX_SYSTEM"); - - if (systemEnv == NULL || *systemEnv == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No environment for NX_SYSTEM.\n" - << logofs_flush; - #endif - - systemEnv = "/usr/NX"; - } - - if (strlen(systemEnv) > DEFAULT_STRING_LENGTH - 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value for the NX " - << "system directory '" << systemEnv - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value for the NX " - << "system directory '" << systemEnv - << "'.\n"; - - HandleCleanup(); - } - - strcpy(systemDir, systemEnv); - - #ifdef TEST - *logofs << "Loop: Assuming system NX directory '" - << systemDir << "'.\n" << logofs_flush; - #endif - } - - char *systemPath = new char[strlen(systemDir) + 1]; - - if (systemPath == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't allocate memory " - << "for the system path.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory " - << "for the system path.\n"; - - HandleCleanup(); - } - - strcpy(systemPath, systemDir); - - return systemPath; -} - -char *GetHomePath() -{ - if (*homeDir == '\0') - { - // - // Check the NX_HOME environment. - // - - const char *homeEnv = getenv("NX_HOME"); - - if (homeEnv == NULL || *homeEnv == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No environment for NX_HOME.\n" - << logofs_flush; - #endif - - homeEnv = getenv("HOME"); - - if (homeEnv == NULL || *homeEnv == '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! No environment for HOME.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": No environment for HOME.\n"; - - HandleCleanup(); - } - } - - if (strlen(homeEnv) > DEFAULT_STRING_LENGTH - 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value for the NX " - << "home directory '" << homeEnv - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value for the NX " - << "home directory '" << homeEnv - << "'.\n"; - - HandleCleanup(); - } - - strcpy(homeDir, homeEnv); - - #ifdef TEST - *logofs << "Loop: Assuming NX user's home directory '" - << homeDir << "'.\n" << logofs_flush; - #endif - } - - char *homePath = new char[strlen(homeDir) + 1]; - - if (homePath == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't allocate memory " - << "for the home path.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory " - << "for the home path.\n"; - - HandleCleanup(); - } - - strcpy(homePath, homeDir); - - return homePath; -} - -char *GetRootPath() -{ - if (*rootDir == '\0') - { - // - // Check the NX_ROOT environment. - // - - const char *rootEnv = getenv("NX_ROOT"); - - if (rootEnv == NULL || *rootEnv == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No environment for NX_ROOT.\n" - << logofs_flush; - #endif - - // - // We will determine the root NX directory - // based on the NX_HOME or HOME directory - // settings. - // - - const char *homeEnv = GetHomePath(); - - if (strlen(homeEnv) > DEFAULT_STRING_LENGTH - - strlen("/.nx") - 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value for the NX " - << "home directory '" << homeEnv - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value for the NX " - << "home directory '" << homeEnv - << "'.\n"; - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "Loop: Assuming NX root directory in " - << "the user's home '" << homeEnv - << "'.\n" << logofs_flush; - #endif - - strcpy(rootDir, homeEnv); - strcat(rootDir, "/.nx"); - - delete [] homeEnv; - - // - // Create the NX root directory. - // - - struct stat dirStat; - - if ((stat(rootDir, &dirStat) == -1) && (EGET() == ENOENT)) - { - if (mkdir(rootDir, 0700) < 0 && (EGET() != EEXIST)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't create directory '" - << rootDir << ". Error is " << EGET() << " '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't create directory '" - << rootDir << ". Error is " << EGET() << " '" - << ESTR() << "'.\n"; - - HandleCleanup(); - } - } - } - else - { - if (strlen(rootEnv) > DEFAULT_STRING_LENGTH - 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value for the NX " - << "root directory '" << rootEnv - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value for the NX " - << "root directory '" << rootEnv - << "'.\n"; - - HandleCleanup(); - } - - strcpy(rootDir, rootEnv); - } - - #ifdef TEST - *logofs << "Loop: Assuming NX root directory '" - << rootDir << "'.\n" << logofs_flush; - #endif - } - - char *rootPath = new char[strlen(rootDir) + 1]; - - if (rootPath == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't allocate memory " - << "for the root path.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory " - << "for the root path.\n"; - - HandleCleanup(); - } - - strcpy(rootPath, rootDir); - - return rootPath; -} - -char *GetCachePath() -{ - char *rootPath = GetRootPath(); - - char *cachePath; - - if (*sessionType != '\0') - { - cachePath = new char[strlen(rootPath) + strlen("/cache-") + - strlen(sessionType) + 1]; - } - else - { - cachePath = new char[strlen(rootPath) + strlen("/cache") + 1]; - } - - strcpy(cachePath, rootPath); - - if (*sessionType != '\0') - { - strcat(cachePath, "/cache-"); - - strcat(cachePath, sessionType); - } - else - { - strcat(cachePath, "/cache"); - } - - // - // Create the cache directory if needed. - // - - struct stat dirStat; - - if ((stat(cachePath, &dirStat) == -1) && (EGET() == ENOENT)) - { - if (mkdir(cachePath, 0700) < 0 && (EGET() != EEXIST)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't create directory '" << cachePath - << ". Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't create directory '" << cachePath - << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; - - delete [] rootPath; - delete [] cachePath; - - return NULL; - } - } - - delete [] rootPath; - - return cachePath; -} - -char *GetImagesPath() -{ - char *rootPath = GetRootPath(); - - char *imagesPath = new char[strlen(rootPath) + strlen("/images") + 1]; - - strcpy(imagesPath, rootPath); - - strcat(imagesPath, "/images"); - - // - // Create the cache directory if needed. - // - - struct stat dirStat; - - if ((stat(imagesPath, &dirStat) == -1) && (EGET() == ENOENT)) - { - if (mkdir(imagesPath, 0700) < 0 && (EGET() != EEXIST)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't create directory '" << imagesPath - << ". Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't create directory '" << imagesPath - << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; - - delete [] rootPath; - delete [] imagesPath; - - return NULL; - } - } - - // - // Create 16 directories in the path to - // hold the images whose name begins with - // the corresponding hexadecimal digit. - // - - char *digitPath = new char[strlen(imagesPath) + 5]; - - strcpy(digitPath, imagesPath); - - // - // Image paths have format "[path][/I-c][\0]", - // where c is the first digit of the checksum. - // - - for (char digit = 0; digit < 16; digit++) - { - sprintf(digitPath + strlen(imagesPath), "/I-%01X", digit); - - if ((stat(digitPath, &dirStat) == -1) && (EGET() == ENOENT)) - { - if (mkdir(digitPath, 0700) < 0 && (EGET() != EEXIST)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't create directory '" << digitPath - << ". Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't create directory '" << digitPath - << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; - - delete [] rootPath; - delete [] imagesPath; - delete [] digitPath; - - return NULL; - } - } - } - - delete [] rootPath; - delete [] digitPath; - - return imagesPath; -} - -char *GetSessionPath() -{ - if (*sessionDir == '\0') - { - char *rootPath = GetRootPath(); - - strcpy(sessionDir, rootPath); - - if (control -> ProxyMode == proxy_client) - { - strcat(sessionDir, "/C-"); - } - else - { - strcat(sessionDir, "/S-"); - } - - if (*sessionId == '\0') - { - char port[DEFAULT_STRING_LENGTH]; - - sprintf(port, "%d", proxyPort); - - strcpy(sessionId, port); - } - - strcat(sessionDir, sessionId); - - struct stat dirStat; - - if ((stat(sessionDir, &dirStat) == -1) && (EGET() == ENOENT)) - { - if (mkdir(sessionDir, 0700) < 0 && (EGET() != EEXIST)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't create directory '" << sessionDir - << ". Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't create directory '" << sessionDir - << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; - - delete [] rootPath; - - return NULL; - } - } - - #ifdef TEST - *logofs << "Loop: Root of NX session is '" << sessionDir - << "'.\n" << logofs_flush; - #endif - - delete [] rootPath; - } - - char *sessionPath = new char[strlen(sessionDir) + 1]; - - strcpy(sessionPath, sessionDir); - - return sessionPath; -} - -// -// Identify requested link characteristics -// and set control parameters accordingly. -// - -int ParseLinkOption(const char *opt) -{ - // - // Normalize the user input. - // - - if (strcasecmp(opt, "modem") == 0 || - strcasecmp(opt, "33k") == 0 || - strcasecmp(opt, "56k") == 0) - { - strcpy(linkSpeedName, "MODEM"); - } - else if (strcasecmp(opt, "isdn") == 0 || - strcasecmp(opt, "64k") == 0 || - strcasecmp(opt, "128k") == 0) - { - strcpy(linkSpeedName, "ISDN"); - } - else if (strcasecmp(opt, "adsl") == 0 || - strcasecmp(opt, "256k") == 0 || - strcasecmp(opt, "640k") == 0) - { - strcpy(linkSpeedName, "ADSL"); - } - else if (strcasecmp(opt, "wan") == 0 || - strcasecmp(opt, "1m") == 0 || - strcasecmp(opt, "2m") == 0 || - strcasecmp(opt, "34m") == 0) - { - strcpy(linkSpeedName, "WAN"); - } - else if (strcasecmp(opt, "lan") == 0 || - strcasecmp(opt, "10m") == 0 || - strcasecmp(opt, "100m") == 0 || - strcasecmp(opt, "local") == 0) - { - strcpy(linkSpeedName, "LAN"); - } - - if (strcasecmp(linkSpeedName, "modem") != 0 && - strcasecmp(linkSpeedName, "isdn") != 0 && - strcasecmp(linkSpeedName, "adsl") != 0 && - strcasecmp(linkSpeedName, "wan") != 0 && - strcasecmp(linkSpeedName, "lan") != 0) - { - return -1; - } - - return 1; -} - -int ParsePackOption(const char *opt) -{ - #ifdef DEBUG - *logofs << "Loop: Pack method is " << packMethod - << " quality is " << packQuality << ".\n" - << logofs_flush; - #endif - - #ifdef DEBUG - *logofs << "Loop: Parsing pack method '" << opt - << "'.\n" << logofs_flush; - #endif - - if (strcasecmp(opt, "0") == 0 || - strcasecmp(opt, "none") == 0 || - strcasecmp(opt, "nopack") == 0 || - strcasecmp(opt, "no-pack") == 0) - { - packMethod = PACK_NONE; - } - else if (strcasecmp(opt, "8") == 0) - { - packMethod = PACK_MASKED_8_COLORS; - } - else if (strcasecmp(opt, "64") == 0) - { - packMethod = PACK_MASKED_64_COLORS; - } - else if (strcasecmp(opt, "256") == 0) - { - packMethod = PACK_MASKED_256_COLORS; - } - else if (strcasecmp(opt, "512") == 0) - { - packMethod = PACK_MASKED_512_COLORS; - } - else if (strcasecmp(opt, "4k") == 0) - { - packMethod = PACK_MASKED_4K_COLORS; - } - else if (strcasecmp(opt, "32k") == 0) - { - packMethod = PACK_MASKED_32K_COLORS; - } - else if (strcasecmp(opt, "64k") == 0) - { - packMethod = PACK_MASKED_64K_COLORS; - } - else if (strcasecmp(opt, "256k") == 0) - { - packMethod = PACK_MASKED_256K_COLORS; - } - else if (strcasecmp(opt, "2m") == 0) - { - packMethod = PACK_MASKED_2M_COLORS; - } - else if (strcasecmp(opt, "16m") == 0) - { - packMethod = PACK_MASKED_16M_COLORS; - } - else if (strncasecmp(opt, "8-jpeg", strlen("8-jpeg")) == 0) - { - packMethod = PACK_JPEG_8_COLORS; - } - else if (strncasecmp(opt, "64-jpeg", strlen("64-jpeg")) == 0) - { - packMethod = PACK_JPEG_64_COLORS; - } - else if (strncasecmp(opt, "256-jpeg", strlen("256-jpeg")) == 0) - { - packMethod = PACK_JPEG_256_COLORS; - } - else if (strncasecmp(opt, "512-jpeg", strlen("512-jpeg")) == 0) - { - packMethod = PACK_JPEG_512_COLORS; - } - else if (strncasecmp(opt, "4k-jpeg", strlen("4k-jpeg")) == 0) - { - packMethod = PACK_JPEG_4K_COLORS; - } - else if (strncasecmp(opt, "32k-jpeg", strlen("32k-jpeg")) == 0) - { - packMethod = PACK_JPEG_32K_COLORS; - } - else if (strncasecmp(opt, "64k-jpeg", strlen("64k-jpeg")) == 0) - { - packMethod = PACK_JPEG_64K_COLORS; - } - else if (strncasecmp(opt, "256k-jpeg", strlen("256k-jpeg")) == 0) - { - packMethod = PACK_JPEG_256K_COLORS; - } - else if (strncasecmp(opt, "2m-jpeg", strlen("2m-jpeg")) == 0) - { - packMethod = PACK_JPEG_2M_COLORS; - } - else if (strncasecmp(opt, "16m-jpeg", strlen("16m-jpeg")) == 0) - { - packMethod = PACK_JPEG_16M_COLORS; - } - else if (strncasecmp(opt, "8-png", strlen("8-png")) == 0) - { - packMethod = PACK_PNG_8_COLORS; - } - else if (strncasecmp(opt, "64-png", strlen("64-png")) == 0) - { - packMethod = PACK_PNG_64_COLORS; - } - else if (strncasecmp(opt, "256-png", strlen("256-png")) == 0) - { - packMethod = PACK_PNG_256_COLORS; - } - else if (strncasecmp(opt, "512-png", strlen("512-png")) == 0) - { - packMethod = PACK_PNG_512_COLORS; - } - else if (strncasecmp(opt, "4k-png", strlen("4k-png")) == 0) - { - packMethod = PACK_PNG_4K_COLORS; - } - else if (strncasecmp(opt, "32k-png", strlen("32k-png")) == 0) - { - packMethod = PACK_PNG_32K_COLORS; - } - else if (strncasecmp(opt, "64k-png", strlen("64k-png")) == 0) - { - packMethod = PACK_PNG_64K_COLORS; - } - else if (strncasecmp(opt, "256k-png", strlen("256k-png")) == 0) - { - packMethod = PACK_PNG_256K_COLORS; - } - else if (strncasecmp(opt, "2m-png", strlen("2m-png")) == 0) - { - packMethod = PACK_PNG_2M_COLORS; - } - else if (strncasecmp(opt, "16m-png", strlen("16m-png")) == 0) - { - packMethod = PACK_PNG_16M_COLORS; - } - else if (strncasecmp(opt, "16m-rgb", strlen("16m-rgb")) == 0 || - strncasecmp(opt, "rgb", strlen("rgb")) == 0) - { - packMethod = PACK_RGB_16M_COLORS; - } - else if (strncasecmp(opt, "16m-rle", strlen("16m-rle")) == 0 || - strncasecmp(opt, "rle", strlen("rle")) == 0) - { - packMethod = PACK_RLE_16M_COLORS; - } - else if (strncasecmp(opt, "16m-bitmap", strlen("16m-bitmap")) == 0 || - strncasecmp(opt, "bitmap", strlen("bitmap")) == 0) - { - packMethod = PACK_BITMAP_16M_COLORS; - } - else if (strncasecmp(opt, "lossy", strlen("lossy")) == 0) - { - packMethod = PACK_LOSSY; - } - else if (strncasecmp(opt, "lossless", strlen("lossless")) == 0) - { - packMethod = PACK_LOSSLESS; - } - else if (strncasecmp(opt, "adaptive", strlen("adaptive")) == 0) - { - packMethod = PACK_ADAPTIVE; - } - else - { - return -1; - } - - if (packMethod == PACK_NONE) - { - strcpy(packMethodName, "none"); - } - else - { - strcpy(packMethodName, opt); - } - - if (packMethod == PACK_RGB_16M_COLORS || - packMethod == PACK_RLE_16M_COLORS || - packMethod == PACK_BITMAP_16M_COLORS || - (packMethod >= PACK_JPEG_8_COLORS && - packMethod <= PACK_JPEG_16M_COLORS) || - (packMethod >= PACK_PNG_8_COLORS && - packMethod <= PACK_PNG_16M_COLORS) || - packMethod == PACK_LOSSY || - packMethod == PACK_LOSSLESS || - packMethod == PACK_ADAPTIVE) - { - const char *dash = strrchr(opt, '-'); - - if (dash != NULL && strlen(dash) == 2 && - *(dash + 1) >= '0' && *(dash + 1) <= '9') - { - packQuality = atoi(dash + 1); - - #ifdef DEBUG - *logofs << "Loop: Using pack quality '" - << packQuality << "'.\n" << logofs_flush; - #endif - } - } - else - { - packQuality = 0; - } - - return 1; -} - -int ParsePackMethod(const int method, const int quality) -{ - switch (method) - { - case PACK_NONE: - { - strcpy(packMethodName, "none"); - - break; - } - case PACK_MASKED_8_COLORS: - { - strcpy(packMethodName, "8"); - - break; - } - case PACK_MASKED_64_COLORS: - { - strcpy(packMethodName, "64"); - - break; - } - case PACK_MASKED_256_COLORS: - { - strcpy(packMethodName, "256"); - - break; - } - case PACK_MASKED_512_COLORS: - { - strcpy(packMethodName, "512"); - - break; - } - case PACK_MASKED_4K_COLORS: - { - strcpy(packMethodName, "4k"); - - break; - } - case PACK_MASKED_32K_COLORS: - { - strcpy(packMethodName, "32k"); - - break; - } - case PACK_MASKED_64K_COLORS: - { - strcpy(packMethodName, "64k"); - - break; - } - case PACK_MASKED_256K_COLORS: - { - strcpy(packMethodName, "256k"); - - break; - } - case PACK_MASKED_2M_COLORS: - { - strcpy(packMethodName, "2m"); - - break; - } - case PACK_MASKED_16M_COLORS: - { - strcpy(packMethodName, "16m"); - - break; - } - case PACK_JPEG_8_COLORS: - { - strcpy(packMethodName, "8-jpeg"); - - break; - } - case PACK_JPEG_64_COLORS: - { - strcpy(packMethodName, "64-jpeg"); - - break; - } - case PACK_JPEG_256_COLORS: - { - strcpy(packMethodName, "256-jpeg"); - - break; - } - case PACK_JPEG_512_COLORS: - { - strcpy(packMethodName, "512-jpeg"); - - break; - } - case PACK_JPEG_4K_COLORS: - { - strcpy(packMethodName, "4k-jpeg"); - - break; - } - case PACK_JPEG_32K_COLORS: - { - strcpy(packMethodName, "32k-jpeg"); - - break; - } - case PACK_JPEG_64K_COLORS: - { - strcpy(packMethodName, "64k-jpeg"); - - break; - } - case PACK_JPEG_256K_COLORS: - { - strcpy(packMethodName, "256k-jpeg"); - - break; - } - case PACK_JPEG_2M_COLORS: - { - strcpy(packMethodName, "2m-jpeg"); - - break; - } - case PACK_JPEG_16M_COLORS: - { - strcpy(packMethodName, "16m-jpeg"); - - break; - } - case PACK_PNG_8_COLORS: - { - strcpy(packMethodName, "8-png"); - - break; - } - case PACK_PNG_64_COLORS: - { - strcpy(packMethodName, "64-png"); - - break; - } - case PACK_PNG_256_COLORS: - { - strcpy(packMethodName, "256-png"); - - break; - } - case PACK_PNG_512_COLORS: - { - strcpy(packMethodName, "512-png"); - - break; - } - case PACK_PNG_4K_COLORS: - { - strcpy(packMethodName, "4k-png"); - - break; - } - case PACK_PNG_32K_COLORS: - { - strcpy(packMethodName, "32k-png"); - - break; - } - case PACK_PNG_64K_COLORS: - { - strcpy(packMethodName, "64k-png"); - - break; - } - case PACK_PNG_256K_COLORS: - { - strcpy(packMethodName, "256k-png"); - - break; - } - case PACK_PNG_2M_COLORS: - { - strcpy(packMethodName, "2m-png"); - - break; - } - case PACK_PNG_16M_COLORS: - { - strcpy(packMethodName, "16m-png"); - - break; - } - case PACK_RGB_16M_COLORS: - { - strcpy(packMethodName, "16m-rgb"); - - break; - } - case PACK_RLE_16M_COLORS: - { - strcpy(packMethodName, "16m-rle"); - - break; - } - case PACK_BITMAP_16M_COLORS: - { - strcpy(packMethodName, "16m-bitmap"); - - break; - } - case PACK_LOSSY: - { - strcpy(packMethodName, "lossy"); - - break; - } - case PACK_LOSSLESS: - { - strcpy(packMethodName, "lossless"); - - break; - } - case PACK_ADAPTIVE: - { - strcpy(packMethodName, "adaptive"); - - break; - } - default: - { - return -1; - } - } - - if (quality < 0 || quality > 9) - { - return -1; - } - - if (packMethod == PACK_RGB_16M_COLORS || - packMethod == PACK_RLE_16M_COLORS || - packMethod == PACK_BITMAP_16M_COLORS || - (packMethod >= PACK_JPEG_8_COLORS && - packMethod <= PACK_JPEG_16M_COLORS) || - (packMethod >= PACK_PNG_8_COLORS && - packMethod <= PACK_PNG_16M_COLORS) || - packMethod == PACK_LOSSY || - packMethod == PACK_LOSSLESS || - packMethod == PACK_ADAPTIVE) - { - sprintf(packMethodName + strlen(packMethodName), - "-%d", quality); - } - - packMethod = method; - packQuality = quality; - - control -> PackMethod = packMethod; - control -> PackQuality = packQuality; - - return 1; -} - -int SetDirectories() -{ - // - // Determine the location of the user's NX - // directory and the other relevant paths. - // The functions below will check the pa- - // rameters passed to the program and will - // query the environment, if needed. - // - - control -> HomePath = GetHomePath(); - control -> RootPath = GetRootPath(); - control -> SystemPath = GetSystemPath(); - control -> TempPath = GetTempPath(); - control -> ClientPath = GetClientPath(); - - return 1; -} - -int SetLogs() -{ - // - // So far we used stderr (or stdout under - // WIN32). Now use the files selected by - // the user. - // - - if (*statsFileName == '\0') - { - strcpy(statsFileName, "stats"); - - #ifdef TEST - *logofs << "Loop: Assuming default statistics file '" - << statsFileName << "'.\n" << logofs_flush; - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Name selected for statistics is '" - << statsFileName << "'.\n" << logofs_flush; - } - #endif - - if (OpenLogFile(statsFileName, statofs) < 0) - { - HandleCleanup(); - } - - #ifndef MIXED - - if (*errorsFileName == '\0') - { - strcpy(errorsFileName, "errors"); - - #ifdef TEST - *logofs << "Loop: Assuming default log file name '" - << errorsFileName << "'.\n" << logofs_flush; - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Name selected for log file is '" - << errorsFileName << "'.\n" << logofs_flush; - } - #endif - - // - // Share the bebug output with the nxssh binder - // process. The file must be made writable by - // everybody because the nxssh process is run by - // nxserver as the nx user. - // - - #ifdef BINDER - - strcpy(errorsFileName, "/tmp/errors"); - - ostream *tmpfs = new ofstream(errorsFileName, ios::out); - - delete tmpfs; - - chmod(errorsFileName, S_IRUSR | S_IWUSR | S_IRGRP | - S_IWGRP | S_IROTH | S_IWOTH); - - #endif - - if (OpenLogFile(errorsFileName, logofs) < 0) - { - HandleCleanup(); - } - - // - // By default the session log is the standard error - // of the process. It is anyway required to set the - // option when running inside SSH, otherwise the - // output will go to the same file as the SSH log, - // depending where the NX client has redirected the - // output. - // - - if (*sessionFileName != '\0') - { - #ifdef TEST - *logofs << "Loop: Name selected for session file is '" - << sessionFileName << "'.\n" << logofs_flush; - #endif - - if (errofs != NULL) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Unexpected value for stream errofs.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Unexpected value for stream errofs.\n"; - } - - if (errsbuf != NULL) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Unexpected value for buffer errsbuf.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Unexpected value for buffer errsbuf.\n"; - } - - errofs = NULL; - errsbuf = NULL; - - if (OpenLogFile(sessionFileName, errofs) < 0) - { - HandleCleanup(); - } - - // - // Redirect the standard error to the file. - // - - errsbuf = cerr.rdbuf(errofs -> rdbuf()); - } - - #endif - - return 1; -} - -int SetPorts() -{ - // - // Depending on the proxy side, we need to determine on which - // port to listen for the given protocol or to which port we - // will have to forward the connection. Three possibilities - // are given for each supported protocol: - // - // Port <= 0: Disable port forwarding. - // Port == 1: Use the default port. - // Port > 1: Use the specified port. - // - // At the connectiong side the user should always explicitly - // set the ports where the connections will be forwarded. This - // is both for security reasons and because, when running both - // proxies on the same host, there is a concrete possibility - // that, by using the default ports, the connection will be - // forwarded to the same port where the peer proxy is listen- - // ing, causing a loop. - // - - useCupsSocket = 0; - if (cupsPort.enabled()) { - if (control -> ProxyMode == proxy_client) { - cupsPort.setDefaultTCPPort(DEFAULT_NX_CUPS_PORT_OFFSET + proxyPort); - useCupsSocket = 1; - } - else - cupsPort.setDefaultTCPPort(631); - } - -#ifdef TEST - *logofs << "Loop: cups port: " << cupsPort << "\n" - << logofs_flush; -#endif - - useAuxSocket = 0; - if (auxPort.enabled()) { - if (control -> ProxyMode == proxy_client) { - auxPort.setDefaultTCPPort(DEFAULT_NX_AUX_PORT_OFFSET + proxyPort); - useAuxSocket = 1; - } - else { - auxPort.setDefaultTCPPort(1); - - if (auxPort.getTCPPort() != 1) { - -#ifdef WARNING - *logofs << "Loop: WARNING! Overriding auxiliary X11 " - << "port with new value '" << 1 << "'.\n" - << logofs_flush; -#endif - - cerr << "Warning" << ": Overriding auxiliary X11 " - << "port with new value '" << 1 << "'.\n"; - - auxPort.setSpec("1"); - } - } - } - -#ifdef TEST - *logofs << "Loop: aux port: " << auxPort << "\n" - << logofs_flush; -#endif - - useSmbSocket = 0; - if (smbPort.enabled()) { - if (control -> ProxyMode == proxy_client) { - auxPort.setDefaultTCPPort(DEFAULT_NX_SMB_PORT_OFFSET + proxyPort); - useAuxSocket = 1; - } - else - auxPort.setDefaultTCPPort(139); - } - - -#ifdef TEST - *logofs << "Loop: smb port: " << smbPort << "\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.getTCPPort() == 1) { -#ifdef PANIC - *logofs << "Loop: PANIC! No port specified for multimedia connections.\n" - << logofs_flush; -#endif - - cerr << "Error" << ": No port specified for multimedia connections.\n"; - - HandleCleanup(); - } - } - -#ifdef TEST - *logofs << "Loop: Using multimedia port '" << mediaPort - << "'.\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 - httpPort.setDefaultTCPPort(80); - } - -#ifdef TEST - *logofs << "Loop: Using HTTP port '" << httpPort - << "'.\n" << logofs_flush; -#endif - - if (ParseFontPath(fontPort) <= 0) - { - #ifdef TEST - *logofs << "Loop: Disabling font server connections.\n" - << logofs_flush; - #endif - - *fontPort = '\0'; - - useFontSocket = 0; - } - else - { - // - // We don't know yet if the remote proxy supports - // the font server connections. If needed, we will - // disable the font server connections at later - // time. - // - - if (control -> ProxyMode == proxy_server) - { - useFontSocket = 1; - } - else - { - useFontSocket = 0; - } - - #ifdef TEST - *logofs << "Loop: Using font server port '" << fontPort - << "'.\n" << logofs_flush; - #endif - } - - useSlaveSocket = 0; - if (slavePort.enabled()) { - useSlaveSocket = 1; - 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 - << "'.\n" << logofs_flush; -#endif - - return 1; -} - -int SetDescriptors() -{ - unsigned int limit = 0; - - #ifdef RLIMIT_NOFILE - - rlimit limits; - - if (getrlimit(RLIMIT_NOFILE, &limits) == 0) - { - if (limits.rlim_max == RLIM_INFINITY) - { - limit = 0; - } - else - { - limit = (unsigned int) limits.rlim_max; - } - } - - #endif - - #ifdef _SC_OPEN_MAX - - if (limit == 0) - { - limit = sysconf(_SC_OPEN_MAX); - } - - #endif - - #ifdef FD_SETSIZE - - if (limit > FD_SETSIZE) - { - limit = FD_SETSIZE; - } - - #endif - - #ifdef RLIMIT_NOFILE - - if (limits.rlim_cur < limit) - { - limits.rlim_cur = limit; - - setrlimit(RLIMIT_NOFILE, &limits); - } - - #endif - - if (limit == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Cannot determine number of available " - << "file descriptors.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot determine number of available " - << "file descriptors.\n"; - - return -1; - } - - return 1; -} - -// -// Find the directory containing the caches -// matching the session type. -// - -int SetCaches() -{ - if ((control -> PersistentCachePath = GetCachePath()) == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error getting or creating the cache path.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error getting or creating the cache path.\n"; - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "Loop: Path of cache files is '" << control -> PersistentCachePath - << "'.\n" << logofs_flush; - #endif - - return 1; -} - -// -// Initialize all configuration parameters. -// - -int SetParameters() -{ - // - // Find out the type of session. - // - - SetSession(); - - // - // Initialize the network and compression - // parameters according to the settings - // suggested by the user. - // - - SetLink(); - - // - // Set compression according to link speed. - // - - SetCompression(); - - // - // Be sure that we have a literal for current - // cache size. Value will reflect control's - // default unless we already parsed a 'cache' - // option. Server side has no control on size - // of cache but is informed at session nego- - // tiation about how much memory is going to - // be used. - // - - SetStorage(); - - // - // Set size of shared memory segments. - // - - SetShmem(); - - // - // Make adjustments to cache based - // on the pack method. - // - - SetPack(); - - // - // Set disk-based image cache. - // - - SetImages(); - - // - // Set CPU and bandwidth limits. - // - - SetLimits(); - - return 1; -} - -// -// According to session literal determine -// the type of traffic that is going to be -// transported. Literals should be better -// standardized in future NX versions. -// - -int SetSession() -{ - if (strncmp(sessionType, "agent", strlen("agent")) == 0 || - strncmp(sessionType, "desktop", strlen("desktop")) == 0 || - strncmp(sessionType, "rootless", strlen("rootless")) == 0 || - strncmp(sessionType, "console", strlen("console")) == 0 || - strncmp(sessionType, "default", strlen("default")) == 0 || - strncmp(sessionType, "gnome", strlen("gnome")) == 0 || - strncmp(sessionType, "kde", strlen("kde")) == 0 || - strncmp(sessionType, "cde", strlen("cde")) == 0 || - strncmp(sessionType, "xdm", strlen("xdm")) == 0) - { - control -> SessionMode = session_agent; - } - else if (strncmp(sessionType, "win", strlen("win")) == 0 || - strncmp(sessionType, "vnc", strlen("vnc")) == 0) - { - control -> SessionMode = session_agent; - } - else if (strncmp(sessionType, "shadow", strlen("shadow")) == 0) - { - control -> SessionMode = session_shadow; - } - else if (strncmp(sessionType, "proxy", strlen("proxy")) == 0 || - strncmp(sessionType, "application", strlen("application")) == 0 || - strncmp(sessionType, "raw", strlen("raw")) == 0) - { - control -> SessionMode = session_proxy; - } - else - { - // - // If the session type is not passed or - // it is not among the recognized strings, - // we assume that the proxy is connected - // to the agent. - // - - // - // Since ProtoStep8 (#issue 108) and also - // with older "unix-" sessions - // - - if (*sessionType != '\0') - { - #ifdef WARNING - *logofs << "Loop: WARNING! Unrecognized session type '" - << sessionType << "'. Assuming agent session.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Unrecognized session type '" - << sessionType << "'. Assuming agent session.\n"; - } - - control -> SessionMode = session_agent; - } - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Assuming session type '" - << DumpSession(control -> SessionMode) << "' with " - << "string '" << sessionType << "'.\n" - << logofs_flush; - #endif - - // - // By default the policy is immediate. Agents - // will set a different policy, if they like. - // Anyway we need to check if the user has - // provided a custom flush policy. - // - - if (usePolicy != -1) - { - if (usePolicy > 0) - { - control -> FlushPolicy = policy_deferred; - } - else - { - control -> FlushPolicy = policy_immediate; - } - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: WARNING! Forcing flush policy to '" - << DumpPolicy(control -> FlushPolicy) - << ".\n" << logofs_flush; - #endif - } - else - { - control -> FlushPolicy = policy_immediate; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Setting initial flush policy to '" - << DumpPolicy(control -> FlushPolicy) - << "'.\n" << logofs_flush; - #endif - } - - // - // Check if the proxy library is run inside - // another program providing encryption, as - // it is the case of the SSH client. - // - - if (useEncryption != -1) - { - if (useEncryption > 0) - { - control -> LinkEncrypted = 1; - } - else - { - control -> LinkEncrypted = 0; - } - } - - if (control -> LinkEncrypted == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Proxy running as part of an " - << "encrypting client.\n" - << logofs_flush; - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Assuming proxy running as a " - << "standalone program.\n" - << logofs_flush; - #endif - } - - // - // Check if the system administrator has - // enabled the respawn of the client at - // the end of session. - // - - if (control -> ProxyMode == proxy_server) - { - struct stat fileStat; - - char fileName[DEFAULT_STRING_LENGTH]; - - snprintf(fileName, DEFAULT_STRING_LENGTH - 1, - "%s/share/noexit", control -> SystemPath); - - *(fileName + DEFAULT_STRING_LENGTH - 1) = '\0'; - - if (stat(fileName, &fileStat) == 0) - { - #ifdef TEST - *logofs << "Loop: Enabling respawn of client at session shutdown.\n" - << logofs_flush; - #endif - - control -> EnableRestartOnShutdown = 1; - } - } - - return 1; -} - -int SetStorage() -{ - // - // If differential compression is disabled - // we don't need a cache at all. - // - - if (control -> LocalDeltaCompression == 0) - { - control -> ClientTotalStorageSize = 0; - control -> ServerTotalStorageSize = 0; - } - - // - // Set a a cache size literal. - // - - int size = control -> getUpperStorageSize(); - - if (size / 1024 > 0) - { - sprintf(cacheSizeName, "%dk", size / 1024); - } - else - { - sprintf(cacheSizeName, "%d", size); - } - - if (control -> ProxyMode == proxy_client) - { - control -> LocalTotalStorageSize = - control -> ClientTotalStorageSize; - - control -> RemoteTotalStorageSize = - control -> ServerTotalStorageSize; - } - else - { - control -> LocalTotalStorageSize = - control -> ServerTotalStorageSize; - - control -> RemoteTotalStorageSize = - control -> ClientTotalStorageSize; - } - - #ifdef DEBUG - *logofs << "Loop: Storage size limit is " - << control -> ClientTotalStorageSize - << " at client and " - << control -> ServerTotalStorageSize - << " at server.\n" - << logofs_flush; - #endif - - #ifdef DEBUG - *logofs << "Loop: Storage local limit set to " - << control -> LocalTotalStorageSize - << " remote limit set to " - << control -> RemoteTotalStorageSize - << ".\n" << logofs_flush; - #endif - - // - // Never reserve for split store more than - // half the memory available for messages. - // - - if (size > 0 && control -> - SplitTotalStorageSize > size / 2) - { - #ifdef TEST - *logofs << "Loop: Reducing size of split store to " - << size / 2 << " bytes.\n" - << logofs_flush; - #endif - - control -> SplitTotalStorageSize = size / 2; - } - - // - // Don't load render from persistent - // cache if extension is hidden or - // not supported by agent. - // - - if (control -> HideRender == 1) - { - #ifdef TEST - *logofs << "Loop: Not loading render extension " - << "from persistent cache.\n" - << logofs_flush; - #endif - - control -> PersistentCacheLoadRender = 0; - } - - return 1; -} - -int SetShmem() -{ - // - // If not set, adjust the size of the shared - // memory segment according to size of the - // message cache. - // - - if (*shsegSizeName == '\0') - { - int size = control -> getUpperStorageSize(); - - const int mega = 1048576; - - if (size > 0) - { - if (size <= 1 * mega) - { - size = 0; - } - else if (size <= 2 * mega) - { - size = 524288; - } - else if (size < 4 * mega) - { - size = 1048576; - } - else - { - size = size / 4; - } - - if (size > 4194304) - { - size = 4194304; - } - - control -> ShmemClientSize = size; - control -> ShmemServerSize = size; - } - else - { - // - // The delta compression is disabled. - // Use a default segment size of 2 MB. - // - - control -> ShmemServerSize = 2 * mega; - } - } - - // - // Client side shared memory support is - // not useful and not implemented. - // - - if (control -> ShmemServerSize >= 524288) - { - control -> ShmemServer = 1; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Set initial shared memory size " - << "to " << control -> ShmemServerSize - << " bytes.\n" << logofs_flush; - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Disabled use of the shared memory " - << "extension.\n" << logofs_flush; - #endif - - control -> ShmemServer = 0; - } - - // For android, no shared memory available - control -> ShmemServer = 0; - control -> ShmemClientSize = 0; - - return 1; -} - -// -// Adjust the pack method according to the -// type of the session. -// - -int SetPack() -{ - #ifdef TEST - *logofs << "Loop: Setting pack with initial method " - << packMethod << " and quality " << packQuality - << ".\n" << logofs_flush; - #endif - - // - // Check if this is a proxy session and, in - // this case, set the pack method to none. - // Packed images are not supported by plain - // X applications. - // - - if (control -> SessionMode == session_proxy) - { - #ifdef TEST - *logofs << "Loop: WARNING! Disabling pack with proxy session.\n" - << logofs_flush; - #endif - - packMethod = PACK_NONE; - } - - // - // Adjust the internal settings according - // to the newly selected pack method. - // - - ParsePackMethod(packMethod, packQuality); - - // - // Don't load messages from persistent - // cache if packed images are disabled. - // - - if (control -> PackMethod == PACK_NONE) - { - control -> PersistentCacheLoadPacked = 0; - - #ifdef TEST - *logofs << "Loop: Not loading packed images " - << "from persistent cache.\n" - << logofs_flush; - #endif - } - - return 1; -} - -// -// Set the disk-based image cache parameters -// according to the user's wishes. -// - -int SetImages() -{ - // - // Be sure we disable the image cache if we - // are connecting to plain X clients. - // - - if (control -> SessionMode == session_proxy) - { - #ifdef TEST - *logofs << "Loop: Disabling image cache with " - << "session '" << DumpSession(control -> - SessionMode) << "'.\n" << logofs_flush; - #endif - - sprintf(imagesSizeName, "0"); - - control -> ImageCacheEnableLoad = 0; - control -> ImageCacheEnableSave = 0; - - return 1; - } - - int size = control -> ImageCacheDiskLimit; - - if (size / 1024 > 0) - { - sprintf(imagesSizeName, "%dk", size / 1024); - } - else - { - sprintf(imagesSizeName, "%d", size); - } - - if (size > 0) - { - control -> ImageCacheEnableLoad = 1; - control -> ImageCacheEnableSave = 1; - - if (control -> ProxyMode == proxy_server) - { - if ((control -> ImageCachePath = GetImagesPath()) == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error getting or creating image cache path.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error getting or creating image cache path.\n"; - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "Loop: Path of image cache files is '" << control -> ImageCachePath - << "'.\n" << logofs_flush; - #endif - } - } - else - { - #ifdef TEST - *logofs << "Loop: Disabling the persistent image cache.\n" - << logofs_flush; - #endif - - control -> ImageCacheEnableLoad = 0; - control -> ImageCacheEnableSave = 0; - } - - return 1; -} - -int SetVersion() -{ - // - // Normalize the different proxy versions. - // - - int local = (control -> LocalVersionMajor << 24) | - (control -> LocalVersionMinor << 16) | - control -> LocalVersionPatch; - - int remote = (control -> RemoteVersionMajor << 24) | - (control -> RemoteVersionMinor << 16) | - control -> RemoteVersionPatch; - - int major = -1; - int minor = -1; - int patch = -1; - - if (control -> RemoteVersionMajor <= 1) - { - // - // The remote proxy uses a different - // logic to determine the version so - // we default to the compatibility - // version. - // - - major = control -> CompatVersionMajor; - minor = control -> CompatVersionMinor; - patch = control -> CompatVersionPatch; - - #ifdef TEST - *logofs << "Loop: Using compatibility version '" - << major << "." << minor << "." << patch - << "'.\n" << logofs_flush; - #endif - } - else if (control -> LocalVersionMajor > - control -> RemoteVersionMajor) - { - // - // We use a more recent version. Let's - // negotiate the version based on the - // version supported by the remote. - // - - major = control -> RemoteVersionMajor; - minor = control -> RemoteVersionMinor; - patch = control -> RemoteVersionPatch; - - #ifdef TEST - *logofs << "Loop: Using remote version '" - << major << "." << minor << "." << patch - << "'.\n" << logofs_flush; - #endif - } - else - { - // - // We support a major version that is - // equal or older than the remote. We - // assume the smaller version between - // the two, including the minor and - // the patch numbers. - // - - if (local > remote) - { - major = control -> RemoteVersionMajor; - minor = control -> RemoteVersionMinor; - patch = control -> RemoteVersionPatch; - - #ifdef TEST - *logofs << "Loop: Using remote version '" - << major << "." << minor << "." << patch - << "'.\n" << logofs_flush; - #endif - } - else - { - major = control -> LocalVersionMajor; - minor = control -> LocalVersionMinor; - patch = control -> LocalVersionPatch; - - #ifdef TEST - *logofs << "Loop: Using local version '" - << major << "." << minor << "." << patch - << "'.\n" << logofs_flush; - #endif - } - } - - // - // Handle versions from 3.5.0. The protocol - // step 10 is the minimum supported version. - // - - int step = 0; - - if (major == 3) - { - if (minor >= 5) - { - step = 10; - } - } - else if (major > 3) - { - step = 10; - } - - if (step == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Unable to set the protocol step value from " - << "the negotiated protocol version " << major << "." << minor - << "." << patch << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unable to set the protocol step value from " - << "the negotiated protocol version " << major << "." << minor - << "." << patch << ".\n"; - - #ifdef PANIC - *logofs << "Loop: PANIC! Incompatible remote version " - << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor - << "." << control -> RemoteVersionPatch << " with local version " - << control -> LocalVersionMajor << "." << control -> LocalVersionMinor - << "." << control -> LocalVersionPatch << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Incompatible remote version " - << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor - << "." << control -> RemoteVersionPatch << " with local version " - << control -> LocalVersionMajor << "." << control -> LocalVersionMinor - << "." << control -> LocalVersionPatch << ".\n"; - - return -1; - } - - #ifdef TEST - *logofs << "Loop: Using NX protocol step " - << step << ".\n" << logofs_flush; - #endif - - control -> setProtoStep(step); - - // - // Ignore the differences in patch version - // and print a warning if the local version - // is different or obsolete compared to - // the remote. - // - - local &= 0xffff0000; - remote &= 0xffff0000; - - if (local != remote) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Connected to remote version " - << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor - << "." << control -> RemoteVersionPatch << " with local version " - << control -> LocalVersionMajor << "." << control -> LocalVersionMinor - << "." << control -> LocalVersionPatch << ".\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Connected to remote version " - << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor - << "." << control -> RemoteVersionPatch << " with local version " - << control -> LocalVersionMajor << "." << control -> LocalVersionMinor - << "." << control -> LocalVersionPatch << ".\n" << logofs_flush; - } - - if (local < remote) - { - cerr << "Warning" << ": Consider checking https://github.com/ArcticaProject/nx-libs/releases for updates.\n"; - } - - // - // Now that we are aware of the remote - // version, let's adjust the options to - // be compatible with the remote proxy. - // - - if (control -> ProxyMode == proxy_client) - { - // - // Since ProtoStep8 (#issue 108) - // - // Now it's assumed that the remote is - // able to handle the selected pack - // method - // - - #ifdef TEST - *logofs << __FILE__ << " : " << __LINE__ << " - " - << "step = " << control -> getProtoStep() - << " packMethod = " << packMethod - << " packQuality = " << packQuality - << ".\n" << logofs_flush; - #endif - - // - // Update the pack method name. - // - - ParsePackMethod(packMethod, packQuality); - } - - // - // At the moment the image cache is not used by the - // agent. Proxy versions older than 3.0.0 assumed - // that it was enabled and sent specific bits as part - // of the encoding. Conversely, it is advisable to - // disable the cache right now. By not enabling the - // the image cache, the house-keeping process will - // only take care of cleaning up the "cache-" direc- - // tories. - // - - // - // Considering that compatibility with older versions - // has been set to cover as far as 3.5.0, the cache can - // be disabled at this point without any concern - // - - // Since ProtoStep8 (#issue 108) - #ifdef TEST - *logofs << "Loop: Disabling image cache with protocol " - << "step '" << control -> getProtoStep() - << "'.\n" << logofs_flush; - #endif - - sprintf(imagesSizeName, "0"); - - control -> ImageCacheEnableLoad = 0; - control -> ImageCacheEnableSave = 0; - - return 1; -} - -// -// Identify the requested link settings -// and update the control parameters -// accordingly. -// - -int SetLink() -{ - #ifdef TEST - *logofs << "Loop: Setting link with initial value " - << linkSpeedName << ".\n" << logofs_flush; - #endif - - if (*linkSpeedName == '\0') - { - strcpy(linkSpeedName, "lan"); - } - - #ifdef TEST - *logofs << "Loop: Link speed is " << linkSpeedName - << ".\n" << logofs_flush; - #endif - - if (strcasecmp(linkSpeedName, "modem") == 0) - { - SetLinkModem(); - } - else if (strcasecmp(linkSpeedName, "isdn") == 0) - { - SetLinkIsdn(); - } - else if (strcasecmp(linkSpeedName, "adsl") == 0) - { - SetLinkAdsl(); - } - else if (strcasecmp(linkSpeedName, "wan") == 0) - { - SetLinkWan(); - } - else if (strcasecmp(linkSpeedName, "lan") == 0) - { - SetLinkLan(); - } - else - { - return -1; - } - - // - // Set TCP_NODELAY according to the user's - // wishes. - // - - if (useNoDelay != -1) - { - control -> OptionProxyClientNoDelay = useNoDelay; - control -> OptionProxyServerNoDelay = useNoDelay; - } - - // - // Select the image compression method. - // - - if (packMethod == -1) - { - packMethod = control -> PackMethod; - } - - if (packQuality == -1) - { - packQuality = control -> PackQuality; - } - - if (ParsePackMethod(packMethod, packQuality) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Unrecognized pack method id " - << packMethod << " with quality " << packQuality - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unrecognized pack method id " - << packMethod << " with quality " << packQuality - << ".\n"; - - HandleCleanup(); - } - - // - // Check if the user disabled the ability - // to generate simple replies at the client - // side. - // - - if (control -> SessionMode == session_proxy) - { - if (useTaint != -1) - { - control -> TaintReplies = (useTaint == 1); - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Forcing taint of replies " - << "with a proxy session.\n" - << logofs_flush; - #endif - - control -> TaintReplies = 1; - } - } - else - { - // - // There is no need to taint the - // replies if we have an agent. - // - - control -> TaintReplies = 0; - } - - // - // Be sure that the requests needing a reply - // are flushed immediately. Normal X clients - // use so many replies to make the queuing - // completely useless. - // - - if (control -> SessionMode == session_proxy) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Forcing flush on priority " - << "with a proxy session.\n" - << logofs_flush; - #endif - - control -> FlushPriority = 1; - } - - return 1; -} - -// -// Parameters for MODEM 28.8/33.6/56 Kbps. -// - -int SetLinkModem() -{ - #ifdef TEST - *logofs << "Loop: Setting parameters for MODEM.\n" - << logofs_flush; - #endif - - control -> LinkMode = LINK_TYPE_MODEM; - - control -> TokenSize = 256; - control -> TokenLimit = 24; - - control -> SplitMode = 1; - control -> SplitTotalSize = 128; - control -> SplitTotalStorageSize = 1048576; - - control -> SplitTimeout = 50; - control -> MotionTimeout = 50; - control -> IdleTimeout = 50; - - control -> PackMethod = PACK_ADAPTIVE; - control -> PackQuality = 3; - - return 1; -} - -// -// Parameters for ISDN 64/128 Kbps. -// - -int SetLinkIsdn() -{ - #ifdef TEST - *logofs << "Loop: Setting parameters for ISDN.\n" - << logofs_flush; - #endif - - control -> LinkMode = LINK_TYPE_ISDN; - - control -> TokenSize = 384; - control -> TokenLimit = 24; - - control -> SplitMode = 1; - control -> SplitTotalSize = 128; - control -> SplitTotalStorageSize = 1048576; - - control -> SplitTimeout = 50; - control -> MotionTimeout = 20; - control -> IdleTimeout = 50; - - control -> PackMethod = PACK_ADAPTIVE; - control -> PackQuality = 5; - - return 1; -} - -// -// Parameters for ADSL 256 Kbps. -// - -int SetLinkAdsl() -{ - #ifdef TEST - *logofs << "Loop: Setting parameters for ADSL.\n" - << logofs_flush; - #endif - - control -> LinkMode = LINK_TYPE_ADSL; - - control -> TokenSize = 1536; - control -> TokenLimit = 24; - - control -> SplitMode = 1; - control -> SplitTotalSize = 128; - control -> SplitTotalStorageSize = 1048576; - - control -> SplitTimeout = 50; - control -> MotionTimeout = 10; - control -> IdleTimeout = 50; - - control -> PackMethod = PACK_ADAPTIVE; - control -> PackQuality = 7; - - return 1; -} - -// -// Parameters for XDSL/FDDI/ATM 1/2/34 Mbps WAN. -// - -int SetLinkWan() -{ - #ifdef TEST - *logofs << "Loop: Setting parameters for WAN.\n" - << logofs_flush; - #endif - - control -> LinkMode = LINK_TYPE_WAN; - - control -> TokenSize = 1536; - control -> TokenLimit = 24; - - control -> SplitMode = 1; - control -> SplitTotalSize = 128; - control -> SplitTotalStorageSize = 1048576; - - control -> SplitTimeout = 50; - control -> MotionTimeout = 5; - control -> IdleTimeout = 50; - - control -> PackMethod = PACK_ADAPTIVE; - control -> PackQuality = 9; - - return 1; -} - -// -// Parameters for LAN 10/100 Mbps. -// - -int SetLinkLan() -{ - #ifdef TEST - *logofs << "Loop: Setting parameters for LAN.\n" - << logofs_flush; - #endif - - control -> LinkMode = LINK_TYPE_LAN; - - control -> TokenSize = 1536; - control -> TokenLimit = 24; - - control -> SplitMode = 1; - control -> SplitTotalSize = 128; - control -> SplitTotalStorageSize = 1048576; - - control -> SplitTimeout = 50; - control -> MotionTimeout = 0; - control -> IdleTimeout = 50; - - control -> PackMethod = PACK_ADAPTIVE; - control -> PackQuality = 9; - - return 1; -} - -// -// Identify the requested link type and set -// the control parameters accordingly. -// - -int SetCompression() -{ - if (strcasecmp(linkSpeedName, "modem") == 0) - { - SetCompressionModem(); - } - else if (strcasecmp(linkSpeedName, "isdn") == 0) - { - SetCompressionIsdn(); - } - else if (strcasecmp(linkSpeedName, "adsl") == 0) - { - SetCompressionAdsl(); - } - else if (strcasecmp(linkSpeedName, "wan") == 0) - { - SetCompressionWan(); - } - else if (strcasecmp(linkSpeedName, "lan") == 0) - { - SetCompressionLan(); - } - else - { - return -1; - } - - if (control -> LocalDeltaCompression < 0) - { - control -> LocalDeltaCompression = 1; - } - - // - // If we didn't set remote delta compression - // (as it should always be the case at client - // side) assume value of local side. - // - - if (control -> RemoteDeltaCompression < 0) - { - control -> RemoteDeltaCompression = - control -> LocalDeltaCompression; - } - - // - // If we didn't set remote compression levels - // assume values of local side. - // - - if (control -> RemoteStreamCompression < 0) - { - control -> RemoteStreamCompressionLevel = - control -> LocalStreamCompressionLevel; - - if (control -> RemoteStreamCompressionLevel > 0) - { - control -> RemoteStreamCompression = 1; - } - else - { - control -> RemoteStreamCompression = 0; - } - } - - if (control -> RemoteDataCompression < 0) - { - control -> RemoteDataCompressionLevel = - control -> LocalDataCompressionLevel; - - if (control -> RemoteDataCompressionLevel > 0) - { - control -> RemoteDataCompression = 1; - } - else - { - control -> RemoteDataCompression = 0; - } - } - - return 1; -} - -// -// Compression for MODEM. -// - -int SetCompressionModem() -{ - if (control -> LocalDataCompression < 0) - { - control -> LocalDataCompression = 1; - control -> LocalDataCompressionLevel = 1; - } - - if (control -> LocalDataCompressionThreshold < 0) - { - control -> LocalDataCompressionThreshold = 32; - } - - if (control -> LocalStreamCompression < 0) - { - control -> LocalStreamCompression = 1; - control -> LocalStreamCompressionLevel = 9; - } - - return 1; -} - -// -// Compression for ISDN. -// - -int SetCompressionIsdn() -{ - if (control -> LocalDataCompression < 0) - { - control -> LocalDataCompression = 1; - control -> LocalDataCompressionLevel = 1; - } - - if (control -> LocalDataCompressionThreshold < 0) - { - control -> LocalDataCompressionThreshold = 32; - } - - if (control -> LocalStreamCompression < 0) - { - control -> LocalStreamCompression = 1; - control -> LocalStreamCompressionLevel = 6; - } - - return 1; -} - -// -// Compression for ADSL. -// - -int SetCompressionAdsl() -{ - if (control -> LocalDataCompression < 0) - { - control -> LocalDataCompression = 1; - control -> LocalDataCompressionLevel = 1; - } - - if (control -> LocalDataCompressionThreshold < 0) - { - control -> LocalDataCompressionThreshold = 32; - } - - if (control -> LocalStreamCompression < 0) - { - control -> LocalStreamCompression = 1; - control -> LocalStreamCompressionLevel = 4; - } - - return 1; -} - -// -// Compression for WAN. -// - -int SetCompressionWan() -{ - if (control -> LocalDataCompression < 0) - { - control -> LocalDataCompression = 1; - control -> LocalDataCompressionLevel = 1; - } - - if (control -> LocalDataCompressionThreshold < 0) - { - control -> LocalDataCompressionThreshold = 32; - } - - if (control -> LocalStreamCompression < 0) - { - control -> LocalStreamCompression = 1; - control -> LocalStreamCompressionLevel = 1; - } - - return 1; -} - -// -// Compression for LAN. -// - -int SetCompressionLan() -{ - // - // Disable delta compression if not - // explicitly enabled. - // - - if (control -> LocalDeltaCompression < 0) - { - control -> LocalDeltaCompression = 0; - } - - if (control -> LocalDataCompression < 0) - { - control -> LocalDataCompression = 0; - control -> LocalDataCompressionLevel = 0; - } - - if (control -> LocalDataCompressionThreshold < 0) - { - control -> LocalDataCompressionThreshold = 0; - } - - if (control -> LocalStreamCompression < 0) - { - control -> LocalStreamCompression = 0; - control -> LocalStreamCompressionLevel = 0; - } - - return 1; -} - -int SetLimits() -{ - // - // Check if the user requested strict - // control flow parameters. - // - - if (useStrict == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: LIMIT! Decreasing the token limit " - << "to " << control -> TokenLimit / 2 - << " with option 'strict'.\n" - << logofs_flush; - #endif - - control -> TokenLimit /= 2; - } - - #ifdef STRICT - - control -> TokenLimit = 1; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: WARNING! LIMIT! Setting the token limit " - << "to " << control -> TokenLimit - << " to simulate the proxy congestion.\n" - << logofs_flush; - #endif - - #endif - - // - // Reduce the size of the log file. - // - - #ifdef QUOTA - - control -> FileSizeLimit = 8388608; - - #endif - - // - // Check the bitrate limits. - // - - if (control -> LocalBitrateLimit == -1) - { - if (control -> ProxyMode == proxy_client) - { - control -> LocalBitrateLimit = - control -> ClientBitrateLimit; - } - else - { - control -> LocalBitrateLimit = - control -> ServerBitrateLimit; - } - } - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: LIMIT! Setting client bitrate limit " - << "to " << control -> ClientBitrateLimit - << " server bitrate limit to " << control -> - ServerBitrateLimit << " with local limit " - << control -> LocalBitrateLimit << ".\n" - << logofs_flush; - #endif - - return 1; -} - -// -// These functions are used to parse literal -// values provided by the user and set the -// control parameters accordingly. -// - -int ParseCacheOption(const char *opt) -{ - int size = ParseArg("", "cache", opt); - - if (size < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value '" - << opt << "' for option 'cache'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value '" - << opt << "' for option 'cache'.\n"; - - return -1; - } - - #ifdef TEST - *logofs << "Loop: Setting size of cache to " - << size << " bytes.\n" << logofs_flush; - #endif - - control -> ClientTotalStorageSize = size; - control -> ServerTotalStorageSize = size; - - strcpy(cacheSizeName, opt); - - if (size == 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Disabling NX delta compression.\n" - << logofs_flush; - #endif - - control -> LocalDeltaCompression = 0; - - #ifdef WARNING - *logofs << "Loop: WARNING! Disabling use of NX persistent cache.\n" - << logofs_flush; - #endif - - control -> PersistentCacheEnableLoad = 0; - control -> PersistentCacheEnableSave = 0; - } - - return 1; -} - -int ParseImagesOption(const char *opt) -{ - int size = ParseArg("", "images", opt); - - if (size < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value '" - << opt << "' for option 'images'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value '" - << opt << "' for option 'images'.\n"; - - return -1; - } - - #ifdef TEST - *logofs << "Loop: Setting size of images cache to " - << size << " bytes.\n" << logofs_flush; - #endif - - control -> ImageCacheDiskLimit = size; - - strcpy(imagesSizeName, opt); - - return 1; -} - -int ParseShmemOption(const char *opt) -{ - int size = ParseArg("", "shseg", opt); - - if (size < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value '" - << opt << "' for option 'shseg'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value '" - << opt << "' for option 'shseg'.\n"; - - return -1; - } - - control -> ShmemClientSize = size; - control -> ShmemServerSize = size; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Set shared memory size to " - << control -> ShmemServerSize << " bytes.\n" - << logofs_flush; - #endif - - strcpy(shsegSizeName, opt); - - return 1; -} - -int ParseBitrateOption(const char *opt) -{ - int bitrate = ParseArg("", "limit", opt); - - if (bitrate < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value '" - << opt << "' for option 'limit'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value '" - << opt << "' for option 'limit'.\n"; - - return -1; - } - - strcpy(bitrateLimitName, opt); - - if (bitrate == 0) - { - #ifdef TEST - *logofs << "Loop: Disabling bitrate limit on proxy link.\n" - << logofs_flush; - #endif - - control -> LocalBitrateLimit = 0; - } - else - { - #ifdef TEST - *logofs << "Loop: Setting bitrate to " << bitrate - << " bits per second.\n" << logofs_flush; - #endif - - // - // Internal representation is in bytes - // per second. - // - - control -> LocalBitrateLimit = bitrate >> 3; - } - - return 1; -} - -int ParseHostOption(const char *opt, char *host, long &port) -{ - #ifdef TEST - *logofs << "Loop: Trying to parse options string '" << opt - << "' as a remote NX host.\n" << logofs_flush; - #endif - - if (opt == NULL || *opt == '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! No host parameter provided.\n" - << logofs_flush; - #endif - - return 0; - } - else if (strlen(opt) >= DEFAULT_STRING_LENGTH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Host parameter exceeds length of " - << DEFAULT_STRING_LENGTH << " characters.\n" - << logofs_flush; - #endif - - return 0; - } - - // - // Look for a host name followed - // by a colon followed by port. - // - - int newPort = port; - - const char *separator = strrchr(opt, ':'); - - if (separator != NULL) - { - const char *check = separator + 1; - - while (*check != '\0' && *check != ',' && - *check != '=' && isdigit(*check) != 0) - { - check++; - } - - newPort = atoi(separator + 1); - - if (newPort < 0 || *check != '\0') - { - #ifdef TEST - *logofs << "Loop: Can't identify remote NX port in string '" - << separator << "'.\n" << logofs_flush; - #endif - - return 0; - } - } - else if (newPort < 0) - { - // - // Complain if port was not passed - // by other means. - // - - #ifdef TEST - *logofs << "Loop: Can't identify remote NX port in string '" - << opt << "'.\n" << logofs_flush; - #endif - - return 0; - } - else - { - separator = opt + strlen(opt); - } - - char newHost[DEFAULT_STRING_LENGTH] = { 0 }; - - strncpy(newHost, opt, strlen(opt) - strlen(separator)); - - *(newHost + strlen(opt) - strlen(separator)) = '\0'; - - const char *check = newHost; - - while (*check != '\0' && *check != ',' && - *check != '=') - { - check++; - } - - if (*check != '\0') - { - #ifdef TEST - *logofs << "Loop: Can't identify remote NX host in string '" - << newHost << "'.\n" << logofs_flush; - #endif - - return 0; - } - else if (*acceptHost != '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't manage to connect and accept connections " - << "at the same time.\n" << logofs_flush; - - *logofs << "Loop: PANIC! Refusing remote NX host with string '" - << opt << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't manage to connect and accept connections " - << "at the same time.\n"; - - cerr << "Error" << ": Refusing remote NX host with string '" - << opt << "'.\n"; - - return -1; - } - - if (*host != '\0' && strcmp(host, newHost) != 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Overriding remote NX host '" - << host << "' with new value '" << newHost - << "'.\n" << logofs_flush; - #endif - } - - strcpy(host, newHost); - - if (port != -1 && port != newPort) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Overriding remote NX port '" - << port << "' with new value '" << newPort - << "'.\n" << logofs_flush; - #endif - } - - #ifdef TEST - *logofs << "Loop: Parsed options string '" << opt - << "' with host '" << newHost << "' and port '" - << newPort << "'.\n" << logofs_flush; - #endif - - port = newPort; - - return 1; -} - -int ParseFontPath(char *path) -{ - char oldPath[DEFAULT_STRING_LENGTH]; - - strcpy(oldPath, path); - - if (path == NULL || *path == '\0' || strcmp(path, "0") == 0) - { - return 0; - } - - #ifdef TEST - *logofs << "Loop: Parsing font server option '" << path - << "'.\n" << logofs_flush; - #endif - - // - // Convert the value to our default port. - // - - if (strcmp(fontPort, "1") == 0) - { - if (control -> ProxyMode == proxy_server) - { - snprintf(fontPort, DEFAULT_STRING_LENGTH - 1, "%d", - DEFAULT_NX_FONT_PORT_OFFSET + proxyPort); - } - else - { - // - // Let the client use the well-known - // "unix/:7100" font path. - // - - snprintf(fontPort, DEFAULT_STRING_LENGTH - 1, "unix/:7100"); - } - } - - // - // Check if a simple numaric value was given. - // - - if (atoi(path) > 0) - { - #ifdef TEST - *logofs << "Loop: Assuming numeric TCP port '" << atoi(path) - << "' for font server.\n" << logofs_flush; - #endif - - return 1; - } - - // - // Let's assume that a port specification "unix/:7100" - // corresponds to "$TEMP/.font-unix/fs7100" and a port - // "unix/:-1" corresponds to "$TEMP/.font-unix/fs-1". - // - - if (strncmp("unix/:", path, 6) == 0) - { - snprintf(path, DEFAULT_STRING_LENGTH - 1, "%s/.font-unix/fs%s", - control -> TempPath, oldPath + 6); - - *(path + DEFAULT_STRING_LENGTH - 1) = '\0'; - - #ifdef TEST - *logofs << "Loop: Assuming Unix socket '" << path - << "' for font server.\n" << logofs_flush; - #endif - } - else if (strncmp("tcp/:", path, 5) == 0) - { - snprintf(path, DEFAULT_STRING_LENGTH - 1, "%d", atoi(oldPath + 5)); - - *(path + DEFAULT_STRING_LENGTH - 1) = '\0'; - - if (atoi(path) <= 0) - { - goto ParseFontPathError; - } - - #ifdef TEST - *logofs << "Loop: Assuming TCP port '" << atoi(path) - << "' for font server.\n" << logofs_flush; - #endif - } - else - { - // - // Accept an absolute file path as - // a valid Unix socket. - // - - if (*path != '/') - { - goto ParseFontPathError; - } - - #ifdef TEST - *logofs << "Loop: Assuming Unix socket '" << path - << "' for font server.\n" << logofs_flush; - #endif - } - - return 1; - -ParseFontPathError: - - #ifdef TEST - *logofs << "Loop: Unable to determine the font server " - << "port in string '" << path << "'.\n" - << logofs_flush; - #endif - - return -1; -} - -int OpenLogFile(char *name, ostream *&stream) -{ - if (name == NULL || *name == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No name provided for output. Using standard error.\n" - << logofs_flush; - #endif - - if (stream == NULL) - { - stream = &cerr; - } - - return 1; - } - - if (stream == NULL || stream == &cerr) - { - if (*name != '/' && *name != '.') - { - char *filePath = GetSessionPath(); - - if (filePath == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Cannot determine directory of NX session file.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Cannot determine directory of NX session file.\n"; - - return -1; - } - - if (strlen(filePath) + strlen("/") + - strlen(name) + 1 > DEFAULT_STRING_LENGTH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Full name of NX file '" << name - << " would exceed length of " << DEFAULT_STRING_LENGTH - << " characters.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Full name of NX file '" << name - << " would exceed length of " << DEFAULT_STRING_LENGTH - << " characters.\n"; - - return -1; - } - - char *file = new char[strlen(filePath) + strlen("/") + - strlen(name) + 1]; - - // - // Transform name in a fully qualified name. - // - - strcpy(file, filePath); - strcat(file, "/"); - strcat(file, name); - - strcpy(name, file); - - delete [] filePath; - delete [] file; - } - - mode_t fileMode = umask(0077); - - for (;;) - { - if ((stream = new ofstream(name, ios::app)) != NULL) - { - break; - } - - usleep(200000); - } - - umask(fileMode); - } - else - { - #ifdef PANIC - *logofs << "Loop: PANIC! Bad stream provided for output.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Bad stream provided for output.\n"; - - return -1; - } - - return 1; -} - -int ReopenLogFile(char *name, ostream *&stream, int limit) -{ - if (*name != '\0' && limit >= 0) - { - struct stat fileStat; - - if (limit > 0) - { - // - // This is used for the log file, if the - // size exceeds the limit. - // - - if (stat(name, &fileStat) != 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Can't get stats of file '" - << name << "'. Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - return 0; - } - else if (fileStat.st_size < (long) limit) - { - return 0; - } - } - - #ifdef TEST - *logofs << "Loop: Deleting file '" << name - << "' with size " << fileStat.st_size - << ".\n" << logofs_flush; - #endif - - // - // Create a new stream over the previous - // file. Trying to delete the file fails - // to work on recent Cygwin installs. - // - - *stream << flush; - - delete stream; - - mode_t fileMode = umask(0077); - - for (;;) - { - if ((stream = new ofstream(name, ios::out)) != NULL) - { - break; - } - - usleep(200000); - } - - umask(fileMode); - - #ifdef TEST - *logofs << "Loop: Reopened file '" << name - << "'.\n" << logofs_flush; - #endif - } - - return 1; -} - -void PrintProcessInfo() -{ - if (agent == NULL) - { - - cerr << endl; - - PrintVersionInfo(); - - cerr << endl; - - cerr << GetCopyrightInfo() - << endl - << GetOtherCopyrightInfo() - << endl - << "See https://github.com/ArcticaProject/nx-libs for more information." << endl << endl; - } - - // - // People get confused by the fact that client - // mode is running on NX server and viceversa. - // Let's adopt an user-friendly naming conven- - // tion here. - // - - cerr << "Info: Proxy running in " - << (control -> ProxyMode == proxy_client ? "client" : "server") - << " mode with pid '" << getpid() << "'.\n"; - - if (agent == NULL) - { - cerr << "Session" << ": Starting session at '" - << strTimestamp() << "'.\n"; - } - - #ifdef TEST - - if (*errorsFileName != '\0') - { - cerr << "Info" << ": Using errors file '" << errorsFileName << "'.\n"; - } - - if (*statsFileName != '\0') - { - cerr << "Info" << ": Using stats file '" << statsFileName << "'.\n"; - } - - #endif -} - -void PrintConnectionInfo() -{ - cerr << "Info" << ": Using " - << linkSpeedName << " link parameters " - << control -> TokenSize - << "/" << control -> TokenLimit - << "/" << control -> FlushPolicy + 1 - << "/" << control -> FlushPriority - << ".\n"; - - if (control -> ProxyMode == proxy_client) - { - cerr << "Info" << ": Using agent parameters " - << control -> PingTimeout - << "/" << control -> MotionTimeout - << "/" << control -> IdleTimeout - << "/" << control -> TaintReplies - << "/" << control -> HideRender - << ".\n"; - } - - if (control -> LocalDeltaCompression == 1) - { - cerr << "Info" << ": Using cache parameters " - << control -> MinimumMessageSize - << "/" << control -> MaximumMessageSize / 1024 << "KB" - << "/" << control -> ClientTotalStorageSize / 1024 << "KB" - << "/" << control -> ServerTotalStorageSize / 1024 << "KB" - << ".\n"; - } - - if (control -> ImageCacheEnableLoad == 1 || - control -> ImageCacheEnableSave == 1) - { - cerr << "Info" << ": Using image streaming parameters " - << control -> SplitTimeout - << "/" << control -> SplitTotalSize - << "/" << control -> SplitTotalStorageSize / 1024 << "KB" - << "/" << control -> SplitDataThreshold - << "/" << control -> SplitDataPacketLimit - << ".\n"; - - cerr << "Info" << ": Using image cache parameters " - << control -> ImageCacheEnableLoad - << "/" << control -> ImageCacheEnableSave - << "/" << control -> ImageCacheDiskLimit / 1024 << "KB" - << ".\n"; - } - - cerr << "Info" << ": Using pack method '" - << packMethodName << "' with session '" - << sessionType << "'.\n"; - - if (*productName != '\0') - { - cerr << "Info" << ": Using product '" << productName - << "'.\n" << logofs_flush; - } - - if (control -> LocalDeltaCompression == 0) - { - cerr << "Info" << ": Not using NX delta compression.\n"; - } - - if (control -> LocalDataCompression == 1 || - control -> RemoteDataCompression == 1) - { - cerr << "Info" << ": Using ZLIB data compression " - << control -> LocalDataCompressionLevel - << "/" << control -> RemoteDataCompressionLevel - << "/" << control -> LocalDataCompressionThreshold - << ".\n"; - } - else - { - cerr << "Info" << ": Not using ZLIB data compression.\n"; - } - - if (control -> LocalStreamCompression == 1 || - control -> RemoteStreamCompression == 1) - { - cerr << "Info" << ": Using ZLIB stream compression " - << control -> LocalStreamCompressionLevel - << "/" << control -> RemoteStreamCompressionLevel - << ".\n"; - } - else - { - cerr << "Info" << ": Not using ZLIB stream compression.\n"; - } - - if (control -> LocalBitrateLimit > 0) - { - cerr << "Info" << ": Using bandwidth limit of " - << bitrateLimitName << " bits per second.\n"; - } - - if (control -> PersistentCacheName != NULL) - { - cerr << "Info" << ": Using cache file '" - << control -> PersistentCachePath << "/" - << control -> PersistentCacheName << "'.\n"; - } - else - { - if (control -> PersistentCacheEnableLoad == 0 || - control -> LocalDeltaCompression == 0) - { - cerr << "Info" << ": Not using a persistent cache.\n"; - } - else - { - cerr << "Info" << ": No suitable cache file found.\n"; - } - } - - if (control -> ProxyMode == proxy_client && - (useUnixSocket > 0 || useTcpSocket > 0 || - useAgentSocket > 0)) - { - cerr << "Info" << ": Listening to X11 connections " - << "on display ':" << xPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_server) - { - cerr << "Info" << ": Forwarding X11 connections " - << "to display '" << displayHost << "'.\n"; - } - - if (control -> ProxyMode == proxy_client && - useCupsSocket > 0 && cupsPort.enabled()) - { - cerr << "Info" << ": Listening to CUPS connections " - << "on port '" << cupsPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_server && - cupsPort.enabled()) - { - cerr << "Info" << ": Forwarding CUPS connections " - << "to port '" << cupsPort << "'.\n"; - } - - if (control -> ProxyMode == proxy_client && - useAuxSocket > 0 && auxPort.enabled()) - { - cerr << "Info" << ": Listening to auxiliary X11 connections " - << "on port '" << auxPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_server && - auxPort.enabled()) - { - cerr << "Info" << ": Forwarding auxiliary X11 connections " - << "to display '" << displayHost << "'.\n"; - } - - if (control -> ProxyMode == proxy_client && - useSmbSocket > 0 && smbPort.enabled()) - { - cerr << "Info" << ": Listening to SMB connections " - << "on port '" << smbPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_server && - smbPort.enabled()) - { - cerr << "Info" << ": Forwarding SMB connections " - << "to port '" << smbPort << "'.\n"; - } - - if (control -> ProxyMode == proxy_client && - useMediaSocket > 0 && mediaPort.enabled()) - { - cerr << "Info" << ": Listening to multimedia connections " - << "on port '" << mediaPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_server && - mediaPort.enabled()) - { - cerr << "Info" << ": Forwarding multimedia connections " - << "to port '" << mediaPort << "'.\n"; - } - - if (control -> ProxyMode == proxy_client && - useHttpSocket > 0 && httpPort.enabled()) - { - cerr << "Info" << ": Listening to HTTP connections " - << "on port '" << httpPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_server && - httpPort.enabled()) - { - cerr << "Info" << ": Forwarding HTTP connections " - << "to port '" << httpPort << "'.\n"; - } - - if (control -> ProxyMode == proxy_server && - useFontSocket > 0 && *fontPort != '\0') - { - cerr << "Info" << ": Listening to font server connections " - << "on port '" << fontPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_client && - *fontPort != '\0') - { - cerr << "Info" << ": Forwarding font server connections " - << "to port '" << fontPort << "'.\n"; - } - - if (useSlaveSocket > 0 && slavePort.enabled()) - { - cerr << "Info" << ": Listening to slave connections " - << "on port '" << slavePort << "'.\n"; - } -} - -void PrintVersionInfo() -{ - cerr << "NXPROXY - " << "Version " - << control -> LocalVersionMajor << "." - << control -> LocalVersionMinor << "." - << control -> LocalVersionPatch << "." - << control -> LocalVersionMaintenancePatch; - - cerr << endl; -} - -void PrintCopyrightInfo() -{ - cerr << endl; - - PrintVersionInfo(); - - cerr << endl; - - cerr << GetCopyrightInfo(); - - // - // Print third party's copyright info. - // - - cerr << endl; - - cerr << GetOtherCopyrightInfo(); - - cerr << endl; -} - -void PrintOptionIgnored(const char *type, const char *name, const char *value) -{ - if (control -> ProxyMode == proxy_server) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring " << type - << " option '" << name << "' with value '" - << value << "' at " << "NX client side.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Ignoring " << type - << " option '" << name << "' with value '" - << value << "' at " << "NX client side.\n"; - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring " << type - << " option '" << name << "' with value '" - << value << "' at " << "NX server side.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Ignoring " << type - << " option '" << name << "' with value '" - << value << "' at " << "NX server side.\n"; - } -} - -const char *GetOptions(const char *options) -{ - if (options != NULL) - { - if (strncasecmp(options, "nx/nx,", 6) != 0 && - strncasecmp(options, "nx,", 3) != 0 && - strncasecmp(options, "nx:", 3) != 0) - { - #ifdef TEST - *logofs << "Loop: PANIC! Display options string '" << options - << "' must start with 'nx' or 'nx/nx' prefix.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Display options string '" << options - << "' must start with 'nx' or 'nx/nx' prefix.\n"; - - HandleCleanup(); - } - } - else - { - options = getenv("DISPLAY"); - } - - return options; -} - -const char *GetArg(int &argi, int argc, const char **argv) -{ - // - // Skip "-" and flag character. - // - - const char *arg = argv[argi] + 2; - - if (*arg == 0) - { - if (argi + 1 == argc) - { - return NULL; - } - else - { - argi++; - - return (*argv[argi] == '-' ? NULL : argv[argi]); - } - } - else - { - return (*arg == '-' ? NULL : arg); - } -} - -int CheckArg(const char *type, const char *name, const char *value) -{ - #ifdef TEST - *logofs << "Loop: Parsing " << type << " option '" << name - << "' with value '" << (value ? value : "(null)") - << "'.\n" << logofs_flush; - #endif - - if (value == NULL || strstr(value, "=") != NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error in " << type << " option '" - << name << "'. No value found.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error in " << type << " option '" - << name << "'. No value found.\n"; - - return -1; - } - else if (strstr(name, ",") != NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Parse error at " << type << " option '" - << name << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Parse error at " << type << " option '" - << name << "'.\n"; - - return -1; - } - else if (strlen(value) >= DEFAULT_STRING_LENGTH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Value '" << value << "' of " - << type << " option '" << name << "' exceeds length of " - << DEFAULT_STRING_LENGTH << " characters.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Value '" << value << "' of " - << type << " option '" << name << "' exceeds length of " - << DEFAULT_STRING_LENGTH << " characters.\n"; - - return -1; - } - - return 1; -} - -int ParseArg(const char *type, const char *name, const char *value) -{ - if (strcasecmp(value, "0") == 0) - { - return 0; - } - - // - // Find the base factor. - // - - double base; - - const char *id = value + strlen(value) - 1; - - if (strcasecmp(id, "g") == 0) - { - base = 1024 * 1024 * 1024; - } - else if (strcasecmp(id, "m") == 0) - { - base = 1024 * 1024; - } - else if (strcasecmp(id, "k") == 0) - { - base = 1024; - } - else if (strcasecmp(id, "b") == 0 || isdigit(*id) == 1) - { - base = 1; - } - else - { - return -1; - } - - char *string = new char[strlen(value)]; - - strncpy(string, value, strlen(value) - 1); - - *(string + (strlen(value) - 1)) = '\0'; - - #ifdef TEST - - *logofs << "Loop: Parsing integer option '" << name - << "' from string '" << string << "' with base set to "; - - switch (tolower(*id)) - { - case 'k': - case 'm': - case 'g': - { - *logofs << (char) toupper(*id); - } - break; - } - - *logofs << ".\n" << logofs_flush; - - #endif - - double result = atof(string) * base; - - if (result < 0 || result > (((unsigned) -1) >> 1)) - { - delete [] string; - - return -1; - } - - delete [] string; - - #ifdef TEST - *logofs << "Loop: Integer option parsed to '" - << (int) result << "'.\n" << logofs_flush; - #endif - - 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); - - if (number < 0) - { - #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(); - } - - return number; -} - -int LowercaseArg(const char *type, const char *name, char *value) -{ - char *next = value; - - while (*next != '\0') - { - *next = tolower(*next); - - next++; - } - - return 1; -} - -int CheckSignal(int signal) -{ - // - // Return 1 if the signal needs to be handled - // by the proxy, 2 if the signal just needs to - // be blocked to avoid interrupting a system - // call. - // - - switch (signal) - { - case SIGCHLD: - case SIGUSR1: - case SIGUSR2: - case SIGHUP: - case SIGINT: - case SIGTERM: - case SIGPIPE: - case SIGALRM: - { - return 1; - } - case SIGVTALRM: - case SIGWINCH: - case SIGIO: - case SIGTSTP: - case SIGTTIN: - case SIGTTOU: - { - return 2; - } - default: - { - #ifdef __CYGWIN32__ - - // - // This signal can be raised by the Cygwin - // library. - // - - if (signal == 12) - { - return 1; - } - - #endif - - return 0; - } - } -} - -static void PrintUsageInfo(const char *option, int error) -{ - if (error == 1) - { - cerr << "Error" << ": Invalid command line option '" << option << "'.\n"; - } - - cerr << GetUsageInfo(); - - if (error == 1) - { - cerr << "Error" << ": NX transport initialization failed.\n"; - } -} - -static void handleCheckSessionInLoop() -{ - // - // Check if we completed the shutdown procedure - // and the remote confirmed the shutdown. The - // tear down should be always initiated by the - // agent, but the X server side may unilateral- - // ly shut down the link without our permission. - // - - if (proxy -> getShutdown() > 0) - { - #ifdef TEST - *logofs << "Loop: End of NX transport requested " - << "by remote.\n" << logofs_flush; - #endif - - handleTerminatingInLoop(); - - if (control -> ProxyMode == proxy_server) - { - #ifdef TEST - *logofs << "Loop: Bytes received so far are " - << (unsigned long long) statistics -> getBytesIn() - << ".\n" << logofs_flush; - #endif - - if (statistics -> getBytesIn() < 1024) - { - cerr << "Info" << ": Your session was closed before reaching " - << "a usable state.\n"; - cerr << "Info" << ": This can be due to the local X server " - << "refusing access to the client.\n"; - cerr << "Info" << ": Please check authorization provided " - << "by the remote X application.\n"; - } - } - - #ifdef TEST - *logofs << "Loop: Shutting down the NX transport.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - else if (proxy -> handlePing() < 0) - { - #ifdef TEST - *logofs << "Loop: Failure handling the ping for " - << "proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - HandleShutdown(); - } - - // - // Check if the watchdog has exited and we didn't - // get the SIGCHLD. This can happen if the parent - // has overridden our signal handlers. - // - - if (IsRunning(lastWatchdog) && CheckProcess(lastWatchdog, "watchdog") == 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Watchdog is gone unnoticed. " - << "Setting the last signal to SIGTERM.\n" - << logofs_flush; - #endif - - lastSignal = SIGTERM; - - #ifdef WARNING - *logofs << "Loop: WARNING! Resetting pid of last " - << "watchdog process.\n" << logofs_flush; - #endif - - SetNotRunning(lastWatchdog); - } - - // - // Let the client proxy find out if the agent's - // channel is gone. This is the normal shutdown - // procedure in the case of an internal connect- - // ion to the agent. - // - - int cleanup = 0; - - if (control -> ProxyMode == proxy_client && - agent != NULL && proxy -> getType(agentFD[1]) == - channel_none && lastKill == 0 && lastDestroy == 1) - { - #ifdef TEST - *logofs << "Loop: End of NX transport requested " - << "by agent.\n" << logofs_flush; - #endif - - #ifdef TEST - *logofs << "Loop: Bytes sent so far are " - << (unsigned long long) statistics -> getBytesOut() - << ".\n" << logofs_flush; - #endif - - if (statistics -> getBytesOut() < 1024) - { - cerr << "Info" << ": Your session has died before reaching " - << "an usable state.\n"; - cerr << "Info" << ": This can be due to the remote X server " - << "refusing access to the client.\n"; - cerr << "Info" << ": Please check the authorization provided " - << "by your X application.\n"; - } - - cleanup = 1; - } - - // - // Check if the user requested the end of the - // session by sending a signal to the proxy. - // All signals are handled in the main loop - // so we need to reset the value to get ready - // for the next iteration. - // - - int signal = 0; - - if (lastSignal != 0) - { - switch (lastSignal) - { - case SIGCHLD: - case SIGUSR1: - case SIGUSR2: - { - break; - } - default: - { - signal = lastSignal; - - cleanup = 1; - - break; - } - } - - lastSignal = 0; - } - - if (cleanup == 1) - { - // - // The first time termination signal is received - // disable all further connections, close down any - // X channel and wait for a second signal. - // - - if (lastKill == 0) - { - // - // Don't print a message if cleanup is - // due to normal termination of agent. - // - - if (signal != 0) - { - #ifdef TEST - *logofs << "Loop: End of NX transport requested by signal '" - << signal << "' '" << DumpSignal(signal) - << "'.\n" << logofs_flush; - #endif - - handleTerminatingInLoop(); - } - - // - // Disable any further connection. - // - - CleanupListeners(); - - // - // Close all the remaining X channels and - // let proxies save their persistent cache - // on disk. - // - - CleanupConnections(); - - // - // We'll need to wait for the X channels - // to be shut down before waiting for the - // cleanup signal. - // - - lastKill = 1; - } - else if (lastKill == 2) - { - #ifdef TEST - *logofs << "Loop: Shutting down the NX transport.\n" - << logofs_flush; - #endif - - proxy -> handleShutdown(); - - HandleCleanup(); - } - } - - if (lastKill == 1 && proxy -> getChannels(channel_x11) == 0) - { - // - // Save the message stores to the - // persistent cache. - // - - proxy -> handleSave(); - - // - // Run a watchdog process so we can finally - // give up at the time the watchdog exits. - // - - if (IsNotRunning(lastWatchdog)) - { - int timeout = control -> CleanupTimeout; - - if (timeout > 0) - { - if (proxy -> getChannels() == 0) - { - timeout = 500; - } - - #ifdef TEST - *logofs << "Loop: Starting watchdog process with timeout " - << "of " << timeout << " Ms.\n" - << logofs_flush; - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Starting watchdog process without " - << "a timeout.\n" << logofs_flush; - } - #endif - - lastWatchdog = NXTransWatchdog(timeout); - - if (IsFailed(lastWatchdog)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't start the NX watchdog " - << "process in shutdown.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't start the NX watchdog " - << "process in shutdown.\n"; - - HandleCleanup(); - } - #ifdef TEST - else - { - *logofs << "Loop: Watchdog started with pid '" - << lastWatchdog << "'.\n" << logofs_flush; - } - #endif - } - else - { - #ifdef PANIC - *logofs << "Loop: PANIC! Previous watchdog detected " - << "in shutdown with pid '" << lastWatchdog - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Previous watchdog detected " - << "in shutdown with pid '" << lastWatchdog - << "'.\n"; - - HandleCleanup(); - } - - if (control -> CleanupTimeout > 0) - { - #ifdef TEST - *logofs << "Loop: Waiting the cleanup timeout to complete.\n" - << logofs_flush; - #endif - - cerr << "Info" << ": Waiting the cleanup timeout to complete.\n"; - } - else - { - // - // The NX server will kill the watchdog - // process after having shut down the - // service channels. - // - - cerr << "Info" << ": Watchdog running with pid '" << lastWatchdog - << "'.\n"; - - #ifdef TEST - *logofs << "Loop: Waiting the watchdog process to complete.\n" - << logofs_flush; - #endif - - cerr << "Info" << ": Waiting the watchdog process to complete.\n"; - } - - lastKill = 2; - } -} - -static void handleCheckBitrateInLoop() -{ - static long int slept = 0; - - #ifdef TEST - *logofs << "Loop: Bitrate is " << statistics -> getBitrateInShortFrame() - << " B/s and " << statistics -> getBitrateInLongFrame() - << " B/s in " << control -> ShortBitrateTimeFrame / 1000 - << "/" << control -> LongBitrateTimeFrame / 1000 - << " seconds timeframes.\n" << logofs_flush; - #endif - - // - // This can be improved. We may not jump out - // of the select often enough to guarantee - // the necessary accuracy. - // - - if (control -> LocalBitrateLimit > 0) - { - #ifdef TEST - *logofs << "Loop: Calculating bandwidth usage with limit " - << control -> LocalBitrateLimit << ".\n" - << logofs_flush; - #endif - - int reference = (statistics -> getBitrateInLongFrame() + - statistics -> getBitrateInShortFrame()) / 2; - - if (reference > control -> LocalBitrateLimit) - { - double ratio = ((double) reference) / - ((double) control -> LocalBitrateLimit); - - if (ratio > 1.2) - { - ratio = 1.2; - } - - slept += (unsigned int) (pow(50000, ratio) / 1000); - - if (slept > 2000) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Sleeping due to " - << "reference bitrate of " << reference - << " B/s.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Sleeping due to " - << "reference bitrate of " << reference - << " B/s.\n"; - - slept %= 2000; - } - - T_timestamp idleTs = getNewTimestamp(); - - usleep((unsigned int) pow(50000, ratio)); - - int diffTs = diffTimestamp(idleTs, getNewTimestamp()); - - statistics -> addIdleTime(diffTs); - - statistics -> subReadTime(diffTs); - } - } -} - -#if defined(TEST) || defined(INFO) - -static void handleCheckStateInLoop(int &setFDs) -{ - int fdLength; - int fdPending; - int fdSplits; - - for (int j = 0; j < setFDs; j++) - { - if (j != proxyFD) - { - fdPending = proxy -> getPending(j); - - if (fdPending > 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Buffer for descriptor FD#" - << j << " has pending bytes to read.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - - fdLength = proxy -> getLength(j); - - if (fdLength > 0) - { - #ifdef TEST - *logofs << "Loop: WARNING! Buffer for descriptor FD#" - << j << " has " << fdLength << " bytes to write.\n" - << logofs_flush; - #endif - } - } - } - - fdPending = proxy -> getPending(proxyFD); - - if (fdPending > 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Buffer for proxy descriptor FD#" - << proxyFD << " has pending bytes to read.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - - fdLength = proxy -> getFlushable(proxyFD); - - if (fdLength > 0) - { - if (control -> FlushPolicy == policy_immediate && - proxy -> getBlocked(proxyFD) == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Buffer for proxy descriptor FD#" - << proxyFD << " has " << fdLength << " bytes " - << "to write with policy 'immediate'.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - else - { - #ifdef TEST - *logofs << "Loop: WARNING! Buffer for proxy descriptor FD#" - << proxyFD << " has " << fdLength << " bytes " - << "to write.\n" << logofs_flush; - #endif - } - } - - fdSplits = proxy -> getSplitSize(); - - if (fdSplits > 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Proxy descriptor FD#" << proxyFD - << " has " << fdSplits << " splits to send.\n" - << logofs_flush; - #endif - } -} - -static void handleCheckSelectInLoop(int &setFDs, fd_set &readSet, - fd_set &writeSet, T_timestamp selectTs) -{ - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Maximum descriptors is [" - << setFDs << "] at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - int i; - - if (setFDs > 0) - { - i = 0; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Selected for read are "; - #endif - - for (int j = 0; j < setFDs; j++) - { - if (FD_ISSET(j, &readSet)) - { - #if defined(TEST) || defined(INFO) - *logofs << "[" << j << "]" << logofs_flush; - #endif - - i++; - } - } - - if (i > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << ".\n" << logofs_flush; - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "[none].\n" << logofs_flush; - #endif - } - - i = 0; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Selected for write are "; - #endif - - for (int j = 0; j < setFDs; j++) - { - if (FD_ISSET(j, &writeSet)) - { - #if defined(TEST) || defined(INFO) - *logofs << "[" << j << "]" << logofs_flush; - #endif - - i++; - } - } - - if (i > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << ".\n" << logofs_flush; - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "[none].\n" << logofs_flush; - #endif - } - } - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Select timeout is " - << selectTs.tv_sec << " S and " - << (double) selectTs.tv_usec / 1000 - << " Ms.\n" << logofs_flush; - #endif -} - -static void handleCheckResultInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs, - struct timeval &startTs) -{ - int diffTs = diffTimestamp(startTs, getNewTimestamp()); - - #if defined(TEST) || defined(INFO) - - if (diffTs >= (control -> PingTimeout - - (control -> LatencyTimeout * 4))) - { - *logofs << "Loop: Select result is [" << resultFDs - << "] at " << strMsTimestamp() << " with no " - << "communication within " << diffTs - << " Ms.\n" << logofs_flush; - } - else - { - *logofs << "Loop: Select result is [" << resultFDs - << "] error is [" << errorFDs << "] at " - << strMsTimestamp() << " after " << diffTs - << " Ms.\n" << logofs_flush; - } - - #endif - - int i; - - if (resultFDs > 0) - { - i = 0; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Selected for read are "; - #endif - - for (int j = 0; j < setFDs; j++) - { - if (FD_ISSET(j, &readSet)) - { - #if defined(TEST) || defined(INFO) - *logofs << "[" << j << "]" << logofs_flush; - #endif - - i++; - } - } - - if (i > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << ".\n" << logofs_flush; - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "[none].\n" << logofs_flush; - #endif - } - - i = 0; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Selected for write are "; - #endif - - for (int j = 0; j < setFDs; j++) - { - if (FD_ISSET(j, &writeSet)) - { - #if defined(TEST) || defined(INFO) - *logofs << "[" << j << "]" << logofs_flush; - #endif - - i++; - } - } - - if (i > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << ".\n" << logofs_flush; - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "[none].\n" << logofs_flush; - #endif - } - } -} - -#endif - -static void handleCheckSessionInConnect() -{ - #ifdef TEST - *logofs << "Loop: Going to check session in connect.\n" - << logofs_flush; - #endif - - if (control -> ProxyMode == proxy_client) - { - HandleAlert(FAILED_PROXY_CONNECTION_CLIENT_ALERT, 1); - } - else if (IsNotRunning(lastDialog)) - { - HandleAlert(FAILED_PROXY_CONNECTION_SERVER_ALERT, 1); - } - - handleAlertInLoop(); -} - -static void handleStatisticsInLoop() -{ - if (lastSignal == 0) - { - return; - } - - int mode = NO_STATS; - - if (control -> EnableStatistics == 1) - { - if (lastSignal == SIGUSR1) - { - // - // Print overall statistics. - // - - mode = TOTAL_STATS; - } - else if (lastSignal == SIGUSR2) - { - // - // Print partial statistics. - // - - mode = PARTIAL_STATS; - } - - if (mode == TOTAL_STATS || mode == PARTIAL_STATS) - { - #ifdef TEST - *logofs << "Loop: Going to request proxy statistics " - << "with signal '" << DumpSignal(lastSignal) - << "'.\n" << logofs_flush; - #endif - - if (proxy != NULL) - { - if (ReopenLogFile(statsFileName, statofs, 0) < 0) - { - HandleCleanup(); - } - - proxy -> handleStatistics(mode, statofs); - } - } - } -} - -static void handleNegotiationInLoop(int &setFDs, fd_set &readSet, - fd_set &writeSet, T_timestamp &selectTs) -{ - int yield = 0; - - while (yield == 0) - { - #ifdef TEST - *logofs << "Loop: Going to run a new negotiation loop " - << "with stage " << control -> ProxyStage - << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - switch (control -> ProxyStage) - { - case stage_undefined: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_undefined" << "'.\n" - << logofs_flush; - #endif - - control -> ProxyStage = stage_initializing; - - break; - } - case stage_initializing: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_initializing" << "'.\n" - << logofs_flush; - #endif - - InitBeforeNegotiation(); - - control -> ProxyStage = stage_connecting; - - break; - } - case stage_connecting: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_connecting" << "'.\n" - << logofs_flush; - #endif - - SetupProxyConnection(); - - control -> ProxyStage = stage_connected; - - break; - } - case stage_connected: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_connected" << "'.\n" - << logofs_flush; - #endif - - // - // Server side proxy must always be the one that - // sends its version and options first, so, in - // some way, client side can be the the one that - // has the last word on the matter. - // - - if (control -> ProxyMode == proxy_server) - { - // - // Check if we have been listening for a - // forwarder. In this case it will have to - // authenticate itself. - // - - if (WE_LISTEN_FORWARDER) - { - control -> ProxyStage = stage_waiting_forwarder_version; - - break; - } - - control -> ProxyStage = stage_sending_proxy_options; - } - else - { - // - // The X client side is the side that has to wait - // for the authorization cookie and any remote - // option. - // - - control -> ProxyStage = stage_waiting_proxy_version; - } - - break; - } - case stage_sending_proxy_options: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_sending_proxy_options" << "'.\n" - << logofs_flush; - #endif - - if (SendProxyOptions(proxyFD) < 0) - { - goto handleNegotiationInLoopError; - } - - if (control -> ProxyMode == proxy_server) - { - control -> ProxyStage = stage_waiting_proxy_version; - } - else - { - control -> ProxyStage = stage_sending_proxy_caches; - } - - break; - } - case stage_waiting_forwarder_version: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_waiting_forwarder_version" << "'.\n" - << logofs_flush; - #endif - - int result = ReadForwarderVersion(proxyFD); - - if (result == 0) - { - yield = 1; - } - else if (result == 1) - { - control -> ProxyStage = stage_waiting_forwarder_options; - } - else - { - goto handleNegotiationInLoopError; - } - - break; - } - case stage_waiting_forwarder_options: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_waiting_forwarder_options" << "'.\n" - << logofs_flush; - #endif - - int result = ReadForwarderOptions(proxyFD); - - if (result == 0) - { - yield = 1; - } - else if (result == 1) - { - control -> ProxyStage = stage_sending_proxy_options; - } - else - { - goto handleNegotiationInLoopError; - } - - break; - } - case stage_waiting_proxy_version: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_waiting_proxy_version" << "'.\n" - << logofs_flush; - #endif - - int result = ReadProxyVersion(proxyFD); - - if (result == 0) - { - yield = 1; - } - else if (result == 1) - { - control -> ProxyStage = stage_waiting_proxy_options; - } - else - { - goto handleNegotiationInLoopError; - } - - break; - } - case stage_waiting_proxy_options: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_waiting_proxy_options" << "'.\n" - << logofs_flush; - #endif - - int result = ReadProxyOptions(proxyFD); - - if (result == 0) - { - yield = 1; - } - else if (result == 1) - { - if (control -> ProxyMode == proxy_server) - { - control -> ProxyStage = stage_waiting_proxy_caches; - } - else - { - control -> ProxyStage = stage_sending_proxy_options; - } - } - else - { - goto handleNegotiationInLoopError; - } - - break; - } - case stage_sending_proxy_caches: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_sending_proxy_caches" << "'.\n" - << logofs_flush; - #endif - - if (SendProxyCaches(proxyFD) < 0) - { - goto handleNegotiationInLoopError; - } - - if (control -> ProxyMode == proxy_server) - { - control -> ProxyStage = stage_operational; - } - else - { - control -> ProxyStage = stage_waiting_proxy_caches; - } - - break; - } - case stage_waiting_proxy_caches: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_waiting_proxy_caches" << "'.\n" - << logofs_flush; - #endif - - int result = ReadProxyCaches(proxyFD); - - if (result == 0) - { - yield = 1; - } - else if (result == 1) - { - if (control -> ProxyMode == proxy_server) - { - control -> ProxyStage = stage_sending_proxy_caches; - } - else - { - control -> ProxyStage = stage_operational; - } - } - else - { - goto handleNegotiationInLoopError; - } - - break; - } - case stage_operational: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_operational" << "'.\n" - << logofs_flush; - #endif - - InitAfterNegotiation(); - - yield = 1; - - break; - } - default: - { - #ifdef PANIC - *logofs << "Loop: PANIC! Unmanaged case '" << control -> ProxyStage - << "' while handling negotiation.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unmanaged case '" << control -> ProxyStage - << "' while handling negotiation.\n"; - - HandleCleanup(); - } - } - } - - // - // Check if the user requested the end of - // the session. - // - - if (CheckAbort() != 0) - { - HandleCleanup(); - } - - // - // Select the proxy descriptor so that we - // can proceed negotiating the session. - // - - FD_SET(proxyFD, &readSet); - - if (proxyFD >= setFDs) - { - setFDs = proxyFD + 1; - } - - setMinTimestamp(selectTs, control -> PingTimeout); - - #ifdef TEST - *logofs << "Loop: Selected proxy FD#" << proxyFD << " in negotiation " - << "phase with timeout of " << selectTs.tv_sec << " S and " - << selectTs.tv_usec << " Ms.\n" << logofs_flush; - #endif - - return; - -handleNegotiationInLoopError: - - #ifdef PANIC - *logofs << "Loop: PANIC! Failure negotiating the session in stage '" - << control -> ProxyStage << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failure negotiating the session in stage '" - << control -> ProxyStage << "'.\n"; - - - if (control -> ProxyMode == proxy_server && - control -> ProxyStage == stage_waiting_proxy_version) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Wrong version or invalid session " - << "authentication cookie.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Wrong version or invalid session " - << "authentication cookie.\n"; - } - - handleTerminatingInLoop(); - - HandleCleanup(); -} - -static void handleTerminatingInLoop() -{ - if (getpid() == lastProxy) - { - if (control -> ProxyStage < stage_terminating) - { - if (agent == NULL) - { - cerr << "Session" << ": Terminating session at '" - << strTimestamp() << "'.\n"; - } - - control -> ProxyStage = stage_terminating; - } - } -} - -static void handleTerminatedInLoop() -{ - if (getpid() == lastProxy) - { - if (control -> ProxyStage < stage_terminated) - { - if (agent == NULL) - { - cerr << "Session" << ": Session terminated at '" - << strTimestamp() << "'.\n"; - } - - control -> ProxyStage = stage_terminated; - } - } -} - -static void handleAlertInLoop() -{ - if (lastAlert.code == 0) - { - return; - } - - // - // Since ProtoStep7 (#issue 108) - // - // Now the remote proxy should always - // be able to handle the alert - // - - if (lastAlert.local == 0) - { - if (proxy != NULL) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Requesting a remote alert with code '" - << lastAlert.code << "'.\n" << logofs_flush; - #endif - - if (proxy -> handleAlert(lastAlert.code) < 0) - { - HandleShutdown(); - } - } - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Handling a local alert with code '" - << lastAlert.code << "'.\n" << logofs_flush; - #endif - - if (control -> ProxyMode == proxy_client) - { - // - // If we are at X client side and server - // proxy is not responding, we don't have - // any possibility to interact with user. - // - - if (lastAlert.code != CLOSE_DEAD_PROXY_CONNECTION_CLIENT_ALERT && - lastAlert.code != RESTART_DEAD_PROXY_CONNECTION_CLIENT_ALERT && - lastAlert.code != FAILED_PROXY_CONNECTION_CLIENT_ALERT) - { - // - // Let the server proxy show the dialog. - // - - if (proxy != NULL && - proxy -> handleAlert(lastAlert.code) < 0) - { - HandleShutdown(); - } - } - } - else - { - char caption[DEFAULT_STRING_LENGTH]; - - strcpy(caption, ALERT_CAPTION_PREFIX); - - int length = strlen(sessionId); - - // - // Get rid of the trailing MD5 from session id. - // - - if (length > (MD5_LENGTH * 2 + 1) && - *(sessionId + (length - (MD5_LENGTH * 2 + 1))) == '-') - { - strncat(caption, sessionId, length - (MD5_LENGTH * 2 + 1)); - } - else - { - strcat(caption, sessionId); - } - - // - // Use the display to which we are forwarding - // the remote X connections. - // - - char *display = displayHost; - - int replace = 1; - int local = 1; - - const char *message; - const char *type; - - switch (lastAlert.code) - { - case CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT: - { - message = CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT_STRING; - type = CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT_TYPE; - - break; - } - case CLOSE_DEAD_X_CONNECTION_SERVER_ALERT: - { - message = CLOSE_DEAD_X_CONNECTION_SERVER_ALERT_STRING; - type = CLOSE_DEAD_X_CONNECTION_SERVER_ALERT_TYPE; - - break; - } - case CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT: - { - message = CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT_STRING; - type = CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT_TYPE; - - break; - } - case RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT: - { - message = RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT_STRING; - type = RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT_TYPE; - - break; - } - case CLOSE_UNRESPONSIVE_X_SERVER_ALERT: - { - message = CLOSE_UNRESPONSIVE_X_SERVER_ALERT_STRING; - type = CLOSE_UNRESPONSIVE_X_SERVER_ALERT_TYPE; - - break; - } - case WRONG_PROXY_VERSION_ALERT: - { - message = WRONG_PROXY_VERSION_ALERT_STRING; - type = WRONG_PROXY_VERSION_ALERT_TYPE; - - break; - } - case FAILED_PROXY_CONNECTION_SERVER_ALERT: - { - message = FAILED_PROXY_CONNECTION_SERVER_ALERT_STRING; - type = FAILED_PROXY_CONNECTION_SERVER_ALERT_TYPE; - - break; - } - case MISSING_PROXY_CACHE_ALERT: - { - message = MISSING_PROXY_CACHE_ALERT_STRING; - type = MISSING_PROXY_CACHE_ALERT_TYPE; - - break; - } - case ABORT_PROXY_CONNECTION_ALERT: - { - message = ABORT_PROXY_CONNECTION_ALERT_STRING; - type = ABORT_PROXY_CONNECTION_ALERT_TYPE; - - break; - } - case DISPLACE_MESSAGE_ALERT: - { - message = DISPLACE_MESSAGE_ALERT_STRING; - type = DISPLACE_MESSAGE_ALERT_TYPE; - - break; - } - case GREETING_MESSAGE_ALERT: - { - message = GREETING_MESSAGE_ALERT_STRING; - type = GREETING_MESSAGE_ALERT_TYPE; - - break; - } - case START_RESUME_SESSION_ALERT: - { - message = START_RESUME_SESSION_ALERT_STRING; - type = START_RESUME_SESSION_ALERT_TYPE; - - break; - } - case FAILED_RESUME_DISPLAY_ALERT: - { - message = FAILED_RESUME_DISPLAY_ALERT_STRING; - type = FAILED_RESUME_DISPLAY_ALERT_TYPE; - - break; - } - case FAILED_RESUME_DISPLAY_BROKEN_ALERT: - { - message = FAILED_RESUME_DISPLAY_BROKEN_STRING; - type = FAILED_RESUME_DISPLAY_BROKEN_TYPE; - - break; - } - case FAILED_RESUME_VISUALS_ALERT: - { - message = FAILED_RESUME_VISUALS_ALERT_STRING; - type = FAILED_RESUME_VISUALS_ALERT_TYPE; - - break; - } - case FAILED_RESUME_COLORMAPS_ALERT: - { - message = FAILED_RESUME_COLORMAPS_ALERT_STRING; - type = FAILED_RESUME_COLORMAPS_ALERT_TYPE; - - break; - } - case FAILED_RESUME_PIXMAPS_ALERT: - { - message = FAILED_RESUME_PIXMAPS_ALERT_STRING; - type = FAILED_RESUME_PIXMAPS_ALERT_TYPE; - - break; - } - case FAILED_RESUME_DEPTHS_ALERT: - { - message = FAILED_RESUME_DEPTHS_ALERT_STRING; - type = FAILED_RESUME_DEPTHS_ALERT_TYPE; - - break; - } - case FAILED_RESUME_RENDER_ALERT: - { - message = FAILED_RESUME_RENDER_ALERT_STRING; - type = FAILED_RESUME_RENDER_ALERT_TYPE; - - break; - } - case FAILED_RESUME_FONTS_ALERT: - { - message = FAILED_RESUME_FONTS_ALERT_STRING; - type = FAILED_RESUME_FONTS_ALERT_TYPE; - - break; - } - case INTERNAL_ERROR_ALERT: - { - message = INTERNAL_ERROR_ALERT_STRING; - type = INTERNAL_ERROR_ALERT_TYPE; - - break; - } - case ABORT_PROXY_NEGOTIATION_ALERT: - { - message = ABORT_PROXY_NEGOTIATION_ALERT_STRING; - type = ABORT_PROXY_NEGOTIATION_ALERT_TYPE; - - break; - } - case ABORT_PROXY_SHUTDOWN_ALERT: - { - message = ABORT_PROXY_SHUTDOWN_ALERT_STRING; - type = ABORT_PROXY_SHUTDOWN_ALERT_TYPE; - - break; - } - case FAILED_XDMCP_CONNECTION_ALERT: - { - message = FAILED_XDMCP_CONNECTION_ALERT_STRING; - type = FAILED_XDMCP_CONNECTION_ALERT_TYPE; - - break; - } - default: - { - if (lastAlert.code > LAST_PROTO_STEP_7_ALERT) - { - #ifdef WARNING - *logofs << "Loop: WARNING! An unrecognized alert type '" - << lastAlert.code << "' was requested.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": An unrecognized alert type '" - << lastAlert.code << "' was requested.\n"; - } - #ifdef WARNING - else - { - *logofs << "Loop: WARNING! Ignoring obsolete alert type '" - << lastAlert.code << "'.\n" << logofs_flush; - } - #endif - - message = NULL; - type = NULL; - - replace = 0; - - break; - } - } - - if (replace == 1 && IsRunning(lastDialog)) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Killing the previous dialog with pid '" - << lastDialog << "'.\n" << logofs_flush; - #endif - - // - // The client ignores the TERM signal - // on Windows. - // - - #ifdef __CYGWIN32__ - - KillProcess(lastDialog, "dialog", SIGKILL, 0); - - #else - - KillProcess(lastDialog, "dialog", SIGTERM, 0); - - #endif - - SetNotRunning(lastDialog); - - if (proxy != NULL) - { - proxy -> handleResetAlert(); - } - } - - if (message != NULL && type != NULL) - { - lastDialog = NXTransDialog(caption, message, 0, type, local, display); - - if (IsFailed(lastDialog)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't start the NX dialog process.\n" - << logofs_flush; - #endif - - SetNotRunning(lastDialog); - } - #if defined(TEST) || defined(INFO) - else - { - *logofs << "Loop: Dialog started with pid '" - << lastDialog << "'.\n" << logofs_flush; - } - #endif - } - #if defined(TEST) || defined(INFO) - else - { - *logofs << "Loop: No new dialog required for code '" - << lastAlert.code << "'.\n" << logofs_flush; - } - #endif - } - } - - // - // Reset state. - // - - lastAlert.code = 0; - lastAlert.local = 0; -} - -static inline void handleSetAgentInLoop(int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs) -{ - #ifdef TEST - *logofs << "Loop: Preparing the masks for the agent descriptors.\n" - << logofs_flush; - #endif - - agent -> saveChannelState(); - - agent -> saveReadMask(&readSet); - agent -> saveWriteMask(&writeSet); - - if (control -> ProxyStage >= stage_operational) - { - if (agent -> remoteCanRead(&readSet) || - agent -> remoteCanWrite(&writeSet) || - agent -> localCanRead() || - agent -> proxyCanRead()) - { - #ifdef TEST - *logofs << "Loop: Setting a null timeout with agent descriptors ready.\n" - << logofs_flush; - #endif - - // - // Force a null timeout so we'll bail out - // of the select immediately. We will ac- - // comodate the result code later. - // - - selectTs.tv_sec = 0; - selectTs.tv_usec = 0; - } - } - - #ifdef TEST - *logofs << "Loop: Clearing the read and write agent descriptors.\n" - << logofs_flush; - #endif - - agent -> clearReadMask(&readSet); - agent -> clearWriteMask(&writeSet); -} - -static inline void handleAgentInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs) -{ - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Setting proxy and local agent descriptors.\n" - << logofs_flush; - #endif - - // - // Check if I/O is possible on the local - // agent or the proxy descriptor. - // - - if (resultFDs >= 0) - { - // - // Save if the proxy can read from the - // the agent descriptor. - // - - agent -> saveChannelState(); - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Values were resultFDs " << resultFDs - << " errorFDs " << errorFDs << " setFDs " - << setFDs << ".\n" << logofs_flush; - #endif - - if (agent -> localCanRead() == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Setting agent descriptor FD#" << agent -> - getLocalFd() << " as ready to read.\n" - << logofs_flush; - #endif - - agent -> setLocalRead(&readSet, &resultFDs); - } - - #if defined(TEST) || defined(INFO) - - if (agent -> proxyCanRead(&readSet) == 0 && - agent -> proxyCanRead() == 1) - { - *logofs << "Loop: WARNING! Can read from proxy FD#" - << proxyFD << " but the descriptor " - << "is not selected.\n" << logofs_flush; - } - - if (agent -> proxyCanRead(&readSet) == 1) - { - *logofs << "Loop: Setting proxy descriptor FD#" << agent -> - getProxyFd() << " as ready to read.\n" - << logofs_flush; - } - - #endif - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Values are now resultFDs " << resultFDs - << " errorFDs " << errorFDs << " setFDs " - << setFDs << ".\n" << logofs_flush; - #endif - } -} - -static inline void handleAgentLateInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs) -{ - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Setting remote agent descriptors.\n" - << logofs_flush; - #endif - - // - // We reset the masks before calling our select. - // We now set the descriptors that are ready but - // only if they were set in the original mask. - // We do this after having executed our loop as - // we may have produced more data and the agent - // descriptors may have become readable or writ- - // able in the meanwhile. - // - - if (resultFDs >= 0) - { - // - // Save if the proxy can read from the - // the agent descriptor. - // - - agent -> saveChannelState(); - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Values were resultFDs " << resultFDs - << " errorFDs " << errorFDs << " setFDs " - << setFDs << ".\n" << logofs_flush; - #endif - - if (agent -> remoteCanRead(agent -> - getSavedReadMask()) == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Setting agent descriptor FD#" << agent -> - getRemoteFd() << " as ready to read.\n" - << logofs_flush; - #endif - - agent -> setRemoteRead(&readSet, &resultFDs); - } - - if (agent -> remoteCanWrite(agent -> - getSavedWriteMask()) == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Setting agent descriptor FD#" << agent -> - getRemoteFd() << " as ready to write.\n" - << logofs_flush; - #endif - - agent -> setRemoteWrite(&writeSet, &resultFDs); - } - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Values are now resultFDs " << resultFDs - << " errorFDs " << errorFDs << " setFDs " - << setFDs << ".\n" << logofs_flush; - #endif - } -} - -static inline void handleReadableInLoop(int &resultFDs, fd_set &readSet) -{ - if (resultFDs > 0) - { - T_channel_type type = channel_none; - - const char *label = NULL; - int domain = -1; - int fd = -1; - - if (tcpFD != -1 && FD_ISSET(tcpFD, &readSet)) - { - type = channel_x11; - label = "X"; - domain = AF_INET; - fd = tcpFD; - - resultFDs--; - } - - if (unixFD != -1 && FD_ISSET(unixFD, &readSet)) - { - type = channel_x11; - label = "X"; - domain = AF_UNIX; - fd = unixFD; - - resultFDs--; - } - - if (cupsFD != -1 && FD_ISSET(cupsFD, &readSet)) - { - type = channel_cups; - label = "CUPS"; - domain = AF_INET; - fd = cupsFD; - - resultFDs--; - } - - if (auxFD != -1 && FD_ISSET(auxFD, &readSet)) - { - // - // Starting from version 1.5.0 we create real X - // connections for the keyboard channel, so they - // can use the fake authorization cookie. This - // means that there is not such a thing like a - // channel_aux anymore. - // - - type = channel_x11; - label = "auxiliary X11"; - domain = AF_INET; - fd = auxFD; - - resultFDs--; - } - - if (smbFD != -1 && FD_ISSET(smbFD, &readSet)) - { - type = channel_smb; - label = "SMB"; - domain = AF_INET; - fd = smbFD; - - resultFDs--; - } - - if (mediaFD != -1 && FD_ISSET(mediaFD, &readSet)) - { - type = channel_media; - label = "media"; - domain = AF_INET; - fd = mediaFD; - - resultFDs--; - } - - if (httpFD != -1 && FD_ISSET(httpFD, &readSet)) - { - type = channel_http; - label = "HTTP"; - domain = AF_INET; - fd = httpFD; - - resultFDs--; - } - - if (fontFD != -1 && FD_ISSET(fontFD, &readSet)) - { - type = channel_font; - label = "font server"; - domain = AF_INET; - fd = fontFD; - - resultFDs--; - } - - if (slaveFD != -1 && FD_ISSET(slaveFD, &readSet)) - { - type = channel_slave; - label = "slave"; - domain = AF_INET; - fd = slaveFD; - - resultFDs--; - } - - if (type != channel_none) - { - int newFD = AcceptConnection(fd, domain, label); - - if (newFD != -1) - { - if (proxy -> handleNewConnection(type, newFD) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating new " << label - << " connection.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Error creating new " << label - << " connection.\n"; - - close(newFD); - - // - // Don't kill the proxy in the case of an error. - // - // HandleCleanup(); - // - } - else if (proxy -> getReadable(newFD) > 0) - { - // - // Add the descriptor, so we can try - // to read immediately. - // - - #ifdef TEST - *logofs << "Loop: Trying to read immediately " - << "from descriptor FD#" << newFD - << ".\n" << logofs_flush; - #endif - - FD_SET(newFD, &readSet); - - resultFDs++; - } - #ifdef TEST - else - { - *logofs << "Loop: Nothing to read immediately " - << "from descriptor FD#" << newFD - << ".\n" << logofs_flush; - } - #endif - } - } - } - - #ifdef DEBUG - *logofs << "Loop: Going to check the readable descriptors.\n" - << logofs_flush; - #endif - - if (proxy -> handleRead(resultFDs, readSet) < 0) - { - #ifdef TEST - *logofs << "Loop: Failure reading from descriptors " - << "for proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - HandleShutdown(); - } -} - -static inline void handleWritableInLoop(int &resultFDs, fd_set &writeSet) -{ - #ifdef DEBUG - *logofs << "Loop: Going to check the writable descriptors.\n" - << logofs_flush; - #endif - - if (resultFDs > 0 && proxy -> handleFlush(resultFDs, writeSet) < 0) - { - #ifdef TEST - *logofs << "Loop: Failure writing to descriptors " - << "for proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - HandleShutdown(); - } -} - -static inline void handleFlushInLoop() -{ - #ifdef DEBUG - *logofs << "Loop: Going to flush any data to the proxy.\n" - << logofs_flush; - #endif - - if (agent == NULL || control -> - FlushPolicy == policy_immediate) - { - #if defined(TEST) || defined(INFO) - - if (usePolicy == -1 && control -> - ProxyMode == proxy_client) - { - *logofs << "Loop: WARNING! Flushing the proxy link " - << "on behalf of the agent.\n" << logofs_flush; - } - - #endif - - if (proxy -> handleFlush() < 0) - { - #ifdef TEST - *logofs << "Loop: Failure flushing the proxy FD#" - << proxyFD << ".\n" << logofs_flush; - #endif - - HandleShutdown(); - } - } -} - -static inline void handleRotateInLoop() -{ - #ifdef DEBUG - *logofs << "Loop: Going to rotate channels " - << "for proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - proxy -> handleRotate(); -} - -static inline void handleEventsInLoop() -{ - #ifdef DEBUG - *logofs << "Loop: Going to check channel events " - << "for proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - if (proxy -> handleEvents() < 0) - { - #ifdef TEST - *logofs << "Loop: Failure handling channel events " - << "for proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - HandleShutdown(); - } -} - -static void handleLogReopenInLoop(T_timestamp &logsTs, T_timestamp &nowTs) -{ - // - // If need to limit the size of the - // log file, check the size at each - // loop. - // - - #ifndef QUOTA - - if (diffTimestamp(logsTs, nowTs) > control -> FileSizeCheckTimeout) - - #endif - { - #ifdef DEBUG - *logofs << "Loop: Checking size of log file '" - << errorsFileName << "'.\n" << logofs_flush; - #endif - - #ifndef MIXED - - if (ReopenLogFile(errorsFileName, logofs, control -> FileSizeLimit) < 0) - { - HandleShutdown(); - } - - #endif - - // - // Reset to current timestamp. - // - - logsTs = nowTs; - } -} - -static inline void handleSetReadInLoop(fd_set &readSet, int &setFDs, struct timeval &selectTs) -{ - proxy -> setReadDescriptors(&readSet, setFDs, selectTs); -} - -static inline void handleSetWriteInLoop(fd_set &writeSet, int &setFDs, struct timeval &selectTs) -{ - proxy -> setWriteDescriptors(&writeSet, setFDs, selectTs); -} - -static void handleSetListenersInLoop(fd_set &readSet, int &setFDs) -{ - // - // Set descriptors of listening sockets. - // - - if (control -> ProxyMode == proxy_client) - { - if (useTcpSocket == 1) - { - FD_SET(tcpFD, &readSet); - - if (tcpFD >= setFDs) - { - setFDs = tcpFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener tcpFD " << tcpFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - - if (useUnixSocket == 1) - { - FD_SET(unixFD, &readSet); - - if (unixFD >= setFDs) - { - setFDs = unixFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener unixFD " << unixFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - - if (useCupsSocket == 1) - { - FD_SET(cupsFD, &readSet); - - if (cupsFD >= setFDs) - { - setFDs = cupsFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener cupsFD " << cupsFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - - if (useAuxSocket == 1) - { - FD_SET(auxFD, &readSet); - - if (auxFD >= setFDs) - { - setFDs = auxFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener auxFD " << auxFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - - if (useSmbSocket == 1) - { - FD_SET(smbFD, &readSet); - - if (smbFD >= setFDs) - { - setFDs = smbFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener smbFD " << smbFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - - if (useMediaSocket == 1) - { - FD_SET(mediaFD, &readSet); - - if (mediaFD >= setFDs) - { - setFDs = mediaFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener mediaFD " << mediaFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - - if (useHttpSocket == 1) - { - FD_SET(httpFD, &readSet); - - if (httpFD >= setFDs) - { - setFDs = httpFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener httpFD " << httpFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - } - else - { - if (useFontSocket == 1) - { - FD_SET(fontFD, &readSet); - - if (fontFD >= setFDs) - { - setFDs = fontFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener fontFD " << fontFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - } - - if (useSlaveSocket == 1) - { - FD_SET(slaveFD, &readSet); - - if (slaveFD >= setFDs) - { - setFDs = slaveFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener slaveFD " << slaveFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } -} |