~freenx-team/nx-x11/nxcomp-upstream

1 by Marcelo Boveto Shima
Import nxcomp 3.3.0-3
1
/**************************************************************************/
2
/*                                                                        */
3
/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/.         */
4
/*                                                                        */
5
/* NXCOMP, NX protocol compression and NX extensions to this software     */
6
/* are copyright of NoMachine. Redistribution and use of the present      */
7
/* software is allowed according to terms specified in the file LICENSE   */
8
/* which comes in the source distribution.                                */
9
/*                                                                        */
10
/* Check http://www.nomachine.com/licensing.html for applicability.       */
11
/*                                                                        */
12
/* NX and NoMachine are trademarks of NoMachine S.r.l.                    */
13
/*                                                                        */
14
/* All rights reserved.                                                   */
15
/*                                                                        */
16
/**************************************************************************/
17
18
#include <stdio.h>
19
#include <stdlib.h>
20
#include <unistd.h>
21
22
#include <errno.h>
23
#include <signal.h>
24
#include <setjmp.h>
25
26
#include <math.h>
27
#include <ctype.h>
28
#include <string.h>
29
#include <dirent.h>
30
#include <pwd.h>
31
32
#include <fcntl.h>
33
34
#include <sys/types.h>
35
#include <sys/stat.h>
36
#include <sys/wait.h>
37
#include <sys/resource.h>
38
#include <sys/utsname.h>
39
40
#include <netdb.h>
41
#include <netinet/in.h>
42
#include <arpa/inet.h>
43
44
#include "Misc.h"
45
46
#ifdef __sun
47
#include <strings.h>
48
#endif
49
50
//
51
// MacOSX 10.4 defines socklen_t. This is
52
// intended to ensure compatibility with
53
// older versions.
54
//
55
56
#ifdef __APPLE__
57
#include <AvailabilityMacros.h>
58
#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_3
59
typedef int socklen_t;
60
#endif
61
#endif
62
63
#ifdef _AIX
64
#include <strings.h>
65
#include <sys/select.h>
66
#endif
67
68
#ifndef __CYGWIN32__
69
#include <netinet/tcp.h>
70
#include <sys/un.h>
71
#endif
72
73
//
74
// NX include files.
75
//
76
77
#include "NX.h"
78
#include "NXalert.h"
79
80
#include "Misc.h"
81
#include "Control.h"
82
#include "Socket.h"
83
#include "Statistics.h"
84
#include "Auth.h"
85
#include "Keeper.h"
86
#include "Agent.h"
87
88
#include "ClientProxy.h"
89
#include "ServerProxy.h"
90
91
#include "Message.h"
92
93
//
94
// System specific defines.
95
//
96
97
#if defined(__EMX__) || defined(__CYGWIN32__)
98
99
struct sockaddr_un
100
{
101
  u_short sun_family;
102
  char sun_path[108];
103
};
104
105
#endif
106
107
//
108
// HP-UX hides this define.
109
//
110
111
#if defined(hpux) && !defined(RLIM_INFINITY)
112
113
#define RLIM_INFINITY  0x7fffffff
114
115
#endif
116
117
//
118
// Set the verbosity level.
119
//
120
121
#define PANIC
122
#define WARNING
123
#undef  TEST
124
#undef  DEBUG
125
#undef  DUMP
126
127
//
128
// Enable log output in signal handler.
129
// This is likely to hang the proxy at
130
// random, at least on Linux.
131
//
132
133
#undef UNSAFE
134
135
//
136
// Let all logs go to the standard error.
137
// This is useful to interleave the Xlib
138
// log output with the proxy output in a
139
// single file.
140
//
141
142
#undef  MIXED
143
144
//
145
// Define this to check if the client and
146
// server caches match at shutdown. This
147
// is a test facility as it requires that
148
// both proxies are running on the same
149
// host.
150
//
151
152
#undef  MATCH
153
154
//
155
// If defined, reduce the size of the log
156
// file and be sure it never exceeds the
157
// limit.
158
//
159
160
#undef  QUOTA
161
162
//
163
// If defined, force very strict limits for
164
// the proxy tokens and force the proxy to
165
// enter often in congestion state.
166
//
167
168
#undef  STRICT
169
170
//
171
// Print a line in the log if the time we
172
// spent inside the select or handling the
173
// messages exceeded a given time value.
174
//
175
176
#undef  TIME
177
178
//
179
// This can be useful when testing the forwarding
180
// of the SSHD connection by nxssh to the agent.
181
// The debug output will go to a well known file
182
// that will be opened also by nxssh when BINDER
183
// is enabled there.
184
//
185
186
#undef  BINDER
187
188
//
189
// Define this to override the limits on
190
// the core dump size.
191
//
192
193
#define COREDUMPS
194
195
//
196
// Upper limit of pre-allocated buffers
197
// for string parameters.
198
//
199
200
#define DEFAULT_STRING_LENGTH              256
201
202
//
203
// Maximum length of remote options data
204
// passed by peer proxy at startup.
205
//
206
207
#define DEFAULT_REMOTE_OPTIONS_LENGTH      512
208
209
//
210
// Maximum length of NX display string.
211
//
212
213
#define DEFAULT_DISPLAY_OPTIONS_LENGTH     1024
214
215
//
216
// Maximum number of cache file names to
217
// send to the server side.
218
//
219
220
#define DEFAULT_REMOTE_CACHE_ENTRIES       100
221
222
//
223
// Maximum length of remote options string
224
// that can be received from the peer proxy.
225
//
226
227
#define MAXIMUM_REMOTE_OPTIONS_LENGTH      4096
228
229
//
230
// Macro is true if we determined our proxy
231
// mode.
232
//
233
234
#define WE_SET_PROXY_MODE         (control -> ProxyMode != proxy_undefined)
235
236
//
237
// Macro is true if our side is the one that
238
// should connect to remote.
239
//
240
241
#define WE_INITIATE_CONNECTION    (*connectHost != '\0')
242
243
//
244
// Is true if we must provide our credentials
245
// to the remote peer.
246
//
247
248
#define WE_PROVIDE_CREDENTIALS    (control -> ProxyMode == proxy_server)
249
250
//
251
// Is true if we listen for a local forwarder
252
// that will tunnel the traffic through a SSH
253
// or HTTP link.
254
//
255
256
#define WE_LISTEN_FORWARDER       (control -> ProxyMode == proxy_server && \
257
                                           listenPort != -1)
258
259
//
260
// You must define FLUSH in Misc.h if
261
// you want an immediate flush of the
262
// log output.
263
//
264
265
ostream *logofs = NULL;
266
267
//
268
// Other stream destriptors used for
269
// logging.
270
//
271
272
ostream *statofs = NULL;
273
ostream *errofs  = NULL;
274
275
//
276
// Save standard error's rdbuf here
277
// and restore it when exiting.
278
//
279
280
static streambuf *errsbuf = NULL;
281
282
//
283
// Allow faults to be recovered by
284
// jumping back into the main loop.
285
//
286
287
jmp_buf context;
288
289
//
290
// Provide operational parameters.
291
//
292
293
Control *control = NULL;
294
295
//
296
// Collect and print statistics.
297
//
298
299
Statistics *statistics = NULL;
300
301
//
302
// Keep data for X11 authentication.
303
//
304
305
Auth *auth = NULL;
306
307
//
308
// This class makes the hard work.
309
//
310
311
Proxy *proxy = NULL;
312
313
//
314
// Used to handle memory-to-memory
315
// transport to the X agent.
316
//
317
318
Agent *agent = NULL;
319
320
//
321
// The image cache house-keeping class.
322
//
323
324
Keeper *keeper = NULL;
325
326
//
327
// Callback set by the child process
328
// to be notified about signals.
329
//
330
331
int (*handler)(int) = NULL;
332
333
//
334
// Signal handling functions.
335
//
336
337
void DisableSignals();
338
void EnableSignals();
339
void InstallSignals();
340
341
static void RestoreSignals();
342
static void HandleSignal(int signal);
343
344
//
345
// Signal handling utilities.
346
//
347
348
static void InstallSignal(int signal, int action);
349
static void RestoreSignal(int signal);
350
351
static int HandleChildren();
352
353
static int HandleChild(int child);
354
static int CheckChild(int pid, int status);
355
static int WaitChild(int child, const char *label, int force);
356
357
int CheckParent(char *name, char *type, int parent);
358
359
void RegisterChild(int child);
360
361
static int CheckAbort();
362
363
//
364
// Timer handling utilities.
365
//
366
367
void SetTimer(int timeout);
368
void ResetTimer();
369
370
static void HandleTimer(int signal);
371
372
//
373
// Kill or check a running child.
374
//
375
376
static int KillProcess(int pid, const char *label, int signal, int wait);
377
static int CheckProcess(int pid, const char *label);
378
379
//
380
// Macros used to test the pid of a child.
381
//
382
383
#define IsFailed(pid)       ((pid) < 0)
384
#define IsRunning(pid)      ((pid) > 1)
385
#define IsNotRunning(pid)   ((pid) == 0)
386
#define IsRestarting(pid)   ((pid) == 1)
387
388
#define SetNotRunning(pid)  ((pid) = 0)
389
#define SetRestarting(pid)  ((pid) = 1)
390
391
//
392
// Start or restart the house-keeper process.
393
//
394
395
static int StartKeeper();
396
397
//
398
// Cleanup functions.
399
//
400
401
void CleanupConnections();
402
void CleanupListeners();
403
void CleanupSockets();
404
void CleanupGlobal();
405
406
static void CleanupChildren();
407
static void CleanupLocal();
408
static void CleanupKeeper();
409
static void CleanupStreams();
410
411
//
412
// Loop forever until the connections
413
// to the peer proxy is dropped.
414
//
415
416
static void WaitCleanup();
417
418
//
419
// Initialization functions.
420
//
421
422
static int InitBeforeNegotiation();
423
static int SetupProxyConnection();
424
static int InitAfterNegotiation();
425
static int SetupProxyInstance();
426
static int SetupAuthInstance();
427
static int SetupAgentInstance();
428
429
static int SetupTcpSocket();
430
static int SetupUnixSocket();
431
static int SetupServiceSockets();
432
static int SetupDisplaySocket(int &xServerAddrFamily, sockaddr *&xServerAddr,
433
                                  unsigned int &xServerAddrLength);
434
435
//
436
// Setup a listening socket and accept
437
// a new connection.
438
//
439
440
static int ListenConnection(int port, const char *label);
441
static int AcceptConnection(int fd, int domain, const char *label);
442
443
//
444
// Other convenience functions.
445
//
446
447
static int WaitForRemote(int portNum);
448
static int ConnectToRemote(const char *const hostName, int portNum);
449
450
static int SendProxyOptions(int fd);
451
static int SendProxyCaches(int fd);
452
static int ReadProxyVersion(int fd);
453
static int ReadProxyOptions(int fd);
454
static int ReadProxyCaches(int fd);
455
static int ReadForwarderVersion(int fd);
456
static int ReadForwarderOptions(int fd);
457
458
static int ReadRemoteData(int fd, char *buffer, int size, char stop);
459
static int WriteLocalData(int fd, const char *buffer, int size);
460
461
static void PrintVersionInfo();
462
static void PrintProcessInfo();
463
static void PrintConnectionInfo();
464
static void PrintUsageInfo(const char *option, const int error);
465
static void PrintOptionIgnored(const char *type, const char *name, const char *value);
466
467
//
468
// This is not static to avoid a warning.
469
//
470
471
void PrintCopyrightInfo();
472
473
static const char *GetOptions(const char *options);
474
static const char *GetArg(int &argi, int argc, const char **argv);
475
static int CheckArg(const char *type, const char *name, const char *value);
476
static int ParseArg(const char *type, const char *name, const char *value);
477
static int ValidateArg(const char *type, const char *name, const char *value);
478
static int LowercaseArg(const char *type, const char *name, char *value);
479
static int CheckSignal(int signal);
480
481
extern "C"
482
{
483
  int ParseCommandLineOptions(int argc, const char **argv);
484
  int ParseEnvironmentOptions(const char *env, int force);
485
  int ParseBindOptions(char **host, int *port);
486
}
487
488
static int ParseFileOptions(const char *file);
489
static int ParseRemoteOptions(char *opts);
490
static int ParseForwarderOptions(char *opts);
491
492
//
493
// These functions are used to parse literal
494
// values provided by the user and set the
495
// control parameters accordingly.
496
//
497
498
static int ParseLinkOption(const char *opt);
499
static int ParseBitrateOption(const char *opt);
500
static int ParseCacheOption(const char *opt);
501
static int ParseShmemOption(const char *opt);
502
static int ParseImagesOption(const char *opt);
503
static int ParsePackOption(const char *opt);
504
505
//
506
// Set host and port where NX proxy is supposed
507
// to be listening in case such parameters are
508
// given on the command line.
509
//
510
511
static int ParseHostOption(const char *opt, char *host, int &port);
512
513
//
514
// Translate a font server port specification
515
// to the corresponding Unix socket path.
516
//
517
518
static int ParseFontPath(char *path);
519
520
//
521
// Determine the interface where to listen for
522
// the remote proxy connection or the local
523
// forwarder.
524
//
525
526
static int ParseListenOption(int &interface);
527
528
//
529
// Translate a pack method id in a literal.
530
//
531
532
static int ParsePackMethod(const int method, const int quality);
533
534
//
535
// Try to increase the size of the allowed
536
// core dumps.
537
//
538
539
static int SetCore();
540
541
//
542
// Set the proxy mode to either client or
543
// server.
544
//
545
546
static int SetMode(int mode);
547
548
//
549
// Determine the path of the NX_* directories
550
// from the environment.
551
//
552
553
static int SetDirectories();
554
555
//
556
// Set the defaults used for the log file and
557
// statistics.
558
//
559
560
static int SetLogs();
561
562
//
563
// Check if local and remote protocol versions
564
// are compatible and, eventually, downgrade
565
// local version to the minimum level that is
566
// known to work.
567
//
568
569
static int SetVersion();
570
571
//
572
// Setup the listening TCP ports used for the
573
// additional channels according to user's
574
// wishes.
575
//
576
577
static int SetPorts();
578
579
//
580
// Set the maximum number of open descriptors.
581
//
582
583
static int SetDescriptors();
584
585
//
586
// Set the path used for choosing the cache.
587
// It must be selected after determining the
588
// session type.
589
//
590
591
static int SetCaches();
592
593
//
594
// Initialize, one after the other, all the
595
// configuration parameters.
596
//
597
598
static int SetParameters();
599
600
//
601
// Set the specific configuration parameter.
602
//
603
604
static int SetSession();
605
static int SetStorage();
606
static int SetShmem();
607
static int SetPack();
608
static int SetImages();
609
static int SetLimits();
610
611
//
612
// Set up the control parameters based on
613
// the link speed negotiated between the
614
// proxies.
615
//
616
617
static int SetLink();
618
619
static int SetLinkModem();
620
static int SetLinkIsdn();
621
static int SetLinkAdsl();
622
static int SetLinkWan();
623
static int SetLinkLan();
624
625
//
626
// Adjust the compression parameters.
627
//
628
629
static int SetCompression();
630
631
static int SetCompressionModem();
632
static int SetCompressionIsdn();
633
static int SetCompressionAdsl();
634
static int SetCompressionWan();
635
static int SetCompressionLan();
636
637
//
638
// Determine the NX paths based on the
639
// user's parameters or the environment.
640
//
641
642
char *GetClientPath();
643
644
static char *GetSystemPath();
645
static char *GetHomePath();
646
static char *GetTempPath();
647
static char *GetRootPath();
648
static char *GetCachePath();
649
static char *GetImagesPath();
650
static char *GetSessionPath();
651
static char *GetLastCache(char *list, const char *path);
652
653
static int OpenLogFile(char *name, ostream *&stream);
654
static int ReopenLogFile(char *name, ostream *&stream, int limit);
655
656
//
657
// Perform operations on the managed
658
// descriptors in the main loop.
659
//
660
661
static void handleCheckSessionInLoop();
662
static void handleCheckBitrateInLoop();
663
664
#if defined(TEST) || defined(INFO)
665
static void handleCheckSelectInLoop(int &setFDs, fd_set &readSet,
666
                                        fd_set &writeSet, T_timestamp selectTs);
667
static void handleCheckResultInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet,
668
                                        fd_set &writeSet, struct timeval &selectTs,
669
                                            struct timeval &startTs);
670
static void handleCheckStateInLoop(int &setFDs);
671
#endif
672
673
static void handleCheckSessionInConnect();
674
675
static inline void handleSetReadInLoop(fd_set &readSet, int &setFDs, struct timeval &selectTs);
676
static inline void handleSetWriteInLoop(fd_set &writeSet, int &setFDs, struct timeval &selectTs);
677
static inline void handleSetListenersInLoop(fd_set &writeSet, int &setFDs);
678
static inline void handleSetAgentInLoop(int &setFDs, fd_set &readSet, fd_set &writeSet,
679
                                            struct timeval &selectTs);
680
681
static void handleAlertInLoop();
682
static void handleStatisticsInLoop();
683
684
static inline void handleAgentInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet,
685
                                         fd_set &writeSet, struct timeval &selectTs);
686
static inline void handleAgentLateInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet,
687
                                             fd_set &writeSet, struct timeval &selectTs);
688
689
static inline void handleReadableInLoop(int &resultFDs, fd_set &readSet);
690
static inline void handleWritableInLoop(int &resultFDs, fd_set &writeSet);
691
692
static inline void handleRotateInLoop();
693
static inline void handleEventsInLoop();
694
static inline void handleFlushInLoop();
695
696
//
697
// Manage the proxy link during the negotiation
698
// phase.
699
//
700
701
static void handleNegotiationInLoop(int &setFDs, fd_set &readSet,
702
                                        fd_set &writeSet, T_timestamp &selectTs);
703
704
//
705
// Print the 'terminating' messages in the
706
// session log.
707
//
708
 
709
static inline void handleTerminatingInLoop();
710
static inline void handleTerminatedInLoop();
711
712
//
713
// Monitor the size of the log file.
714
//
715
716
static void handleLogReopenInLoop(T_timestamp &logsTs, T_timestamp &nowTs);
717
718
//
719
// Directory where the NX binaries and libraries reside.
720
//
721
722
static char systemDir[DEFAULT_STRING_LENGTH] = { 0 };
723
724
//
725
// Directory used for temporary files.
726
//
727
728
static char tempDir[DEFAULT_STRING_LENGTH] = { 0 };
729
730
//
731
// Actually the full path to the client.
732
//
733
734
static char clientDir[DEFAULT_STRING_LENGTH] = { 0 };
735
736
//
737
// User's home directory.
738
//
739
740
static char homeDir[DEFAULT_STRING_LENGTH] = { 0 };
741
742
//
743
// Root of directory structure to be created by proxy.
744
//
745
746
static char rootDir[DEFAULT_STRING_LENGTH] = { 0 };
747
748
//
749
// Root of statistics and log files to be created by proxy.
750
//
751
752
static char sessionDir[DEFAULT_STRING_LENGTH] = { 0 };
753
754
//
755
// Log files for errors and statistics. Error log is
756
// the place where we print also debug informations.
757
// Both files are closed, deleted and reopened as
758
// their size exceed the limit set in control class.
759
// The session log is not reopened, as it is used by
760
// the NX client and server to track the advance of
761
// the session.
762
//
763
764
static char errorsFileName[DEFAULT_STRING_LENGTH]  = { 0 };
765
static char statsFileName[DEFAULT_STRING_LENGTH]   = { 0 };
766
static char sessionFileName[DEFAULT_STRING_LENGTH] = { 0 };
767
static char optionsFileName[DEFAULT_STRING_LENGTH] = { 0 };
768
769
//
770
// String literal representing selected link speed
771
// parameter. Value is translated in control values
772
// used by proxies to stay synchronized.
773
//
774
775
static char linkSpeedName[DEFAULT_STRING_LENGTH] = { 0 };
776
777
//
778
// String literal representing selected
779
// cache size.
780
//
781
782
static char cacheSizeName[DEFAULT_STRING_LENGTH] = { 0 };
783
784
//
785
// String literal representing selected
786
// shared memory segment size.
787
//
788
789
static char shsegSizeName[DEFAULT_STRING_LENGTH] = { 0 };
790
791
//
792
// String literal of images cache size.
793
//
794
795
static char imagesSizeName[DEFAULT_STRING_LENGTH] = { 0 };
796
797
//
798
// String literal for bandwidth limit.
799
//
800
801
static char bitrateLimitName[DEFAULT_STRING_LENGTH] = { 0 };
802
803
//
804
// String literal for image packing method.
805
//
806
807
static char packMethodName[DEFAULT_STRING_LENGTH] = { 0 };
808
809
//
810
// Product name provided by the server or client.
811
//
812
813
static char productName[DEFAULT_STRING_LENGTH] = { 0 };
814
815
//
816
// Its corresponding value from NXpack.h.
817
//
818
819
static int packMethod  = -1;
820
static int packQuality = -1;
821
822
//
823
// String literal for session type. Persistent caches
824
// are searched in directory whose name matches this
825
// parameter.
826
//
827
828
static char sessionType[DEFAULT_STRING_LENGTH] = { 0 };
829
830
//
831
// Unique id assigned to session. It is used as
832
// name of directory where all files are placed.
833
//
834
835
static char sessionId[DEFAULT_STRING_LENGTH] = { 0 };
836
837
//
838
// Set if we already parsed the options.
839
//
840
841
static int parsedOptions = 0;
842
static int parsedCommand = 0;
843
844
//
845
// Buffer data received from the remote proxy at
846
// session negotiation.
847
//
848
849
static char remoteData[MAXIMUM_REMOTE_OPTIONS_LENGTH] = { 0 };
850
static int  remotePosition = 0;
851
852
//
853
// Main loop file descriptors.
854
//
855
856
static int tcpFD   = -1;
857
static int unixFD  = -1;
858
static int cupsFD  = -1;
859
static int auxFD   = -1;
860
static int smbFD   = -1;
861
static int mediaFD = -1;
862
static int httpFD  = -1;
863
static int fontFD  = -1;
864
static int slaveFD = -1;
865
static int proxyFD = -1;
866
867
//
868
// Used for internal communication
869
// with the X agent.
870
//
871
872
static int agentFD[2] = { -1, -1 };
873
874
//
875
// Flags determining which protocols and
876
// ports are forwarded.
877
//
878
879
int useUnixSocket = 1;
880
881
static int useTcpSocket   = 1;
882
static int useCupsSocket  = 0;
883
static int useAuxSocket   = 0;
884
static int useSmbSocket   = 0;
885
static int useMediaSocket = 0;
886
static int useHttpSocket  = 0;
887
static int useFontSocket  = 0;
888
static int useSlaveSocket = 0;
889
static int useAgentSocket = 0;
890
891
//
892
// Set if the launchd service is running
893
// and its socket must be used as X socket.
894
//
895
896
static int useLaunchdSocket = 0;
897
898
//
899
// Set by user if he/she wants to modify
900
// the default TCP_NODELAY option as set
901
// in control.
902
//
903
904
static int useNoDelay = -1;
905
906
//
907
// Set if user wants to override default
908
// flush timeout set according to link.
909
//
910
911
static int usePolicy = -1;
912
913
//
914
// Set if user wants to hide the RENDER
915
// extension or wants to short-circuit
916
// some simple replies at client side.
917
//
918
919
static int useRender = -1;
920
static int useTaint  = -1;
921
922
//
923
// Set if the user wants to reduce the
924
// nominal size of the token messages
925
// exchanged between the proxies.
926
//
927
928
static int useStrict = -1;
929
930
//
931
// Set if the proxy is running as part
932
// of SSH on the client.
933
//
934
935
static int useEncryption = -1;
936
937
//
938
// Name of Unix socket created by the client proxy to
939
// accept client connections. File must be unlinked
940
// by cleanup function.
941
//
942
943
static char unixSocketName[DEFAULT_STRING_LENGTH] = { 0 };
944
945
//
946
// Other parameters.
947
//
948
949
static char connectHost[DEFAULT_STRING_LENGTH] = { 0 };
950
static char acceptHost[DEFAULT_STRING_LENGTH]  = { 0 };
951
static char listenHost[DEFAULT_STRING_LENGTH]  = { 0 };
952
static char displayHost[DEFAULT_STRING_LENGTH] = { 0 };
953
static char authCookie[DEFAULT_STRING_LENGTH]  = { 0 };
954
955
static int proxyPort = DEFAULT_NX_PROXY_PORT;
956
static int xPort     = DEFAULT_NX_X_PORT;
957
958
//
959
// Used to setup the connection the real
960
// X display socket.
961
//
962
963
static int xServerAddrFamily          = -1;
964
static sockaddr *xServerAddr          = NULL;
965
static unsigned int xServerAddrLength = 0;
966
967
//
968
// The port where the local proxy will await
969
// the peer connection or where the remote
970
// proxy will be contacted.
971
//
972
973
static int listenPort  = -1;
974
static int connectPort = -1;
975
976
//
977
// Helper channels are disabled by default.
978
//
979
980
static int cupsPort  = -1;
981
static int auxPort   = -1;
982
static int smbPort   = -1;
983
static int mediaPort = -1;
984
static int httpPort  = -1;
985
static int slavePort = -1;
986
987
//
988
// Can be either a port number or a Unix
989
// socket.
990
//
991
992
static char fontPort[DEFAULT_STRING_LENGTH] = { 0 };
993
994
//
995
// Host and port where the existing proxy
996
// is running.
997
//
998
999
static char bindHost[DEFAULT_STRING_LENGTH] = { 0 };
1000
static int  bindPort = -1;
1001
1002
//
1003
// Pointers to the callback functions and
1004
// parameter set by the agent
1005
//
1006
1007
static void (*flushCallback)(void *, int) = NULL;
1008
static void *flushParameter = NULL;
1009
1010
static void (*statisticsCallback)(void *, int) = NULL;
1011
static void *statisticsParameter = NULL;
1012
1013
//
1014
// State variables shared between the init
1015
// function and the main loop.
1016
//
1017
1018
T_timestamp initTs;
1019
T_timestamp startTs;
1020
T_timestamp logsTs;
1021
T_timestamp nowTs;
1022
1023
int diffTs;
1024
1025
//
1026
// This is set to the main proxy process id.
1027
// 
1028
1029
int lastProxy = 0;
1030
1031
//
1032
// Set to last dialog process launched by proxy.
1033
// 
1034
1035
int lastDialog = 0;
1036
1037
//
1038
// Set to watchdog process launched by proxy.
1039
// 
1040
1041
int lastWatchdog = 0;
1042
1043
//
1044
// Set if a cache house-keeper process is running.
1045
// 
1046
1047
int lastKeeper = 0;
1048
1049
//
1050
// Let an inner routine register the pid of a slave
1051
// process.
1052
//
1053
1054
static int lastChild = 0;
1055
1056
//
1057
// Exit code of the last child process exited.
1058
//
1059
1060
static int lastStatus = 0;
1061
1062
//
1063
// Set if shutdown was requested through a signal.
1064
//
1065
1066
static int lastKill = 0;
1067
1068
//
1069
// Set if the agent confirmed the destruction of
1070
// the NX transport.
1071
//
1072
1073
static int lastDestroy = 0;
1074
1075
//
1076
// This is set to the code and local flag of the
1077
// last requested alert.
1078
// 
1079
1080
static struct
1081
{
1082
  int code;
1083
  int local;
1084
1085
} lastAlert;
1086
1087
//
1088
// Manage the current signal masks.
1089
//
1090
1091
static struct
1092
{
1093
  sigset_t saved;
1094
1095
  int blocked;
1096
  int installed;
1097
1098
  int enabled[32];
1099
  int forward[32];
1100
1101
  struct sigaction action[32];
1102
1103
} lastMasks;
1104
1105
//
1106
// Manage the current timer.
1107
//
1108
1109
static struct
1110
{
1111
  struct sigaction action;
1112
  struct itimerval value;
1113
  struct timeval   start;
1114
  struct timeval   next;
1115
1116
} lastTimer;
1117
1118
//
1119
// This is set to last signal received in handler.
1120
//
1121
1122
static int lastSignal = 0;
1123
1124
//
1125
// Set to the last time bytes readable were queried
1126
// by the agent.
1127
//
1128
1129
static T_timestamp lastReadableTs = nullTimestamp();
1130
1131
//
1132
// Here are interfaces declared in NX.h.
1133
//
1134
1135
int NXTransProxy(int fd, int mode, const char* options)
1136
{
1137
  //
1138
  // Let the log temporarily go to the standard
1139
  // error. Be also sure we have a jump context,
1140
  // in the case any subsequent operation will
1141
  // cause a cleanup.
1142
  //
1143
1144
  if (logofs == NULL)
1145
  {
1146
    logofs = &cerr;
1147
  }
1148
1149
  if (setjmp(context) == 1)
1150
  {
1151
    #ifdef TEST
1152
    *logofs << "NXTransProxy: Out of the long jump with pid '"
1153
            << lastProxy << "'.\n" << logofs_flush;
1154
    #endif
1155
    
1156
    return -1;
1157
  }
1158
1159
  //
1160
  // Check if have already performed a parsing of
1161
  // parameters, as in the case we are running as
1162
  // a stand-alone process. If needed create the
1163
  // parameters repository
1164
  //
1165
1166
  if (control == NULL)
1167
  {
1168
    control = new Control();
1169
  }
1170
1171
  lastProxy = getpid();
1172
1173
  #ifdef TEST
1174
  *logofs << "NXTransProxy: Main process started with pid '"
1175
          << lastProxy << "'.\n" << logofs_flush;
1176
  #endif
1177
1178
  SetMode(mode);
1179
1180
  if (mode == NX_MODE_CLIENT)
1181
  {
1182
    if (fd != NX_FD_ANY)
1183
    {
1184
      #ifdef TEST
1185
1186
      *logofs << "NXTransProxy: Agent descriptor for X client connections is FD#"
1187
              << fd << ".\n" << logofs_flush;
1188
1189
      *logofs << "NXTransProxy: Disabling listening on further X client connections.\n"
1190
              << logofs_flush;
1191
1192
      #endif
1193
1194
      useTcpSocket   = 0;
1195
      useUnixSocket  = 0;
1196
      useAgentSocket = 1;
1197
1198
      agentFD[1] = fd;
1199
    }
1200
  }
1201
  else if (mode == NX_MODE_SERVER)
1202
  {
1203
    if (fd != NX_FD_ANY)
1204
    {
1205
      #ifdef TEST
1206
      *logofs << "NXTransProxy: PANIC! Agent descriptor for X server connections "
1207
              << "not supported yet.\n" << logofs_flush;
1208
      #endif
1209
1210
      cerr << "Error" << ": Agent descriptor for X server connections "
1211
           << "not supported yet.\n";
1212
1213
      return -1;
1214
    }
1215
  }
1216
1217
  const char *env = GetOptions(options);
1218
1219
  if (ParseEnvironmentOptions(env, 0) < 0)
1220
  {
1221
    cerr << "Error" << ": Parsing of NX transport options failed.\n";
1222
1223
    return -1;
1224
  }
1225
1226
  //
1227
  // Set the path of the NX directories.
1228
  //
1229
1230
  SetDirectories();
1231
1232
  //
1233
  // Open the log files.
1234
  //
1235
1236
  SetLogs();
1237
1238
  #ifdef TEST
1239
  *logofs << "NXTransProxy: Going to run the NX transport loop.\n"
1240
          << logofs_flush;
1241
  #endif
1242
1243
  WaitCleanup();
1244
1245
  //
1246
  // This function should never return.
1247
  //
1248
1249
  exit(0);
1250
}
1251
1252
void NXTransExit(int code)
1253
{
1254
  if (logofs == NULL)
1255
  {
1256
    logofs = &cerr;
1257
  }
1258
1259
  static int recurse;
1260
1261
  if (++recurse > 1)
1262
  {
1263
    #ifdef TEST
1264
    *logofs << "NXTransExit: Aborting process with pid '"
1265
            << getpid() << "' due to recursion through "
1266
            << "exit.\n" << logofs_flush;
1267
    #endif
1268
1269
    abort();
1270
  }
1271
1272
  #ifdef TEST
1273
  *logofs << "NXTransExit: Process with pid '"
1274
          << getpid() << "' called exit with code '"
1275
          << code << "'.\n" << logofs_flush;
1276
  #endif
1277
1278
  if (control != NULL)
1279
  {
1280
    //
1281
    // Be sure that there we can detect the
1282
    // termination of the watchdog.
1283
    //
1284
1285
    EnableSignals();
1286
1287
    //
1288
    // Close the NX transport if it was not
1289
    // shut down already.
1290
    //
1291
1292
    NXTransDestroy(NX_FD_ANY);
1293
  }
1294
1295
  exit(code);
1296
}
1297
1298
int NXTransParseCommandLine(int argc, const char **argv)
1299
{
1300
  return ParseCommandLineOptions(argc, argv);
1301
}
1302
1303
int NXTransParseEnvironment(const char *env, int force)
1304
{
1305
  return ParseEnvironmentOptions(env, force);
1306
}
1307
1308
void NXTransCleanup()
1309
{
1310
  HandleCleanup();
1311
}
1312
1313
//
1314
// Check the parameters for subsequent
1315
// initialization of the NX transport.
1316
//
1317
1318
int NXTransCreate(int fd, int mode, const char* options)
1319
{
1320
  if (logofs == NULL)
1321
  {
1322
    logofs = &cerr;
1323
  }
1324
1325
  //
1326
  // Be sure we have a jump context, in the
1327
  // case a subsequent operation will cause
1328
  // a cleanup.
1329
  //
1330
1331
  if (setjmp(context) == 1)
1332
  {
1333
    return -1;
1334
  }
1335
1336
  //
1337
  // Create the parameters repository
1338
  //
1339
1340
  if (control != NULL)
1341
  {
1342
    #ifdef PANIC
1343
    *logofs << "NXTransCreate: PANIC! The NX transport seems "
1344
            << "to be already running.\n" << logofs_flush;
1345
    #endif
1346
1347
    cerr << "Error" << ": The NX transport seems "
1348
         << "to be already running.\n";
1349
1350
    return -1;
1351
  }
1352
1353
  control = new Control();
1354
1355
  if (control == NULL)
1356
  {
1357
    #ifdef PANIC
1358
    *logofs << "Loop: PANIC! Error creating the NX transport.\n"
1359
            << logofs_flush;
1360
    #endif
1361
1362
    cerr << "Error" << ": Error creating the NX transport.\n";
1363
1364
    return -1;
1365
  }
1366
1367
  lastProxy = getpid();
1368
1369
  #ifdef TEST
1370
  *logofs << "NXTransCreate: Caller process running with pid '"
1371
          << lastProxy << "'.\n" << logofs_flush;
1372
  #endif
1373
1374
  //
1375
  // Set the local proxy mode an parse the
1376
  // display NX options.
1377
  //
1378
1379
  SetMode(mode);
1380
1381
  const char *env = GetOptions(options);
1382
1383
  if (ParseEnvironmentOptions(env, 0) < 0)
1384
  {
1385
    cerr << "Error" << ": Parsing of NX transport options failed.\n";
1386
1387
    return -1;
1388
  }
1389
1390
  //
1391
  // Set the path of the NX directories.
1392
  //
1393
1394
  SetDirectories();
1395
1396
  //
1397
  // Open the log files.
1398
  //
1399
1400
  SetLogs();
1401
1402
  //
1403
  // Use the provided descriptor.
1404
  //
1405
1406
  proxyFD = fd;
1407
1408
  #ifdef TEST
1409
  *logofs << "NXTransCreate: Called with NX proxy descriptor '"
1410
          << proxyFD << "'.\n" << logofs_flush;
1411
  #endif
1412
1413
  #ifdef TEST
1414
  *logofs << "NXTransCreate: Creation of the NX transport completed.\n"
1415
          << logofs_flush;
1416
  #endif
1417
1418
  return 1;
1419
}
1420
1421
//
1422
// Tell the proxy to use the descriptor as the internal
1423
// connection to the X client side NX agent. This will
1424
// have the side effect of disabling listening for add-
1425
// itional X client connections.
1426
//
1427
1428
int NXTransAgent(int fd[2])
1429
{
1430
  //
1431
  // Be sure we have a jump context, in the
1432
  // case a subsequent operation will cause
1433
  // a cleanup.
1434
  //
1435
1436
  if (logofs == NULL)
1437
  {
1438
    logofs = &cerr;
1439
  }
1440
1441
  if (setjmp(context) == 1)
1442
  {
1443
    return -1;
1444
  }
1445
1446
  if (control == NULL)
1447
  {
1448
    cerr << "Error" << ": Can't set the NX agent without a NX transport.\n";
1449
1450
    return -1;
1451
  }
1452
  else if (control -> ProxyMode != proxy_client)
1453
  {
1454
    #ifdef PANIC
1455
    *logofs << "NXTransAgent: Invalid mode while setting the NX agent.\n"
1456
            << logofs_flush;
1457
    #endif
1458
1459
    cerr << "Error" << ": Invalid mode while setting the NX agent.\n\n";
1460
1461
    return -1;
1462
  }
1463
1464
  useTcpSocket   = 0;
1465
  useUnixSocket  = 0;
1466
  useAgentSocket = 1;
1467
1468
  agentFD[0] = fd[0];
1469
  agentFD[1] = fd[1];
1470
1471
  #ifdef TEST
1472
1473
  *logofs << "NXTransAgent: Internal descriptors for agent are FD#"
1474
          << agentFD[0] << " and FD#" << agentFD[1] << ".\n"
1475
          << logofs_flush;
1476
1477
  *logofs << "NXTransAgent: Disabling listening for further X client "
1478
          << "connections.\n" << logofs_flush;
1479
1480
  #endif
1481
1482
  agent = new Agent(agentFD);
1483
1484
  if (agent == NULL || agent -> isValid() != 1)
1485
  {
1486
    #ifdef PANIC
1487
    *logofs << "Loop: PANIC! Error creating the NX memory transport .\n"
1488
            << logofs_flush;
1489
    #endif
1490
1491
    cerr << "Error" << ": Error creating the NX memory transport.\n";
1492
1493
    HandleCleanup();
1494
  }
1495
1496
  #ifdef TEST
1497
  *logofs << "NXTransAgent: Enabling memory-to-memory transport.\n"
1498
          << logofs_flush;
1499
  #endif
1500
1501
  return 1;
1502
}
1503
1504
int NXTransClose(int fd)
1505
{
1506
  if (logofs == NULL)
1507
  {
1508
    logofs = &cerr;
1509
  }
1510
1511
  /*
1512
   * Only handle the proxy connection. The X
1513
   * transport will take care of closing its
1514
   * end of the socket pair.
1515
   */
1516
1517
  if (control != NULL && (agent != NULL &&
1518
          (fd == agentFD[0] || fd == NX_FD_ANY)) ||
1519
              (fd == proxyFD || fd == NX_FD_ANY))
1520
  {
1521
    if (proxy != NULL)
1522
    {
1523
      #ifdef TEST
1524
      *logofs << "NXTransClose: Closing down all the X connections.\n"
1525
              << logofs_flush;
1526
      #endif
1527
1528
      CleanupConnections();
1529
    }
1530
  }
1531
  #ifdef TEST
1532
  else
1533
  {
1534
    *logofs << "NXTransClose: The NX transport is not running.\n"
1535
            << logofs_flush;
1536
  }
1537
  #endif
1538
1539
  return 1;
1540
}
1541
1542
//
1543
// Close down the transport and free the
1544
// allocated NX resources.
1545
//
1546
1547
int NXTransDestroy(int fd)
1548
{
1549
  if (logofs == NULL)
1550
  {
1551
    logofs = &cerr;
1552
  }
1553
1554
  if (control != NULL && (agent != NULL &&
1555
          (fd == agentFD[0] || fd == NX_FD_ANY)) ||
1556
              (fd == proxyFD || fd == NX_FD_ANY))
1557
  {
1558
    //
1559
    // Shut down the X connections and
1560
    // wait the cleanup to complete.
1561
    //
1562
1563
    if (proxy != NULL)
1564
    {
1565
      #ifdef TEST
1566
      *logofs << "NXTransDestroy: Closing down all the X connections.\n"
1567
              << logofs_flush;
1568
      #endif
1569
1570
      CleanupConnections();
1571
    }
1572
1573
    #ifdef TEST
1574
    *logofs << "NXTransDestroy: Waiting for the NX transport to terminate.\n"
1575
            << logofs_flush;
1576
    #endif
1577
1578
    lastDestroy = 1;
1579
1580
    WaitCleanup();
1581
  }
1582
  #ifdef TEST
1583
  else
1584
  {
1585
    *logofs << "NXTransDestroy: The NX transport is not running.\n"
1586
            << logofs_flush;
1587
  }
1588
  #endif
1589
1590
  return 1;
1591
}
1592
1593
//
1594
// Assume that the NX transport is valid
1595
// as long as the control class has not
1596
// been destroyed.
1597
//
1598
1599
int NXTransRunning(int fd)
1600
{
1601
  return (control != NULL);
1602
}
1603
1604
int NXTransContinue(struct timeval *selectTs)
1605
{
1606
  if (control != NULL)
1607
  {
1608
    //
1609
    // If no timeout is provided use
1610
    // the default.
1611
    //
1612
1613
    T_timestamp newTs;
1614
1615
    if (selectTs == NULL)
1616
    {
1617
      setTimestamp(newTs, control -> PingTimeout);
1618
1619
      selectTs = &newTs;
1620
    }
1621
1622
    //
1623
    // Use empty masks and only get the
1624
    // descriptors set by the proxy.
1625
    //
1626
1627
    fd_set readSet;
1628
    fd_set writeSet;
1629
1630
    int setFDs;
1631
    int errorFDs;
1632
    int resultFDs;
1633
1634
    setFDs = 0;
1635
1636
    FD_ZERO(&readSet);
1637
    FD_ZERO(&writeSet);
1638
1639
    //
1640
    // Run a new loop. If the transport
1641
    // is gone avoid sleeping until the
1642
    // timeout.
1643
    //
1644
1645
    if (NXTransPrepare(&setFDs, &readSet, &writeSet, selectTs) != 0)
1646
    {
1647
      NXTransSelect(&resultFDs, &errorFDs, &setFDs, &readSet, &writeSet, selectTs);
1648
1649
      NXTransExecute(&resultFDs, &errorFDs, &setFDs, &readSet, &writeSet, selectTs);
1650
    }
1651
  }
1652
1653
  return (control != NULL);
1654
}
1655
1656
int NXTransSignal(int signal, int action)
1657
{
1658
  if (logofs == NULL)
1659
  {
1660
    logofs = &cerr;
1661
  }
1662
1663
  if (control == NULL)
1664
  {
1665
    return 0;
1666
  }
1667
1668
  if (action == NX_SIGNAL_RAISE)
1669
  {
1670
    #ifdef TEST
1671
    *logofs << "NXTransSignal: Raising signal '" << DumpSignal(signal)
1672
            << "' in the proxy handler.\n" << logofs_flush;
1673
    #endif
1674
1675
    HandleSignal(signal);
1676
1677
    return 1;
1678
  }
1679
  else if (signal == NX_SIGNAL_ANY)
1680
  {
1681
    #ifdef TEST
1682
    *logofs << "NXTransSignal: Setting action of all signals to '"
1683
            << action << "'.\n" << logofs_flush;
1684
    #endif
1685
1686
    for (int i = 0; i < 32; i++)
1687
    {
1688
      if (CheckSignal(i) == 1)
1689
      {
1690
        NXTransSignal(i, action);
1691
      }
1692
    }
1693
1694
    return 1;
1695
  }
1696
  else if (CheckSignal(signal) == 1)
1697
  {
1698
    #ifdef TEST
1699
    *logofs << "NXTransSignal: Setting action of signal '"
1700
            << DumpSignal(signal) << "' to '" << action
1701
            << "'.\n" << logofs_flush;
1702
    #endif
1703
1704
    if (action == NX_SIGNAL_ENABLE ||
1705
            action == NX_SIGNAL_FORWARD)
1706
    {
1707
      InstallSignal(signal, action);
1708
1709
      return 1;
1710
    }
1711
    else if (action == NX_SIGNAL_DISABLE)
1712
    {
1713
      RestoreSignal(signal);
1714
1715
      return 1;
1716
    }
1717
  }
1718
1719
  #ifdef WARNING
1720
  *logofs << "NXTransSignal: WARNING! Unable to perform action '"
1721
          << action << "' on signal '" << DumpSignal(signal)
1722
          << "'.\n" << logofs_flush;
1723
  #endif
1724
1725
  cerr << "Warning" << ": Unable to perform action '" << action
1726
       << "' on signal '" << DumpSignal(signal)
1727
       << "'.\n";
1728
1729
  return -1;
1730
}
1731
1732
int NXTransCongestion(int fd)
1733
{
1734
  if (control != NULL && proxy != NULL)
1735
  {
1736
    #ifdef DUMP
1737
1738
    int congestion = proxy -> getCongestion(proxyFD);
1739
1740
    *logofs << "NXTransCongestion: Returning " << congestion
1741
            << " as current congestion level.\n" << logofs_flush;
1742
1743
    return congestion;
1744
1745
    #endif
1746
1747
    return (proxy -> getCongestion(proxyFD));
1748
  }
1749
1750
  return 0;
1751
}
1752
1753
int NXTransHandler(int fd, int type, void (*handler)(void *parameter,
1754
                       int reason), void *parameter)
1755
{
1756
  if (logofs == NULL)
1757
  {
1758
    logofs = &cerr;
1759
  }
1760
1761
  switch (type)
1762
  {
1763
    case NX_HANDLER_FLUSH:
1764
    {
1765
      flushCallback  = handler;
1766
      flushParameter = parameter;
1767
1768
      break;
1769
    }
1770
    case NX_HANDLER_STATISTICS:
1771
    {
1772
      //
1773
      // Reporting of statistics by the agent
1774
      // still needs to be implemented.
1775
      //
1776
1777
      statisticsCallback  = handler;
1778
      statisticsParameter = parameter;
1779
1780
      break;
1781
    }
1782
    default:
1783
    {
1784
      #ifdef TEST
1785
      *logofs << "NXTransHandler: WARNING! Failed to set "
1786
              << "the NX callback for event '" << type << "' to '"
1787
              << (void *) handler << "' and parameter '"
1788
              << parameter << "'.\n" << logofs_flush;
1789
      #endif
1790
1791
      return 0;
1792
    }
1793
  }
1794
1795
  #ifdef TEST
1796
  *logofs << "NXTransHandler: Set the NX "
1797
          << "callback for event '" << type << "' to '"
1798
          << (void *) handler << "' and parameter '"
1799
          << parameter << "'.\n" << logofs_flush;
1800
  #endif
1801
1802
  return 1;
1803
}
1804
1805
int NXTransRead(int fd, char *data, int size)
1806
{
1807
  if (logofs == NULL)
1808
  {
1809
    logofs = &cerr;
1810
  }
1811
1812
  if (control != NULL && agent != NULL &&
1813
          fd == agentFD[0])
1814
  {
1815
    #ifdef DUMP
1816
    *logofs << "NXTransRead: Dequeuing " << size << " bytes "
1817
            << "from FD#" << agentFD[0] << ".\n" << logofs_flush;
1818
    #endif
1819
1820
    int result = agent -> dequeueData(data, size);
1821
1822
    #ifdef DUMP
1823
1824
    if (result < 0 && EGET() == EAGAIN)
1825
    {
1826
      *logofs << "NXTransRead: WARNING! Dequeuing from FD#"
1827
              << agentFD[0] << " would block.\n" << logofs_flush;
1828
    }
1829
    else
1830
    {
1831
      *logofs << "NXTransRead: Dequeued " << result << " bytes "
1832
              << "to FD#" << agentFD[0] << ".\n" << logofs_flush;
1833
    }
1834
1835
    #endif
1836
1837
    return result;
1838
  }
1839
  else
1840
  {
1841
    #ifdef DUMP
1842
    *logofs << "NXTransRead: Reading " << size << " bytes "
1843
            << "from FD#" << fd << ".\n" << logofs_flush;
1844
    #endif
1845
1846
    return read(fd, data, size);
1847
  }
1848
}
1849
1850
int NXTransReadVector(int fd, struct iovec *iovdata, int iovsize)
1851
{
1852
  if (logofs == NULL)
1853
  {
1854
    logofs = &cerr;
1855
  }
1856
1857
  if (control != NULL && agent != NULL &&
1858
          fd == agentFD[0])
1859
  {
1860
    #if defined(DUMP)
1861
1862
    if (control -> ProxyStage >= stage_operational &&
1863
            agent -> localReadable() > 0)
1864
    {
1865
      *logofs << "NXTransReadVector: WARNING! Agent has data readable.\n"
1866
              << logofs_flush;
1867
    }
1868
1869
    #endif
1870
1871
    char *base;
1872
1873
    int length;
1874
    int result;
1875
1876
    struct iovec *vector = iovdata;
1877
    int count = iovsize;
1878
1879
    ESET(0);
1880
1881
    int i = 0;
1882
    int total = 0;
1883
1884
    for (;  i < count;  i++, vector++)
1885
    {
1886
      length = vector -> iov_len;
1887
      base = (char *) vector -> iov_base;
1888
1889
      while (length > 0)
1890
      {
1891
        #ifdef DUMP
1892
        *logofs << "NXTransReadVector: Dequeuing " << length
1893
                << " bytes " << "from FD#" << agentFD[0] << ".\n"
1894
                << logofs_flush;
1895
        #endif
1896
1897
        result = agent -> dequeueData(base, length);
1898
1899
        #ifdef DUMP
1900
1901
        if (result < 0 && EGET() == EAGAIN)
1902
        {
1903
          *logofs << "NXTransReadVector: WARNING! Dequeuing from FD#"
1904
                  << agentFD[0] << " would block.\n" << logofs_flush;
1905
        }
1906
        else
1907
        {
1908
          *logofs << "NXTransReadVector: Dequeued " << result
1909
                  << " bytes " << "from FD#" << agentFD[0] << ".\n"
1910
                  << logofs_flush;
1911
        }
1912
1913
        #endif
1914
1915
        if (result < 0 && total == 0)
1916
        {
1917
          return result;
1918
        }
1919
        else if (result <= 0)
1920
        {
1921
          return total;
1922
        }
1923
1924
        ESET(0);
1925
1926
        length -= result;
1927
        total  += result;
1928
        base   += result;
1929
      }
1930
    }
1931
1932
    return total;
1933
  }
1934
  else
1935
  {
1936
    #ifdef DUMP
1937
    *logofs << "NXTransReadVector: Reading vector with "
1938
            << iovsize << " elements from FD#" << fd << ".\n"
1939
            << logofs_flush;
1940
    #endif
1941
1942
    return readv(fd, iovdata, iovsize);
1943
  }
1944
}
1945
1946
int NXTransReadable(int fd, int *readable)
1947
{
1948
  if (logofs == NULL)
1949
  {
1950
    logofs = &cerr;
1951
  }
1952
1953
  if (control == NULL || agent == NULL ||
1954
          fd != agentFD[0])
1955
  {
1956
    #ifdef DUMP
1957
1958
    int result = GetBytesReadable(fd, readable);
1959
1960
    if (result == -1)
1961
    {
1962
      *logofs << "NXTransReadable: Error detected on FD#"
1963
              << fd << ".\n" << logofs_flush;
1964
    }
1965
    else
1966
    {
1967
      *logofs << "NXTransReadable: Returning " << *readable
1968
              << " bytes as readable from FD#" << fd
1969
              << ".\n" << logofs_flush;
1970
    }
1971
1972
    return result;
1973
1974
    #else
1975
1976
    return GetBytesReadable(fd, readable);
1977
1978
    #endif
1979
  }
1980
1981
  int result = agent -> dequeuableData();
1982
1983
  switch (result)
1984
  {
1985
    case 0:
1986
    {
1987
      //
1988
      // The client might have enqueued data to our side
1989
      // and is now checking for the available events. As
1990
      // _XEventsQueued() may omit to call _XSelect(), we
1991
      // handle here the new data that is coming from the
1992
      // proxy to avoid spinning through this function
1993
      // again.
1994
      //
1995
1996
      if (proxy != NULL && proxy -> canRead() == 1)
1997
      {
1998
        #if defined(TEST) || defined(INFO)
1999
        *logofs << "NXTransReadable: WARNING! Trying to "
2000
                << "read to generate new agent data.\n"
2001
                << logofs_flush;
2002
        #endif
2003
2004
        //
2005
        // Set the context as the function
2006
        // can cause a cleanup.
2007
        //
2008
2009
        if (setjmp(context) == 1)
2010
        {
2011
          return -1;
2012
        }
2013
2014
        if (proxy -> handleRead() < 0)
2015
        {
2016
          #if defined(TEST) || defined(INFO)
2017
          *logofs << "NXTransReadable: Failure reading "
2018
                  << "messages from proxy FD#" << proxyFD
2019
                  << ".\n" << logofs_flush;
2020
          #endif
2021
2022
          HandleShutdown();
2023
        }
2024
2025
        //
2026
        // Call again the routine. By reading
2027
        // new control messages from the proxy
2028
        // the agent channel may be gone.
2029
        //
2030
2031
        return NXTransReadable(fd, readable);
2032
      }
2033
2034
      #ifdef DUMP
2035
      *logofs << "NXTransReadable: Returning " << 0
2036
              << " bytes as readable from FD#" << fd
2037
              << " with result 0.\n" << logofs_flush;
2038
      #endif
2039
2040
      *readable = 0;
2041
2042
      return 0;
2043
    }
2044
    case -1:
2045
    {
2046
      #ifdef DUMP
2047
      *logofs << "NXTransReadable: Returning " << 0
2048
              << " bytes as readable from FD#" << fd
2049
              << " with result -1.\n" << logofs_flush;
2050
      #endif
2051
2052
      *readable = 0;
2053
2054
      return -1;
2055
    }
2056
    default:
2057
    {
2058
      #ifdef DUMP
2059
      *logofs << "NXTransReadable: Returning " << result
2060
              << " bytes as readable from FD#" << fd
2061
              << " with result 0.\n" << logofs_flush;
2062
      #endif
2063
2064
      *readable = result;
2065
2066
      return 0;
2067
    }
2068
  }
2069
}
2070
2071
int NXTransWrite(int fd, char *data, int size)
2072
{
2073
  //
2074
  // Be sure we have a valid log file.
2075
  //
2076
2077
  if (logofs == NULL)
2078
  {
2079
    logofs = &cerr;
2080
  }
2081
2082
  if (control != NULL && agent != NULL &&
2083
          fd == agentFD[0])
2084
  {
2085
    int result;
2086
2087
    if (proxy != NULL)
2088
    {
2089
      if (proxy -> canRead(agentFD[1]) == 0)
2090
      {
2091
        #if defined(DUMP) || defined(TEST)
2092
        *logofs << "NXTransWrite: WARNING! Delayed enqueuing to FD#"
2093
                << agentFD[0] << " with proxy unable to read.\n"
2094
                << logofs_flush;
2095
        #endif
2096
2097
        ESET(EAGAIN);
2098
2099
        return -1;
2100
      }
2101
2102
      //
2103
      // Set the context as the function
2104
      // can cause a cleanup.
2105
      //
2106
2107
      if (setjmp(context) == 1)
2108
      {
2109
        return -1;
2110
      }
2111
2112
      //
2113
      // Don't enqueue the data to the transport
2114
      // but let the channel borrow the buffer.
2115
      //
2116
2117
      #ifdef DUMP
2118
      *logofs << "NXTransWrite: Letting the channel borrow "
2119
              << size << " bytes from FD#" << agentFD[0]
2120
              << ".\n" << logofs_flush;
2121
      #endif
2122
2123
      result = proxy -> handleRead(agentFD[1], data, size);
2124
2125
      if (result == 1)
2126
      {
2127
        result = size;
2128
      }
2129
      else
2130
      {
2131
        if (result == 0)
2132
        {
2133
          ESET(EAGAIN);
2134
        }
2135
        else
2136
        {
2137
          ESET(EPIPE);
2138
        }
2139
2140
        result = -1;
2141
      }
2142
    }
2143
    else
2144
    {
2145
      //
2146
      // We don't have a proxy connection, yet.
2147
      // Enqueue the data to the agent transport.
2148
      //
2149
2150
      #ifdef DUMP
2151
      *logofs << "NXTransWrite: Enqueuing " << size << " bytes "
2152
              << "to FD#" << agentFD[0] << ".\n" << logofs_flush;
2153
      #endif
2154
2155
      result = agent -> enqueueData(data, size);
2156
    }
2157
2158
    #ifdef DUMP
2159
2160
    if (result < 0)
2161
    {
2162
      if (EGET() == EAGAIN)
2163
      {
2164
        *logofs << "NXTransWrite: WARNING! Enqueuing to FD#"
2165
                << agentFD[0] << " would block.\n"
2166
                << logofs_flush;
2167
      }
2168
      else
2169
      {
2170
        *logofs << "NXTransWrite: WARNING! Error enqueuing to FD#"
2171
                << agentFD[0] << ".\n" << logofs_flush;
2172
      }
2173
    }
2174
    else
2175
    {
2176
      *logofs << "NXTransWrite: Enqueued " << result << " bytes "
2177
              << "to FD#" << agentFD[0] << ".\n" << logofs_flush;
2178
    }
2179
2180
    #endif
2181
2182
    return result;
2183
  }
2184
  else
2185
  {
2186
    #ifdef DUMP
2187
    *logofs << "NXTransWrite: Writing " << size << " bytes "
2188
            << "to FD#" << fd << ".\n" << logofs_flush;
2189
    #endif
2190
2191
    return write(fd, data, size);
2192
  }
2193
}
2194
2195
int NXTransWriteVector(int fd, struct iovec *iovdata, int iovsize)
2196
{
2197
  //
2198
  // Be sure we have a valid log file and a
2199
  // jump context because we will later call
2200
  // functions that can perform a cleanup.
2201
  //
2202
2203
  if (logofs == NULL)
2204
  {
2205
    logofs = &cerr;
2206
  }
2207
2208
  int result = 0;
2209
2210
  if (control != NULL && agent != NULL &&
2211
          fd == agentFD[0])
2212
  {
2213
    //
2214
    // See the comment in NXTransWrite().
2215
    //
2216
2217
    if (proxy != NULL)
2218
    {
2219
      if (proxy -> canRead(agentFD[1]) == 0)
2220
      {
2221
        #if defined(DUMP) || defined(TEST)
2222
        *logofs << "NXTransWriteVector: WARNING! Delayed enqueuing to FD#"
2223
                << agentFD[0] << " with proxy unable to read.\n"
2224
                << logofs_flush;
2225
        #endif
2226
2227
        ESET(EAGAIN);
2228
2229
        return -1;
2230
      }
2231
    }
2232
2233
    //
2234
    // Set the context as the function
2235
    // can cause a cleanup.
2236
    //
2237
2238
    if (setjmp(context) == 1)
2239
    {
2240
      return -1;
2241
    }
2242
2243
    char *base;
2244
2245
    int length;
2246
2247
    struct iovec *vector = iovdata;
2248
    int count = iovsize;
2249
2250
    ESET(0);
2251
2252
    int i = 0;
2253
    int total = 0;
2254
2255
    for (;  i < count;  i++, vector++)
2256
    {
2257
      length = vector -> iov_len;
2258
      base = (char *) vector -> iov_base;
2259
2260
      while (length > 0)
2261
      {
2262
        if (proxy != NULL)
2263
        {
2264
          //
2265
          // Don't enqueue the data to the transport
2266
          // but let the channel borrow the buffer.
2267
          //
2268
2269
          #ifdef DUMP
2270
          *logofs << "NXTransWriteVector: Letting the channel borrow "
2271
                  << length << " bytes from FD#" << agentFD[0]
2272
                  << ".\n" << logofs_flush;
2273
          #endif
2274
2275
          result = proxy -> handleRead(agentFD[1], base, length);
2276
2277
          if (result == 1)
2278
          {
2279
            result = length;
2280
          }
2281
          else
2282
          {
2283
            if (result == 0)
2284
            {
2285
              ESET(EAGAIN);
2286
            }
2287
            else
2288
            {
2289
              ESET(EPIPE);
2290
            }
2291
2292
            result = -1;
2293
          }
2294
        }
2295
        else
2296
        {
2297
          //
2298
          // We don't have a proxy connection, yet.
2299
          // Enqueue the data to the agent transport.
2300
          //
2301
2302
          #ifdef DUMP
2303
          *logofs << "NXTransWriteVector: Enqueuing " << length
2304
                  << " bytes " << "to FD#" << agentFD[0] << ".\n"
2305
                  << logofs_flush;
2306
          #endif
2307
2308
          result = agent -> enqueueData(base, length);
2309
        }
2310
2311
        #ifdef DUMP
2312
2313
        if (result < 0)
2314
        {
2315
          if (EGET() == EAGAIN)
2316
          {
2317
            *logofs << "NXTransWriteVector: WARNING! Enqueuing to FD#"
2318
                    << agentFD[0] << " would block.\n"
2319
                    << logofs_flush;
2320
          }
2321
          else
2322
          {
2323
            *logofs << "NXTransWriteVector: WARNING! Error enqueuing to FD#"
2324
                    << agentFD[0] << ".\n" << logofs_flush;
2325
          }
2326
        }
2327
        else
2328
        {
2329
          *logofs << "NXTransWriteVector: Enqueued " << result
2330
                  << " bytes " << "to FD#" << agentFD[0] << ".\n"
2331
                  << logofs_flush;
2332
        }
2333
2334
        #endif
2335
2336
        if (result < 0 && total == 0)
2337
        {
2338
          return result;
2339
        }
2340
        else if (result <= 0)
2341
        {
2342
          return total;
2343
        }
2344
2345
        ESET(0);
2346
2347
        length -= result;
2348
        total  += result;
2349
        base   += result;
2350
      }
2351
    }
2352
2353
    return total;
2354
  }
2355
  else
2356
  {
2357
    #ifdef DUMP
2358
    *logofs << "NXTransWriteVector: Writing vector with "
2359
            << iovsize << " elements to FD#" << fd << ".\n"
2360
            << logofs_flush;
2361
    #endif
2362
2363
    return writev(fd, iovdata, iovsize);
2364
  }
2365
}
2366
2367
int NXTransPolicy(int fd, int type)
2368
{
2369
  if (control != NULL)
2370
  {
2371
    if (usePolicy == -1)
2372
    {
2373
      #if defined(TEST) || defined(INFO)
2374
      *logofs << "NXTransPolicy: Setting flush policy on "
2375
              << "proxy FD#" << proxyFD << " to '"
2376
              << DumpPolicy(type == NX_POLICY_DEFERRED ?
2377
                     policy_deferred : policy_immediate)
2378
              << "'.\n" << logofs_flush;
2379
      #endif
2380
2381
      control -> FlushPolicy = (type == NX_POLICY_DEFERRED ?
2382
                                    policy_deferred : policy_immediate);
2383
2384
      if (proxy != NULL)
2385
      {
2386
        proxy -> handleFlush();
2387
      }
2388
2389
      return 1;
2390
    }
2391
    else
2392
    {
2393
      #if defined(TEST) || defined(INFO)
2394
      *logofs << "NXTransPolicy: Ignoring the agent "
2395
              << "setting with user policy set to '"
2396
              << DumpPolicy(control -> FlushPolicy)
2397
              << "'.\n" << logofs_flush;
2398
      #endif
2399
2400
      return 0;
2401
    }
2402
  }
2403
2404
  return 0;
2405
}
2406
2407
int NXTransFlushable(int fd)
2408
{
2409
  if (proxy == NULL || agent == NULL ||
2410
          fd != agentFD[0])
2411
  {
2412
    #ifdef DUMP
2413
    *logofs << "NXTransFlushable: Returning 0 bytes as "
2414
            << "flushable for unrecognized FD#" << fd
2415
            << ".\n" << logofs_flush;
2416
    #endif
2417
2418
    return 0;
2419
  }
2420
  else
2421
  {
2422
    #if defined(DUMP) || defined(INFO)
2423
    *logofs << "NXTransFlushable: Returning " << proxy ->
2424
               getFlushable(proxyFD) << " as bytes flushable on "
2425
            << "proxy FD#" << proxyFD << ".\n"
2426
            << logofs_flush;
2427
    #endif
2428
2429
    return proxy -> getFlushable(proxyFD);
2430
  }
2431
}
2432
2433
int NXTransFlush(int fd)
2434
{
2435
  if (proxy != NULL)
2436
  {
2437
    #if defined(TEST) || defined(INFO)
2438
    *logofs << "NXTransFlush: Requesting an immediate flush of "
2439
            << "proxy FD#" << proxyFD << ".\n"
2440
            << logofs_flush;
2441
    #endif
2442
2443
    return proxy -> handleFlush();
2444
  }
2445
2446
  return 0;
2447
}
2448
2449
int NXTransChannel(int fd, int channelFd, int type)
2450
{
2451
  if (proxy != NULL)
2452
  {
2453
    //
2454
    // Set the context as the function
2455
    // can cause a cleanup.
2456
    //
2457
2458
    if (setjmp(context) == 1)
2459
    {
2460
      return -1;
2461
    }
2462
2463
    #if defined(TEST) || defined(INFO)
2464
    *logofs << "NXTransChannel: Going to create a new channel "
2465
            << "with type '" << type << "' on FD#" << channelFd
2466
            << ".\n" << logofs_flush;
2467
    #endif
2468
2469
    int result = -1;
2470
2471
    switch (type)
2472
    {
2473
      case NX_CHANNEL_X11:
2474
      {
2475
        if (useUnixSocket == 1 || useTcpSocket == 1 ||
2476
                useAgentSocket == 1 || useAuxSocket == 1)
2477
        {
2478
          result = proxy -> handleNewConnection(channel_x11, channelFd);
2479
        }
2480
2481
        break;
2482
      }
2483
      case NX_CHANNEL_CUPS:
2484
      {
2485
        if (useCupsSocket == 1)
2486
        {
2487
          result = proxy -> handleNewConnection(channel_cups, channelFd);
2488
        }
2489
2490
        break;
2491
      }
2492
      case NX_CHANNEL_SMB:
2493
      {
2494
        if (useSmbSocket == 1)
2495
        {
2496
          result = proxy -> handleNewConnection(channel_smb, channelFd);
2497
        }
2498
2499
        break;
2500
      }
2501
      case NX_CHANNEL_MEDIA:
2502
      {
2503
        if (useMediaSocket == 1)
2504
        {
2505
          result = proxy -> handleNewConnection(channel_media, channelFd);
2506
        }
2507
2508
        break;
2509
      }
2510
      case NX_CHANNEL_HTTP:
2511
      {
2512
        if (useHttpSocket == 1)
2513
        {
2514
          result = proxy -> handleNewConnection(channel_http, channelFd);
2515
        }
2516
2517
        break;
2518
      }
2519
      case NX_CHANNEL_FONT:
2520
      {
2521
        if (useFontSocket == 1)
2522
        {
2523
          result = proxy -> handleNewConnection(channel_font, channelFd);
2524
        }
2525
2526
        break;
2527
      }
2528
      case NX_CHANNEL_SLAVE:
2529
      {
2530
        if (useSlaveSocket == 1)
2531
        {
2532
          result = proxy -> handleNewConnection(channel_slave, channelFd);
2533
        }
2534
2535
        break;
2536
      }
2537
      default:
2538
      {
2539
        #ifdef WARNING
2540
        *logofs << "NXTransChannel: WARNING! Unrecognized channel "
2541
                << "type '" << type << "'.\n" << logofs_flush;
2542
        #endif
2543
2544
        break;
2545
      }
2546
    }
2547
2548
    #ifdef WARNING
2549
2550
    if (result != 1)
2551
    {
2552
      *logofs << "NXTransChannel: WARNING! Could not create the "
2553
                << "new channel with type '" << type << "' on FD#"
2554
                << channelFd << ".\n" << logofs_flush;
2555
    }
2556
2557
    #endif
2558
2559
    return result;
2560
  }
2561
2562
  return 0;
2563
}
2564
2565
const char *NXTransFile(int type)
2566
{
2567
  char *name = NULL;
2568
2569
  switch (type)
2570
  {
2571
    case NX_FILE_SESSION:
2572
    {
2573
      name = sessionFileName;
2574
2575
      break;
2576
    }
2577
    case NX_FILE_ERRORS:
2578
    {
2579
      name = errorsFileName;
2580
2581
      break;
2582
    }
2583
    case NX_FILE_OPTIONS:
2584
    {
2585
      name = optionsFileName;
2586
2587
      break;
2588
    }
2589
    case NX_FILE_STATS:
2590
    {
2591
      name = statsFileName;
2592
2593
      break;
2594
    }
2595
  }
2596
2597
  if (name != NULL && *name != '\0')
2598
  {
2599
    return name;
2600
  }
2601
2602
  return NULL;
2603
}
2604
2605
long NXTransTime()
2606
{
2607
  static T_timestamp last = getTimestamp();
2608
2609
  T_timestamp now = getTimestamp();
2610
2611
  long diff = diffTimestamp(last, now);
2612
2613
  last = now;
2614
2615
  return diff;
2616
}
2617
2618
int NXTransAlert(int code, int local)
2619
{
2620
  if (proxy != NULL)
2621
  {
2622
    #if defined(DUMP) || defined(INFO)
2623
    *logofs << "NXTransAlert: Requesting a NX dialog with code "
2624
            << code << " and local " << local << ".\n"
2625
            << logofs_flush;
2626
    #endif
2627
2628
    if (local == 0)
2629
    {
2630
      //
2631
      // Set the context as the function
2632
      // can cause a cleanup.
2633
      //
2634
2635
      if (setjmp(context) == 1)
2636
      {
2637
        return -1;
2638
      }
2639
2640
      proxy -> handleAlert(code);
2641
    }
2642
    else
2643
    {
2644
      //
2645
      // Show the alert at the next loop.
2646
      //
2647
2648
      HandleAlert(code, local);
2649
    }
2650
2651
    return 1;
2652
  }
2653
  #if defined(DUMP) || defined(INFO)
2654
  else
2655
  {
2656
    if (logofs == NULL)
2657
    {
2658
      logofs = &cerr;
2659
    }
2660
2661
    *logofs << "NXTransAlert: Can't request an alert without "
2662
            << "a valid NX transport.\n" << logofs_flush;
2663
  }
2664
  #endif
2665
2666
  return 0;
2667
}
2668
2669
//
2670
// Prepare the file sets and the timeout
2671
// for a later execution of the select().
2672
//
2673
2674
int NXTransPrepare(int *setFDs, fd_set *readSet,
2675
                       fd_set *writeSet, struct timeval *selectTs)
2676
{
2677
  if (logofs == NULL)
2678
  {
2679
    logofs = &cerr;
2680
  }
2681
2682
  //
2683
  // Control is NULL if the NX transport was
2684
  // reset or was never created. If control
2685
  // is valid then prepare to jump back when
2686
  // the transport is destroyed.
2687
  //
2688
2689
  if (control == NULL || setjmp(context) == 1)
2690
  {
2691
    return 0;
2692
  }
2693
2694
  #if defined(TEST) || defined(INFO)
2695
  *logofs << "\nNXTransPrepare: Going to prepare the NX transport.\n"
2696
          << logofs_flush;
2697
  #endif
2698
2699
  if (control -> ProxyStage < stage_operational)
2700
  {
2701
    handleNegotiationInLoop(*setFDs, *readSet, *writeSet, *selectTs);
2702
  }
2703
  else
2704
  {
2705
    #if defined(TEST) || defined(INFO)
2706
2707
    if (isTimestamp(*selectTs) == 0)
2708
    {
2709
      *logofs << "Loop: WARNING! Preparing the select with requested "
2710
              << "timeout of " << selectTs -> tv_sec << " S and "
2711
              << (double) selectTs -> tv_usec / 1000 << " Ms.\n"
2712
              << logofs_flush;
2713
    }
2714
    else
2715
    {
2716
      *logofs << "Loop: Preparing the select with requested "
2717
              << "timeout of " << selectTs -> tv_sec << " S and "
2718
              << (double) selectTs -> tv_usec / 1000 << " Ms.\n"
2719
              << logofs_flush;
2720
    }
2721
2722
    #endif
2723
2724
    //
2725
    // Set descriptors of listening sockets.
2726
    //
2727
2728
    handleSetListenersInLoop(*readSet, *setFDs);
2729
2730
    //
2731
    // Set descriptors of both proxy and X
2732
    // connections.
2733
    //
2734
2735
    handleSetReadInLoop(*readSet, *setFDs, *selectTs);
2736
2737
    //
2738
    // Find out which file descriptors have
2739
    // data to write.
2740
    //
2741
2742
    handleSetWriteInLoop(*writeSet, *setFDs, *selectTs);
2743
  }
2744
2745
  //
2746
  // Prepare the masks for handling the memory-
2747
  // to-memory transport. This is required even
2748
  // during session negotiation.
2749
  //
2750
2751
  if (agent != NULL)
2752
  {
2753
    handleSetAgentInLoop(*setFDs, *readSet, *writeSet, *selectTs);
2754
  }
2755
2756
  //
2757
  // Register time spent handling messages.
2758
  //
2759
2760
  nowTs = getNewTimestamp();
2761
2762
  diffTs = diffTimestamp(startTs, nowTs);
2763
2764
  #ifdef TEST
2765
  *logofs << "Loop: Mark - 0 - at " << strMsTimestamp()
2766
          << " with " << diffTs << " Ms elapsed.\n"
2767
          << logofs_flush;
2768
  #endif
2769
2770
  //
2771
  // TODO: Should add the read time in two
2772
  // parts otherwise the limits are checked
2773
  // before the counters are updated with
2774
  // time spent in the last loop.
2775
  //
2776
2777
  if (control -> ProxyStage >= stage_operational)
2778
  {
2779
    statistics -> addReadTime(diffTs);
2780
  }
2781
2782
  startTs = nowTs;
2783
2784
  #ifdef DEBUG
2785
  *logofs << "Loop: New timestamp is " << strMsTimestamp(startTs)
2786
          << ".\n" << logofs_flush;
2787
  #endif
2788
2789
  return 1;
2790
}
2791
2792
//
2793
// Let's say that we call select() to find out
2794
// if any of the handled descriptors has data,
2795
// but actually things are a bit more complex
2796
// than that.
2797
//
2798
2799
int NXTransSelect(int *resultFDs, int *errorFDs, int *setFDs, fd_set *readSet,
2800
                      fd_set *writeSet, struct timeval *selectTs)
2801
{
2802
  #ifdef TIME
2803
2804
  static T_timestamp lastTs;
2805
2806
  #endif
2807
2808
  if (logofs == NULL)
2809
  {
2810
    logofs = &cerr;
2811
  }
2812
2813
  //
2814
  // Control is NULL if the NX transport was
2815
  // reset or never created. If control is
2816
  // valid then prepare for jumping back in
2817
  // the case of an error.
2818
  //
2819
2820
  if (control == NULL || setjmp(context) == 1)
2821
  {
2822
    *resultFDs = select(*setFDs, readSet, writeSet, NULL, selectTs);
2823
2824
    *errorFDs = errno;
2825
2826
    return 0;
2827
  }
2828
2829
  #if defined(TEST) || defined(INFO)
2830
  *logofs << "\nNXTransSelect: Going to select the NX descriptors.\n"
2831
          << logofs_flush;
2832
  #endif
2833
2834
  #if defined(TEST) || defined(INFO)
2835
2836
  handleCheckSelectInLoop(*setFDs, *readSet, *writeSet, *selectTs);
2837
2838
  #endif
2839
2840
  #ifdef TIME
2841
2842
  diffTs = diffTimestamp(lastTs, getNewTimestamp());
2843
2844
  if (diffTs > 20)
2845
  {
2846
    *logofs << "Loop: TIME! Spent " << diffTs
2847
            << " Ms handling messages for proxy FD#"
2848
            << proxyFD << ".\n" << logofs_flush;
2849
  }
2850
2851
  lastTs = getNewTimestamp();
2852
2853
  #endif
2854
2855
  #if defined(TEST) || defined(INFO)
2856
2857
  if (isTimestamp(*selectTs) == 0)
2858
  {
2859
    *logofs << "Loop: WARNING! Executing the select with requested "
2860
            << "timeout of " << selectTs -> tv_sec << " S and "
2861
            << (double) selectTs -> tv_usec / 1000 << " Ms.\n"
2862
            << logofs_flush;
2863
  }
2864
  else if (proxy != NULL && proxy -> getFlushable(proxyFD) > 0)
2865
  {
2866
    *logofs << "Loop: WARNING! Proxy FD#" << proxyFD
2867
            << " has " << proxy -> getFlushable(proxyFD)
2868
            << " bytes to write but timeout is "
2869
            << selectTs -> tv_sec << " S and "
2870
            << selectTs -> tv_usec / 1000 << " Ms.\n"
2871
            << logofs_flush;
2872
  }
2873
2874
  #endif
2875
2876
  //
2877
  // Wait for the selected sockets
2878
  // or the timeout.
2879
  //
2880
2881
  ESET(0);
2882
2883
  *resultFDs = select(*setFDs, readSet, writeSet, NULL, selectTs);
2884
2885
  *errorFDs = EGET();
2886
2887
  #ifdef TIME
2888
2889
  diffTs = diffTimestamp(lastTs, getNewTimestamp());
2890
2891
  if (diffTs > 100)
2892
  {
2893
    *logofs << "Loop: TIME! Spent " << diffTs
2894
            << " Ms waiting for new data for proxy FD#"
2895
            << proxyFD << ".\n" << logofs_flush;
2896
  }
2897
2898
  lastTs = getNewTimestamp();
2899
2900
  #endif
2901
2902
  //
2903
  // Check the result of the select.
2904
  //
2905
2906
  #if defined(TEST) || defined(INFO)
2907
2908
  handleCheckResultInLoop(*resultFDs, *errorFDs, *setFDs, *readSet, *writeSet, *selectTs, startTs);
2909
2910
  #endif
2911
2912
  //
2913
  // Get time spent in select. The accouting is done
2914
  // in milliseconds. This is a real problem on fast
2915
  // machines where each loop is unlikely to take
2916
  // more than 500 us, so consider that the results
2917
  // can be inaccurate.
2918
  //
2919
2920
  nowTs = getNewTimestamp();
2921
2922
  diffTs = diffTimestamp(startTs, nowTs);
2923
2924
  #ifdef TEST
2925
  *logofs << "Loop: Out of select after " << diffTs << " Ms "
2926
          << "at " << strMsTimestamp(nowTs) << " with result "
2927
          << *resultFDs << ".\n" << logofs_flush;
2928
  #endif
2929
2930
  startTs = nowTs;
2931
2932
  #ifdef DEBUG
2933
  *logofs << "Loop: New timestamp is " << strMsTimestamp(startTs)
2934
          << ".\n" << logofs_flush;
2935
  #endif
2936
2937
  if (control -> ProxyStage >= stage_operational)
2938
  {
2939
    statistics -> addIdleTime(diffTs);
2940
  }
2941
2942
  if (*resultFDs < 0)
2943
  {
2944
    //
2945
    // Check if the call was interrupted or if any of the
2946
    // managed descriptors has become invalid. This can
2947
    // happen to the X11 code, before the descriptor is
2948
    // removed from the managed set.
2949
    //
2950
2951
    #ifdef __sun
2952
2953
    if (*errorFDs == EINTR || *errorFDs == EBADF ||
2954
            *errorFDs == EINVAL)
2955
2956
    #else
2957
2958
    if (*errorFDs == EINTR || *errorFDs == EBADF)
2959
2960
    #endif
2961
2962
    {
2963
      #ifdef TEST
2964
2965
      if (*errorFDs == EINTR)
2966
      {
2967
        *logofs << "Loop: Select failed due to EINTR error.\n"
2968
                << logofs_flush;
2969
      }
2970
      else
2971
      {
2972
        *logofs << "Loop: WARNING! Call to select failed. Error is "
2973
                << EGET() << " '" << ESTR() << "'.\n"
2974
                << logofs_flush;
2975
      }
2976
2977
      #endif
2978
    }
2979
    else
2980
    {
2981
      #ifdef PANIC
2982
      *logofs << "Loop: PANIC! Call to select failed. Error is "
2983
              << EGET() << " '" << ESTR() << "'.\n"
2984
              << logofs_flush;
2985
      #endif
2986
2987
      cerr << "Error" << ": Call to select failed. Error is "
2988
           << EGET() << " '" << ESTR() << "'.\n";
2989
2990
      HandleCleanup();
2991
    }
2992
  }
2993
2994
  return 1;
2995
}
2996
2997
//
2998
// Perform the required actions on all
2999
// the descriptors having I/O pending.
3000
//
3001
3002
int NXTransExecute(int *resultFDs, int *errorFDs, int *setFDs, fd_set *readSet,
3003
                       fd_set *writeSet, struct timeval *selectTs)
3004
{
3005
  if (logofs == NULL)
3006
  {
3007
    logofs = &cerr;
3008
  }
3009
3010
  //
3011
  // Control is NULL if the NX transport was
3012
  // reset or never created. If control is
3013
  // valid then prepare for jumping back in
3014
  // the case of an error.
3015
  //
3016
3017
  if (control == NULL || setjmp(context) == 1)
3018
  {
3019
    return 0;
3020
  }
3021
3022
  #if defined(TEST) || defined(INFO)
3023
  *logofs << "\nNXTransExecute: Going to execute I/O on the NX descriptors.\n"
3024
          << logofs_flush;
3025
  #endif
3026
3027
  if (control -> ProxyStage >= stage_operational)
3028
  {
3029
    //
3030
    // Check if I/O is possible on the proxy and
3031
    // local agent descriptors.
3032
    //
3033
3034
    if (agent != NULL)
3035
    {
3036
      handleAgentInLoop(*resultFDs, *errorFDs, *setFDs, *readSet, *writeSet, *selectTs);
3037
    }
3038
3039
    #ifdef TEST
3040
    *logofs << "Loop: Mark - 1 - at " << strMsTimestamp()
3041
            << " with " << diffTimestamp(startTs, getTimestamp())
3042
            << " Ms elapsed.\n" << logofs_flush;
3043
    #endif
3044
3045
    //
3046
    // Rotate the channel that will be handled
3047
    // first.
3048
    //
3049
3050
    handleRotateInLoop();
3051
3052
    //
3053
    // Flush any data on newly writable sockets.
3054
    //
3055
3056
    handleWritableInLoop(*resultFDs, *writeSet);
3057
3058
    #ifdef TEST
3059
    *logofs << "Loop: Mark - 2 - at " << strMsTimestamp()
3060
            << " with " << diffTimestamp(startTs, getTimestamp())
3061
            << " Ms elapsed.\n" << logofs_flush;
3062
    #endif
3063
3064
    //
3065
    // Check if any socket has become readable.
3066
    //
3067
3068
    handleReadableInLoop(*resultFDs, *readSet);
3069
3070
    #ifdef TEST
3071
    *logofs << "Loop: Mark - 3 - at " << strMsTimestamp()
3072
            << " with " << diffTimestamp(startTs, getTimestamp())
3073
            << " Ms elapsed.\n" << logofs_flush;
3074
    #endif
3075
3076
    //
3077
    // Handle the scheduled events on channels.
3078
    //
3079
    // - Restart, if possible, any client that was
3080
    //   put to sleep.
3081
    //
3082
    // - Check if there are pointer motion events to
3083
    //   flush. This applies only to X server side.
3084
    //
3085
    // - Check if any channel has exited the conges-
3086
    //   tion state.
3087
    //
3088
    // - Check if there are images that are currently
3089
    //   being streamed.
3090
    //
3091
3092
    handleEventsInLoop();
3093
3094
    #ifdef TEST
3095
    *logofs << "Loop: Mark - 4 - at " << strMsTimestamp()
3096
            << " with " << diffTimestamp(startTs, getTimestamp())
3097
            << " Ms elapsed.\n" << logofs_flush;
3098
    #endif
3099
3100
    //
3101
    // Check if user sent a signal to produce
3102
    // statistics.
3103
    //
3104
3105
    handleStatisticsInLoop();
3106
3107
    //
3108
    // We may have flushed the proxy link or
3109
    // handled data coming from the remote.
3110
    // Post-process the masks and set the
3111
    // selected agent descriptors as ready.
3112
    //
3113
3114
    if (agent != NULL)
3115
    {
3116
      handleAgentLateInLoop(*resultFDs, *errorFDs, *setFDs, *readSet, *writeSet, *selectTs);
3117
    }
3118
3119
    #ifdef TEST
3120
    *logofs << "Loop: Mark - 5 - at " << strMsTimestamp()
3121
            << " with " << diffTimestamp(startTs, getTimestamp())
3122
            << " Ms elapsed.\n" << logofs_flush;
3123
    #endif
3124
3125
    //
3126
    // Check if there is any data to flush.
3127
    // Agents should flush the proxy link
3128
    // explicitly.
3129
    //
3130
3131
    handleFlushInLoop();
3132
3133
    #ifdef TEST
3134
    *logofs << "Loop: Mark - 6 - at " << strMsTimestamp()
3135
            << " with " << diffTimestamp(startTs, getTimestamp())
3136
            << " Ms elapsed.\n" << logofs_flush;
3137
    #endif
3138
  }
3139
3140
  //
3141
  // Check if we have an alert to show.
3142
  //
3143
3144
  handleAlertInLoop();
3145
3146
  if (control -> ProxyStage >= stage_operational)
3147
  {
3148
    //
3149
    // Check if it's time to give up.
3150
    //
3151
3152
    handleCheckSessionInLoop();
3153
3154
    //
3155
    // Check if local proxy is consuming
3156
    // too many resources.
3157
    //
3158
3159
    handleCheckBitrateInLoop();
3160
3161
    //
3162
    // Check coherency of internal state.
3163
    //
3164
3165
    #if defined(TEST) || defined(INFO)
3166
3167
    handleCheckStateInLoop(*setFDs);
3168
3169
    #endif
3170
3171
    #ifdef TEST
3172
    *logofs << "Loop: Mark - 7 - at " << strMsTimestamp()
3173
            << " with " << diffTimestamp(startTs, getTimestamp())
3174
            << " Ms elapsed.\n" << logofs_flush;
3175
    #endif
3176
  }
3177
3178
  //
3179
  // Truncate the logs if needed.
3180
  //
3181
3182
  handleLogReopenInLoop(logsTs, nowTs);
3183
3184
  return 1;
3185
}
3186
3187
//
3188
// Initialize the connection parameters and
3189
// prepare for negotiating the link with the
3190
// remote proxy.
3191
//
3192
3193
int InitBeforeNegotiation()
3194
{
3195
  //
3196
  // Disable limits on core dumps.
3197
  //
3198
3199
  SetCore();
3200
3201
  //
3202
  // Install the signal handlers.
3203
  //
3204
3205
  InstallSignals();
3206
3207
  //
3208
  // Track how much time we spent in initialization.
3209
  //
3210
3211
  nowTs = getNewTimestamp();
3212
3213
  startTs = nowTs;
3214
  initTs  = nowTs;
3215
3216
  #ifdef TEST
3217
  *logofs << "Loop: INIT! Taking mark for initialization at "
3218
          << strMsTimestamp(initTs) << ".\n"
3219
          << logofs_flush;
3220
  #endif
3221
3222
  //
3223
  // If not explicitly specified, determine if local
3224
  // mode is client or server according to parameters
3225
  // provided so far.
3226
  //
3227
3228
  if (WE_SET_PROXY_MODE == 0)
3229
  {
3230
    cerr << "Error" << ": Please specify either the -C or -S option.\n";
3231
3232
    HandleCleanup();
3233
  }
3234
3235
  //
3236
  // Start a watchdog. If initialization cannot
3237
  // be completed before timeout, then clean up
3238
  // everything and exit.
3239
  //
3240
3241
  if (control -> ProxyMode == proxy_client)
3242
  {
3243
    #ifdef TEST
3244
    *logofs << "Loop: Starting watchdog process with timeout of "
3245
            << control -> InitTimeout / 1000 << " seconds.\n"
3246
            << logofs_flush;
3247
    #endif
3248
3249
    lastWatchdog = NXTransWatchdog(control -> InitTimeout);
3250
3251
    if (IsFailed(lastWatchdog))
3252
    {
3253
      #ifdef PANIC
3254
      *logofs << "Loop: PANIC! Can't start the NX watchdog process.\n"
3255
              << logofs_flush;
3256
      #endif
3257
3258
      SetNotRunning(lastWatchdog);
3259
    }
3260
    #ifdef TEST
3261
    else
3262
    {
3263
      *logofs << "Loop: Watchdog started with pid '"
3264
              << lastWatchdog << "'.\n" << logofs_flush;
3265
    }
3266
    #endif
3267
  }
3268
3269
  //
3270
  // Print preliminary info.
3271
  //
3272
3273
  PrintProcessInfo();
3274
3275
  //
3276
  // Set cups, multimedia and other
3277
  // auxiliary ports.
3278
  //
3279
3280
  SetPorts();
3281
3282
  //
3283
  // Increase the number of maximum open
3284
  // file descriptors for this process.
3285
  //
3286
3287
  SetDescriptors();
3288
3289
  //
3290
  // Set local endianess.
3291
  //
3292
3293
  unsigned int test = 1;
3294
3295
  setHostBigEndian(*((unsigned char *) (&test)) == 0);
3296
3297
  #ifdef TEST
3298
  *logofs << "Loop: Local host is "
3299
          << (hostBigEndian() ? "big endian" : "little endian")
3300
          << ".\n" << logofs_flush;
3301
  #endif
3302
3303
  if (control -> ProxyMode == proxy_client)
3304
  {
3305
    //
3306
    // Listen on sockets that mimic an X display to
3307
    // which X clients will be able to connect (e.g.
3308
    // unix:8 and/or localhost:8).
3309
    //
3310
3311
    if (useTcpSocket == 1)
3312
    {
3313
      SetupTcpSocket();
3314
    }
3315
3316
    if (useUnixSocket == 1)
3317
    {
3318
      SetupUnixSocket();
3319
    }
3320
  }
3321
  else
3322
  {
3323
    //
3324
    // Don't listen for X connections.
3325
    //
3326
3327
    useUnixSocket  = 0;
3328
    useTcpSocket   = 0;
3329
    useAgentSocket = 0;
3330
3331
    //
3332
    // Get ready to open the local display.
3333
    //
3334
3335
    SetupDisplaySocket(xServerAddrFamily, xServerAddr, xServerAddrLength);
3336
  }
3337
3338
  //
3339
  // If we are the NX server-side proxy we need to
3340
  // complete our initializazion. We will mandate
3341
  // our parameters at the time the NX client will
3342
  // connect.
3343
  //
3344
3345
  if (control -> ProxyMode == proxy_client)
3346
  {
3347
    SetParameters();
3348
  }
3349
3350
  return 1;
3351
}
3352
3353
int SetupProxyConnection()
3354
{
3355
  if (proxyFD == -1)
3356
  {
3357
    if (WE_INITIATE_CONNECTION)
3358
    {
3359
      if (connectPort < 0)
3360
      {
3361
        connectPort = DEFAULT_NX_PROXY_PORT_OFFSET + proxyPort;
3362
      }
3363
3364
      #ifdef TEST
3365
      *logofs << "Loop: Going to connect to " << connectHost
3366
              << ":" << connectPort << ".\n" << logofs_flush;
3367
      #endif
3368
3369
      proxyFD = ConnectToRemote(connectHost, connectPort);
3370
3371
      #ifdef TEST
3372
      *logofs << "Loop: Connected to remote proxy on FD#"
3373
              << proxyFD << ".\n" << logofs_flush;
3374
      #endif
3375
3376
      cerr << "Info" << ": Connection to remote proxy '" << connectHost
3377
           << ":" << connectPort << "' established.\n";
3378
    }
3379
    else
3380
    {
3381
      if (listenPort < 0)
3382
      {
3383
        listenPort = DEFAULT_NX_PROXY_PORT_OFFSET + proxyPort;
3384
      }
3385
3386
      #ifdef TEST
3387
      *logofs << "Loop: Going to wait for connection on port " 
3388
              << listenPort << ".\n" << logofs_flush;
3389
      #endif
3390
3391
      proxyFD = WaitForRemote(listenPort);
3392
3393
      #ifdef TEST
3394
3395
      if (WE_LISTEN_FORWARDER)
3396
      {
3397
        *logofs << "Loop: Connected to remote forwarder on FD#"
3398
                << proxyFD << ".\n" << logofs_flush;
3399
      }
3400
      else
3401
      {
3402
        *logofs << "Loop: Connected to remote proxy on FD#"
3403
                << proxyFD << ".\n" << logofs_flush;
3404
      }
3405
3406
      #endif
3407
    }
3408
  }
3409
  #ifdef TEST
3410
  else
3411
  {
3412
    *logofs << "Loop: Using the inherited connection on FD#"
3413
            << proxyFD << ".\n" << logofs_flush;
3414
  }
3415
  #endif
3416
3417
  //
3418
  // Set TCP_NODELAY on proxy descriptor
3419
  // to reduce startup time. Option will
3420
  // later be disabled if needed.
3421
  //
3422
3423
  SetNoDelay(proxyFD, 1);
3424
3425
  //
3426
  // We need non-blocking input since the
3427
  // negotiation phase.
3428
  //
3429
3430
  SetNonBlocking(proxyFD, 1);
3431
3432
  return 1;
3433
}
3434
3435
//
3436
// Create the required proxy and channel classes
3437
// and get ready for handling the encoded traffic.
3438
//
3439
3440
int InitAfterNegotiation()
3441
{
3442
  #ifdef TEST
3443
  *logofs << "Loop: Connection with remote proxy completed.\n"
3444
          << logofs_flush;
3445
  #endif
3446
3447
  cerr << "Info" << ": Connection with remote proxy completed.\n"
3448
        << logofs_flush;
3449
3450
  //
3451
  // If we are the server proxy we completed
3452
  // our initializazion phase according to
3453
  // the values provided by the client side.
3454
  //
3455
3456
  if (control -> ProxyMode == proxy_server)
3457
  {
3458
    SetParameters();
3459
  }
3460
3461
  //
3462
  // Set up the listeners for the additional
3463
  // services.
3464
  //
3465
3466
  SetupServiceSockets();
3467
3468
  //
3469
  // Create the proxy class and the statistics
3470
  // repository and pass all the configuration
3471
  // data we negotiated with the remote peer.
3472
  //
3473
3474
  SetupProxyInstance();
3475
3476
  //
3477
  // We completed both parsing of user's parameters
3478
  // and handlshaking with remote proxy. Now print
3479
  // a brief summary including the most significant
3480
  // control values.
3481
  //
3482
3483
  PrintConnectionInfo();
3484
3485
  //
3486
  // Cancel the initialization watchdog.
3487
  //
3488
3489
  if (IsRunning(lastWatchdog))
3490
  {
3491
    KillProcess(lastWatchdog, "watchdog", SIGTERM, 1);
3492
3493
    SetNotRunning(lastWatchdog);
3494
3495
    lastSignal = 0;
3496
  }
3497
3498
  //
3499
  // Start the house-keeper process. It will
3500
  // remove the oldest persistent caches, if
3501
  // the amount of storage exceed the limits
3502
  // set by the user.
3503
  //
3504
3505
  StartKeeper();
3506
3507
  //
3508
  // Set the log size check timestamp.
3509
  //
3510
3511
  nowTs = getNewTimestamp();
3512
3513
  logsTs = nowTs;
3514
3515
  //
3516
  // TODO: Due to the way the new NX transport is working,
3517
  // the accounting of time spent handling messages must
3518
  // be rewritten. In particular, at the moment it only
3519
  // shows the time spent encoding and decoding messages
3520
  // in the main loop, after executing a select. It doesn't
3521
  // take into account the time spent in the NXTrans* calls
3522
  // where messages can be encoded and decoded implicitly,
3523
  // on demand of the agent. When the agent transport is
3524
  // in use, these calls constitute the vast majority of
3525
  // the encoding activity. The result is that the number
3526
  // of KB encoded per second shown by the proxy statistics
3527
  // is actually much lower than the real throughput gene-
3528
  // rated by the proxy.
3529
  //
3530
3531
  #ifdef TEST
3532
  *logofs << "Loop: INIT! Completed initialization at "
3533
          << strMsTimestamp(nowTs) << " with "
3534
          << diffTimestamp(initTs, nowTs) << " Ms "
3535
          << "since the init mark.\n" << logofs_flush;
3536
  #endif
3537
3538
  initTs = getNewTimestamp();
3539
3540
  //
3541
  // We can now start handling binary data from
3542
  // our peer proxy.
3543
  //
3544
3545
  if (agent == NULL)
3546
  {
3547
    cerr << "Session" << ": Session started at '"
3548
         << strTimestamp() << "'.\n";
3549
  }
3550
3551
  return 1;
3552
}
3553
3554
int SetMode(int mode)
3555
{
3556
  //
3557
  // Set the local proxy mode.
3558
  //
3559
3560
  if (control -> ProxyMode == proxy_undefined)
3561
  {
3562
    if (mode == NX_MODE_CLIENT)
3563
    {
3564
      #ifdef TEST
3565
      *logofs << "Loop: INIT! Initializing with mode "
3566
              << "NX_MODE_CLIENT at " << strMsTimestamp()
3567
              << ".\n" << logofs_flush;
3568
      #endif
3569
3570
      control -> ProxyMode = proxy_client;
3571
    }
3572
    else if (mode == NX_MODE_SERVER)
3573
    {
3574
      #ifdef TEST
3575
      *logofs << "Loop: INIT! Initializing with mode "
3576
              << "NX_MODE_SERVER at " << strMsTimestamp()
3577
              << ".\n" << logofs_flush;
3578
      #endif
3579
3580
      control -> ProxyMode = proxy_server;
3581
    }
3582
    else
3583
    {
3584
      cerr << "Error" << ": Please specify either "
3585
           << "the -C or -S option.\n";
3586
3587
      HandleCleanup();
3588
    }
3589
  }
3590
3591
  return 1;
3592
}
3593
3594
int SetupProxyInstance()
3595
{
3596
  if (control -> ProxyMode == proxy_client)
3597
  {
3598
    proxy = new ClientProxy(proxyFD);
3599
  }
3600
  else
3601
  {
3602
    proxy = new ServerProxy(proxyFD);
3603
  }
3604
3605
  if (proxy == NULL)
3606
  {
3607
    #ifdef PANIC
3608
    *logofs << "Loop: PANIC! Error creating the NX proxy.\n"
3609
            << logofs_flush;
3610
    #endif
3611
3612
    cerr << "Error" << ": Error creating the NX proxy.\n";
3613
3614
    HandleCleanup();
3615
  }
3616
3617
  //
3618
  // Create the statistics repository.
3619
  //
3620
3621
  statistics = new Statistics(proxy);
3622
3623
  if (statistics == NULL)
3624
  {
3625
    #ifdef PANIC
3626
    *logofs << "Loop: PANIC! Error creating the NX statistics.\n"
3627
            << logofs_flush;
3628
    #endif
3629
3630
    cerr << "Error" << ": Error creating the NX statistics.\n";
3631
3632
    HandleCleanup();
3633
  }
3634
3635
  //
3636
  // If user gave us a proxy cookie than create the
3637
  // X11 authorization repository and find the real
3638
  // cookie to be used for our X display.
3639
  //
3640
3641
  SetupAuthInstance();
3642
3643
  //
3644
  // Reset the static members in channels.
3645
  //
3646
3647
  proxy -> handleChannelConfiguration();
3648
3649
  //
3650
  // Inform the proxies about the ports where they
3651
  // will have to forward the network connections.
3652
  //
3653
3654
  proxy -> handleDisplayConfiguration(displayHost, xServerAddrFamily,
3655
                                          xServerAddr, xServerAddrLength);
3656
3657
  proxy -> handlePortConfiguration(cupsPort, smbPort, mediaPort,
3658
                                       httpPort, fontPort);
3659
3660
  //
3661
  // We handed over the sockaddr structure we
3662
  // created when we set up the display socket
3663
  // to the proxy.
3664
  //
3665
3666
  xServerAddr = NULL;
3667
3668
  //
3669
  // Set socket options on proxy link, then propagate link
3670
  // configuration to proxy. This includes translating some
3671
  // control parameters in 'local' and 'remote'. Finally
3672
  // adjust cache parameters according to pack method and
3673
  // session type selected by user.
3674
  //
3675
3676
  if (proxy -> handleSocketConfiguration() < 0 ||
3677
          proxy -> handleLinkConfiguration() < 0 ||
3678
              proxy -> handleCacheConfiguration() < 0)
3679
  {
3680
    #ifdef PANIC
3681
    *logofs << "Loop: PANIC! Error configuring the NX transport.\n"
3682
            << logofs_flush;
3683
    #endif
3684
3685
    cerr << "Error" << ": Error configuring the NX transport.\n";
3686
3687
    HandleCleanup();
3688
  }
3689
3690
  //
3691
  // Load the message stores from the persistent
3692
  // cache.
3693
  //
3694
3695
  proxy -> handleLoad(load_if_first);
3696
3697
  //
3698
  // Inform the proxy that from now on it can
3699
  // start handling the encoded data.
3700
  //
3701
3702
  proxy -> setOperational();
3703
3704
  //
3705
  // Are we going to use an internal IPC connection
3706
  // with an agent? In this case create the channel
3707
  // by using the socket descriptor provided by the
3708
  // caller at the proxy initialization.
3709
  //
3710
3711
  SetupAgentInstance();
3712
3713
  //
3714
  // Check if we need to verify the existence of
3715
  // a matching client cache at shutdown.
3716
  //
3717
3718
  #ifdef MATCH
3719
3720
  control -> PersistentCacheCheckOnShutdown = 1;
3721
3722
  #endif
3723
3724
  //
3725
  // Flush any data produced so far.
3726
  //
3727
3728
  proxy -> handleFlush();
3729
3730
  #if defined(TEST) || defined(INFO)
3731
3732
  if (proxy -> getFlushable(proxyFD) > 0)
3733
  {
3734
    *logofs << "Loop: WARNING! Proxy FD#" << proxyFD << " has data "
3735
            << "to flush after setup of the NX transport.\n"
3736
            << logofs_flush;
3737
  }
3738
3739
  #endif
3740
3741
  return 1;
3742
}
3743
3744
int SetupAuthInstance()
3745
{
3746
  //
3747
  // If user gave us a proxy cookie, then create the
3748
  // X11 authorization repository and find the real
3749
  // cookie to be used for our X display.
3750
  //
3751
3752
  if (control -> ProxyMode == proxy_server)
3753
  {
3754
    if (authCookie != NULL && *authCookie != '\0')
3755
    {
3756
      if (useLaunchdSocket == 1)
3757
      {
3758
        //
3759
        // If we are going to retrieve the X11 autho-
3760
        // rization through the launchd service, make
3761
        // a connection to its socket to trigger the
3762
        // X server starting.
3763
        //
3764
3765
        sockaddr_un launchdAddrUnix;
3766
3767
        unsigned int launchdAddrLength = sizeof(sockaddr_un);
3768
3769
        int launchdAddrFamily = AF_UNIX;
3770
3771
        launchdAddrUnix.sun_family = AF_UNIX;
3772
3773
        const int launchdAddrNameLength = 108;
3774
3775
        int success = -1;
3776
3777
        strncpy(launchdAddrUnix.sun_path, displayHost, launchdAddrNameLength);
3778
3779
        *(launchdAddrUnix.sun_path + launchdAddrNameLength - 1) = '\0';
3780
3781
        #ifdef TEST
3782
        *logofs << "Loop: Connecting to launchd service "
3783
                << "on Unix port '" << displayHost << "'.\n" << logofs_flush;
3784
        #endif
3785
3786
        int launchdFd = socket(launchdAddrFamily, SOCK_STREAM, PF_UNSPEC);
3787
3788
        if (launchdFd < 0)
3789
        {
3790
          #ifdef PANIC
3791
          *logofs << "Loop: PANIC! Call to socket failed. "
3792
                  << "Error is " << EGET() << " '" << ESTR()
3793
                  << "'.\n" << logofs_flush;
3794
          #endif
3795
        }
3796
        else if ((success = connect(launchdFd, (sockaddr *) &launchdAddrUnix, launchdAddrLength)) < 0)
3797
        {
3798
          #ifdef WARNING
3799
          *logofs << "Loop: WARNING! Connection to launchd service "
3800
                  << "on Unix port '" << displayHost << "' failed "
3801
                  << "with error " << EGET() << ", '" << ESTR() << "'.\n"
3802
                  << logofs_flush;
3803
          #endif
3804
        }
3805
3806
        if (launchdFd >= 0)
3807
        {
3808
          close(launchdFd);
3809
        }
3810
3811
        //
3812
        // The real cookie will not be available
3813
        // until the X server starts. Query for the
3814
        // cookie in a loop, unless the connection
3815
        // to the launchd service failed.
3816
        //
3817
3818
        int attempts = (success < 0 ? 1 : 10);
3819
3820
        for (int i = 0; i < attempts; i++)
3821
        {
3822
          delete auth;
3823
3824
          auth = new Auth(displayHost, authCookie);
3825
3826
          if (auth != NULL && auth -> isFake() == 1)
3827
          {
3828
            usleep(200000);
3829
3830
            continue;
3831
          }
3832
3833
          break;
3834
        }
3835
      }
3836
      else
3837
      {
3838
        auth = new Auth(displayHost, authCookie);
3839
      }
3840
3841
      if (auth == NULL || auth -> isValid() != 1)
3842
      {
3843
        #ifdef PANIC
3844
        *logofs << "Loop: PANIC! Error creating the X authorization.\n"
3845
                << logofs_flush;
3846
        #endif
3847
3848
        cerr << "Error" << ": Error creating the X authorization.\n";
3849
3850
        HandleCleanup();
3851
      }
3852
      else if (auth -> isFake() == 1)
3853
      {
3854
        #ifdef WARNING
3855
        *logofs << "Loop: WARNING! Could not retrieve the X server "
3856
                << "authentication cookie.\n"
3857
                << logofs_flush;
3858
        #endif
3859
3860
        cerr << "Warning" << ": Failed to read data from the X "
3861
             << "auth command.\n";
3862
3863
        cerr << "Warning" << ": Generated a fake cookie for X "
3864
             << "authentication.\n";
3865
      }
3866
    }
3867
    else
3868
    {
3869
      #ifdef TEST
3870
      *logofs << "Loop: No proxy cookie was provided for "
3871
              << "authentication.\n" << logofs_flush;
3872
      #endif
3873
3874
      cerr << "Info" << ": No proxy cookie was provided for "
3875
           << "authentication.\n";
3876
3877
      #ifdef TEST
3878
      *logofs << "Loop: Forwarding the real X authorization "
3879
              << "cookie.\n" << logofs_flush;
3880
      #endif
3881
3882
      cerr << "Info" << ": Forwarding the real X authorization "
3883
           << "cookie.\n";
3884
    }
3885
  }
3886
3887
  return 1;
3888
}
3889
3890
int SetupAgentInstance()
3891
{
3892
  if (control -> ProxyMode == proxy_client &&
3893
          useAgentSocket == 1)
3894
  {
3895
    //
3896
    // This will temporarily disable signals to safely
3897
    // load the cache, then will send a control packet
3898
    // to the remote end, telling that cache has to be
3899
    // loaded, so it's important that proxy is already
3900
    // set in operational state.
3901
    //
3902
3903
    int result;
3904
3905
    if (agent != NULL)
3906
    {
3907
      result = proxy -> handleNewAgentConnection(agent);
3908
    }
3909
    else
3910
    {
3911
      result = proxy -> handleNewConnection(channel_x11, agentFD[1]);
3912
    }
3913
3914
    if (result < 0)
3915
    {
3916
      #ifdef PANIC
3917
      *logofs << "Loop: PANIC! Error creating the NX agent connection.\n"
3918
              << logofs_flush;
3919
      #endif
3920
3921
      cerr << "Error" << ": Error creating the NX agent connection.\n";
3922
3923
      HandleCleanup();
3924
    }
3925
  }
3926
3927
  return 1;
3928
}
3929
3930
int SetupTcpSocket()
3931
{
3932
  //
3933
  // Open TCP socket emulating local display.
3934
  //
3935
3936
  tcpFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
3937
3938
  if (tcpFD == -1)
3939
  {
3940
    #ifdef PANIC
3941
    *logofs << "Loop: PANIC! Call to socket failed for TCP socket"
3942
            << ". Error is " << EGET() << " '" << ESTR() << "'.\n"
3943
            << logofs_flush;
3944
    #endif
3945
3946
    cerr << "Error" << ": Call to socket failed for TCP socket"
3947
         << ". Error is " << EGET() << " '" << ESTR() << "'.\n";
3948
3949
    HandleCleanup();
3950
  }
3951
  else if (SetReuseAddress(tcpFD) < 0)
3952
  {
3953
    HandleCleanup();
3954
  }
3955
3956
  unsigned int proxyPortTCP = X_TCP_PORT + proxyPort;
3957
3958
  sockaddr_in tcpAddr;
3959
3960
  tcpAddr.sin_family = AF_INET;
3961
  tcpAddr.sin_port = htons(proxyPortTCP);
3962
  tcpAddr.sin_addr.s_addr = htonl(INADDR_ANY);
3963
3964
  if (bind(tcpFD, (sockaddr *) &tcpAddr, sizeof(tcpAddr)) == -1)
3965
  {
3966
    #ifdef PANIC
3967
    *logofs << "Loop: PANIC! Call to bind failed for TCP port "
3968
            << proxyPortTCP << ". Error is " << EGET() << " '" << ESTR()
3969
            << "'.\n" << logofs_flush;
3970
    #endif
3971
3972
    cerr << "Error" << ": Call to bind failed for TCP port "
3973
         << proxyPortTCP << ". Error is " << EGET() << " '" << ESTR()
3974
         << "'.\n";
3975
3976
    HandleCleanup();
3977
  }
3978
3979
  if (listen(tcpFD, 8) == -1)
3980
  {
3981
    #ifdef PANIC
3982
    *logofs << "Loop: PANIC! Call to listen failed for TCP port "
3983
            << proxyPortTCP << ". Error is " << EGET() << " '" << ESTR()
3984
            << "'.\n" << logofs_flush;
3985
    #endif
3986
3987
    cerr << "Error" << ": Call to listen failed for TCP port "
3988
         << proxyPortTCP << ". Error is " << EGET() << " '" << ESTR()
3989
         << "'.\n";
3990
3991
    HandleCleanup();
3992
  }
3993
3994
  return 1;
3995
}
3996
3997
int SetupUnixSocket()
3998
{
3999
  //
4000
  // Open UNIX domain socket for display.
4001
  //
4002
4003
  unixFD = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC);
4004
4005
  if (unixFD == -1)
4006
  {
4007
    #ifdef PANIC
4008
    *logofs << "Loop: PANIC! Call to socket failed for UNIX domain"
4009
            << ". Error is " << EGET() << " '" << ESTR() << "'.\n"
4010
            << logofs_flush;
4011
    #endif
4012
4013
    cerr << "Error" << ": Call to socket failed for UNIX domain"
4014
         << ". Error is " << EGET() << " '" << ESTR() << "'.\n";
4015
4016
    HandleCleanup();
4017
  }
4018
4019
  sockaddr_un unixAddr;
4020
  unixAddr.sun_family = AF_UNIX;
4021
4022
  char dirName[DEFAULT_STRING_LENGTH];
4023
4024
  snprintf(dirName, DEFAULT_STRING_LENGTH - 1, "%s/.X11-unix",
4025
               control -> TempPath);
4026
4027
  *(dirName + DEFAULT_STRING_LENGTH - 1) = '\0';
4028
4029
  struct stat dirStat;
4030
4031
  if ((stat(dirName, &dirStat) == -1) && (EGET() == ENOENT))
4032
  {
4033
    mkdir(dirName, (0777 | S_ISVTX));
4034
    chmod(dirName, (0777 | S_ISVTX));
4035
  }
4036
4037
  snprintf(unixSocketName,  DEFAULT_STRING_LENGTH - 1, "%s/X%d",
4038
               dirName, proxyPort);
4039
4040
  strncpy(unixAddr.sun_path, unixSocketName, 108);
4041
4042
  #ifdef TEST
4043
  *logofs << "Loop: Assuming Unix socket with name '"
4044
          << unixAddr.sun_path << "'.\n"
4045
          << logofs_flush;
4046
  #endif
4047
4048
  *(unixAddr.sun_path + 107) = '\0';
4049
4050
  if (bind(unixFD, (sockaddr *) &unixAddr, sizeof(unixAddr)) == -1)
4051
  {
4052
    #ifdef PANIC
4053
    *logofs << "Loop: PANIC! Call to bind failed for UNIX domain socket "
4054
            << unixSocketName << ". Error is " << EGET() << " '" << ESTR()
4055
            << "'.\n" << logofs_flush;
4056
    #endif
4057
4058
    cerr << "Error" << ":  Call to bind failed for UNIX domain socket "
4059
         << unixSocketName << ". Error is " << EGET() << " '" << ESTR()
4060
         << "'.\n";
4061
4062
    HandleCleanup();
4063
  }
4064
4065
  if (listen(unixFD, 8) == -1)
4066
  {
4067
    #ifdef PANIC
4068
    *logofs << "Loop: PANIC! Call to listen failed for UNIX domain socket "
4069
            << unixSocketName << ". Error is " << EGET() << " '" << ESTR()
4070
            << "'.\n" << logofs_flush;
4071
    #endif
4072
4073
    cerr << "Error" << ":  Call to listen failed for UNIX domain socket "
4074
         << unixSocketName << ". Error is " << EGET() << " '" << ESTR()
4075
         << "'.\n";
4076
4077
    HandleCleanup();
4078
  }
4079
4080
  //
4081
  // Let any local user to gain access to socket.
4082
  //
4083
4084
  chmod(unixSocketName, 0777);
4085
4086
  return 1;
4087
}
4088
4089
//
4090
// The following is a dumb copy-paste. The
4091
// nxcompsh library should offer a better
4092
// implementation.
4093
//
4094
4095
int SetupDisplaySocket(int &xServerAddrFamily, sockaddr *&xServerAddr,
4096
                           unsigned int &xServerAddrLength)
4097
{
4098
  xServerAddrFamily = AF_INET;
4099
  xServerAddr = NULL;
4100
  xServerAddrLength = 0;
4101
4102
  char *display;
4103
4104
  if (*displayHost == '\0')
4105
  {
4106
    //
4107
    // Assume DISPLAY as the X server to which
4108
    // we will forward the proxied connections.
4109
    // This means that NX parameters have been
4110
    // passed through other means.
4111
    //
4112
4113
    display = getenv("DISPLAY");
4114
4115
    if (display == NULL || *display == '\0')
4116
    {
4117
      #ifdef PANIC
4118
      *logofs << "Loop: PANIC! Host X server DISPLAY is not set.\n"
4119
              << logofs_flush;
4120
      #endif
4121
4122
      cerr << "Error" << ": Host X server DISPLAY is not set.\n";
4123
4124
      HandleCleanup();
4125
    }
4126
    else if (strncasecmp(display, "nx/nx,", 6) == 0 ||
4127
                 strncasecmp(display, "nx,", 3) == 0 ||
4128
                     strncasecmp(display, "nx:", 3) == 0)
4129
    {
4130
      #ifdef PANIC
4131
      *logofs << "Loop: PANIC! NX transport on host X server '"
4132
              << display << "' not supported.\n" << logofs_flush;
4133
      #endif
4134
4135
      cerr << "Error" << ": NX transport on host X server '"
4136
           << display << "' not supported.\n";
4137
4138
      cerr << "Error" << ": Please run the local proxy specifying "
4139
           << "the host X server to connect to.\n";
4140
4141
      HandleCleanup();
4142
    }
4143
    else if (strlen(display) >= DEFAULT_STRING_LENGTH)
4144
    {
4145
      #ifdef PANIC
4146
      *logofs << "Loop: PANIC! Host X server DISPLAY cannot exceed "
4147
              << DEFAULT_STRING_LENGTH << " characters.\n"
4148
              << logofs_flush;
4149
      #endif
4150
4151
      cerr << "Error" << ": Host X server DISPLAY cannot exceed "
4152
           << DEFAULT_STRING_LENGTH << " characters.\n";
4153
4154
      HandleCleanup();
4155
    }
4156
4157
    strcpy(displayHost, display);
4158
  }
4159
4160
  display = new char[strlen(displayHost) + 1];
4161
4162
  if (display == NULL)
4163
  {
4164
    #ifdef PANIC
4165
    *logofs << "Loop: PANIC! Out of memory handling DISPLAY variable.\n"
4166
            << logofs_flush;
4167
    #endif
4168
4169
    cerr << "Error" << ": Out of memory handling DISPLAY variable.\n";
4170
4171
    HandleCleanup();
4172
  }
4173
4174
  strcpy(display, displayHost);
4175
4176
  #ifdef __APPLE__
4177
4178
  if (strncasecmp(display, "/tmp/launch", 11) == 0)
4179
  {
4180
    #ifdef TEST
4181
    *logofs << "Loop: Using launchd service on socket '"
4182
            << display << "'.\n" << logofs_flush;
4183
    #endif
4184
4185
    useLaunchdSocket = 1;
4186
  }
4187
4188
  #endif
4189
4190
  char *separator = rindex(display, ':');
4191
4192
  if ((separator == NULL) || !isdigit(*(separator + 1)))
4193
  {
4194
    #ifdef PANIC
4195
    *logofs << "Loop: PANIC! Invalid display '" << display << "'.\n"
4196
            << logofs_flush;
4197
    #endif
4198
4199
    cerr << "Error" << ": Invalid display '" << display << "'.\n";
4200
4201
    HandleCleanup();
4202
  }
4203
4204
  *separator = '\0';
4205
4206
  xPort = atoi(separator + 1);
4207
4208
  #ifdef TEST
4209
  *logofs << "Loop: Using local X display '" << displayHost
4210
          << "' with host '" << display << "' and port '"
4211
          << xPort << "'.\n" << logofs_flush;
4212
  #endif
4213
4214
  #ifdef __APPLE__
4215
4216
  if (separator == display || strcmp(display, "unix") == 0 ||
4217
          useLaunchdSocket == 1)
4218
4219
  #else
4220
4221
  if (separator == display || strcmp(display, "unix") == 0)
4222
4223
  #endif
4224
  {
4225
    //
4226
    // UNIX domain port.
4227
    //
4228
4229
    #ifdef TEST
4230
    *logofs << "Loop: Using real X server on UNIX domain socket.\n"
4231
            << logofs_flush;
4232
    #endif
4233
4234
    sockaddr_un *xServerAddrUNIX = new sockaddr_un;
4235
4236
    xServerAddrFamily = AF_UNIX;
4237
    xServerAddrUNIX -> sun_family = AF_UNIX;
4238
4239
    //
4240
    // The scope of this function is to fill either the sockaddr_un
4241
    // (when the display is set to the Unix Domain socket) or the
4242
    // sockaddr_in structure (when connecting by TCP) only once, so
4243
    // that the structure will be later used at the time the server
4244
    // proxy will try to forward the connection to the X server. We
4245
    // don't need to verify that the socket does exist at the pre-
4246
    // sent moment. The method that forwards the connection will
4247
    // perform the required checks and will retry, if needed. Anyway
4248
    // we need to select the name of the socket, so we check if the
4249
    // well-known directory exists and take that as an indication of
4250
    // where the socket will be created.
4251
    //
4252
4253
    struct stat statInfo;
4254
4255
    char unixSocketDir[DEFAULT_STRING_LENGTH];
4256
4257
    snprintf(unixSocketDir, DEFAULT_STRING_LENGTH - 1, "%s/.X11-unix",
4258
                 control -> TempPath);
4259
4260
    #ifdef __APPLE__
4261
4262
    if (useLaunchdSocket == 1)
4263
    {
4264
      snprintf(unixSocketDir, DEFAULT_STRING_LENGTH - 1, "%s", display);
4265
    }
4266
4267
    #endif
4268
4269
    *(unixSocketDir + DEFAULT_STRING_LENGTH - 1) = '\0';
4270
4271
    #ifdef TEST
4272
    *logofs << "Loop: Assuming X socket in directory '"
4273
            << unixSocketDir << "'.\n" << logofs_flush;
4274
    #endif
4275
4276
    if (stat(unixSocketDir, &statInfo) < 0)
4277
    {
4278
      #ifdef PANIC
4279
      *logofs << "Loop: PANIC! Can't determine the location of "
4280
              << "the X display socket.\n" << logofs_flush;
4281
      #endif
4282
4283
      cerr << "Error" << ": Can't determine the location of "
4284
           << "the X display socket.\n";
4285
4286
      #ifdef PANIC
4287
      *logofs << "Loop: PANIC! Error " << EGET() << " '" << ESTR()
4288
              << "' checking '" << unixSocketDir << "'.\n"
4289
              << logofs_flush;
4290
      #endif
4291
4292
      cerr << "Error" << ": Error " << EGET() << " '" << ESTR()
4293
           << "' checking '" << unixSocketDir << "'.\n";
4294
4295
      HandleCleanup();
4296
    }
4297
4298
    sprintf(unixSocketName, "%s/X%d", unixSocketDir, xPort);
4299
4300
    #ifdef __APPLE__
4301
4302
    if (useLaunchdSocket == 1)
4303
    {
4304
      sprintf(unixSocketName, "%s:%d", unixSocketDir, xPort);
4305
    }
4306
4307
    #endif
4308
4309
    #ifdef TEST
4310
    *logofs << "Loop: Assuming X socket name '" << unixSocketName
4311
            << "'.\n" << logofs_flush;
4312
    #endif
4313
4314
    strcpy(xServerAddrUNIX -> sun_path, unixSocketName);
4315
4316
    xServerAddr = (sockaddr *) xServerAddrUNIX;
4317
    xServerAddrLength = sizeof(sockaddr_un);
4318
  }
4319
  else
4320
  {
4321
    //
4322
    // TCP port.
4323
    //
4324
4325
    #ifdef TEST
4326
    *logofs << "Loop: Using real X server on TCP port.\n"
4327
            << logofs_flush;
4328
    #endif
4329
4330
    xServerAddrFamily = AF_INET;
4331
4332
    int xServerIPAddr = GetHostAddress(display);
4333
4334
    if (xServerIPAddr == 0)
4335
    {
4336
      #ifdef PANIC
4337
      *logofs << "Loop: PANIC! Unknown display host '" << display
4338
              << "'.\n" << logofs_flush;
4339
      #endif
4340
4341
      cerr << "Error" << ": Unknown display host '" << display
4342
           << "'.\n";
4343
4344
      HandleCleanup();
4345
    }
4346
4347
    sockaddr_in *xServerAddrTCP = new sockaddr_in;
4348
4349
    xServerAddrTCP -> sin_family = AF_INET;
4350
    xServerAddrTCP -> sin_port = htons(X_TCP_PORT + xPort);
4351
    xServerAddrTCP -> sin_addr.s_addr = xServerIPAddr;
4352
4353
    xServerAddr = (sockaddr *) xServerAddrTCP;
4354
    xServerAddrLength = sizeof(sockaddr_in);
4355
  }
4356
4357
  delete [] display;
4358
4359
  return 1;
4360
}
4361
4362
int SetupServiceSockets()
4363
{
4364
  if (control -> ProxyMode == proxy_client)
4365
  {
4366
    if (useCupsSocket)
4367
    {
4368
      if ((cupsFD = ListenConnection(cupsPort, "CUPS")) < 0)
4369
      {
4370
        useCupsSocket = 0;
4371
      }
4372
    }
4373
4374
    if (useAuxSocket)
4375
    {
4376
      if ((auxFD = ListenConnection(auxPort, "auxiliary X11")) < 0)
4377
      {
4378
        useAuxSocket = 0;
4379
      }
4380
    }
4381
4382
    if (useSmbSocket)
4383
    {
4384
      if ((smbFD = ListenConnection(smbPort, "SMB")) < 0)
4385
      {
4386
        useSmbSocket = 0;
4387
      }
4388
    }
4389
4390
    if (useMediaSocket)
4391
    {
4392
      if ((mediaFD = ListenConnection(mediaPort, "media")) < 0)
4393
      {
4394
        useMediaSocket = 0;
4395
      }
4396
    }
4397
4398
    if (useHttpSocket)
4399
    {
4400
      if ((httpFD = ListenConnection(httpPort, "http")) < 0)
4401
      {
4402
        useHttpSocket = 0;
4403
      }
4404
    }
4405
4406
    useFontSocket = 0;
4407
  }
4408
  else
4409
  {
4410
    //
4411
    // Disable the font server connections if
4412
    // they are not supported by the remote
4413
    // proxy.
4414
    //
4415
4416
    if (useFontSocket)
4417
    {
4418
      if (control -> isProtoStep7() == 1)
4419
      {
4420
        int port = atoi(fontPort);
4421
4422
        if ((fontFD = ListenConnection(port, "font")) < 0)
4423
        {
4424
          useFontSocket = 0;
4425
        }
4426
      }
4427
      else
4428
      {
4429
        #ifdef WARNING
4430
        *logofs << "Loop: WARNING! Font server connections not supported "
4431
                << "by the remote proxy.\n" << logofs_flush;
4432
        #endif
4433
4434
        cerr << "Warning" << ": Font server connections not supported "
4435
             << "by the remote proxy.\n";
4436
4437
        useFontSocket = 0;
4438
      }
4439
    }
4440
4441
    useCupsSocket  = 0;
4442
    useAuxSocket   = 0;
4443
    useSmbSocket   = 0;
4444
    useMediaSocket = 0;
4445
    useHttpSocket  = 0;
4446
  }
4447
4448
  //
4449
  // Slave channels can be originated
4450
  // by both sides.
4451
  //
4452
4453
  if (useSlaveSocket)
4454
  {
4455
    if (control -> isProtoStep7() == 1)
4456
    {
4457
      if ((slaveFD = ListenConnection(slavePort, "slave")) < 0)
4458
      {
4459
        useSlaveSocket = 0;
4460
      }
4461
    }
4462
    else
4463
    {
4464
      #ifdef WARNING
4465
      *logofs << "Loop: WARNING! Slave connections not supported "
4466
                << "by the remote proxy.\n" << logofs_flush;
4467
      #endif
4468
4469
      cerr << "Warning" << ": Slave connections not supported "
4470
           << "by the remote proxy.\n";
4471
4472
      useSlaveSocket = 0;
4473
    }
4474
  }
4475
4476
  return 1;
4477
}
4478
4479
int ListenConnection(int port, const char *label)
4480
{
4481
  sockaddr_in tcpAddr;
4482
4483
  unsigned int portTCP = port;
4484
4485
  int newFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
4486
4487
  if (newFD == -1)
4488
  {
4489
    #ifdef PANIC
4490
    *logofs << "Loop: PANIC! Call to socket failed for " << label
4491
            << " TCP socket. Error is " << EGET() << " '"
4492
            << ESTR() << "'.\n" << logofs_flush;
4493
    #endif
4494
4495
    cerr << "Error" << ": Call to socket failed for " << label
4496
         << " TCP socket. Error is " << EGET() << " '"
4497
         << ESTR() << "'.\n";
4498
4499
    goto SetupSocketError;
4500
  }
4501
  else if (SetReuseAddress(newFD) < 0)
4502
  {
4503
    goto SetupSocketError;
4504
  }
4505
4506
  tcpAddr.sin_family = AF_INET;
4507
  tcpAddr.sin_port = htons(portTCP);
4508
  tcpAddr.sin_addr.s_addr = htonl(INADDR_ANY);
4509
4510
  if (bind(newFD, (sockaddr *) &tcpAddr, sizeof(tcpAddr)) == -1)
4511
  {
4512
    #ifdef PANIC
4513
    *logofs << "Loop: PANIC! Call to bind failed for " << label
4514
            << " TCP port " << port << ". Error is " << EGET()
4515
            << " '" << ESTR() << "'.\n" << logofs_flush;
4516
    #endif
4517
4518
    cerr << "Error" << ": Call to bind failed for " << label
4519
         << " TCP port " << port << ". Error is " << EGET()
4520
         << " '" << ESTR() << "'.\n";
4521
4522
    goto SetupSocketError;
4523
  }
4524
4525
  if (listen(newFD, 8) == -1)
4526
  {
4527
    #ifdef PANIC
4528
    *logofs << "Loop: PANIC! Call to bind failed for " << label
4529
            << " TCP port " << port << ". Error is " << EGET()
4530
            << " '" << ESTR() << "'.\n" << logofs_flush;
4531
    #endif
4532
4533
    cerr << "Error" << ": Call to bind failed for " << label
4534
         << " TCP port " << port << ". Error is " << EGET()
4535
         << " '" << ESTR() << "'.\n";
4536
4537
    goto SetupSocketError;
4538
  }
4539
4540
  return newFD;
4541
4542
SetupSocketError:
4543
4544
  if (newFD != -1)
4545
  {
4546
    close(newFD);
4547
  }
4548
4549
  //
4550
  // May optionally return. The session would
4551
  // continue without the service. The problem
4552
  // with this approach is that it would make
4553
  // harder to track problems with allocation
4554
  // of ports in clients and server.
4555
  //
4556
4557
  HandleCleanup();
4558
}
4559
4560
static int AcceptConnection(int fd, int domain, const char *label)
4561
{
4562
  struct sockaddr newAddr;
4563
4564
  socklen_t addrLen = sizeof(newAddr);
4565
4566
  #ifdef TEST
4567
4568
  if (domain == AF_UNIX)
4569
  {
4570
    *logofs << "Loop: Going to accept new Unix " << label
4571
            << " connection on FD#" << fd << ".\n"
4572
            << logofs_flush;
4573
  }
4574
  else
4575
  {
4576
    *logofs << "Loop: Going to accept new TCP " << label
4577
            << " connection on FD#" << fd << ".\n"
4578
            << logofs_flush;
4579
  }
4580
4581
  #endif
4582
4583
  int newFD = accept(fd, &newAddr, &addrLen);
4584
4585
  if (newFD < 0)
4586
  {
4587
    #ifdef PANIC
4588
    *logofs << "Loop: PANIC! Call to accept failed for "
4589
            << label << " connection. Error is " << EGET()
4590
            << " '" << ESTR() << "'.\n" << logofs_flush;
4591
    #endif
4592
4593
    cerr << "Error" << ": Call to accept failed for "
4594
         << label << " connection. Error is " << EGET()
4595
         << " '" << ESTR() << "'.\n";
4596
  }
4597
4598
  return newFD;
4599
}
4600
4601
void HandleShutdown()
4602
{
4603
  if (proxy -> getShutdown() == 0)
4604
  {
4605
    #ifdef PANIC
4606
    *logofs << "Loop: PANIC! No shutdown of proxy link "
4607
            << "performed by remote proxy.\n"
4608
            << logofs_flush;
4609
    #endif
4610
4611
    //
4612
    // Close the socket before showing the alert.
4613
    // It seems that the closure of the socket can
4614
    // sometimes take several seconds, even after
4615
    // the connection is broken. The result is that
4616
    // the dialog can be shown long after the user
4617
    // has gone after the failed session. Note that
4618
    // disabling the linger timeout does not seem
4619
    // to make any difference.
4620
    //
4621
4622
    CleanupSockets();
4623
4624
    cerr << "Error" << ": Connection with remote peer broken.\n";
4625
4626
    #ifdef TEST
4627
    *logofs << "Loop: Bytes received so far are "
4628
            << (unsigned long long) statistics -> getBytesIn()
4629
            << ".\n" << logofs_flush;
4630
    #endif
4631
4632
    cerr << "Error" << ": Please check the state of your "
4633
         << "network and retry.\n";
4634
4635
    handleTerminatingInLoop();
4636
4637
    if (control -> ProxyMode == proxy_server)
4638
    {
4639
      #ifdef TEST
4640
      *logofs << "Loop: Showing the proxy abort dialog.\n"
4641
              << logofs_flush;
4642
      #endif
4643
4644
      HandleAlert(ABORT_PROXY_CONNECTION_ALERT, 1);
4645
4646
      handleAlertInLoop();
4647
    }
4648
  }
4649
  #ifdef TEST
4650
  else
4651
  {
4652
    *logofs << "Loop: Finalized the remote proxy shutdown.\n"
4653
            << logofs_flush;
4654
  }
4655
  #endif
4656
4657
  HandleCleanup();
4658
}
4659
4660
4661
void WaitCleanup()
4662
{
4663
  T_timestamp selectTs;
4664
4665
  while (NXTransRunning(NX_FD_ANY))
4666
  {
4667
    setTimestamp(selectTs, control -> PingTimeout);
4668
4669
    NXTransContinue(&selectTs);
4670
  }
4671
}
4672
4673
int KillProcess(int pid, const char *label, int signal, int wait)
4674
{
4675
  if (pid > 0)
4676
  {
4677
    #if defined(TEST) || defined(INFO)
4678
    *logofs << "Loop: Killing the " << label << " process '"
4679
            << pid << "' from process with pid '" << getpid()
4680
            << "' with signal '" << DumpSignal(signal)
4681
            << "'.\n" << logofs_flush;
4682
    #endif
4683
4684
    signal = (signal == 0 ? SIGTERM : signal);
4685
4686
    if (kill(pid, signal) < 0 && EGET() != ESRCH)
4687
    {
4688
      #ifdef PANIC
4689
      *logofs << "Loop: PANIC! Couldn't kill the " << label
4690
              << " process with pid '" << pid << "'.\n"
4691
              << logofs_flush;
4692
      #endif
4693
4694
      cerr << "Error" << ": Couldn't kill the " << label
4695
           << " process with pid '" << pid << "'.\n";
4696
    }
4697
4698
    if (wait == 1)
4699
    {
4700
      WaitChild(pid, label, 1);
4701
    }
4702
4703
    return 1;
4704
  }
4705
  else
4706
  {
4707
    #ifdef TEST
4708
    *logofs << "Loop: No " << label << " process "
4709
            << "to kill with pid '" << pid
4710
            << "'.\n" << logofs_flush;
4711
    #endif
4712
4713
    return 0;
4714
  }
4715
}
4716
4717
int CheckProcess(int pid, const char *label)
4718
{
4719
  #if defined(TEST) || defined(INFO)
4720
  *logofs << "Loop: Checking the " << label << " process '"
4721
          << pid << "' from process with pid '" << getpid()
4722
          << "'.\n" << logofs_flush;
4723
  #endif
4724
4725
  if (kill(pid, SIGCONT) < 0 && EGET() == ESRCH)
4726
  {
4727
    #ifdef WARNING
4728
    *logofs << "Loop: WARNING! The " << label << " process "
4729
            << "with pid '" << pid << "' has exited.\n"
4730
            << logofs_flush;
4731
    #endif
4732
4733
    cerr << "Warning" << ": The " << label << " process "
4734
         << "with pid '" << pid << "' has exited.\n";
4735
4736
    return 0;
4737
  }
4738
4739
  return 1;
4740
}
4741
4742
int StartKeeper()
4743
{
4744
  #if defined(TEST) || defined(INFO)
4745
4746
  if (IsRunning(lastKeeper) == 1 ||
4747
          IsRestarting(lastKeeper) == 1)
4748
  {
4749
    #ifdef PANIC
4750
    *logofs << "Loop: PANIC! The house-keeping process is "
4751
            << "alreay running with pid '" << lastKeeper
4752
            << "'.\n" << logofs_flush;
4753
    #endif
4754
4755
    HandleCleanup();
4756
  }
4757
4758
  #endif
4759
4760
  //
4761
  // Don't care harvesting the persistent caches if
4762
  // the memory cache is not enabled. If the memory
4763
  // cache is not enabled neither we produced per-
4764
  // sistent caches. The user can still delete any
4765
  // persistent cache produced by the previous runs
4766
  // by using the client GUI.
4767
  //
4768
  // TODO: At the moment the user doesn't have a way
4769
  // to specify the amount of disk space to use for
4770
  // the persistent caches, but only the amount of
4771
  // space to use for images.
4772
  //
4773
4774
  if (control -> LocalTotalStorageSize > 0)
4775
  {
4776
    #ifdef TEST
4777
    *logofs << "Loop: Starting the house-keeping process with "
4778
            << "storage size " << control -> PersistentCacheDiskLimit
4779
            << ".\n" << logofs_flush;
4780
    #endif
4781
4782
    lastKeeper = NXTransKeeper(control -> PersistentCacheDiskLimit,
4783
                                   0, control -> RootPath);
4784
4785
    if (IsFailed(lastKeeper))
4786
    {
4787
      #ifdef WARNING
4788
      *logofs << "Loop: WARNING! Failed to start the NX keeper process.\n"
4789
              << logofs_flush;
4790
      #endif
4791
4792
      cerr << "Warning" << ": Failed to start the NX keeper process.\n";
4793
4794
      SetNotRunning(lastKeeper);
4795
    }
4796
    #ifdef TEST
4797
    else
4798
    {
4799
      *logofs << "Loop: Keeper started with pid '"
4800
              << lastKeeper << "'.\n" << logofs_flush;
4801
    }
4802
    #endif
4803
  }
4804
  #ifdef TEST
4805
  else
4806
  {
4807
    *logofs << "Loop: Nothing to do for the keeper process "
4808
            << "with persistent cache not enabled.\n"
4809
            << logofs_flush;
4810
  }
4811
  #endif
4812
4813
  return 1;
4814
}
4815
4816
void HandleCleanup(int code)
4817
{
4818
  #ifdef TEST
4819
  *logofs << "Loop: Going to clean up system resources "
4820
          << "in process '" << getpid() << "'.\n"
4821
          << logofs_flush;
4822
  #endif
4823
4824
  handleTerminatedInLoop();
4825
4826
  //
4827
  // Suspend any signal while cleaning up.
4828
  //
4829
4830
  DisableSignals();
4831
4832
  if (getpid() == lastProxy)
4833
  {
4834
    //
4835
    // Terminate all the children.
4836
    //
4837
4838
    CleanupChildren();
4839
  
4840
    //
4841
    // Close all listeners.
4842
    //
4843
4844
    CleanupListeners();
4845
4846
    //
4847
    // Close all sockets.
4848
    //
4849
4850
    CleanupSockets();
4851
4852
    //
4853
    // Release the global objects.
4854
    //
4855
4856
    CleanupGlobal();
4857
4858
    //
4859
    // Restore the original signal handlers.
4860
    //
4861
4862
    RestoreSignals();
4863
  }
4864
4865
  //
4866
  // This is our last chance to print a message. If this
4867
  // is the process which created the transport we will
4868
  // jump back into the loop, letting the caller find out
4869
  // that the connection is broken, otherwise we assume
4870
  // that this is a child of the proxy and so we will
4871
  // safely exit.
4872
  //
4873
4874
  #ifdef TEST
4875
4876
  if (getpid() == lastProxy)
4877
  {
4878
    *logofs << "Loop: Reverting to loop context in process with "
4879
            << "pid '" << getpid() << "' at " << strMsTimestamp()
4880
            << ".\n" << logofs_flush;
4881
  }
4882
  else
4883
  {
4884
    *logofs << "Loop: Exiting from child process with pid '"
4885
            << getpid() << "' at " << strMsTimestamp()
4886
            << ".\n" << logofs_flush;
4887
  }
4888
4889
  #endif
4890
4891
  if (getpid() == lastProxy)
4892
  {
4893
    //
4894
    // Reset all values to their default.
4895
    //
4896
4897
    CleanupLocal();
4898
4899
    CleanupStreams();
4900
4901
    longjmp(context, 1);
4902
  }
4903
  else
4904
  {
4905
    //
4906
    // Give a last chance to the process
4907
    // to cleanup the ancillary classes.
4908
    //
4909
4910
    CleanupKeeper();
4911
4912
    CleanupStreams();
4913
4914
    exit(code);
4915
  }
4916
}
4917
4918
void CleanupKeeper()
4919
{
4920
  if (keeper != NULL)
4921
  {
4922
    #ifdef TEST
4923
    *logofs << "Loop: Freeing up keeper in process "
4924
            << "with pid '" << getpid() << "'.\n"
4925
            << logofs_flush;
4926
    #endif
4927
4928
    delete keeper;
4929
4930
    keeper = NULL;
4931
  }
4932
}
4933
4934
void CleanupStreams()
4935
{
4936
  //
4937
  // TODO: The cleanup procedure skips deletion of
4938
  // the I/O streams under Windows. This is intended
4939
  // to avoid a strange segfault occurring randomly,
4940
  // at the time the proxy is being shut down.
4941
  //
4942
4943
  #ifndef __CYGWIN32__
4944
4945
  #ifdef TEST
4946
  *logofs << "Loop: Freeing up streams in process "
4947
          << "with pid '" << getpid() << "'.\n"
4948
          << logofs_flush;
4949
  #endif
4950
4951
  if (logofs != NULL && logofs != &cerr &&
4952
          *errorsFileName != '\0')
4953
  {
4954
    *logofs << flush;
4955
4956
    delete logofs;
4957
4958
    //
4959
    // Let the log go again to the standard
4960
    // error.
4961
    //
4962
4963
    logofs = &cerr;
4964
  }
4965
4966
  if (statofs != NULL && statofs != &cerr &&
4967
          *statsFileName != '\0')
4968
  {
4969
    *statofs << flush;
4970
4971
    delete statofs;
4972
4973
    statofs = NULL;
4974
  }
4975
4976
  if (errofs != NULL)
4977
  {
4978
    *errofs << flush;
4979
4980
    if (errofs == &cerr)
4981
    {
4982
      errofs = NULL;
4983
    }
4984
    else if (errsbuf != NULL)
4985
    {
4986
      cerr.rdbuf(errsbuf);
4987
4988
      errsbuf = NULL;
4989
4990
      delete errofs;
4991
    }
4992
4993
    errofs = NULL;
4994
  }
4995
4996
  #endif /* #ifndef __CYGWIN32__ */
4997
4998
  //
4999
  // Reset these as they can't be reset
5000
  // in CleanupLocal().
5001
  //
5002
5003
  *sessionFileName = '\0';
5004
  *errorsFileName  = '\0';
5005
  *optionsFileName = '\0';
5006
  *statsFileName   = '\0';
5007
}
5008
5009
void CleanupChildren()
5010
{
5011
  //
5012
  // Remove any watchdog.
5013
  //
5014
5015
  if (IsRunning(lastWatchdog))
5016
  {
5017
    KillProcess(lastWatchdog, "watchdog", SIGTERM, 1);
5018
5019
    SetNotRunning(lastWatchdog);
5020
5021
    lastSignal = 0;
5022
  }
5023
5024
  //
5025
  // Kill the cache house-keeping process.
5026
  //
5027
5028
  if (IsRunning(lastKeeper))
5029
  {
5030
    KillProcess(lastKeeper, "house-keeping", SIGTERM, 1);
5031
5032
    SetNotRunning(lastKeeper);
5033
  }
5034
5035
  //
5036
  // Let any running dialog to continue until it is
5037
  // closed by the user. In general this is the exp-
5038
  // ected behaviour, as for example when we are
5039
  // exiting because the link was abrouptedly shut
5040
  // down.
5041
  //
5042
5043
  if (IsRunning(lastDialog))
5044
  {
5045
    #if defined(TEST) || defined(INFO)
5046
    *logofs << "Loop: WARNING! Leaving the dialog process '"
5047
            << lastDialog << "' running in process "
5048
            << "with pid '" << getpid() << "'.\n"
5049
            << logofs_flush;
5050
    #endif
5051
5052
    SetNotRunning(lastDialog);
5053
  }
5054
5055
  //
5056
  // Give user a chance to start a new session.
5057
  //
5058
5059
  if (control -> EnableRestartOnShutdown == 1)
5060
  {
5061
    #ifdef WARNING
5062
    *logofs << "Loop: WARNING! Respawning the NX client "
5063
            << "on display '" << displayHost << "'.\n"
5064
            << logofs_flush;
5065
    #endif
5066
5067
    NXTransClient(displayHost);
5068
  }
5069
5070
  for (int i = 0; i < control -> KillDaemonOnShutdownNumber; i++)
5071
  {
5072
    #ifdef WARNING
5073
    *logofs << "Loop: WARNING! Killing the NX daemon with "
5074
            << "pid '" << control -> KillDaemonOnShutdown[i]
5075
            << "'.\n" << logofs_flush;
5076
    #endif
5077
5078
    KillProcess(control -> KillDaemonOnShutdown[i], "daemon", SIGTERM, 0);
5079
  }    
5080
}
5081
5082
void CleanupGlobal()
5083
{
5084
  if (proxy != NULL)
5085
  {
5086
    #ifdef TEST
5087
    *logofs << "Loop: Freeing up proxy in process "
5088
            << "with pid '" << getpid() << "'.\n"
5089
            << logofs_flush;
5090
    #endif
5091
5092
    delete proxy;
5093
5094
    proxy = NULL;
5095
  }
5096
5097
  if (agent != NULL)
5098
  {
5099
    #ifdef TEST
5100
    *logofs << "Loop: Freeing up agent in process "
5101
            << "with pid '" << getpid() << "'.\n"
5102
            << logofs_flush;
5103
    #endif
5104
5105
    delete agent;
5106
5107
    agent = NULL;
5108
  }
5109
5110
  if (auth != NULL)
5111
  {
5112
    #ifdef TEST
5113
    *logofs << "Loop: Freeing up auth data in process "
5114
            << "with pid '" << getpid() << "'.\n"
5115
            << logofs_flush;
5116
    #endif
5117
5118
    delete auth;
5119
5120
    auth = NULL;
5121
  }
5122
5123
  if (statistics != NULL)
5124
  {
5125
    #ifdef TEST
5126
    *logofs << "Loop: Freeing up statistics in process "
5127
            << "with pid '" << getpid() << "'.\n"
5128
            << logofs_flush;
5129
    #endif
5130
5131
    delete statistics;
5132
5133
    statistics = NULL;
5134
  }
5135
5136
  if (control != NULL)
5137
  {
5138
    #ifdef TEST
5139
    *logofs << "Loop: Freeing up control in process "
5140
            << "with pid '" << getpid() << "'.\n"
5141
            << logofs_flush;
5142
    #endif
5143
5144
    delete control;
5145
5146
    control = NULL;
5147
  }
5148
}
5149
5150
void CleanupConnections()
5151
{
5152
  if (proxy -> getChannels(channel_x11) != 0)
5153
  {
5154
    #ifdef TEST
5155
    *logofs << "Loop: Closing any remaining X connections.\n"
5156
            << logofs_flush;
5157
    #endif
5158
5159
    proxy -> handleCloseAllXConnections();
5160
5161
    #ifdef TEST
5162
    *logofs << "Loop: Closing any remaining listener.\n"
5163
            << logofs_flush;
5164
    #endif
5165
5166
    proxy -> handleCloseAllListeners();
5167
  }
5168
5169
  proxy -> handleFinish();
5170
}
5171
5172
void CleanupListeners()
5173
{
5174
  if (useTcpSocket == 1)
5175
  {
5176
    if (tcpFD != -1)
5177
    {
5178
      #ifdef TEST
5179
      *logofs << "Loop: Closing TCP listener in process "
5180
              << "with pid '" << getpid() << "'.\n"
5181
              << logofs_flush;
5182
      #endif
5183
5184
      close(tcpFD);
5185
5186
      tcpFD = -1;
5187
    }
5188
5189
    useTcpSocket = 0;
5190
  }
5191
5192
  if (useUnixSocket == 1)
5193
  {
5194
    if (unixFD != -1)
5195
    {
5196
      #ifdef TEST
5197
      *logofs << "Loop: Closing UNIX listener in process "
5198
              << "with pid '" << getpid() << "'.\n"
5199
              << logofs_flush;
5200
      #endif
5201
5202
      close(unixFD);
5203
5204
      unixFD = -1;
5205
    }
5206
5207
    if (*unixSocketName != '\0')
5208
    {
5209
      #ifdef TEST
5210
      *logofs << "Loop: Going to remove the Unix domain socket '"
5211
              << unixSocketName << "' in process " << "with pid '"
5212
              << getpid() << "'.\n" << logofs_flush;
5213
      #endif
5214
5215
      unlink(unixSocketName);
5216
    }
5217
5218
    useUnixSocket = 0;
5219
  }
5220
5221
  if (useAgentSocket == 1)
5222
  {
5223
    //
5224
    // There is no listener for the
5225
    // agent descriptor.
5226
    //
5227
5228
    useAgentSocket = 0;
5229
  }
5230
5231
  if (useCupsSocket == 1)
5232
  {
5233
    if (cupsFD != -1)
5234
    {
5235
      #ifdef TEST
5236
      *logofs << "Loop: Closing CUPS listener in process "
5237
              << "with pid '" << getpid() << "'.\n"
5238
              << logofs_flush;
5239
      #endif
5240
5241
      close(cupsFD);
5242
5243
      cupsFD = -1;
5244
    }
5245
5246
    useCupsSocket = 0;
5247
  }
5248
5249
  if (useAuxSocket == 1)
5250
  {
5251
    if (auxFD != -1)
5252
    {
5253
      #ifdef TEST
5254
      *logofs << "Loop: Closing auxiliary X11 listener "
5255
              << "in process " << "with pid '" << getpid()
5256
              << "'.\n" << logofs_flush;
5257
      #endif
5258
5259
      close(auxFD);
5260
5261
      auxFD = -1;
5262
    }
5263
5264
    useAuxSocket = 0;
5265
  }
5266
5267
  if (useSmbSocket == 1)
5268
  {
5269
    if (smbFD != -1)
5270
    {
5271
      #ifdef TEST
5272
      *logofs << "Loop: Closing SMB listener in process "
5273
              << "with pid '" << getpid() << "'.\n"
5274
              << logofs_flush;
5275
      #endif
5276
5277
      close(smbFD);
5278
5279
      smbFD = -1;
5280
    }
5281
5282
    useSmbSocket = 0;
5283
  }
5284
5285
  if (useMediaSocket == 1)
5286
  {
5287
    if (mediaFD != -1)
5288
    {
5289
      #ifdef TEST
5290
      *logofs << "Loop: Closing multimedia listener in process "
5291
              << "with pid '" << getpid() << "'.\n"
5292
              << logofs_flush;
5293
      #endif
5294
5295
      close(mediaFD);
5296
5297
      mediaFD = -1;
5298
    }
5299
5300
    useMediaSocket = 0;
5301
  }
5302
5303
  if (useHttpSocket == 1)
5304
  {
5305
    if (httpFD != -1)
5306
    {
5307
      #ifdef TEST
5308
      *logofs << "Loop: Closing http listener in process "
5309
              << "with pid '" << getpid() << "'.\n"
5310
              << logofs_flush;
5311
      #endif
5312
5313
      close(httpFD);
5314
5315
      httpFD = -1;
5316
    }
5317
5318
    useHttpSocket = 0;
5319
  }
5320
5321
  if (useFontSocket == 1)
5322
  {
5323
    if (fontFD != -1)
5324
    {
5325
      #ifdef TEST
5326
      *logofs << "Loop: Closing font server listener in process "
5327
              << "with pid '" << getpid() << "'.\n"
5328
              << logofs_flush;
5329
      #endif
5330
5331
      close(fontFD);
5332
5333
      fontFD = -1;
5334
    }
5335
5336
    useFontSocket = 0;
5337
  }
5338
5339
  if (useSlaveSocket == 1)
5340
  {
5341
    if (slaveFD != -1)
5342
    {
5343
      #ifdef TEST
5344
      *logofs << "Loop: Closing slave listener in process "
5345
              << "with pid '" << getpid() << "'.\n"
5346
              << logofs_flush;
5347
      #endif
5348
5349
      close(slaveFD);
5350
5351
      slaveFD = -1;
5352
    }
5353
5354
    useSlaveSocket = 0;
5355
  }
5356
}
5357
5358
void CleanupSockets()
5359
{
5360
  if (proxyFD != -1)
5361
  {
5362
    #ifdef TEST
5363
    *logofs << "Loop: Closing proxy FD in process "
5364
            << "with pid '" << getpid() << "'.\n"
5365
            << logofs_flush;
5366
    #endif
5367
5368
    close(proxyFD);
5369
5370
    proxyFD = -1;
5371
  }
5372
5373
  if (agentFD[1] != -1)
5374
  {
5375
    #ifdef TEST
5376
    *logofs << "Loop: Closing agent FD in process "
5377
            << "with pid '" << getpid() << "'.\n"
5378
            << logofs_flush;
5379
    #endif
5380
5381
    close(agentFD[1]);
5382
5383
    agentFD[0] = -1;
5384
    agentFD[1] = -1;
5385
  }
5386
}
5387
5388
void CleanupLocal()
5389
{
5390
  *homeDir    = '\0';
5391
  *rootDir    = '\0';
5392
  *tempDir    = '\0';
5393
  *systemDir  = '\0';
5394
  *sessionDir = '\0';
5395
5396
  *linkSpeedName    = '\0';
5397
  *cacheSizeName    = '\0';
5398
  *shsegSizeName    = '\0';
5399
  *imagesSizeName   = '\0';
5400
  *bitrateLimitName = '\0';
5401
  *packMethodName   = '\0';
5402
  *productName      = '\0';
5403
5404
  packMethod  = -1;
5405
  packQuality = -1;
5406
5407
  *sessionType = '\0';
5408
  *sessionId   = '\0';
5409
5410
  parsedOptions = 0;
5411
  parsedCommand = 0;
5412
5413
  *remoteData = '\0';
5414
  remotePosition = 0;
5415
5416
  tcpFD   = -1;
5417
  unixFD  = -1;
5418
  cupsFD  = -1;
5419
  auxFD   = -1;
5420
  smbFD   = -1;
5421
  mediaFD = -1;
5422
  httpFD  = -1;
5423
  fontFD  = -1;
5424
  slaveFD = -1;
5425
  proxyFD = -1;
5426
5427
  agentFD[0] = -1;
5428
  agentFD[1] = -1;
5429
5430
  useUnixSocket  = 1;
5431
  useTcpSocket   = 1;
5432
  useCupsSocket  = 0;
5433
  useAuxSocket   = 0;
5434
  useSmbSocket   = 0;
5435
  useMediaSocket = 0;
5436
  useHttpSocket  = 0;
5437
  useFontSocket  = 0;
5438
  useSlaveSocket = 0;
5439
  useAgentSocket = 0;
5440
5441
  useNoDelay = -1;
5442
  usePolicy  = -1;
5443
  useRender  = -1;
5444
  useTaint   = -1;
5445
5446
  *unixSocketName = '\0';
5447
5448
  *connectHost = '\0';
5449
  *acceptHost  = '\0';
5450
  *listenHost  = '\0';
5451
  *displayHost = '\0';
5452
  *authCookie  = '\0';
5453
5454
  proxyPort = DEFAULT_NX_PROXY_PORT;
5455
  xPort     = DEFAULT_NX_X_PORT;
5456
5457
  xServerAddrFamily = -1;
5458
  xServerAddrLength = 0;
5459
5460
  delete xServerAddr;
5461
5462
  xServerAddr = NULL;
5463
5464
  listenPort  = -1;
5465
  connectPort = -1;
5466
5467
  cupsPort  = -1;
5468
  auxPort   = -1;
5469
  smbPort   = -1;
5470
  mediaPort = -1;
5471
  httpPort  = -1;
5472
  slavePort = -1;
5473
5474
  *fontPort = '\0';
5475
5476
  *bindHost = '\0';
5477
  bindPort = -1;
5478
5479
  initTs  = nullTimestamp();
5480
  startTs = nullTimestamp();
5481
  logsTs  = nullTimestamp();
5482
  nowTs   = nullTimestamp();
5483
5484
  diffTs = 0;
5485
5486
  lastProxy    = 0;
5487
  lastDialog   = 0;
5488
  lastWatchdog = 0;
5489
  lastKeeper   = 0;
5490
  lastStatus   = 0;
5491
  lastKill     = 0;
5492
  lastDestroy  = 0;
5493
5494
  lastReadableTs = nullTimestamp();
5495
5496
  lastAlert.code  = 0;
5497
  lastAlert.local = 0;
5498
5499
  lastMasks.blocked   = 0;
5500
  lastMasks.installed = 0;
5501
5502
  memset(&lastMasks.saved, 0, sizeof(sigset_t));
5503
5504
  for (int i = 0; i < 32; i++)
5505
  {
5506
    lastMasks.enabled[i] = 0;
5507
    lastMasks.forward[i] = 0;
5508
5509
    memset(&lastMasks.action[i], 0, sizeof(struct sigaction));
5510
  }
5511
5512
  lastSignal = 0;
5513
5514
  memset(&lastTimer.action, 0, sizeof(struct sigaction));
5515
  memset(&lastTimer.value,  0, sizeof(struct itimerval));
5516
5517
  lastTimer.start = nullTimestamp();
5518
  lastTimer.next  = nullTimestamp();
5519
}
5520
5521
int CheckAbort()
5522
{
5523
  if (lastSignal != 0)
5524
  {
5525
    #ifdef TEST
5526
    *logofs << "Loop: Aborting the procedure due to signal '"
5527
            << lastSignal << "', '" << DumpSignal(lastSignal)
5528
            << "'.\n" << logofs_flush;
5529
    #endif
5530
5531
    cerr << "Info" << ": Aborting the procedure due to signal '"
5532
         << lastSignal << "'.\n";
5533
5534
    lastSignal = 0;
5535
5536
    return 1;
5537
  }
5538
5539
  return 0;
5540
}
5541
5542
void HandleAbort()
5543
{
5544
  if (logofs == NULL)
5545
  {
5546
    logofs = &cerr;
5547
  }
5548
5549
  *logofs << flush;
5550
5551
  handleTerminatingInLoop();
5552
5553
  if (lastSignal == SIGHUP)
5554
  {
5555
    lastSignal = 0;
5556
  }
5557
5558
  //
5559
  // The current default is to just quit the program.
5560
  // Code has not been updated to deal with the new
5561
  // NX transport loop.
5562
  //
5563
5564
  if (control -> EnableCoreDumpOnAbort == 1)
5565
  {
5566
    if (agent != NULL)
5567
    {
5568
      cerr << "Session" << ": Terminating session at '"
5569
           << strTimestamp() << "'.\n";
5570
    }
5571
5572
    cerr << "Error" << ": Generating a core file to help "
5573
         << "the investigations.\n";
5574
5575
    cerr << "Session" << ": Session terminated at '"
5576
         << strTimestamp() << "'.\n";
5577
5578
    cerr << flush;
5579
5580
    signal(SIGABRT, SIG_DFL);
5581
5582
    raise(SIGABRT);
5583
  }
5584
5585
  #ifdef TEST
5586
  *logofs << "Loop: Showing the proxy abort dialog.\n"
5587
          << logofs_flush;
5588
  #endif
5589
5590
  if (control -> ProxyMode == proxy_server)
5591
  {
5592
    //
5593
    // Close the socket before showing the alert.
5594
    // It seems that the closure of the socket can
5595
    // sometimes take several seconds, even after
5596
    // the connection is broken.
5597
    //
5598
5599
    CleanupSockets();
5600
5601
    if (lastKill == 0)
5602
    {
5603
      HandleAlert(ABORT_PROXY_CONNECTION_ALERT, 1);
5604
    }
5605
    else
5606
    {
5607
      HandleAlert(ABORT_PROXY_SHUTDOWN_ALERT, 1);
5608
    }
5609
5610
    handleAlertInLoop();
5611
  }
5612
5613
  HandleCleanup();
5614
}
5615
5616
void HandleAlert(int code, int local)
5617
{
5618
  if (lastAlert.code == 0)
5619
  {
5620
    #if defined(TEST) || defined(INFO)
5621
    *logofs << "Loop: Requesting an alert dialog with code "
5622
            << code << " and local " << local << ".\n"
5623
            << logofs_flush;
5624
    #endif
5625
5626
    lastAlert.code  = code;
5627
    lastAlert.local = local;
5628
  }
5629
  #if defined(TEST) || defined(INFO)
5630
  else
5631
  {
5632
    *logofs << "Loop: WARNING! Alert dialog already requested "
5633
            << "with code " << lastAlert.code << ".\n"
5634
            << logofs_flush;
5635
  }
5636
  #endif
5637
5638
  return;
5639
}
5640
5641
void FlushCallback(int length)
5642
{
5643
  if (flushCallback != NULL)
5644
  {
5645
    #if defined(TEST) || defined(INFO)
5646
    *logofs << "Loop: Reporting a flush request at "
5647
            << strMsTimestamp() << " with " << length
5648
            << " bytes written.\n" << logofs_flush;
5649
    #endif
5650
5651
    (*flushCallback)(flushParameter, length);
5652
  }
5653
  #if defined(TEST) || defined(INFO)
5654
  else if (control -> ProxyMode == proxy_client)
5655
  {
5656
    *logofs << "Loop: WARNING! Can't find a flush "
5657
            << "callback in process with pid '" << getpid()
5658
            << "'.\n" << logofs_flush;
5659
  }
5660
  #endif
5661
}
5662
5663
void KeeperCallback()
5664
{
5665
  if (IsRunning(lastKeeper) == 0)
5666
  {
5667
    //
5668
    // Let the house-keeping process take care
5669
    // of the persistent image cache.
5670
    //
5671
5672
    if (control -> ImageCacheEnableLoad == 1 ||
5673
            control -> ImageCacheEnableSave == 1)
5674
    {
5675
      #ifdef TEST
5676
      *logofs << "Loop: Starting the house-keeping process with "
5677
              << "image storage size " << control -> ImageCacheDiskLimit
5678
              << ".\n" << logofs_flush;
5679
      #endif
5680
5681
      lastKeeper = NXTransKeeper(0, control -> ImageCacheDiskLimit,
5682
                                     control -> RootPath);
5683
5684
      if (IsFailed(lastKeeper))
5685
      {
5686
        #ifdef WARNING
5687
        *logofs << "Loop: WARNING! Can't start the NX keeper process.\n"
5688
                << logofs_flush;
5689
        #endif
5690
5691
        SetNotRunning(lastKeeper);
5692
      }
5693
      #ifdef TEST
5694
      else
5695
      {
5696
        *logofs << "Loop: Keeper started with pid '"
5697
                << lastKeeper << "'.\n" << logofs_flush;
5698
      }
5699
      #endif
5700
    }
5701
    #ifdef TEST
5702
    else
5703
    {
5704
      *logofs << "Loop: Nothing to do for the keeper process "
5705
              << "with image cache not enabled.\n"
5706
              << logofs_flush;
5707
    }
5708
    #endif
5709
  }
5710
  #ifdef TEST
5711
  else
5712
  {
5713
    *logofs << "Loop: Nothing to do with the keeper process "
5714
            << "already running.\n" << logofs_flush;
5715
  }
5716
  #endif
5717
}
5718
5719
void InstallSignals()
5720
{
5721
  #ifdef TEST
5722
  *logofs << "Loop: Installing signals in process with pid '"
5723
          << getpid() << "'.\n" << logofs_flush;
5724
  #endif
5725
5726
  for (int i = 0; i < 32; i++)
5727
  {
5728
    if (CheckSignal(i) == 1 &&
5729
          lastMasks.enabled[i] == 0)
5730
    {
5731
      InstallSignal(i, NX_SIGNAL_ENABLE);
5732
    }
5733
  }
5734
5735
  lastMasks.installed = 1;
5736
}
5737
5738
void RestoreSignals()
5739
{
5740
  #ifdef TEST
5741
  *logofs << "Loop: Restoring signals in process with pid '"
5742
          << getpid() << "'.\n" << logofs_flush;
5743
  #endif
5744
5745
  if (lastMasks.installed == 1)
5746
  {
5747
    //
5748
    // Need to keep monitoring the children.
5749
    //
5750
5751
    for (int i = 0; i < 32; i++)
5752
    {
5753
      if (lastMasks.enabled[i] == 1)
5754
      {
5755
        RestoreSignal(i);
5756
      }
5757
    }
5758
  }
5759
5760
  lastMasks.installed = 0;
5761
5762
  if (lastMasks.blocked == 1)
5763
  {
5764
    EnableSignals();
5765
  }
5766
}
5767
5768
void DisableSignals()
5769
{
5770
  if (lastMasks.blocked == 0)
5771
  {
5772
    sigset_t newMask;
5773
5774
    sigemptyset(&newMask);
5775
5776
    //
5777
    // Block also the other signals that may be
5778
    // installed by the agent, that are those
5779
    // signals for which the function returns 2.
5780
    //
5781
5782
    for (int i = 0; i < 32; i++)
5783
    {
5784
      if (CheckSignal(i) > 0)
5785
      {
5786
        #ifdef DUMP
5787
        *logofs << "Loop: Disabling signal " << i << " '"
5788
                << DumpSignal(i) << "' in process with pid '"
5789
                << getpid() << "'.\n" << logofs_flush;
5790
        #endif
5791
5792
        sigaddset(&newMask, i);
5793
      }
5794
    }
5795
5796
    sigprocmask(SIG_BLOCK, &newMask, &lastMasks.saved);
5797
5798
    lastMasks.blocked++;
5799
  }
5800
  #ifdef TEST
5801
  else
5802
  {
5803
    *logofs << "Loop: WARNING! Signals were already blocked in "
5804
            << "process with pid '" << getpid() << "'.\n"
5805
            << logofs_flush;
5806
  }
5807
  #endif
5808
}
5809
5810
void EnableSignals()
5811
{
5812
  if (lastMasks.blocked == 1)
5813
  {
5814
    #ifdef TEST
5815
    *logofs << "Loop: Enabling signals in process with pid '"
5816
            << getpid() << "'.\n" << logofs_flush;
5817
    #endif
5818
5819
    sigprocmask(SIG_SETMASK, &lastMasks.saved, NULL);
5820
5821
    lastMasks.blocked = 0;
5822
  }
5823
  else
5824
  {
5825
    #ifdef WARNING
5826
    *logofs << "Loop: WARNING! Signals were not blocked in "
5827
            << "process with pid '" << getpid() << "'.\n"
5828
            << logofs_flush;
5829
    #endif
5830
5831
    cerr << "Warning" << ": Signals were not blocked in "
5832
         << "process with pid '" << getpid() << "'.\n";
5833
  }
5834
}
5835
5836
void InstallSignal(int signal, int action)
5837
{
5838
  if (lastMasks.enabled[signal] == 1)
5839
  {
5840
    if (action == NX_SIGNAL_FORWARD)
5841
    {
5842
      #ifdef TEST
5843
      *logofs << "Loop: Forwarding handler for signal " << signal
5844
              << " '" << DumpSignal(signal) << "' in process "
5845
              << "with pid '" << getpid() << "'.\n"
5846
              << logofs_flush;
5847
      #endif
5848
5849
      lastMasks.forward[signal] = 1;
5850
5851
      return;
5852
    }
5853
    #ifdef TEST
5854
    else
5855
    {
5856
      *logofs << "Loop: Reinstalling handler for signal " << signal
5857
              << " '" << DumpSignal(signal) << "' in process "
5858
              << "with pid '" << getpid() << "'.\n"
5859
              << logofs_flush;
5860
    }
5861
    #endif
5862
  }
5863
  #ifdef TEST
5864
  else
5865
  {
5866
    *logofs << "Loop: Installing handler for signal " << signal
5867
            << " '" << DumpSignal(signal) << "' in process "
5868
            << "with pid '" << getpid() << "'.\n"
5869
            << logofs_flush;
5870
  }
5871
  #endif
5872
5873
  if (signal == SIGALRM && isTimestamp(lastTimer.start))
5874
  {
5875
    ResetTimer();
5876
  }
5877
5878
  struct sigaction newAction;
5879
5880
  newAction.sa_handler = HandleSignal;
5881
5882
  //
5883
  // This field doesn't exist on most OSes except
5884
  // Linux. We keep setting the field to NULL to
5885
  // avoid side-effects in the case the field is
5886
  // a value return.
5887
  //
5888
5889
  #if defined(__linux__)
5890
5891
  newAction.sa_restorer = NULL;
5892
5893
  #endif
5894
5895
  sigemptyset(&(newAction.sa_mask));
5896
5897
  if (signal == SIGCHLD)
5898
  {
5899
    newAction.sa_flags = SA_NOCLDSTOP;
5900
  }
5901
  else
5902
  {
5903
    newAction.sa_flags = 0;
5904
  }
5905
5906
  sigaction(signal, &newAction, &lastMasks.action[signal]);
5907
5908
  lastMasks.enabled[signal] = 1;
5909
5910
  if (action == NX_SIGNAL_FORWARD)
5911
  {
5912
    lastMasks.forward[signal] = 1;
5913
  }
5914
}
5915
5916
void RestoreSignal(int signal)
5917
{
5918
  if (lastMasks.enabled[signal] == 0)
5919
  {
5920
    #ifdef WARNING
5921
    *logofs << "Loop: WARNING! Signal '" << DumpSignal(signal)
5922
            << " not installed in process with pid '"
5923
            << getpid() << "'.\n" << logofs_flush;
5924
    #endif
5925
5926
    cerr << "Warning" << ": Signal '" << DumpSignal(signal)
5927
         << " not installed in process with pid '"
5928
         << getpid() << "'.\n";
5929
5930
    return;
5931
  }
5932
5933
  #ifdef TEST
5934
  *logofs << "Loop: Restoring handler for signal " << signal
5935
          << " '" << DumpSignal(signal) << "' in process "
5936
          << "with pid '" << getpid() << "'.\n"
5937
          << logofs_flush;
5938
  #endif
5939
5940
  if (signal == SIGALRM && isTimestamp(lastTimer.start))
5941
  {
5942
    ResetTimer();
5943
  }
5944
5945
  sigaction(signal, &lastMasks.action[signal], NULL);
5946
5947
  lastMasks.enabled[signal] = 0;
5948
  lastMasks.forward[signal] = 0;
5949
}
5950
5951
void HandleSignal(int signal)
5952
{
5953
  if (logofs == NULL)
5954
  {
5955
    logofs = &cerr;
5956
  }
5957
5958
  #if defined(UNSAFE) && (defined(TEST) || defined(INFO))
5959
5960
  if (lastSignal != 0)
5961
  {
5962
    *logofs << "Loop: WARNING! Last signal is '" << lastSignal
5963
            << "', '" << DumpSignal(signal) << "' and not zero "
5964
            << "in process with pid '" << getpid() << "'.\n"
5965
            << logofs_flush;
5966
  }
5967
5968
  *logofs << "Loop: Signal '" << signal << "', '"
5969
          << DumpSignal(signal) << "' received in process "
5970
          << "with pid '" << getpid() << "'.\n" << logofs_flush;
5971
5972
  #endif
5973
5974
  if (getpid() != lastProxy && handler != NULL)
5975
  {
5976
    #if defined(UNSAFE) && (defined(TEST) || defined(INFO))
5977
    *logofs << "Loop: Calling slave handler in process "
5978
            << "with pid '" << getpid() << "'.\n"
5979
            << logofs_flush;
5980
    #endif
5981
5982
    if ((*handler)(signal) == 0)
5983
    {
5984
      return;
5985
    }
5986
  }
5987
5988
  switch (signal)
5989
  {
5990
    case SIGUSR1:
5991
    {
5992
      if (proxy != NULL && lastSignal == 0)
5993
      {
5994
        lastSignal = SIGUSR1;
5995
      }
5996
5997
      break;
5998
    }
5999
    case SIGUSR2:
6000
    {
6001
      if (proxy != NULL && lastSignal == 0)
6002
      {
6003
        lastSignal = SIGUSR2;
6004
      }
6005
6006
      break;
6007
    }
6008
    case SIGPIPE:
6009
    {
6010
      //
6011
      // It can happen that SIGPIPE is delivered
6012
      // to the proxy even in the case some other
6013
      // descriptor is unexpectedly closed.
6014
      //
6015
      // if (agentFD[1] != -1)
6016
      // {
6017
      //   cerr << "Info" << ": Received signal 'SIGPIPE'. "
6018
      //        << "Closing agent conection.\n";
6019
      //
6020
      //   shutdown(agentFD[1], SHUT_RDWR);
6021
      // }
6022
      //
6023
6024
      break;
6025
    }
6026
    case SIGALRM:
6027
    {
6028
      //
6029
      // Nothing to do. Just wake up the
6030
      // process on blocking operations.
6031
      //
6032
6033
      break;
6034
    }
6035
    case SIGCHLD:
6036
    {
6037
      //
6038
      // Check if any of our children has exited.
6039
      //
6040
6041
      if (HandleChildren() != 0)
6042
      {
6043
        signal = 0;
6044
      }
6045
6046
      //
6047
      // Don't save this signal or it will override
6048
      // any previous signal sent by child before
6049
      // exiting.
6050
      //
6051
6052
      break;
6053
    }
6054
6055
    #ifdef __CYGWIN32__
6056
6057
    case 12:
6058
    {
6059
      //
6060
      // Nothing to do. This signal is what is delivered
6061
      // by the Cygwin library when trying use a shared
6062
      // memory function if the daemon is not running.
6063
      //
6064
6065
      #ifdef TEST
6066
      *logofs << "Loop: WARNING! Received signal '12' in "
6067
              << "process with pid '" << getpid() << "'.\n"
6068
              << logofs_flush;
6069
6070
      *logofs << "Loop: WARNING! Please check that the "
6071
              << "cygserver daemon is running.\n"
6072
              << logofs_flush;
6073
      #endif
6074
6075
      break;
6076
    }
6077
6078
    #endif
6079
6080
    default:
6081
    {
6082
      //
6083
      // Register the signal so we can handle it
6084
      // inside the main loop. We will probably
6085
      // dispose any resource and exit.
6086
      //
6087
6088
      if (getpid() == lastProxy)
6089
      {
6090
        #if defined(UNSAFE) && defined(TEST)
6091
        *logofs << "Loop: Registering end of session request "
6092
                << "due to signal '" << signal << "', '"
6093
                << DumpSignal(signal) << "'.\n"
6094
                << logofs_flush;
6095
        #endif
6096
6097
        lastSignal = signal;
6098
      }
6099
      else
6100
      {
6101
        //
6102
        // This is a child, so exit immediately.
6103
        //
6104
6105
        HandleCleanup();
6106
      }
6107
    }
6108
  }
6109
6110
  if (signal != 0 && lastMasks.forward[signal] == 1)
6111
  {
6112
    if (lastMasks.action[signal].sa_handler != NULL &&
6113
            lastMasks.action[signal].sa_handler != HandleSignal)
6114
    {
6115
      #if defined(UNSAFE) && defined(TEST)
6116
      *logofs << "Loop: Forwarding signal '" << signal << "', '"
6117
              << DumpSignal(signal) << "' to previous handler.\n"
6118
              << logofs_flush;
6119
      #endif
6120
6121
      lastMasks.action[signal].sa_handler(signal);
6122
    }
6123
    #ifdef WARNING
6124
    else if (lastMasks.action[signal].sa_handler == NULL)
6125
    {
6126
      *logofs << "Loop: WARNING! Parent requested to forward "
6127
              << "signal '" << signal << "', '" << DumpSignal(signal)
6128
              << "' but didn't set a handler.\n" << logofs_flush;
6129
    }
6130
    #endif
6131
  }
6132
}
6133
6134
int HandleChildren()
6135
{
6136
  //
6137
  // Try to waitpid() for each child because the
6138
  // call might have return ECHILD and so we may
6139
  // have lost any of the processes.
6140
  //
6141
6142
  if (IsRunning(lastDialog) && HandleChild(lastDialog) == 1)
6143
  {
6144
    #if defined(UNSAFE) && defined(TEST)
6145
    *logofs << "Loop: Resetting pid of last dialog process "
6146
            << "in handler.\n" << logofs_flush;
6147
    #endif
6148
6149
    SetNotRunning(lastDialog);
6150
6151
    if (proxy != NULL)
6152
    {
6153
      proxy -> handleResetAlert();
6154
    }
6155
6156
    return 1;
6157
  }
6158
6159
  if (IsRunning(lastWatchdog) && HandleChild(lastWatchdog) == 1)
6160
  {
6161
    #if defined(UNSAFE) && defined(TEST)
6162
    *logofs << "Loop: Watchdog is gone. Setting the last "
6163
            << "signal to SIGHUP.\n" << logofs_flush;
6164
    #endif
6165
6166
    lastSignal = SIGHUP;
6167
6168
    #if defined(UNSAFE) && defined(TEST)
6169
    *logofs << "Loop: Resetting pid of last watchdog process "
6170
            << "in handler.\n" << logofs_flush;
6171
    #endif
6172
6173
    SetNotRunning(lastWatchdog);
6174
6175
    return 1;
6176
  }
6177
6178
  //
6179
  // The house-keeping process exits after a
6180
  // number of iterations to keep the memory
6181
  // pollution low. It is restarted on demand
6182
  // by the lower layers, using the callback
6183
  // function.
6184
  //
6185
6186
  if (IsRunning(lastKeeper) && HandleChild(lastKeeper) == 1)
6187
  {
6188
    #if defined(UNSAFE) && defined(TEST)
6189
    *logofs << "Loop: Resetting pid of last house-keeping "
6190
            << "process in handler.\n" << logofs_flush;
6191
    #endif
6192
6193
    SetNotRunning(lastKeeper);
6194
6195
    return 1;
6196
  }
6197
6198
  //
6199
  // The pid will be checked by the code
6200
  // that registered the child.
6201
  //
6202
6203
  if (IsRunning(lastChild))
6204
  {
6205
    #if defined(UNSAFE) && defined(TEST)
6206
    *logofs << "Loop: Resetting pid of last child process "
6207
            << "in handler.\n" << logofs_flush;
6208
    #endif
6209
6210
    SetNotRunning(lastChild);
6211
6212
    return 1;
6213
  }
6214
6215
  //
6216
  // This can actually happen either because we
6217
  // reset the pid of the child process as soon
6218
  // as we kill it, or because of a child process
6219
  // of our parent.
6220
  //
6221
6222
  #if defined(UNSAFE) && (defined(TEST) || defined(INFO))
6223
  *logofs << "Loop: Ignoring signal received for the "
6224
          << "unregistered child.\n" << logofs_flush;
6225
  #endif
6226
6227
  return 0;
6228
}
6229
6230
int HandleChild(int child)
6231
{
6232
  int pid;
6233
6234
  int status  = 0;
6235
  int options = WNOHANG | WUNTRACED;
6236
6237
  while ((pid = waitpid(child, &status, options)) &&
6238
             pid == -1 && EGET() == EINTR);
6239
6240
  return CheckChild(pid, status);
6241
}
6242
6243
int WaitChild(int child, const char* label, int force)
6244
{
6245
  int pid;
6246
6247
  int status  = 0;
6248
  int options = WUNTRACED;
6249
6250
  for (;;)
6251
  {
6252
    #if defined(TEST) || defined(INFO)
6253
    *logofs << "Loop: Waiting for the " << label
6254
            << " process '" << child << "' to die.\n"
6255
            << logofs_flush;
6256
    #endif
6257
6258
    pid = waitpid(child, &status, options);
6259
6260
    if (pid == -1 && EGET() == EINTR)
6261
    {
6262
      if (force == 0)
6263
      {
6264
        return 0;
6265
      }
6266
6267
      #ifdef WARNING
6268
      *logofs << "Loop: WARNING! Ignoring signal while "
6269
              << "waiting for the " << label << " process '"
6270
              << child << "' to die.\n"
6271
              << logofs_flush;
6272
      #endif
6273
6274
      continue;
6275
    }
6276
6277
    break;
6278
  }
6279
6280
  return (EGET() == ECHILD ? 1 : CheckChild(pid, status));
6281
}
6282
6283
int CheckChild(int pid, int status)
6284
{
6285
  lastStatus = 0;
6286
6287
  if (pid > 0)
6288
  {
6289
    if (WIFSTOPPED(status))
6290
    {
6291
      #if defined(UNSAFE) && defined(TEST)
6292
      *logofs << "Loop: Child process '" << pid << "' was stopped "
6293
              << "with signal " << (WSTOPSIG(status)) << ".\n"
6294
              << logofs_flush;
6295
      #endif
6296
6297
      return 0;
6298
    }
6299
    else
6300
    {
6301
      if (WIFEXITED(status))
6302
      {
6303
        #if defined(UNSAFE) && defined(TEST)
6304
        *logofs << "Loop: Child process '" << pid << "' exited "
6305
                << "with status '" << (WEXITSTATUS(status))
6306
                << "'.\n" << logofs_flush;
6307
        #endif
6308
6309
        lastStatus = WEXITSTATUS(status);
6310
      }
6311
      else if (WIFSIGNALED(status))
6312
      {
6313
        if (CheckSignal(WTERMSIG(status)) != 1)
6314
        {
6315
          #ifdef WARNING
6316
          *logofs << "Loop: WARNING! Child process '" << pid
6317
                  << "' died because of signal " << (WTERMSIG(status))
6318
                  << ", '" << DumpSignal(WTERMSIG(status)) << "'.\n"
6319
                  << logofs_flush;
6320
          #endif
6321
6322
          cerr << "Warning" << ": Child process '" << pid
6323
               << "' died because of signal " << (WTERMSIG(status))
6324
               << ", '" << DumpSignal(WTERMSIG(status)) << "'.\n";
6325
        }
6326
        #if defined(UNSAFE) && defined(TEST)
6327
        else
6328
        {
6329
          *logofs << "Loop: Child process '" << pid
6330
                  << "' died because of signal " << (WTERMSIG(status))
6331
                  << ", '" << DumpSignal(WTERMSIG(status)) << "'.\n"
6332
                  << logofs_flush;
6333
        }
6334
        #endif
6335
6336
        lastStatus = 1;
6337
      }
6338
6339
      return 1;
6340
    }
6341
  }
6342
  else if (pid < 0)
6343
  {
6344
    if (EGET() != ECHILD)
6345
    {
6346
      #ifdef PANIC
6347
      *logofs << "Loop: PANIC! Call to waitpid failed. "
6348
              << "Error is " << EGET() << " '" << ESTR()
6349
              << "'.\n" << logofs_flush;
6350
      #endif
6351
6352
      cerr << "Error" << ": Call to waitpid failed. "
6353
           << "Error is " << EGET() << " '" << ESTR()
6354
           << "'.\n";
6355
6356
      HandleCleanup();
6357
    }
6358
6359
    //
6360
    // This can happen when the waitpid() is
6361
    // blocking, as the SIGCHLD is received
6362
    // within the call.
6363
    //
6364
6365
    #ifdef TEST
6366
    *logofs << "Loop: No more children processes running.\n"
6367
            << logofs_flush;
6368
    #endif
6369
6370
    return 1;
6371
  }
6372
6373
  return 0;
6374
}
6375
6376
void RegisterChild(int child)
6377
{
6378
  #if defined(TEST) || defined(INFO)
6379
6380
  if (IsNotRunning(lastChild))
6381
  {
6382
    *logofs << "Loop: Registering child process '" << child
6383
            << "' in process with pid '" << getpid()
6384
            << "'.\n" << logofs_flush;
6385
  }
6386
  else
6387
  {
6388
    *logofs << "Loop: WARNING! Overriding registered child '"
6389
            << lastChild << "' with new child '" << child
6390
            << "' in process with pid '" << getpid()
6391
            << "'.\n" << logofs_flush;
6392
  }
6393
6394
  #endif
6395
6396
  lastChild = child;
6397
}
6398
6399
int CheckParent(char *name, char *type, int parent)
6400
{
6401
  if (parent != getppid() || parent == 1)
6402
  {
6403
    #ifdef WARNING
6404
    *logofs << name << ": WARNING! Parent process appears "
6405
            << "to be dead. Exiting " << type << ".\n"
6406
            << logofs_flush;
6407
    #endif
6408
6409
    cerr << "Warning" << ": Parent process appears "
6410
         << "to be dead. Exiting " << type << ".\n";
6411
6412
    return 0;
6413
  }
6414
6415
  return 1;
6416
}
6417
6418
void HandleTimer(int signal)
6419
{
6420
  if (signal == SIGALRM)
6421
  {
6422
    if (isTimestamp(lastTimer.start))
6423
    {
6424
      #if defined(UNSAFE) && defined(TEST)
6425
      *logofs << "Loop: Timer expired at " << strMsTimestamp()
6426
              << " in process with pid '" << getpid() << "'.\n"
6427
              << logofs_flush;
6428
      #endif
6429
6430
      if (proxy != NULL)
6431
      {
6432
        proxy -> handleTimer();
6433
      }
6434
6435
      ResetTimer();
6436
    }
6437
    else
6438
    {
6439
      #ifdef PANIC
6440
      *logofs << "Loop: PANIC! Inconsistent timer state "
6441
              << " in process with pid '" << getpid() << "'.\n"
6442
              << logofs_flush;
6443
      #endif
6444
6445
      cerr << "Error" << ": Inconsistent timer state "
6446
           << " in process with pid '" << getpid() << "'.\n";
6447
    }
6448
  }
6449
  else
6450
  {
6451
    #ifdef PANIC
6452
    *logofs << "Loop: PANIC! Inconsistent signal '"
6453
            << signal << "', '" << DumpSignal(signal)
6454
            << "' received in process with pid '"
6455
            << getpid() << "'.\n" << logofs_flush;
6456
    #endif
6457
6458
    cerr << "Error" << ": Inconsistent signal '"
6459
         << signal << "', '" << DumpSignal(signal)
6460
         << "' received in process with pid '"
6461
         << getpid() << "'.\n";
6462
  }
6463
}
6464
6465
void SetTimer(int value)
6466
{
6467
  getNewTimestamp();
6468
6469
  if (isTimestamp(lastTimer.start))
6470
  {
6471
    int diffTs = diffTimestamp(lastTimer.start, getTimestamp());
6472
6473
    if (diffTs > lastTimer.next.tv_usec / 1000 * 2)
6474
    {
6475
      #ifdef WARNING
6476
      *logofs << "Loop: WARNING! Timer missed to expire at "
6477
              << strMsTimestamp() << " in process with pid '"
6478
              << getpid() << "'.\n" << logofs_flush;
6479
      #endif
6480
6481
      cerr << "Warning" << ": Timer missed to expire at "
6482
           << strMsTimestamp() << " in process with pid '"
6483
           << getpid() << "'.\n";
6484
6485
      HandleTimer(SIGALRM);
6486
    }
6487
    else
6488
    {
6489
      #ifdef TEST
6490
      *logofs << "Loop: Timer already running at "
6491
              << strMsTimestamp() << " in process with pid '"
6492
              << getpid() << "'.\n" << logofs_flush;
6493
      #endif
6494
6495
      return;
6496
    }
6497
  }
6498
6499
  //
6500
  // Save the former handler.
6501
  //
6502
6503
  struct sigaction action;
6504
6505
  action.sa_handler = HandleTimer;
6506
6507
  #if defined(__linux__)
6508
6509
  action.sa_restorer = NULL;
6510
6511
  #endif
6512
6513
  sigemptyset(&action.sa_mask);
6514
6515
  action.sa_flags = 0;
6516
6517
  sigaction(SIGALRM, &action, &lastTimer.action);
6518
6519
  //
6520
  // Start the timer.
6521
  //
6522
6523
  lastTimer.next = getTimestamp(value);
6524
6525
  struct itimerval timer;
6526
6527
  timer.it_interval = lastTimer.next;
6528
  timer.it_value    = lastTimer.next;
6529
6530
  #ifdef TEST
6531
  *logofs << "Loop: Timer set to " << lastTimer.next.tv_sec
6532
          << " S and " << lastTimer.next.tv_usec / 1000
6533
          << " Ms at " << strMsTimestamp() << " in process "
6534
          << "with pid '" << getpid() << "'.\n"
6535
          << logofs_flush;
6536
  #endif
6537
6538
  if (setitimer(ITIMER_REAL, &timer, &lastTimer.value) < 0)
6539
  {
6540
    #ifdef PANIC
6541
    *logofs << "Loop: PANIC! Call to setitimer failed. "
6542
            << "Error is " << EGET() << " '" << ESTR()
6543
            << "'.\n" << logofs_flush;
6544
    #endif
6545
6546
    cerr << "Error" << ": Call to setitimer failed. "
6547
         << "Error is " << EGET() << " '" << ESTR()
6548
         << "'.\n";
6549
6550
    lastTimer.next = nullTimestamp();
6551
6552
    return;
6553
  }
6554
6555
  lastTimer.start = getTimestamp();
6556
}
6557
6558
void ResetTimer()
6559
{
6560
  if (isTimestamp(lastTimer.start) == 0)
6561
  {
6562
    #if defined(UNSAFE) && defined(TEST)
6563
    *logofs << "Loop: Timer not running in process "
6564
            << "with pid '" << getpid() << "'.\n"
6565
            << logofs_flush;
6566
    #endif
6567
6568
    return;
6569
  }
6570
6571
  #if defined(UNSAFE) && defined(TEST)
6572
  *logofs << "Loop: Timer reset at " << strMsTimestamp()
6573
          << " in process with pid '" << getpid()
6574
          << "'.\n" << logofs_flush;
6575
  #endif
6576
6577
  //
6578
  // Restore the old signal mask and timer.
6579
  //
6580
6581
  if (setitimer(ITIMER_REAL, &lastTimer.value, NULL) < 0)
6582
  {
6583
    #ifdef PANIC
6584
    *logofs << "Loop: PANIC! Call to setitimer failed. "
6585
            << "Error is " << EGET() << " '" << ESTR()
6586
            << "'.\n" << logofs_flush;
6587
    #endif
6588
6589
    cerr << "Error" << ": Call to setitimer failed. "
6590
         << "Error is " << EGET() << " '" << ESTR()
6591
         << "'.\n";
6592
  }
6593
6594
  if (sigaction(SIGALRM, &lastTimer.action, NULL) < 0)
6595
  {
6596
    #ifdef PANIC
6597
    *logofs << "Loop: PANIC! Call to sigaction failed. "
6598
            << "Error is " << EGET() << " '" << ESTR()
6599
            << "'.\n" << logofs_flush;
6600
    #endif
6601
6602
    cerr << "Error" << ": Call to sigaction failed. "
6603
         << "Error is " << EGET() << " '" << ESTR()
6604
         << "'.\n";
6605
  }
6606
6607
  lastTimer.start = lastTimer.next = nullTimestamp();
6608
}
6609
6610
//
6611
// Open TCP socket to listen for remote proxy and
6612
// block until remote connects. If successful close
6613
// the listening socket and return FD on which the
6614
// other party is connected.
6615
//
6616
6617
int WaitForRemote(int portNum)
6618
{
6619
  char hostLabel[DEFAULT_STRING_LENGTH] = { 0 };
6620
6621
  int retryAccept  = -1;
6622
  int listenIPAddr = -1;
6623
6624
  int proxyFD = -1;
6625
  int newFD   = -1;
6626
6627
  //
6628
  // Get IP address of host to be awaited.
6629
  //
6630
6631
  int acceptIPAddr = 0;
6632
6633
  if (*acceptHost != '\0')
6634
  {
6635
    acceptIPAddr = GetHostAddress(acceptHost);
6636
6637
    if (acceptIPAddr == 0)
6638
    {
6639
      #ifdef PANIC
6640
      *logofs << "Loop: PANIC! Cannot accept connections from unknown host '"
6641
              << acceptHost << "'.\n" << logofs_flush;
6642
      #endif
6643
6644
      cerr << "Error" << ": Cannot accept connections from unknown host '"
6645
           << acceptHost << "'.\n";
6646
6647
      goto WaitForRemoteError;
6648
    }
6649
  }
6650
6651
  proxyFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
6652
6653
  if (proxyFD == -1)
6654
  {
6655
    #ifdef PANIC
6656
    *logofs << "Loop: PANIC! Call to socket failed for TCP socket. "
6657
            << "Error is " << EGET() << " '" << ESTR() << "'.\n"
6658
            << logofs_flush;
6659
    #endif
6660
6661
    cerr << "Error" << ": Call to socket failed for TCP socket. "
6662
         << "Error is " << EGET() << " '" << ESTR() << "'.\n";
6663
6664
    goto WaitForRemoteError;
6665
  }
6666
  else if (SetReuseAddress(proxyFD) < 0)
6667
  {
6668
    goto WaitForRemoteError;
6669
  }
6670
6671
  listenIPAddr = 0;
6672
6673
  ParseListenOption(listenIPAddr);
6674
6675
  sockaddr_in tcpAddr;
6676
6677
  tcpAddr.sin_family = AF_INET;
6678
  tcpAddr.sin_port = htons(portNum);
6679
6680
  //
6681
  // Quick patch to run on MacOS/X where inet_addr("127.0.0.1")
6682
  // alone seems to fail to return a valid interface. It probably
6683
  // just needs a htonl() or something like that.
6684
  // 
6685
  // TODO: We have to give another look at inet_addr("127.0.0.1")
6686
  // on the Mac.
6687
  //
6688
6689
  #ifdef __APPLE__
6690
6691
  tcpAddr.sin_addr.s_addr = htonl(INADDR_ANY);
6692
6693
  #else
6694
6695
  tcpAddr.sin_addr.s_addr = listenIPAddr;
6696
6697
  #endif
6698
6699
  if (bind(proxyFD, (sockaddr *) &tcpAddr, sizeof(tcpAddr)) == -1)
6700
  {
6701
    #ifdef PANIC
6702
    *logofs << "Loop: PANIC! Call to bind failed for TCP port "
6703
            << portNum << ". Error is " << EGET() << " '" << ESTR()
6704
            << "'.\n" << logofs_flush;
6705
    #endif
6706
6707
    cerr << "Error" << ": Call to bind failed for TCP port "
6708
         << portNum << ". Error is " << EGET() << " '" << ESTR()
6709
         << "'.\n";
6710
6711
    goto WaitForRemoteError;
6712
  }
6713
6714
  if (listen(proxyFD, 4) == -1)
6715
  {
6716
    #ifdef PANIC
6717
    *logofs << "Loop: PANIC! Call to listen failed for TCP port "
6718
            << portNum << ". Error is " << EGET() << " '" << ESTR()
6719
            << "'.\n" << logofs_flush;
6720
    #endif
6721
6722
    cerr << "Error" << ": Call to listen failed for TCP port "
6723
         << portNum << ". Error is " << EGET() << " '" << ESTR()
6724
         << "'.\n";
6725
6726
    goto WaitForRemoteError;
6727
  }
6728
6729
  if (*acceptHost != '\0')
6730
  {
6731
    strcat(hostLabel, "'");
6732
    strcat(hostLabel, acceptHost);
6733
    strcat(hostLabel, "'");
6734
  }
6735
  else
6736
  {
6737
    strcpy(hostLabel, "any host");
6738
  }
6739
6740
  #ifdef TEST
6741
  *logofs << "Loop: Waiting for connection from "
6742
          << hostLabel  << " on port '" << portNum
6743
          << "'.\n" << logofs_flush;
6744
  #endif
6745
6746
  cerr << "Info" << ": Waiting for connection from "
6747
       << hostLabel << " on port '" << portNum
6748
       << "'.\n";
6749
6750
  //
6751
  // How many times to loop waiting for connections
6752
  // from the selected host? Each loop wait for at
6753
  // most 20 seconds so a default value of 3 gives
6754
  // a timeout of 1 minute.
6755
  //
6756
  // TODO: Handling of timeouts and retry attempts
6757
  // must be rewritten.
6758
  //
6759
6760
  retryAccept = control -> OptionProxyRetryAccept;
6761
6762
  for (;;)
6763
  {
6764
    fd_set readSet;
6765
6766
    FD_ZERO(&readSet);
6767
    FD_SET(proxyFD, &readSet);
6768
6769
    T_timestamp selectTs;
6770
6771
    selectTs.tv_sec  = 20;
6772
    selectTs.tv_usec = 0;
6773
6774
    int result = select(proxyFD + 1, &readSet, NULL, NULL, &selectTs);
6775
6776
    getNewTimestamp();
6777
6778
    if (result == -1)
6779
    {
6780
      if (EGET() == EINTR)
6781
      {
6782
        if (CheckAbort() != 0)
6783
        {
6784
          goto WaitForRemoteError;
6785
        }
6786
6787
        continue;
6788
      }
6789
 
6790
      #ifdef PANIC
6791
      *logofs << "Loop: PANIC! Call to select failed. Error is "
6792
              << EGET() << " '" << ESTR() << "'.\n"
6793
              << logofs_flush;
6794
      #endif
6795
6796
      cerr << "Error" << ": Call to select failed. Error is "
6797
           << EGET() << " '" << ESTR() << "'.\n";
6798
6799
      goto WaitForRemoteError;
6800
    }
6801
    else if (result > 0 && FD_ISSET(proxyFD, &readSet))
6802
    {
6803
      sockaddr_in newAddr;
6804
6805
      size_t addrLen = sizeof(sockaddr_in);
6806
6807
      newFD = accept(proxyFD, (sockaddr *) &newAddr, (socklen_t *) &addrLen);
6808
6809
      if (newFD == -1)
6810
      {
6811
        #ifdef PANIC
6812
        *logofs << "Loop: PANIC! Call to accept failed. Error is "
6813
                << EGET() << " '" << ESTR() << "'.\n"
6814
                << logofs_flush;
6815
        #endif
6816
6817
        cerr << "Error" << ": Call to accept failed. Error is "
6818
             << EGET() << " '" << ESTR() << "'.\n";
6819
6820
        goto WaitForRemoteError;
6821
      }
6822
6823
      char *connectedHost = inet_ntoa(newAddr.sin_addr);
6824
6825
      if (*acceptHost == '\0' || (int) newAddr.sin_addr.s_addr == acceptIPAddr)
6826
      {
6827
        #ifdef TEST
6828
6829
        unsigned int connectedPort = ntohs(newAddr.sin_port);
6830
6831
        *logofs << "Loop: Accepted connection from '" << connectedHost
6832
                << "' with port '" << connectedPort << "'.\n"
6833
                << logofs_flush;
6834
        #endif
6835
6836
        cerr << "Info" << ": Accepted connection from '"
6837
             << connectedHost << "'.\n";
6838
6839
        break;
6840
      }
6841
      else
6842
      {
6843
        #ifdef PANIC
6844
        *logofs << "Loop: WARNING! Refusing connection from '" << connectedHost
6845
                << "' on port '" << portNum << "'.\n" << logofs_flush;
6846
        #endif
6847
6848
        cerr << "Warning" << ": Refusing connection from '"
6849
             << connectedHost << "'.\n";
6850
      }
6851
6852
      //
6853
      // Not the best way to elude a DOS attack...
6854
      //
6855
6856
      sleep(5);
6857
6858
      close(newFD);
6859
    }
6860
6861
    if (--retryAccept == 0)
6862
    {
6863
      if (*acceptHost == '\0')
6864
      {
6865
        #ifdef PANIC
6866
        *logofs << "Loop: PANIC! Connection with remote host "
6867
                << "could not be established.\n"
6868
                << logofs_flush;
6869
        #endif
6870
6871
        cerr << "Error" << ": Connection with remote host "
6872
             << "could not be established.\n";
6873
      }
6874
      else
6875
      {
6876
        #ifdef PANIC
6877
        *logofs << "Loop: PANIC! Connection with remote host '"
6878
                << acceptHost << "' could not be established.\n"
6879
                << logofs_flush;
6880
        #endif
6881
6882
        cerr << "Error" << ": Connection with remote host '"
6883
             << acceptHost << "' could not be established.\n";
6884
      }
6885
6886
      goto WaitForRemoteError;
6887
    }
6888
    else
6889
    {
6890
      handleCheckSessionInConnect();
6891
    }
6892
  }
6893
6894
  close(proxyFD);
6895
6896
  return newFD;
6897
6898
WaitForRemoteError:
6899
6900
  close(proxyFD);
6901
6902
  HandleCleanup();
6903
}
6904
6905
//
6906
// Connect to remote proxy. If successful
6907
// return FD of connection, else return -1.
6908
//
6909
6910
int ConnectToRemote(const char *const hostName, int portNum)
6911
{
6912
  int proxyFD = -1;
6913
6914
  int remoteIPAddr = GetHostAddress(hostName);
6915
6916
  if (remoteIPAddr == 0)
6917
  {
6918
    #ifdef PANIC
6919
    *logofs << "Loop: PANIC! Unknown remote host '"
6920
            << hostName << "'.\n" << logofs_flush;
6921
    #endif
6922
6923
    cerr << "Error" << ": Unknown remote host '"
6924
         << hostName << "'.\n";
6925
6926
    HandleCleanup();
6927
  }
6928
6929
  #ifdef TEST
6930
  *logofs << "Loop: Connecting to remote host '" 
6931
          << hostName << ":" << portNum << "'.\n"
6932
          << logofs_flush;
6933
  #endif
6934
6935
  cerr << "Info" << ": Connecting to remote host '"
6936
       << hostName << ":" << portNum << "'.\n"
6937
       << logofs_flush;
6938
6939
  //
6940
  // How many times we retry to connect to remote
6941
  // host in case of failure?
6942
  //
6943
6944
  int retryConnect = control -> OptionProxyRetryConnect;
6945
6946
  //
6947
  // Show an alert after 20 seconds and use the
6948
  // same timeout to interrupt the connect. The
6949
  // retry timeout is incremental, starting from
6950
  // 100 miliseconds up to 1 second.
6951
  //
6952
6953
  int alertTimeout   = 20000;
6954
  int connectTimeout = 20000;
6955
  int retryTimeout   = 100;
6956
6957
  T_timestamp lastRetry = getNewTimestamp();
6958
6959
  sockaddr_in addr;
6960
6961
  addr.sin_family = AF_INET;
6962
  addr.sin_port = htons(portNum);
6963
  addr.sin_addr.s_addr = remoteIPAddr;
6964
6965
  for (;;)
6966
  {
6967
    proxyFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
6968
6969
    if (proxyFD == -1)
6970
    {
6971
      #ifdef PANIC
6972
      *logofs << "Loop: PANIC! Call to socket failed. "
6973
              << "Error is " << EGET() << " '" << ESTR()
6974
              << "'.\n" << logofs_flush;
6975
      #endif
6976
6977
      cerr << "Error" << ": Call to socket failed. "
6978
           << "Error is " << EGET() << " '" << ESTR()
6979
           << "'.\n";
6980
6981
      goto ConnectToRemoteError;
6982
    }
6983
    else if (SetReuseAddress(proxyFD) < 0)
6984
    {
6985
      goto ConnectToRemoteError;
6986
    }
6987
6988
    //
6989
    // Ensure operation is timed out
6990
    // if there is a network problem.
6991
    //
6992
6993
    #ifdef DEBUG
6994
    *logofs << "Loop: Timer set to " << connectTimeout / 1000
6995
            << " S " << "with retry set to " << retryConnect
6996
            << " in process with pid '" << getpid()
6997
            << "'.\n" << logofs_flush;
6998
    #endif
6999
7000
    SetTimer(connectTimeout);
7001
7002
    int result = connect(proxyFD, (sockaddr *) &addr, sizeof(sockaddr_in));
7003
7004
    int reason = EGET();
7005
7006
    ResetTimer();
7007
7008
    if (result < 0)
7009
    {
7010
      close(proxyFD);
7011
7012
      if (CheckAbort() != 0)
7013
      {
7014
        goto ConnectToRemoteError;
7015
      }
7016
      else if (--retryConnect == 0)
7017
      {
7018
        ESET(reason);
7019
7020
        #ifdef PANIC
7021
        *logofs << "Loop: PANIC! Connection to '" << hostName
7022
                << ":" << portNum << "' failed. Error is "
7023
                << EGET() << " '" << ESTR() << "'.\n"
7024
                << logofs_flush;
7025
        #endif
7026
7027
        cerr << "Error" << ": Connection to '" << hostName
7028
             << ":" << portNum << "' failed. Error is "
7029
             << EGET() << " '" << ESTR() << "'.\n";
7030
7031
        goto ConnectToRemoteError;
7032
      }
7033
      else
7034
      {
7035
        #ifdef TEST
7036
        *logofs << "Loop: Sleeping " << retryTimeout 
7037
                << " Ms before retrying.\n"
7038
                << logofs_flush;
7039
        #endif
7040
7041
        usleep(retryTimeout * 1000);
7042
7043
        retryTimeout <<= 1;
7044
7045
        if (retryTimeout > 1000 * 1000)
7046
        {
7047
          retryTimeout = 1000 * 1000;
7048
        }
7049
      }
7050
7051
      //
7052
      // Check if it is time to show an alert dialog.
7053
      //
7054
7055
      if (diffTimestamp(lastRetry, getNewTimestamp()) >=
7056
              (alertTimeout - control -> LatencyTimeout))
7057
      {
7058
        if (IsNotRunning(lastDialog))
7059
        {
7060
          handleCheckSessionInConnect();
7061
7062
          //
7063
          // Wait for the dialog process to die
7064
          // unless a signal is received.
7065
          //
7066
7067
          while (IsRunning(lastDialog))
7068
          {
7069
            WaitChild(lastDialog, "dialog", 0);
7070
7071
            if (CheckAbort() != 0)
7072
            {
7073
              //
7074
              // The client ignores the TERM signal
7075
              // on Windows.
7076
              //
7077
7078
              #ifdef __CYGWIN32__
7079
7080
              KillProcess(lastDialog, "dialog", SIGKILL, 1);
7081
7082
              #else
7083
7084
              KillProcess(lastDialog, "dialog", SIGTERM, 1);
7085
7086
              #endif
7087
7088
              goto ConnectToRemoteError;
7089
            }
7090
          }
7091
7092
          lastRetry = getTimestamp();
7093
        }
7094
      }
7095
      #ifdef TEST
7096
      {
7097
        *logofs << "Loop: Not showing the dialog with "
7098
                << (diffTimestamp(lastRetry, getTimestamp()) / 1000)
7099
                << " seconds elapsed.\n" << logofs_flush;
7100
      }
7101
      #endif
7102
7103
      ESET(reason);
7104
7105
      #ifdef TEST
7106
      *logofs << "Loop: Connection to '" << hostName
7107
              << ":" << portNum << "' failed with error '"
7108
              << ESTR() << "'. Retrying.\n"
7109
              << logofs_flush;
7110
      #endif
7111
    }
7112
    else
7113
    {
7114
      //
7115
      // Connection was successful.
7116
      //
7117
7118
      break;
7119
    }
7120
  }
7121
7122
  return proxyFD;
7123
7124
ConnectToRemoteError:
7125
7126
  if (proxyFD != -1)
7127
  {
7128
    close(proxyFD);
7129
  }
7130
7131
  HandleCleanup();
7132
}
7133
7134
//
7135
// Make a string of options for the remote
7136
// proxy and write it to the descriptor.
7137
// The string includes the local version.
7138
//
7139
7140
int SendProxyOptions(int fd)
7141
{
7142
  char options[DEFAULT_REMOTE_OPTIONS_LENGTH];
7143
7144
  //
7145
  // Send the "compatibility" version first, then our
7146
  // actual version. Old proxies will take the first
7147
  // value and ignore the second.
7148
  //
7149
7150
  sprintf(options, "NXPROXY-1.5.0-%i.%i.%i", control -> LocalVersionMajor,
7151
              control -> LocalVersionMinor, control -> LocalVersionPatch);
7152
7153
  //
7154
  // If you want to send options from proxy
7155
  // initiating the connection use something
7156
  // like this:
7157
  //
7158
  // if (WE_PROVIDE_CREDENTIALS)
7159
  // {
7160
  //   sprintf(options + strlen(options), "%s=%s", option, value);
7161
  // }
7162
  //
7163
  // If you want to send options according to
7164
  // local proxy mode use something like this:
7165
  //
7166
  // if (control -> ProxyMode == proxy_client)
7167
  // {
7168
  //   sprintf(options + strlen(options), "%s=%s", option, value);
7169
  // }
7170
  //
7171
7172
  //
7173
  // Send the authorization cookie if any. We assume
7174
  // user can choose to not provide any auth cookie
7175
  // and allow any connection to be accepted.
7176
  //
7177
7178
  if (WE_PROVIDE_CREDENTIALS && *authCookie != '\0')
7179
  {
7180
    sprintf(options + strlen(options), " cookie=%s,", authCookie);
7181
  }
7182
  else
7183
  {
7184
    sprintf(options + strlen(options), " ");
7185
  }
7186
7187
  //
7188
  // Now link characteristics and compression
7189
  // options. Delta compression, as well as
7190
  // preferred pack method, are imposed by
7191
  // client proxy.
7192
  //
7193
7194
  if (control -> ProxyMode == proxy_client)
7195
  {
7196
    sprintf(options + strlen(options), "link=%s,pack=%s,cache=%s,",
7197
                linkSpeedName, packMethodName, cacheSizeName);
7198
7199
    if (*bitrateLimitName != '\0')
7200
    {
7201
      sprintf(options + strlen(options), "limit=%s,",
7202
                  bitrateLimitName);
7203
    }
7204
7205
    //
7206
    // Let the user disable the render extension
7207
    // and let the X client proxy know if it can
7208
    // short-circuit the X replies. Also pass
7209
    // along the session type to ensure that the
7210
    // remote proxy gets the right value.
7211
    //
7212
7213
    sprintf(options + strlen(options), "render=%d,taint=%d,",
7214
                (control -> HideRender == 0),
7215
                    control -> TaintReplies);
7216
7217
    if (*sessionType != '\0')
7218
    {
7219
      sprintf(options + strlen(options), "type=%s,", sessionType);
7220
    }
7221
    else
7222
    {
7223
      sprintf(options + strlen(options), "type=default,");
7224
    }
7225
7226
    //
7227
    // Add the 'strict' option, if needed.
7228
    //
7229
7230
    if (control -> isProtoStep7() == 1 &&
7231
            useStrict != -1)
7232
    {
7233
      sprintf(options + strlen(options), "strict=%d,", useStrict);
7234
    }
7235
7236
    //
7237
    // Tell the remote the size of the shared
7238
    // memory segment.
7239
    //
7240
7241
    if (control -> isProtoStep7() == 1 &&
7242
            *shsegSizeName != '\0')
7243
    {
7244
      sprintf(options + strlen(options), "shseg=%s,", shsegSizeName);
7245
    }
7246
7247
    //
7248
    // Send image cache parameters.
7249
    //
7250
7251
    sprintf(options + strlen(options), "images=%s,", imagesSizeName);
7252
7253
    sprintf(options + strlen(options), "delta=%d,stream=%d,data=%d ",
7254
                control -> LocalDeltaCompression,
7255
                    control -> LocalStreamCompressionLevel,
7256
                        control -> LocalDataCompressionLevel);
7257
  }
7258
  else
7259
  {
7260
    //
7261
    // If no special compression level was selected,
7262
    // server side will use compression levels set
7263
    // by client.
7264
    //
7265
7266
    if (control -> LocalStreamCompressionLevel < 0)
7267
    {
7268
      sprintf(options + strlen(options), "stream=default,");
7269
    }
7270
    else
7271
    {
7272
      sprintf(options + strlen(options), "stream=%d,",
7273
                  control -> LocalStreamCompressionLevel);
7274
    }
7275
7276
    if (control -> LocalDataCompressionLevel < 0)
7277
    {
7278
      sprintf(options + strlen(options), "data=default ");
7279
    }
7280
    else
7281
    {
7282
      sprintf(options + strlen(options), "data=%d ",
7283
                  control -> LocalDataCompressionLevel);
7284
    }
7285
  }
7286
7287
  #ifdef TEST
7288
  *logofs << "Loop: Sending remote options '"
7289
          << options << "'.\n" << logofs_flush;
7290
  #endif
7291
7292
  return WriteLocalData(fd, options, strlen(options));
7293
}
7294
7295
int ReadProxyVersion(int fd)
7296
{
7297
  #ifdef TEST
7298
  *logofs << "Loop: Going to read the remote proxy version "
7299
          << "from FD#" << fd << ".\n" << logofs_flush;
7300
  #endif
7301
7302
  //
7303
  // Read until the first space in string.
7304
  // We expect the remote version number.
7305
  //
7306
7307
  char options[DEFAULT_REMOTE_OPTIONS_LENGTH];
7308
7309
  int result = ReadRemoteData(fd, options, sizeof(options), ' ');
7310
7311
  if (result <= 0)
7312
  {
7313
    if (result < 0)
7314
    {
7315
      if (control -> ProxyMode == proxy_server)
7316
      {
7317
        HandleAlert(ABORT_PROXY_NEGOTIATION_ALERT, 1);
7318
      }
7319
7320
      handleAlertInLoop();
7321
    }
7322
7323
    return result;
7324
  }
7325
7326
  #ifdef TEST
7327
  *logofs << "Loop: Received remote version string '"
7328
          << options << "' from FD#" << fd << ".\n"
7329
          << logofs_flush;
7330
  #endif
7331
7332
  if (strncmp(options, "NXPROXY-", strlen("NXPROXY-")) != 0)
7333
  {
7334
    #ifdef PANIC
7335
    *logofs << "Loop: PANIC! Parse error in remote options string '"
7336
            << options << "'.\n" << logofs_flush;
7337
    #endif
7338
7339
    cerr << "Error" << ": Parse error in remote options string '"
7340
         << options << "'.\n";
7341
7342
    return -1;
7343
  }
7344
7345
  //
7346
  // Try to determine if this is a pre-2.0.0
7347
  // version advertising itself as compatible
7348
  // with the 1.2.2.
7349
  //
7350
7351
  int major = -1;
7352
  int minor = -1;
7353
  int patch = -1;
7354
7355
  sscanf(options, "NXPROXY-%i.%i.%i-%i.%i.%i", &(control -> RemoteVersionMajor),
7356
             &(control -> RemoteVersionMinor), &(control -> RemoteVersionPatch),
7357
                 &major, &minor, &patch);
7358
7359
  if (control -> RemoteVersionMajor == 1 &&
7360
          control -> RemoteVersionMinor == 2 &&
7361
              control -> RemoteVersionPatch == 2 &&
7362
                  major != -1 && minor != -1 && patch != -1)
7363
  {
7364
    #ifdef TEST
7365
    *logofs << "Loop: Read trailing remote version '" << major
7366
            << "." << minor << "." << patch << "'.\n"
7367
            << logofs_flush;
7368
    #endif
7369
7370
    control -> CompatVersionMajor = major;
7371
    control -> CompatVersionMinor = minor;
7372
    control -> CompatVersionPatch = patch;
7373
7374
    control -> RemoteVersionMajor = major;
7375
    control -> RemoteVersionMinor = minor;
7376
    control -> RemoteVersionPatch = patch;
7377
  }
7378
  else
7379
  {
7380
    //
7381
    // We read the remote version at the first
7382
    // round. If the second version is missing,
7383
    // we will retain the values read before.
7384
    //
7385
7386
    sscanf(options, "NXPROXY-%i.%i.%i-%i.%i.%i", &(control -> CompatVersionMajor),
7387
               &(control -> CompatVersionMinor), &(control -> CompatVersionPatch),
7388
                   &(control -> RemoteVersionMajor), &(control -> RemoteVersionMinor),
7389
                       &(control -> RemoteVersionPatch));
7390
  }
7391
7392
  #ifdef TEST
7393
  *logofs << "Loop: Identified remote version '" << control -> RemoteVersionMajor
7394
          << "." << control -> RemoteVersionMinor << "." << control -> RemoteVersionPatch
7395
          << "'.\n" << logofs_flush;
7396
7397
  *logofs << "Loop: Remote compatibility version '" << control -> CompatVersionMajor
7398
          << "." << control -> CompatVersionMinor << "." << control -> CompatVersionPatch
7399
          << "'.\n" << logofs_flush;
7400
7401
  *logofs << "Loop: Local version '" << control -> LocalVersionMajor
7402
          << "." << control -> LocalVersionMinor << "." << control -> LocalVersionPatch
7403
          << "'.\n" << logofs_flush;
7404
  #endif
7405
7406
  if (SetVersion() < 0)
7407
  {
7408
    if (control -> ProxyMode == proxy_server)
7409
    {
7410
      HandleAlert(WRONG_PROXY_VERSION_ALERT, 1);
7411
    }
7412
7413
    handleAlertInLoop();
7414
7415
    return -1;
7416
  }
7417
7418
  return 1;
7419
}
7420
7421
int ReadProxyOptions(int fd)
7422
{
7423
  #ifdef TEST
7424
  *logofs << "Loop: Going to read the remote proxy options "
7425
          << "from FD#" << fd << ".\n" << logofs_flush;
7426
  #endif
7427
7428
  char options[DEFAULT_REMOTE_OPTIONS_LENGTH];
7429
7430
  int result = ReadRemoteData(fd, options, sizeof(options), ' ');
7431
7432
  if (result <= 0)
7433
  {
7434
    return result;
7435
  }
7436
7437
  #ifdef TEST
7438
  *logofs << "Loop: Received remote options string '"
7439
          << options << "' from FD#" << fd << ".\n"
7440
          << logofs_flush;
7441
  #endif
7442
7443
  //
7444
  // Get the remote options, delimited by a space character.
7445
  // Note that there will be a further initialization phase
7446
  // at the time proxies negotiate cache file to restore.
7447
  //
7448
7449
  if (ParseRemoteOptions(options) < 0)
7450
  {
7451
    #ifdef PANIC
7452
    *logofs << "Loop: PANIC! Couldn't negotiate a valid "
7453
            << "session with remote NX proxy.\n"
7454
            << logofs_flush;
7455
    #endif
7456
7457
    cerr << "Error" << ": Couldn't negotiate a valid "
7458
         << "session with remote NX proxy.\n";
7459
7460
    return -1;
7461
  }
7462
7463
  return 1;
7464
}
7465
7466
int SendProxyCaches(int fd)
7467
{
7468
  #ifdef TEST
7469
  *logofs << "Loop: Synchronizing local and remote caches.\n"
7470
          << logofs_flush;
7471
  #endif
7472
7473
  if (control -> ProxyMode == proxy_client)
7474
  {
7475
    //
7476
    // Prepare a list of caches matching this
7477
    // session type and send it to the remote.
7478
    //
7479
7480
    #ifdef TEST
7481
    *logofs << "Loop: Going to send the list of local caches.\n"
7482
            << logofs_flush;
7483
    #endif
7484
7485
    SetCaches();
7486
7487
    int entries = DEFAULT_REMOTE_CACHE_ENTRIES;
7488
7489
    const char prefix = 'C';
7490
7491
    if (control -> LocalDeltaCompression == 0 ||
7492
            control -> PersistentCacheEnableLoad == 0)
7493
    {
7494
      #ifdef TEST
7495
      *logofs << "Loop: Writing an empty list to FD#" << fd
7496
              << ".\n" << logofs_flush;
7497
      #endif
7498
7499
      return WriteLocalData(fd, "cachelist=none ", strlen("cachelist=none "));
7500
    }
7501
7502
    int count = 0;
7503
7504
    #ifdef TEST
7505
    *logofs << "Loop: Looking for cache files in directory '"
7506
            << control -> PersistentCachePath << "'.\n" << logofs_flush;
7507
    #endif
7508
7509
    DIR *cacheDir = opendir(control -> PersistentCachePath);
7510
7511
    if (cacheDir != NULL)
7512
    {
7513
      dirent *dirEntry;
7514
7515
      int prologue = 0;
7516
7517
      while (((dirEntry = readdir(cacheDir)) != NULL) && (count < entries))
7518
      {
7519
        if (*dirEntry -> d_name == prefix &&
7520
                strlen(dirEntry -> d_name) == (MD5_LENGTH * 2 + 2))
7521
        {
7522
          if (prologue == 0)
7523
          {
7524
            WriteLocalData(fd, "cachelist=", strlen("cachelist="));
7525
7526
            prologue = 1;
7527
          }
7528
          else
7529
          {
7530
            WriteLocalData(fd, ",", strlen(","));
7531
          }
7532
7533
          #ifdef TEST
7534
          *logofs << "Loop: Writing entry '" << control -> PersistentCachePath
7535
                  << "/" << dirEntry -> d_name << "' to FD#" << fd
7536
                  << ".\n" << logofs_flush;
7537
          #endif
7538
7539
          //
7540
          // Write cache file name to the socket,
7541
          // including leading 'C-' or 'S-'.
7542
          //
7543
7544
          WriteLocalData(fd, dirEntry -> d_name, MD5_LENGTH * 2 + 2);
7545
7546
          count++;
7547
        }
7548
      }
7549
7550
      closedir(cacheDir);
7551
    }
7552
7553
    if (count == 0)
7554
    {
7555
      #ifdef TEST
7556
      *logofs << "Loop: Writing an empty list to FD#" << fd
7557
              << ".\n" << logofs_flush;
7558
      #endif
7559
7560
      return WriteLocalData(fd, "cachelist=none ", strlen("cachelist=none "));
7561
    }
7562
    else
7563
    {
7564
      return WriteLocalData(fd, " ", 1);
7565
    }
7566
  }
7567
  else
7568
  {
7569
    //
7570
    // Send back the selected cache name.
7571
    //
7572
7573
    #ifdef TEST
7574
    *logofs << "Loop: Going to send the selected cache.\n"
7575
            << logofs_flush;
7576
    #endif
7577
7578
    char buffer[DEFAULT_STRING_LENGTH];
7579
7580
    if (control -> PersistentCacheName != NULL)
7581
    {
7582
      #ifdef TEST
7583
      *logofs << "Loop: Name of selected cache file is '"
7584
              << control -> PersistentCacheName << "'.\n"
7585
              << logofs_flush;
7586
      #endif
7587
7588
      sprintf(buffer, "cachefile=%s%s ",
7589
                  *(control -> PersistentCacheName) == 'C' ? "S-" : "C-",
7590
                      control -> PersistentCacheName + 2);
7591
    }
7592
    else
7593
    {
7594
      #ifdef TEST
7595
      *logofs << "Loop: No valid cache file was selected.\n"
7596
              << logofs_flush;
7597
      #endif
7598
7599
      sprintf(buffer, "cachefile=none ");
7600
    }
7601
7602
    #ifdef TEST
7603
    *logofs << "Loop: Sending string '" << buffer
7604
            << "' as selected cache file.\n"
7605
            << logofs_flush;
7606
    #endif
7607
7608
    return WriteLocalData(fd, buffer, strlen(buffer));
7609
  }
7610
}
7611
7612
int ReadProxyCaches(int fd)
7613
{
7614
  if (control -> ProxyMode == proxy_client)
7615
  {
7616
    #ifdef TEST
7617
    *logofs << "Loop: Going to receive the selected proxy cache.\n"
7618
            << logofs_flush;
7619
    #endif
7620
7621
    //
7622
    // We will read the name of cache plus the stop character.
7623
    //
7624
7625
    char buffer[DEFAULT_STRING_LENGTH];
7626
7627
    //
7628
    // Leave space for a trailing null.
7629
    //
7630
7631
    int result = ReadRemoteData(fd, buffer, sizeof("cachefile=") + MD5_LENGTH * 2 + 3, ' ');
7632
7633
    if (result <= 0)
7634
    {
7635
      return result;
7636
    }
7637
7638
    char *cacheName = strstr(buffer, "cachefile=");
7639
7640
    if (cacheName == NULL)
7641
    {
7642
      #ifdef PANIC
7643
      *logofs << "Loop: PANIC! Invalid cache file option '"
7644
              << buffer << "' provided by remote proxy.\n"
7645
              << logofs_flush;
7646
      #endif
7647
7648
      cerr << "Error" << ": Invalid cache file option '"
7649
           << buffer << "' provided by remote proxy.\n";
7650
7651
      HandleCleanup();
7652
    }
7653
7654
    cacheName += strlen("cachefile=");
7655
7656
    if (control -> PersistentCacheName != NULL)
7657
    {
7658
      delete [] control -> PersistentCacheName;
7659
    }
7660
7661
    control -> PersistentCacheName = NULL;
7662
7663
    if (strncasecmp(cacheName, "none", strlen("none")) == 0)
7664
    {
7665
      #ifdef TEST
7666
      *logofs << "Loop: No cache file selected by remote proxy.\n"
7667
              << logofs_flush;
7668
      #endif
7669
    }
7670
    else if (strlen(cacheName) != MD5_LENGTH * 2 + 3 ||
7671
                 *(cacheName + MD5_LENGTH * 2 + 2) != ' ')
7672
    {
7673
      #ifdef PANIC
7674
      *logofs << "Loop: PANIC! Invalid cache file name '"
7675
              << cacheName << "' provided by remote proxy.\n"
7676
              << logofs_flush;
7677
      #endif
7678
7679
      cerr << "Error" << ": Invalid cache file name '"
7680
           << cacheName << "' provided by remote proxy.\n";
7681
7682
      HandleCleanup();
7683
    }
7684
    else
7685
    {
7686
      //
7687
      // It is "C-" + 32 + "\0".
7688
      //
7689
7690
      control -> PersistentCacheName = new char[MD5_LENGTH * 2 + 3];
7691
7692
      *(cacheName + MD5_LENGTH * 2 + 2) = '\0';
7693
7694
      strcpy(control -> PersistentCacheName, cacheName);
7695
7696
      #ifdef TEST
7697
      *logofs << "Loop: Cache file '" << control -> PersistentCacheName
7698
              << "' selected by remote proxy.\n" << logofs_flush;
7699
      #endif
7700
    }
7701
  }
7702
  else
7703
  {
7704
    #ifdef TEST
7705
    *logofs << "Loop: Going to receive the list of remote caches.\n"
7706
            << logofs_flush;
7707
    #endif
7708
7709
    SetCaches();
7710
7711
    int size = ((MD5_LENGTH * 2 + 2) + strlen(",")) * DEFAULT_REMOTE_CACHE_ENTRIES +
7712
                   strlen("cachelist=") + strlen(" ") + 1;
7713
7714
    char *buffer = new char[size];
7715
7716
    int result = ReadRemoteData(fd, buffer, size - 1, ' ');
7717
7718
    if (result <= 0)
7719
    {
7720
      delete [] buffer;
7721
7722
      return result;
7723
    }
7724
7725
    #ifdef TEST
7726
    *logofs << "Loop: Read list of caches from remote side as '"
7727
            << buffer << "'.\n" << logofs_flush;
7728
    #endif
7729
7730
    //
7731
    // Prepare the buffer. What we want is a list
7732
    // like "cache1,cache2,cache2" terminated by
7733
    // null.
7734
    //
7735
7736
    *(buffer + strlen(buffer) - 1) = '\0';
7737
7738
    if (strncasecmp(buffer, "cachelist=", strlen("cachelist=")) != 0)
7739
    {
7740
      #ifdef PANIC
7741
      *logofs << "Loop: Wrong format for list of cache files "
7742
              << "read from FD#" << fd << ".\n" << logofs_flush;
7743
      #endif
7744
7745
      cerr << "Error" << ": Wrong format for list of cache files.\n";
7746
7747
      delete [] buffer;
7748
7749
      return -1;
7750
    }
7751
7752
    control -> PersistentCacheName = GetLastCache(buffer, control -> PersistentCachePath);
7753
7754
    //
7755
    // Get rid of list of caches.
7756
    //
7757
7758
    delete [] buffer;
7759
  }
7760
7761
  return 1;
7762
}
7763
7764
int ReadForwarderVersion(int fd)
7765
{
7766
  #ifdef TEST
7767
  *logofs << "Loop: Going to negotiate the forwarder version.\n"
7768
          << logofs_flush;
7769
  #endif
7770
7771
  //
7772
  // Check if we actually expect the session cookie.
7773
  //
7774
7775
  if (*authCookie == '\0')
7776
  {
7777
    #ifdef TEST
7778
    *logofs << "Loop: No authentication cookie required "
7779
            << "from FD#" << fd << ".\n" << logofs_flush;
7780
    #endif
7781
7782
    return 1;
7783
  }
7784
7785
  char options[DEFAULT_REMOTE_OPTIONS_LENGTH];
7786
7787
  int result = ReadRemoteData(fd, options, sizeof(options), ' ');
7788
7789
  if (result <= 0)
7790
  {
7791
    return result;
7792
  }
7793
7794
  #ifdef TEST
7795
  *logofs << "Loop: Received forwarder version string '" << options
7796
          << "' from FD#" << fd << ".\n" << logofs_flush;
7797
  #endif
7798
7799
  if (strncmp(options, "NXSSH-", strlen("NXSSH-")) != 0)
7800
  {
7801
    #ifdef PANIC
7802
    *logofs << "Loop: PANIC! Parse error in forwarder options string '"
7803
            << options << "'.\n" << logofs_flush;
7804
    #endif
7805
7806
    cerr << "Error" << ": Parse error in forwarder options string '"
7807
         << options << "'.\n";
7808
7809
    return -1;
7810
  }
7811
7812
  //
7813
  // Accept whatever forwarder version.
7814
  //
7815
7816
  sscanf(options, "NXSSH-%i.%i.%i", &(control -> RemoteVersionMajor),
7817
             &(control -> RemoteVersionMinor), &(control -> RemoteVersionPatch));
7818
7819
  #ifdef TEST
7820
  *logofs << "Loop: Read forwarder version '" << control -> RemoteVersionMajor
7821
          << "." << control -> RemoteVersionMinor << "." << control -> RemoteVersionPatch
7822
          << "'.\n" << logofs_flush;
7823
  #endif
7824
7825
  return 1;
7826
}
7827
7828
int ReadForwarderOptions(int fd)
7829
{
7830
  //
7831
  // Get the forwarder cookie.
7832
  //
7833
7834
  if (*authCookie == '\0')
7835
  {
7836
    #ifdef TEST
7837
    *logofs << "Loop: No authentication cookie required "
7838
            << "from FD#" << fd << ".\n" << logofs_flush;
7839
    #endif
7840
7841
    return 1;
7842
  }
7843
7844
  char options[DEFAULT_REMOTE_OPTIONS_LENGTH];
7845
7846
  int result = ReadRemoteData(fd, options, sizeof(options), ' ');
7847
7848
  if (result <= 0)
7849
  {
7850
    return result;
7851
  }
7852
7853
  #ifdef TEST
7854
  *logofs << "Loop: Received forwarder options string '"
7855
          << options << "' from FD#" << fd << ".\n"
7856
          << logofs_flush;
7857
  #endif
7858
7859
  if (ParseForwarderOptions(options) < 0)
7860
  {
7861
    #ifdef PANIC
7862
    *logofs << "Loop: PANIC! Couldn't negotiate a valid "
7863
            << "cookie with the NX forwarder.\n"
7864
            << logofs_flush;
7865
    #endif
7866
7867
    cerr << "Error" << ": Couldn't negotiate a valid "
7868
         << "cookie with the NX forwarder.\n";
7869
7870
    return -1;
7871
  }
7872
7873
  return 1;
7874
}
7875
7876
int ReadRemoteData(int fd, char *buffer, int size, char stop)
7877
{
7878
  #ifdef TEST
7879
  *logofs << "Loop: Going to read remote data from FD#"
7880
          << fd << ".\n" << logofs_flush;
7881
  #endif
7882
7883
  if (size >= MAXIMUM_REMOTE_OPTIONS_LENGTH)
7884
  {
7885
    #ifdef PANIC
7886
    *logofs << "Loop: PANIC! Maximum remote options buffer "
7887
            << "limit exceeded.\n" << logofs_flush;
7888
    #endif
7889
7890
    cerr << "Error" << ": Maximum remote options buffer "
7891
         << "limit exceeded.\n";
7892
7893
    HandleCleanup();
7894
  }
7895
7896
  while (remotePosition < (size - 1))
7897
  {
7898
    int result = read(fd, remoteData + remotePosition, 1);
7899
7900
    getNewTimestamp();
7901
7902
    if (result <= 0)
7903
    {
7904
      if (result == -1)
7905
      {
7906
        if (EGET() == EAGAIN)
7907
        {
7908
          #ifdef TEST
7909
          *logofs << "Loop: Reading data from FD#" << fd
7910
                  << " would block.\n" << logofs_flush;
7911
          #endif
7912
7913
          return 0;
7914
        }
7915
        else if (EGET() == EINTR)
7916
        {
7917
          if (CheckAbort() != 0)
7918
          {
7919
            return -1;
7920
          }
7921
7922
          continue;
7923
        }
7924
      }
7925
7926
      #ifdef PANIC
7927
      *logofs << "Loop: PANIC! The remote NX proxy closed "
7928
              << "the connection.\n" << logofs_flush;
7929
      #endif
7930
7931
      cerr << "Error" << ": The remote NX proxy closed "
7932
           << "the connection.\n";
7933
7934
      return -1;
7935
    }
7936
    else if (*(remoteData + remotePosition) == stop)
7937
    {
7938
      #ifdef TEST
7939
      *logofs << "Loop: Read stop character from FD#"
7940
              << fd << ".\n" << logofs_flush;
7941
      #endif
7942
7943
      remotePosition++;
7944
7945
      //
7946
      // Copy the fake terminating null
7947
      // in the buffer.
7948
      //
7949
7950
      *(remoteData + remotePosition) = '\0';
7951
7952
      memcpy(buffer, remoteData, remotePosition + 1);
7953
7954
      #ifdef TEST
7955
      *logofs << "Loop: Remote string '" << remoteData
7956
              << "' read from FD#" << fd << ".\n"
7957
              << logofs_flush;
7958
      #endif
7959
7960
      int t = remotePosition;
7961
7962
      remotePosition = 0;
7963
7964
      return t;
7965
    }
7966
    else
7967
    {
7968
      //
7969
      // Make sure string received
7970
      // from far end is printable.
7971
      //
7972
7973
      if (isgraph(*(remoteData + remotePosition)) == 0)
7974
      {
7975
        #ifdef WARNING
7976
        *logofs << "Loop: WARNING! Non printable character decimal '"
7977
                << (unsigned int) *(remoteData + remotePosition)
7978
                << "' received in remote data from FD#"
7979
                << fd << ".\n" << logofs_flush;
7980
        #endif
7981
7982
        cerr << "Warning" << ": Non printable character decimal '"
7983
                << (unsigned int) *(remoteData + remotePosition)
7984
                << "' received in remote data from FD#"
7985
                << fd << ".\n" << logofs_flush;
7986
7987
        *(remoteData + remotePosition) = ' ';
7988
      }
7989
7990
      #ifdef DEBUG
7991
      *logofs << "Loop: Read a further character "
7992
              << "from FD#" << fd << ".\n"
7993
              << logofs_flush;
7994
      #endif
7995
7996
      remotePosition++;
7997
    }
7998
  }
7999
8000
  *(remoteData + remotePosition) = '\0';
8001
8002
  #ifdef PANIC
8003
  *logofs << "Loop: PANIC! Stop character missing "
8004
          << "from FD#" << fd << " after " << remotePosition 
8005
          << " characters read in string '" << remoteData
8006
          << "'.\n" << logofs_flush;
8007
  #endif
8008
8009
  cerr << "Error" << ": Stop character missing "
8010
       << "from FD#" << fd << " after " << remotePosition 
8011
       << " characters read in string '" << remoteData
8012
       << "'.\n";
8013
8014
  memcpy(buffer, remoteData, remotePosition);
8015
8016
  remotePosition = 0;
8017
8018
  return -1;
8019
}
8020
8021
int WriteLocalData(int fd, const char *buffer, int size)
8022
{
8023
  int position = 0;
8024
8025
  while (position < size)
8026
  {
8027
    int result = write(fd, buffer + position, size - position);
8028
8029
    getNewTimestamp();
8030
8031
    if (result <= 0)
8032
    {
8033
      if (result < 0 && EGET() == EINTR)
8034
      {
8035
        continue;
8036
      }
8037
8038
      #ifdef TEST
8039
      *logofs << "Loop: Error writing data to FD#"
8040
              << fd << ".\n" << logofs_flush;
8041
      #endif
8042
8043
      return -1;
8044
    }
8045
8046
    position += result;
8047
  }
8048
8049
  return position;
8050
}
8051
8052
//
8053
// Parse the string passed by calling process in
8054
// the environment. This is not necessarily the
8055
// content of DISPLAY variable, but can be the
8056
// parameters passed when creating the process
8057
// or thread.
8058
//
8059
8060
int ParseEnvironmentOptions(const char *env, int force)
8061
{
8062
  //
8063
  // Be sure log file is valid.
8064
  //
8065
8066
  if (logofs == NULL)
8067
  {
8068
    logofs = &cerr;
8069
  }
8070
8071
  //
8072
  // Be sure we have a parameters repository
8073
  // and a context to jump into because this
8074
  // can be called before creating the proxy.
8075
  //
8076
8077
  if (control == NULL)
8078
  {
8079
    control = new Control();
8080
  }
8081
8082
  if (setjmp(context) == 1)
8083
  {
8084
    #ifdef TEST
8085
    *logofs << "Loop: Out of the long jump while parsing "
8086
            << "the environment options.\n"
8087
            << logofs_flush;
8088
    #endif
8089
    
8090
    return -1;
8091
  }
8092
8093
  if (force == 0 && parsedOptions == 1)
8094
  {
8095
    #ifdef TEST
8096
    *logofs << "Loop: Skipping a further parse of environment "
8097
            << "options string '" << (env != NULL ? env : "")
8098
            << "'.\n" << logofs_flush;
8099
    #endif
8100
8101
    return 1;
8102
  }
8103
8104
  if (env == NULL || *env == '\0')
8105
  {
8106
    #ifdef TEST
8107
    *logofs << "Loop: Nothing to do with empty environment "
8108
            << "options string '" << (env != NULL ? env : "")
8109
            << "'.\n" << logofs_flush;
8110
    #endif
8111
8112
    return 0;
8113
  }
8114
8115
  #ifdef TEST
8116
  *logofs << "Loop: Going to parse the environment options "
8117
          << "string '" << env << "'.\n"
8118
          << logofs_flush;
8119
  #endif
8120
8121
  parsedOptions = 1;
8122
8123
  //
8124
  // Copy the string passed as parameter
8125
  // because we need to modify it.
8126
  //
8127
8128
  char opts[DEFAULT_DISPLAY_OPTIONS_LENGTH];
8129
8130
  #ifdef VALGRIND
8131
8132
  memset(opts, '\0', DEFAULT_DISPLAY_OPTIONS_LENGTH);
8133
8134
  #endif
8135
8136
  if (strlen(env) >= DEFAULT_DISPLAY_OPTIONS_LENGTH)
8137
  {
8138
    #ifdef PANIC
8139
    *logofs << "Loop: PANIC! Environment options string '" << env
8140
            << "' exceeds length of " << DEFAULT_DISPLAY_OPTIONS_LENGTH
8141
            << " characters.\n" << logofs_flush;
8142
    #endif
8143
8144
    cerr << "Error" << ": Environment options string '" << env
8145
         << "' exceeds length of " << DEFAULT_DISPLAY_OPTIONS_LENGTH
8146
         << " characters.\n";
8147
8148
    return -1;
8149
  }
8150
8151
  strcpy(opts, env);
8152
8153
  char *nextOpts = opts;
8154
8155
  //
8156
  // Ensure that DISPLAY environment variable
8157
  // (roughly) follows the X convention for
8158
  // transport notation.
8159
  //
8160
8161
  if (strncasecmp(opts, "nx/nx,:", 7) == 0 ||
8162
          strncasecmp(opts, "nx,:", 4) == 0)
8163
  {
8164
    #ifdef PANIC
8165
    *logofs << "Loop: PANIC! Parse error in options string '"
8166
            << opts << "' at 'nx,:'.\n" << logofs_flush;
8167
    #endif
8168
8169
    cerr << "Error" << ": Parse error in options string '"
8170
         << opts << "' at 'nx,:'.\n";
8171
8172
    return -1;
8173
  }
8174
  else if (strncasecmp(opts, "nx/nx,", 6) == 0)
8175
  {
8176
    nextOpts += 6;
8177
  }
8178
  else if (strncasecmp(opts, "nx,", 3) == 0)
8179
  {
8180
    nextOpts += 3;
8181
  }
8182
  else if (strncasecmp(opts, "nx:", 3) == 0)
8183
  {
8184
    nextOpts += 3;
8185
  }
8186
  else if (force == 0)
8187
  {
8188
    #ifdef TEST
8189
    *logofs << "Loop: Ignoring host X server display string '"
8190
            << opts << "'.\n" << logofs_flush;
8191
    #endif
8192
8193
    return 0;
8194
  }
8195
8196
  //
8197
  // Save here the name of the options file and
8198
  // parse it after all the other options.
8199
  //
8200
8201
  char fileOptions[DEFAULT_STRING_LENGTH] = { 0 };
8202
8203
  //
8204
  // The options string is intended to be a series
8205
  // of name/value tuples in the form name=value
8206
  // separated by the ',' character ended by a ':'
8207
  // followed by remote NX proxy port.
8208
  //
8209
8210
  char *name;
8211
  char *value;
8212
8213
  value = rindex(nextOpts, ':');
8214
8215
  if (value != NULL)
8216
  {
8217
    char *check = value + 1;
8218
8219
    if (*check == '\0' || isdigit(*check) == 0)
8220
    {
8221
      #ifdef PANIC
8222
      *logofs << "Loop: PANIC! Can't identify NX port in string '"
8223
              << value << "'.\n" << logofs_flush;
8224
      #endif
8225
8226
      cerr << "Error" << ": Can't identify NX port in string '"
8227
           << value << "'.\n";
8228
8229
      return -1;
8230
    }
8231
8232
    proxyPort = atoi(check);
8233
8234
    //
8235
    // Get rid of the port specification.
8236
    //
8237
8238
    *value = '\0';
8239
  }
8240
  else if (proxyPort == DEFAULT_NX_PROXY_PORT && force == 0)
8241
  {
8242
    //
8243
    // Complain only if user didn't specify
8244
    // the port on the command line.
8245
    //
8246
8247
    #ifdef PANIC
8248
    *logofs << "Loop: PANIC! Can't identify NX port in string '"
8249
            << opts << "'.\n" << logofs_flush;
8250
    #endif
8251
8252
    cerr << "Error" << ": Can't identify NX port in string '"
8253
         << opts << "'.\n";
8254
8255
    return -1;
8256
  }
8257
8258
  #ifdef TEST
8259
  *logofs << "Loop: Parsing options string '"
8260
          << nextOpts << "'.\n" << logofs_flush;
8261
  #endif
8262
8263
  //
8264
  // Now all the other optional parameters.
8265
  //
8266
8267
  name = strtok(nextOpts, "=");
8268
8269
  while (name)
8270
  {
8271
    value = strtok(NULL, ",");
8272
8273
    if (CheckArg("environment", name, value) < 0)
8274
    {
8275
      return -1;
8276
    }
8277
8278
    if (strcasecmp(name, "options") == 0)
8279
    {
8280
      strncpy(fileOptions, value, DEFAULT_STRING_LENGTH - 1);
8281
    }
8282
    else if (strcasecmp(name, "display") == 0)
8283
    {
8284
      strncpy(displayHost, value, DEFAULT_STRING_LENGTH - 1);
8285
    }
8286
    else if (strcasecmp(name, "link") == 0)
8287
    {
8288
      if (control -> ProxyMode == proxy_server)
8289
      {
8290
        PrintOptionIgnored("local", name, value);
8291
      }
8292
      else if (ParseLinkOption(value) < 0)
8293
      {
8294
        #ifdef PANIC
8295
        *logofs << "Loop: PANIC! Can't identify 'link' option in string '"
8296
                << value << "'.\n" << logofs_flush;
8297
        #endif
8298
8299
        cerr << "Error" << ": Can't identify 'link' option in string '"
8300
             << value << "'.\n";
8301
8302
        return -1;
8303
      }
8304
    }
8305
    else if (strcasecmp(name, "limit") == 0)
8306
    {
8307
      if (control -> ProxyMode == proxy_server)
8308
      {
8309
        PrintOptionIgnored("local", name, value);
8310
      }
8311
      else if (ParseBitrateOption(value) < 0)
8312
      {
8313
        #ifdef PANIC
8314
        *logofs << "Loop: PANIC! Can't identify option 'limit' in string '"
8315
                << value << "'.\n" << logofs_flush;
8316
        #endif
8317
8318
        cerr << "Error" << ": Can't identify option 'limit' in string '"
8319
             << value << "'.\n";
8320
8321
        return -1;
8322
      }
8323
    }
8324
    else if (strcasecmp(name, "type") == 0)
8325
    {
8326
      //
8327
      // Type of session, for example "desktop",
8328
      // "application", "windows", etc.
8329
      //
8330
8331
      if (control -> ProxyMode == proxy_server)
8332
      {
8333
        PrintOptionIgnored("local", name, value);
8334
      }
8335
      else
8336
      {
8337
        if (strcasecmp(value, "default") == 0)
8338
        {
8339
          *sessionType = '\0';
8340
        }
8341
        else
8342
        {
8343
          strncpy(sessionType, value, DEFAULT_STRING_LENGTH - 1);
8344
        }
8345
      }
8346
    }
8347
    else if (strcasecmp(name, "listen") == 0)
8348
    {
8349
      if (*connectHost != '\0')
8350
      {
8351
        #ifdef PANIC
8352
        *logofs << "Loop: PANIC! Can't handle 'listen' and 'connect' parameters "
8353
                << "at the same time.\n" << logofs_flush;
8354
8355
        *logofs << "Loop: PANIC! Refusing 'listen' parameter with 'connect' being '"
8356
                << connectHost << "'.\n" << logofs_flush;
8357
        #endif
8358
8359
        cerr << "Error" << ": Can't handle 'listen' and 'connect' parameters "
8360
             << "at the same time.\n";
8361
8362
        cerr << "Error" << ": Refusing 'listen' parameter with 'connect' being '"
8363
             << connectHost << "'.\n";
8364
8365
        return -1;
8366
      }
8367
8368
      listenPort = ValidateArg("local", name, value);
8369
    }
8370
    else if (strcasecmp(name, "accept") == 0)
8371
    {
8372
      if (*connectHost != '\0')
8373
      {
8374
        #ifdef PANIC
8375
        *logofs << "Loop: PANIC! Can't handle 'accept' and 'connect' parameters "
8376
                << "at the same time.\n" << logofs_flush;
8377
8378
        *logofs << "Loop: PANIC! Refusing 'accept' parameter with 'connect' being '"
8379
                << connectHost << "'.\n" << logofs_flush;
8380
        #endif
8381
8382
        cerr << "Error" << ": Can't handle 'accept' and 'connect' parameters "
8383
             << "at the same time.\n";
8384
8385
        cerr << "Error" << ": Refusing 'accept' parameter with 'connect' being '"
8386
             << connectHost << "'.\n";
8387
8388
        return -1;
8389
      }
8390
8391
      strncpy(acceptHost, value, DEFAULT_STRING_LENGTH - 1);
8392
    }
8393
    else if (strcasecmp(name, "connect") == 0)
8394
    {
8395
      if (*acceptHost != '\0')
8396
      {
8397
        #ifdef PANIC
8398
        *logofs << "Loop: PANIC! Can't handle 'connect' and 'accept' parameters "
8399
                << "at the same time.\n" << logofs_flush;
8400
8401
        *logofs << "Loop: PANIC! Refusing 'connect' parameter with 'accept' being '"
8402
                << acceptHost << "'.\n" << logofs_flush;
8403
        #endif
8404
8405
        cerr << "Error" << ": Can't handle 'connect' and 'accept' parameters "
8406
             << "at the same time.\n";
8407
8408
        cerr << "Error" << ": Refusing 'connect' parameter with 'accept' being '"
8409
             << acceptHost << "'.\n";
8410
8411
        return -1;
8412
      }
8413
8414
      strncpy(connectHost, value, DEFAULT_STRING_LENGTH - 1);
8415
    }
8416
    else if (strcasecmp(name, "port") == 0)
8417
    {
8418
      connectPort = ValidateArg("local", name, value);
8419
    }
8420
    else if (strcasecmp(name, "retry") == 0)
8421
    {
8422
      control -> OptionProxyRetryConnect  = ValidateArg("local", name, value);
8423
      control -> OptionServerRetryConnect = ValidateArg("local", name, value);
8424
    }
8425
    else if (strcasecmp(name, "session") == 0)
8426
    {
8427
      strncpy(sessionFileName, value, DEFAULT_STRING_LENGTH - 1);
8428
    }
8429
    else if (strcasecmp(name, "errors") == 0)
8430
    {
8431
      //
8432
      // The old name of the parameter was 'log'
8433
      // but the default name for the file is
8434
      // 'errors' so it is more logical to use
8435
      // the same name.
8436
      //
8437
8438
      strncpy(errorsFileName, value, DEFAULT_STRING_LENGTH - 1);
8439
    }
8440
    else if (strcasecmp(name, "root") == 0)
8441
    {
8442
      strncpy(rootDir, value, DEFAULT_STRING_LENGTH - 1);
8443
    }
8444
    else if (strcasecmp(name, "id") == 0)
8445
    {
8446
      strncpy(sessionId, value, DEFAULT_STRING_LENGTH - 1);
8447
    }
8448
    else if (strcasecmp(name, "stats") == 0)
8449
    {
8450
      control -> EnableStatistics = 1;
8451
8452
      strncpy(statsFileName, value, DEFAULT_STRING_LENGTH - 1);
8453
    }
8454
    else if (strcasecmp(name, "cookie") == 0)
8455
    {
8456
      LowercaseArg("local", name, value);
8457
8458
      strncpy(authCookie, value, DEFAULT_STRING_LENGTH - 1);
8459
    }
8460
    else if (strcasecmp(name, "nodelay") == 0)
8461
    {
8462
      useNoDelay = ValidateArg("local", name, value);
8463
    }
8464
    else if (strcasecmp(name, "policy") == 0)
8465
    {
8466
      if (control -> ProxyMode == proxy_server)
8467
      {
8468
        PrintOptionIgnored("local", name, value);
8469
      }
8470
      else
8471
      {
8472
        usePolicy = ValidateArg("local", name, value);
8473
      }
8474
    }
8475
    else if (strcasecmp(name, "render") == 0)
8476
    {
8477
      if (control -> ProxyMode == proxy_server)
8478
      {
8479
        PrintOptionIgnored("local", name, value);
8480
      }
8481
      else
8482
      {
8483
        useRender = ValidateArg("local", name, value);
8484
      }
8485
    }
8486
    else if (strcasecmp(name, "taint") == 0)
8487
    {
8488
      if (control -> ProxyMode == proxy_server)
8489
      {
8490
        PrintOptionIgnored("local", name, value);
8491
      }
8492
      else
8493
      {
8494
        useTaint = ValidateArg("local", name, value);
8495
      }
8496
    }
8497
    else if (strcasecmp(name, "delta") == 0)
8498
    {
8499
      if (control -> ProxyMode == proxy_server)
8500
      {
8501
        PrintOptionIgnored("local", name, value);
8502
      }
8503
      else
8504
      {
8505
        control -> LocalDeltaCompression = ValidateArg("local", name, value);
8506
      }
8507
    }
8508
    else if (strcasecmp(name, "data") == 0)
8509
    {
8510
      control -> LocalDataCompressionLevel = ValidateArg("local", name, value);
8511
8512
      if (control -> LocalDataCompressionLevel == 0)
8513
      {
8514
        control -> LocalDataCompression = 0;
8515
      }
8516
      else
8517
      {
8518
        control -> LocalDataCompression = 1;
8519
      }
8520
    }
8521
    else if (strcasecmp(name, "stream") == 0)
8522
    {
8523
      control -> LocalStreamCompressionLevel = ValidateArg("local", name, value);
8524
8525
      if (control -> LocalStreamCompressionLevel == 0)
8526
      {
8527
        control -> LocalStreamCompression = 0;
8528
      }
8529
      else
8530
      {
8531
        control -> LocalStreamCompression = 1;
8532
      }
8533
    }
8534
    else if (strcasecmp(name, "memory") == 0)
8535
    {
8536
      control -> LocalMemoryLevel = ValidateArg("local", name, value);
8537
    }
8538
    else if (strcasecmp(name, "cache") == 0)
8539
    {
8540
      if (control -> ProxyMode == proxy_server)
8541
      {
8542
        PrintOptionIgnored("local", name, value);
8543
      }
8544
      else if (ParseCacheOption(value) < 0)
8545
      {
8546
        #ifdef PANIC
8547
        *logofs << "Loop: PANIC! Can't identify cache size for string '"
8548
                << value << "'.\n" << logofs_flush;
8549
        #endif
8550
8551
        cerr << "Error" << ": Can't identify cache size for string '"
8552
             << value << "'.\n";
8553
8554
        return -1;
8555
      }
8556
    }
8557
    else if (strcasecmp(name, "images") == 0)
8558
    {
8559
      if (control -> ProxyMode == proxy_server)
8560
      {
8561
        PrintOptionIgnored("local", name, value);
8562
      }
8563
      else if (ParseImagesOption(value) < 0)
8564
      {
8565
        #ifdef PANIC
8566
        *logofs << "Loop: PANIC! Can't identify images cache size for string '"
8567
                << value << "'.\n" << logofs_flush;
8568
        #endif
8569
8570
        cerr << "Error" << ": Can't identify images cache size for string '"
8571
             << value << "'.\n";
8572
8573
        return -1;
8574
      }
8575
    }
8576
    else if (strcasecmp(name, "shseg") == 0)
8577
    {
8578
      //
8579
      // The 'shmem' option is used by the agent, together
8580
      // with 'shpix' literal. We make the 'shseg' option
8581
      // specific to the proxy and use it to determine the
8582
      // size of the shared memory segment, or otherwise 0,
8583
      // if the use of the shared memory extension should
8584
      // not be enabled on the real X server.
8585
      //
8586
 
8587
      if (control -> ProxyMode == proxy_server)
8588
      {
8589
        PrintOptionIgnored("local", name, value);
8590
      }
8591
      else if (ParseShmemOption(value) < 0)
8592
      {
8593
        #ifdef PANIC
8594
        *logofs << "Loop: PANIC! Can't identify size of shared memory "
8595
                << "segment in string '" << value << "'.\n"
8596
                << logofs_flush;
8597
        #endif
8598
8599
        cerr << "Error" << ": Can't identify size of shared memory "
8600
             << "segment in string '" << value << "'.\n";
8601
8602
        return -1;
8603
      }
8604
    }
8605
    else if (strcasecmp(name, "load") == 0)
8606
    {
8607
      if (control -> ProxyMode == proxy_server)
8608
      {
8609
        PrintOptionIgnored("local", name, value);
8610
      }
8611
      else
8612
      {
8613
        control -> PersistentCacheEnableLoad = ValidateArg("local", name, value);
8614
8615
        if (control -> PersistentCacheEnableLoad > 0)
8616
        {
8617
          control -> PersistentCacheEnableLoad = 1;
8618
        }
8619
        else
8620
        {
8621
          if (control -> PersistentCacheName != NULL)
8622
          {
8623
            delete [] control -> PersistentCacheName;
8624
          }
8625
8626
          control -> PersistentCacheName = NULL;
8627
8628
          control -> PersistentCacheEnableLoad = 0;
8629
        }
8630
      }
8631
    }
8632
    else if (strcasecmp(name, "save") == 0)
8633
    {
8634
      if (control -> ProxyMode == proxy_server)
8635
      {
8636
        PrintOptionIgnored("local", name, value);
8637
      }
8638
      else
8639
      {
8640
        control -> PersistentCacheEnableSave = ValidateArg("local", name, value);
8641
8642
        if (control -> PersistentCacheEnableSave > 0)
8643
        {
8644
          control -> PersistentCacheEnableSave = 1;
8645
        }
8646
        else
8647
        {
8648
          if (control -> PersistentCacheName != NULL)
8649
          {
8650
            delete [] control -> PersistentCacheName;
8651
          }
8652
8653
          control -> PersistentCacheName = NULL;
8654
8655
          control -> PersistentCacheEnableSave = 0;
8656
        }
8657
      }
8658
    }
8659
    else if (strcasecmp(name, "cups") == 0)
8660
    {
8661
      cupsPort = ValidateArg("local", name, value);
8662
    }
8663
    else if (strcasecmp(name, "sync") == 0)
8664
    {
8665
      #ifdef WARNING
8666
      *logofs << "Loop: WARNING! No 'sync' channel in current version. "
8667
              << "Assuming 'cups' channel.\n" << logofs_flush;
8668
      #endif
8669
8670
      cerr << "Warning" << ": No 'sync' channel in current version. "
8671
           << "Assuming 'cups' channel.\n";
8672
8673
      cupsPort = ValidateArg("local", name, value);
8674
    }
8675
    else if (strcasecmp(name, "keybd") == 0 ||
8676
                 strcasecmp(name, "aux") == 0)
8677
    {
8678
      auxPort = ValidateArg("local", name, value);
8679
    }
8680
    else if (strcasecmp(name, "samba") == 0 ||
8681
                 strcasecmp(name, "smb") == 0)
8682
    {
8683
      smbPort = ValidateArg("local", name, value);
8684
    }
8685
    else if (strcasecmp(name, "media") == 0)
8686
    {
8687
      mediaPort = ValidateArg("local", name, value);
8688
    }
8689
    else if (strcasecmp(name, "http") == 0)
8690
    {
8691
      httpPort = ValidateArg("local", name, value);
8692
    }
8693
    else if (strcasecmp(name, "font") == 0)
8694
    {
8695
      strncpy(fontPort, value, DEFAULT_STRING_LENGTH - 1);
8696
    }
8697
    else if (strcasecmp(name, "slave") == 0)
8698
    {
8699
      slavePort = ValidateArg("local", name, value);
8700
    }
8701
    else if (strcasecmp(name, "mask") == 0)
8702
    {
8703
      control -> ChannelMask = ValidateArg("local", name, value);
8704
    }
8705
    else if (strcasecmp(name, "timeout") == 0)
8706
    {
8707
      int timeout = ValidateArg("local", name, value);
8708
8709
      if (timeout == 0)
8710
      {
8711
        #ifdef TEST
8712
        *logofs << "Loop: Disabling timeout on broken "
8713
                << "proxy connection.\n" << logofs_flush;
8714
        #endif
8715
8716
        control -> ProxyTimeout = 0;
8717
      }
8718
      else
8719
      {
8720
        control -> ProxyTimeout = timeout * 1000;
8721
      }
8722
    }
8723
    else if (strcasecmp(name, "cleanup") == 0)
8724
    {
8725
      int cleanup = ValidateArg("local", name, value);
8726
8727
      if (cleanup == 0)
8728
      {
8729
        #ifdef TEST
8730
        *logofs << "Loop: Disabling grace timeout on "
8731
                << "proxy shutdown.\n" << logofs_flush;
8732
        #endif
8733
8734
        control -> CleanupTimeout = 0;
8735
      }
8736
      else
8737
      {
8738
        control -> CleanupTimeout = cleanup * 1000;
8739
      }
8740
    }
8741
    else if (strcasecmp(name, "pack") == 0)
8742
    {
8743
      if (control -> ProxyMode == proxy_server)
8744
      {
8745
        PrintOptionIgnored("local", name, value);
8746
      }
8747
      else if (ParsePackOption(value) < 0)
8748
      {
8749
        #ifdef PANIC
8750
        *logofs << "Loop: PANIC! Can't identify pack method for string '"
8751
                << value << "'.\n" << logofs_flush;
8752
        #endif
8753
8754
        cerr << "Error" << ": Can't identify pack method for string '"
8755
             << value << "'.\n";
8756
8757
        return -1;
8758
      }
8759
    }
8760
    else if (strcasecmp(name, "core") == 0)
8761
    {
8762
      control -> EnableCoreDumpOnAbort = ValidateArg("local", name, value);
8763
    }
8764
    else if (strcasecmp(name, "kill") == 0)
8765
    {
8766
      if (control -> KillDaemonOnShutdownNumber <
8767
              control -> KillDaemonOnShutdownLimit)
8768
      {
8769
        #ifdef TEST
8770
        *logofs << "Loop: WARNING! Adding process with pid '"
8771
                << ValidateArg("local", name, value) << " to the "
8772
                << "daemons to kill at shutdown.\n"
8773
                << logofs_flush;
8774
        #endif
8775
8776
        control -> KillDaemonOnShutdown[control ->
8777
                       KillDaemonOnShutdownNumber] =
8778
                           ValidateArg("local", name, value);
8779
8780
        control -> KillDaemonOnShutdownNumber++;
8781
      }
8782
      else
8783
      {
8784
        #ifdef WARNING
8785
        *logofs << "Loop: WARNING! Number of daemons to kill "
8786
                << "at shutdown exceeded.\n" << logofs_flush;
8787
        #endif
8788
8789
        cerr << "Warning" << ": Number of daemons to kill "
8790
             << "at shutdown exceeded.\n";
8791
      }
8792
    }
8793
    else if (strcasecmp(name, "strict") == 0)
8794
    {
8795
      if (control -> ProxyMode == proxy_server)
8796
      {
8797
        PrintOptionIgnored("local", name, value);
8798
      }
8799
      else
8800
      {
8801
        useStrict = ValidateArg("local", name, value);
8802
      }
8803
    }
8804
    else if (strcasecmp(name, "encryption") == 0)
8805
    {
8806
      useEncryption = ValidateArg("local", name, value);
8807
    }
8808
    else if (strcasecmp(name, "product") == 0)
8809
    {
8810
      strncpy(productName, value, DEFAULT_STRING_LENGTH - 1);
8811
    }
8812
    else if (strcasecmp(name, "rootless") == 0 ||
8813
                 strcasecmp(name, "geometry") == 0 ||
8814
                     strcasecmp(name, "resize") == 0 ||
8815
                         strcasecmp(name, "fullscreen") == 0 ||
8816
                             strcasecmp(name, "keyboard") == 0 ||
8817
                                 strcasecmp(name, "clipboard") == 0 ||
8818
                                     strcasecmp(name, "streaming") == 0 ||
8819
                                         strcasecmp(name, "backingstore") == 0)
8820
    {
8821
      #ifdef DEBUG
8822
      *logofs << "Loop: Ignoring agent option '" << name
8823
              << "' with value '" << value << "'.\n"
8824
              << logofs_flush;
8825
      #endif
8826
    }
8827
    else if (strcasecmp(name, "composite") == 0 ||
8828
                 strcasecmp(name, "shmem") == 0 ||
8829
                     strcasecmp(name, "shpix") == 0 ||
8830
                         strcasecmp(name, "kbtype") == 0 ||
8831
                             strcasecmp(name, "client") == 0 ||
8832
                                 strcasecmp(name, "shadow") == 0 ||
8833
                                     strcasecmp(name, "shadowuid") == 0 ||
8834
                                         strcasecmp(name, "shadowmode") == 0 ||
8835
                                             strcasecmp(name, "clients") == 0)
8836
    {
8837
      #ifdef DEBUG
8838
      *logofs << "Loop: Ignoring agent option '" << name
8839
              << "' with value '" << value << "'.\n"
8840
              << logofs_flush;
8841
      #endif
8842
    }
8843
    else if (strcasecmp(name, "defer") == 0 ||
8844
                 strcasecmp(name, "tile") == 0 ||
8845
                     strcasecmp(name, "menu") == 0)
8846
    {
8847
      #ifdef DEBUG
8848
      *logofs << "Loop: Ignoring agent option '" << name
8849
              << "' with value '" << value << "'.\n"
8850
              << logofs_flush;
8851
      #endif
8852
    }
8853
    else
8854
    {
8855
      #ifdef WARNING
8856
      *logofs << "Loop: WARNING! Ignoring unknown option '"
8857
              << name << "' with value '" << value << "'.\n"
8858
              << logofs_flush;
8859
      #endif
8860
8861
      cerr << "Warning" << ": Ignoring unknown option '"
8862
           << name << "' with value '" << value << "'.\n";
8863
    }
8864
8865
    name = strtok(NULL, "=");
8866
8867
  } // End of while (name) ...
8868
8869
  #ifdef TEST
8870
  *logofs << "Loop: Completed parsing of string '"
8871
          << env << "'.\n" << logofs_flush;
8872
  #endif
8873
8874
  if (*fileOptions != '\0')
8875
  {
8876
    if (strcmp(fileOptions, optionsFileName) != 0)
8877
    {
8878
      #ifdef TEST
8879
      *logofs << "Loop: Reading options from '" << fileOptions
8880
              << "'.\n" << logofs_flush;
8881
      #endif
8882
8883
      if (ParseFileOptions(fileOptions) < 0)
8884
      {
8885
        return -1;
8886
      }
8887
    }
8888
    #ifdef WARNING
8889
    else
8890
    {
8891
      *logofs << "Loop: WARNING! Name of the options file "
8892
              << "specified multiple times. Not parsing "
8893
              << "again.\n" << logofs_flush;
8894
    }
8895
    #endif
8896
8897
    if (*optionsFileName == '\0')
8898
    {
8899
      strncpy(optionsFileName, value, DEFAULT_STRING_LENGTH - 1);
8900
8901
      #ifdef TEST
8902
      *logofs << "Loop: Assuming name of options file '"
8903
              << optionsFileName << "'.\n"
8904
              << logofs_flush;
8905
      #endif
8906
    }
8907
  }
8908
8909
  //
8910
  // If port where proxy is acting as an X server
8911
  // was not specified assume the same port where
8912
  // proxy is listening for the remote peer.
8913
  //
8914
8915
  if (xPort == DEFAULT_NX_X_PORT)
8916
  {
8917
    xPort = proxyPort;
8918
  }
8919
8920
  return 1;
8921
}
8922
8923
//
8924
// Parse the command line options passed by user when
8925
// running proxy in stand alone mode. Note that passing
8926
// parameters this way is strongly discouraged. These
8927
// command line switch can change (and they do often).
8928
// Please, use the form "option=value" instead and set
8929
// the DISPLAY environment variable.
8930
//
8931
8932
int ParseCommandLineOptions(int argc, const char **argv)
8933
{
8934
  //
8935
  // Be sure log file is valid.
8936
  //
8937
8938
  if (logofs == NULL)
8939
  {
8940
    logofs = &cerr;
8941
  }
8942
8943
  if (setjmp(context) == 1)
8944
  {
8945
    #ifdef TEST
8946
    *logofs << "Loop: Out of the long jump while parsing "
8947
            << "the command line options.\n"
8948
            << logofs_flush;
8949
    #endif
8950
    
8951
    return -1;
8952
  }
8953
8954
  //
8955
  // Be sure we have a parameters repository
8956
  //
8957
8958
  if (control == NULL)
8959
  {
8960
    control = new Control();
8961
  }
8962
8963
  if (parsedCommand == 1)
8964
  {
8965
    #ifdef TEST
8966
    *logofs << "Loop: Skipping a further parse of command line options.\n"
8967
            << logofs_flush;
8968
    #endif
8969
8970
    return 1;
8971
  }
8972
8973
  #ifdef TEST
8974
  *logofs << "Loop: Going to parse the command line options.\n"
8975
          << logofs_flush;
8976
  #endif
8977
8978
  parsedCommand = 1;
8979
8980
  //
8981
  // Print out arguments.
8982
  //
8983
8984
  #ifdef TEST
8985
8986
  *logofs << "Loop: Argc is " << argc << ".\n" << logofs_flush;
8987
8988
  for (int argi = 0; argi < argc; argi++)
8989
  {
8990
    *logofs << "Loop: Argv[" << argi << "] is " << argv[argi]
8991
            << ".\n" << logofs_flush;
8992
  }
8993
8994
  #endif
8995
8996
  //
8997
  // Shall use getopt here.
8998
  //
8999
9000
  for (int argi = 1; argi < argc; argi++)
9001
  {
9002
    const char *nextArg = argv[argi];
9003
9004
    if (*nextArg == '-')
9005
    {
9006
      switch (*(nextArg + 1))
9007
      {
9008
        case 'h':
9009
        {
9010
          PrintUsageInfo(nextArg, 0);
9011
9012
          return -1;
9013
        }
9014
        case 'C':
9015
        {
9016
          //
9017
          // Start proxy in CLIENT mode.
9018
          //
9019
9020
          if (WE_SET_PROXY_MODE == 0)
9021
          {
9022
            #ifdef TEST
9023
            *logofs << "Loop: Setting local proxy mode to proxy_client.\n"
9024
                    << logofs_flush;
9025
            #endif
9026
9027
            control -> ProxyMode = proxy_client;
9028
          }
9029
          else if (control -> ProxyMode != proxy_client)
9030
          {
9031
            #ifdef PANIC
9032
            *logofs << "Loop: PANIC! Can't redefine local proxy to "
9033
                    << "client mode.\n" << logofs_flush;
9034
            #endif
9035
9036
            cerr << "Error" << ": Can't redefine local proxy to "
9037
                 << "client mode.\n";
9038
9039
            return -1;
9040
          }
9041
9042
          break;
9043
        }
9044
        case 'S':
9045
        {
9046
          //
9047
          // Start proxy in SERVER mode.
9048
          //
9049
9050
          if (WE_SET_PROXY_MODE == 0)
9051
          {
9052
            #ifdef TEST
9053
            *logofs << "Loop: Setting local proxy mode to proxy_server.\n"
9054
                    << logofs_flush;
9055
            #endif
9056
9057
            control -> ProxyMode = proxy_server;
9058
          }
9059
          else if (control -> ProxyMode != proxy_server)
9060
          {
9061
            #ifdef PANIC
9062
            *logofs << "Loop: PANIC! Can't redefine local proxy to "
9063
                    << "server mode.\n" << logofs_flush;
9064
            #endif
9065
9066
            cerr << "Error" << ": Can't redefine local proxy to "
9067
                 << "server mode.\n";
9068
9069
            return -1;
9070
          }
9071
9072
          break;
9073
        }
9074
        case 'v':
9075
        {
9076
          PrintVersionInfo();
9077
9078
          return -1;
9079
        }
9080
        default:
9081
        {
9082
          PrintUsageInfo(nextArg, 1);
9083
9084
          //
9085
          // Function GetArg() is not used anymore.
9086
          // Add a dummy call to avoid the warning.
9087
          //
9088
9089
          if (0)
9090
          {
9091
            GetArg(argi, argc, argv);
9092
          }
9093
9094
          return -1;
9095
        }
9096
      }
9097
    }
9098
    else
9099
    {
9100
      if (nextArg)
9101
      {
9102
        //
9103
        // Try to parse the option as a remote host:port
9104
        // specification as in 'localhost:8'. Such a
9105
        // parameter can be specified at the end of the
9106
        // command line at the connecting side.
9107
        //
9108
9109
        if (ParseHostOption(nextArg, connectHost, connectPort) > 0)
9110
        {
9111
          //
9112
          // Assume port is at a proxied display offset.
9113
          //
9114
9115
          proxyPort = connectPort;
9116
9117
          connectPort += DEFAULT_NX_PROXY_PORT_OFFSET;
9118
        }
9119
        else if (ParseEnvironmentOptions(nextArg, 1) < 0)
9120
        {
9121
          return -1;
9122
        }
9123
      }
9124
    }
9125
  }
9126
9127
  return 1;
9128
}
9129
9130
//
9131
// Set the variable to the values of host and
9132
// port where this proxy is going to hook to
9133
// an existing proxy.
9134
//
9135
9136
int ParseBindOptions(char **host, int *port)
9137
{
9138
  if (*bindHost != '\0')
9139
  {
9140
    *host = bindHost;
9141
    *port = bindPort;
9142
9143
    return 1;
9144
  }
9145
  else
9146
  {
9147
    return 0;
9148
  }
9149
}
9150
9151
//
9152
// Read options from file and merge with environment.
9153
//
9154
9155
int ParseFileOptions(const char *file)
9156
{
9157
  char *fileName;
9158
9159
  if (*file != '/' && *file != '.')
9160
  {
9161
    char *filePath = GetSessionPath();
9162
9163
    if (filePath == NULL)
9164
    {
9165
      cerr << "Error" << ": Cannot determine directory for NX option file.\n";
9166
9167
      HandleCleanup();
9168
    }
9169
9170
    fileName = new char[strlen(filePath) + strlen("/") +
9171
                            strlen(file) + 1];
9172
9173
    strcpy(fileName, filePath);
9174
9175
    strcat(fileName, "/");
9176
    strcat(fileName, file);
9177
9178
    delete [] filePath;
9179
  }
9180
  else
9181
  {
9182
    fileName = new char[strlen(file) + 1];
9183
9184
    strcpy(fileName, file);
9185
  }
9186
9187
  #ifdef TEST
9188
  *logofs << "Loop: Going to read options from file '"
9189
          << fileName << "'.\n" << logofs_flush;
9190
  #endif
9191
9192
  FILE *filePtr = fopen(fileName, "r");
9193
9194
  if (filePtr == NULL)
9195
  {
9196
    #ifdef PANIC
9197
    *logofs << "Loop: PANIC! Can't open options file '" << fileName
9198
            << "'. Error is " << EGET() << " '" << ESTR() << "'.\n"
9199
            << logofs_flush;
9200
    #endif
9201
9202
    cerr << "Error" << ": Can't open options file '" << fileName
9203
         << "'. Error is " << EGET() << " '" << ESTR() << "'.\n";
9204
9205
    delete [] fileName;
9206
9207
    return -1;
9208
  }
9209
9210
  char options[DEFAULT_DISPLAY_OPTIONS_LENGTH];
9211
9212
  #ifdef VALGRIND
9213
9214
  memset(options, '\0', DEFAULT_DISPLAY_OPTIONS_LENGTH);
9215
9216
  #endif
9217
9218
  if (fgets(options, DEFAULT_DISPLAY_OPTIONS_LENGTH, filePtr) == NULL)
9219
  {
9220
    #ifdef PANIC
9221
    *logofs << "Loop: PANIC! Can't read options from file '" << fileName
9222
            << "'. Error is " << EGET() << " '" << ESTR() << "'.\n"
9223
            << logofs_flush;
9224
    #endif
9225
9226
    cerr << "Error" << ": Can't read options from file '" << fileName
9227
         << "'. Error is " << EGET() << " '" << ESTR() << "'.\n";
9228
9229
    fclose(filePtr);
9230
9231
    delete [] fileName;
9232
9233
    return -1;
9234
  }
9235
9236
  fclose(filePtr);
9237
9238
  //
9239
  // Purge the newline and the other non-
9240
  // printable characters in the string.
9241
  //
9242
9243
  char *next = options;
9244
  
9245
  while (*next != '\0')
9246
  {
9247
    if (isprint(*next) == 0)
9248
    {
9249
      *next = '\0';
9250
    }
9251
9252
    next++;
9253
  }
9254
9255
  #ifdef TEST
9256
  *logofs << "Loop: Read options '" << options << "' from file '"
9257
          << fileName << "'.\n" << logofs_flush;
9258
  #endif
9259
9260
  if (ParseEnvironmentOptions(options, 1) < 0)
9261
  {
9262
    delete [] fileName;
9263
9264
    return -1;
9265
  }
9266
9267
  delete [] fileName;
9268
9269
  return 1;
9270
}
9271
9272
//
9273
// Parse the option string passed from the
9274
// remote proxy at startup.
9275
//
9276
9277
int ParseRemoteOptions(char *opts)
9278
{
9279
  #ifdef TEST
9280
  *logofs << "Loop: Going to parse the remote options "
9281
          << "string '" << opts << "'.\n"
9282
          << logofs_flush;
9283
  #endif
9284
9285
  char *name;
9286
  char *value;
9287
9288
  //
9289
  // The options string is intended to be a series
9290
  // of name/value tuples in the form name=value
9291
  // separated by the ',' character.
9292
  //
9293
9294
  int hasCookie = 0;
9295
  int hasLink   = 0;
9296
  int hasPack   = 0;
9297
  int hasCache  = 0;
9298
  int hasImages = 0;
9299
  int hasDelta  = 0;
9300
  int hasStream = 0;
9301
  int hasData   = 0;
9302
  int hasLimit  = 0;
9303
  int hasRender = 0;
9304
  int hasTaint  = 0;
9305
  int hasType   = 0;
9306
  int hasStrict = 0;
9307
  int hasShseg  = 0;
9308
9309
  //
9310
  // Get rid of the terminating space.
9311
  //
9312
9313
  if (*(opts + strlen(opts) - 1) == ' ')
9314
  {
9315
    *(opts + strlen(opts) - 1) = '\0';
9316
  }
9317
9318
  name = strtok(opts, "=");
9319
9320
  while (name)
9321
  {
9322
    value = strtok(NULL, ",");
9323
9324
    if (CheckArg("remote", name, value) < 0)
9325
    {
9326
      return -1;
9327
    }
9328
9329
    if (strcasecmp(name, "cookie") == 0)
9330
    {
9331
      if (WE_PROVIDE_CREDENTIALS)
9332
      {
9333
        #ifdef WARNING
9334
        *logofs << "Loop: WARNING! Ignoring remote option 'cookie' "
9335
                << "with value '" << value << "' when initiating "
9336
                << "connection.\n" << logofs_flush;
9337
        #endif
9338
9339
        cerr << "Warning" << ": Ignoring remote option 'cookie' "
9340
             << "with value '" << value << "' when initiating "
9341
             << "connection.\n";
9342
      }
9343
      else if (strncasecmp(authCookie, value, strlen(authCookie)) != 0)
9344
      {
9345
        #ifdef PANIC
9346
        *logofs << "Loop: PANIC! Authentication cookie '" << value
9347
                << "' doesn't match '" << authCookie << "'.\n"
9348
                << logofs_flush;
9349
        #endif
9350
9351
        cerr << "Error" << ": Authentication cookie '" << value
9352
             << "' doesn't match '" << authCookie << "'.\n";
9353
9354
        return -1;
9355
      }
9356
9357
      hasCookie = 1;
9358
    }
9359
    else if (strcasecmp(name, "link") == 0)
9360
    {
9361
      if (control -> ProxyMode == proxy_client)
9362
      {
9363
        PrintOptionIgnored("remote", name, value);
9364
      }
9365
      else
9366
      {
9367
        if (*linkSpeedName != '\0' && strcasecmp(linkSpeedName, value) != 0)
9368
        {
9369
          #ifdef WARNING
9370
          *logofs << "Loop: WARNING! Overriding option 'link' "
9371
                  << "with new value '" << value << "'.\n"
9372
                  << logofs_flush;
9373
          #endif
9374
9375
          cerr << "Warning" << ": Overriding option 'link' "
9376
               << "with new value '" << value << "'.\n";
9377
        }
9378
9379
        if (ParseLinkOption(value) < 0)
9380
        {
9381
          #ifdef PANIC
9382
          *logofs << "Loop: PANIC! Can't identify remote 'link' "
9383
                  << "option in string '" << value << "'.\n"
9384
                  << logofs_flush;
9385
          #endif
9386
9387
          cerr << "Error" << ": Can't identify remote 'link' "
9388
               << "option in string '" << value << "'.\n";
9389
9390
          return -1;
9391
        }
9392
      }
9393
9394
      hasLink = 1;
9395
    }
9396
    else if (strcasecmp(name, "pack") == 0)
9397
    {
9398
      if (control -> ProxyMode == proxy_client)
9399
      {
9400
        PrintOptionIgnored("remote", name, value);
9401
      }
9402
      else
9403
      {
9404
        if (*packMethodName != '\0' && strcasecmp(packMethodName, value) != 0)
9405
        {
9406
          #ifdef WARNING
9407
          *logofs << "Loop: WARNING! Overriding option 'pack' "
9408
                  << "with remote value '" << value << "'.\n"
9409
                  << logofs_flush;
9410
          #endif
9411
9412
          cerr << "Warning" << ": Overriding option 'pack' "
9413
               << "with remote value '" << value << "'.\n";
9414
        }
9415
9416
        if (ParsePackOption(value) < 0)
9417
        {
9418
          #ifdef PANIC
9419
          *logofs << "Loop: PANIC! Invalid pack option '"
9420
                  << value << "' requested by remote.\n"
9421
                  << logofs_flush;
9422
          #endif
9423
9424
          cerr << "Error" << ": Invalid pack option '"
9425
               << value << "' requested by remote.\n";
9426
9427
          return -1;
9428
        }
9429
      }
9430
9431
      hasPack = 1;
9432
    }
9433
    else if (strcasecmp(name, "cache") == 0)
9434
    {
9435
      if (control -> ProxyMode == proxy_client)
9436
      {
9437
        PrintOptionIgnored("remote", name, value);
9438
      }
9439
      else
9440
      {
9441
        //
9442
        // Cache size is sent as a hint of how much memory
9443
        // the remote proxy is going to consume. A very low
9444
        // powered thin client could choose to refuse the
9445
        // connection.
9446
        //
9447
9448
        if (ParseCacheOption(value) < 0)
9449
        {
9450
          #ifdef PANIC
9451
          *logofs << "Loop: PANIC! Can't identify remote 'cache' "
9452
                  << "option in string '" << value << "'.\n"
9453
                  << logofs_flush;
9454
          #endif
9455
9456
          cerr << "Error" << ": Can't identify remote 'cache' "
9457
               << "option in string '" << value << "'.\n";
9458
9459
          return -1;
9460
        }
9461
      }
9462
9463
      hasCache = 1;
9464
    }
9465
    else if (strcasecmp(name, "images") == 0)
9466
    {
9467
      if (control -> ProxyMode == proxy_client)
9468
      {
9469
        PrintOptionIgnored("remote", name, value);
9470
      }
9471
      else
9472
      {
9473
        //
9474
        // Images cache size is sent as a hint.
9475
        // There is no obbligation for the local
9476
        // proxy to use the persistent cache.
9477
        //
9478
9479
        if (ParseImagesOption(value) < 0)
9480
        {
9481
          #ifdef PANIC
9482
          *logofs << "Loop: PANIC! Can't identify remote 'images' "
9483
                  << "option in string '" << value << "'.\n"
9484
                  << logofs_flush;
9485
          #endif
9486
9487
          cerr << "Error" << ": Can't identify remote 'images' "
9488
               << "option in string '" << value << "'.\n";
9489
9490
          return -1;
9491
        }
9492
      }
9493
9494
      hasImages = 1;
9495
    }
9496
    else if (strcasecmp(name, "limit") == 0)
9497
    {
9498
      if (control -> ProxyMode == proxy_client)
9499
      {
9500
        PrintOptionIgnored("remote", name, value);
9501
      }
9502
      else
9503
      {
9504
        if (*bitrateLimitName != '\0' &&
9505
                strcasecmp(bitrateLimitName, value) != 0)
9506
        {
9507
          #ifdef WARNING
9508
          *logofs << "Loop: WARNING! Overriding option 'limit' "
9509
                  << "with new value '" << value << "'.\n"
9510
                  << logofs_flush;
9511
          #endif
9512
9513
          cerr << "Warning" << ": Overriding option 'limit' "
9514
               << "with new value '" << value << "'.\n";
9515
        }
9516
9517
        if (ParseBitrateOption(value) < 0)
9518
        {
9519
          #ifdef PANIC
9520
          *logofs << "Loop: PANIC! Can't identify 'limit' "
9521
                  << "option in string '" << value << "'.\n"
9522
                  << logofs_flush;
9523
          #endif
9524
9525
          cerr << "Error" << ": Can't identify 'limit' "
9526
               << "option in string '" << value << "'.\n";
9527
9528
          return -1;
9529
        }
9530
      }
9531
9532
      hasLimit = 1;
9533
    }
9534
    else if (strcasecmp(name, "render") == 0)
9535
    {
9536
      if (control -> ProxyMode == proxy_client)
9537
      {
9538
        PrintOptionIgnored("remote", name, value);
9539
      }
9540
      else
9541
      {
9542
        useRender = ValidateArg("remote", name, value);
9543
      }
9544
9545
      hasRender = 1;
9546
    }
9547
    else if (strcasecmp(name, "taint") == 0)
9548
    {
9549
      if (control -> ProxyMode == proxy_client)
9550
      {
9551
        PrintOptionIgnored("remote", name, value);
9552
      }
9553
      else
9554
      {
9555
        useTaint = ValidateArg("remote", name, value);
9556
      }
9557
9558
      hasTaint = 1;
9559
    }
9560
    else if (strcasecmp(name, "type") == 0)
9561
    {
9562
      if (control -> ProxyMode == proxy_client)
9563
      {
9564
        PrintOptionIgnored("remote", name, value);
9565
      }
9566
      else
9567
      {
9568
        if (strcasecmp(value, "default") == 0)
9569
        {
9570
          *sessionType = '\0';
9571
        }
9572
        else
9573
        {
9574
          strncpy(sessionType, value, DEFAULT_STRING_LENGTH - 1);
9575
        }
9576
      }
9577
9578
      hasType = 1;
9579
    }
9580
    else if (strcasecmp(name, "strict") == 0)
9581
    {
9582
      if (control -> ProxyMode == proxy_client)
9583
      {
9584
        PrintOptionIgnored("remote", name, value);
9585
      }
9586
      else
9587
      {
9588
        useStrict = ValidateArg("remote", name, value);
9589
      }
9590
9591
      hasStrict = 1;
9592
    }
9593
    else if (strcasecmp(name, "shseg") == 0)
9594
    {
9595
      if (control -> ProxyMode == proxy_client)
9596
      {
9597
        PrintOptionIgnored("remote", name, value);
9598
      }
9599
      else if (ParseShmemOption(value) < 0)
9600
      {
9601
        #ifdef PANIC
9602
        *logofs << "Loop: PANIC! Can't identify size of shared memory "
9603
                << "segment in string '" << value << "'.\n"
9604
               << logofs_flush;
9605
        #endif
9606
9607
        cerr << "Error" << ": Can't identify size of shared memory "
9608
             << "segment in string '" << value << "'.\n";
9609
9610
        return -1;
9611
      }
9612
9613
      hasShseg = 1;
9614
    }
9615
    else if (strcasecmp(name, "delta") == 0)
9616
    {
9617
      if (control -> ProxyMode == proxy_client)
9618
      {
9619
        PrintOptionIgnored("remote", name, value);
9620
      }
9621
      else
9622
      {
9623
        control -> RemoteDeltaCompression = ValidateArg("remote", name, value);
9624
9625
        //
9626
        // Follow for delta compression the
9627
        // same settings as the client proxy.
9628
        //
9629
9630
        control -> LocalDeltaCompression  = control -> RemoteDeltaCompression;
9631
      }
9632
9633
      hasDelta = 1;
9634
    }
9635
    else if (strcasecmp(name, "stream") == 0)
9636
    {
9637
      //
9638
      // If remote side didn't choose its own
9639
      // stream compression level then assume
9640
      // local settings.
9641
      //
9642
9643
      if (strcasecmp(value, "default") == 0)
9644
      {
9645
        //
9646
        // This applies only at client side.
9647
        //
9648
9649
        control -> RemoteStreamCompression =
9650
            control -> LocalStreamCompression;
9651
9652
        control -> RemoteStreamCompressionLevel =
9653
            control -> LocalStreamCompressionLevel;
9654
      }
9655
      else
9656
      {
9657
        control -> RemoteStreamCompressionLevel = ValidateArg("remote", name, value);
9658
9659
        if (control -> RemoteStreamCompressionLevel > 0)
9660
        {
9661
          control -> RemoteStreamCompression = 1;
9662
        }
9663
        else
9664
        {
9665
          control -> RemoteStreamCompression = 0;
9666
        }
9667
9668
        if (control -> LocalStreamCompressionLevel < 0)
9669
        {
9670
          control -> LocalStreamCompressionLevel = ValidateArg("remote", name, value);
9671
9672
          if (control -> LocalStreamCompressionLevel > 0)
9673
          {
9674
            control -> LocalStreamCompression = 1;
9675
          }
9676
          else
9677
          {
9678
            control -> LocalStreamCompression = 0;
9679
          }
9680
        }
9681
      }
9682
9683
      hasStream = 1;
9684
    }
9685
    else if (strcasecmp(name, "data") == 0)
9686
    {
9687
      //
9688
      // Apply the same to data compression level.
9689
      //
9690
9691
      if (strcasecmp(value, "default") == 0)
9692
      {
9693
        control -> RemoteDataCompression =
9694
            control -> LocalDataCompression;
9695
9696
        control -> RemoteDataCompressionLevel =
9697
            control -> LocalDataCompressionLevel;
9698
      }
9699
      else
9700
      {
9701
        control -> RemoteDataCompressionLevel = ValidateArg("remote", name, value);
9702
9703
        if (control -> RemoteDataCompressionLevel > 0)
9704
        {
9705
          control -> RemoteDataCompression = 1;
9706
        }
9707
        else
9708
        {
9709
          control -> RemoteDataCompression = 0;
9710
        }
9711
9712
        if (control -> LocalDataCompressionLevel < 0)
9713
        {
9714
          control -> LocalDataCompressionLevel = ValidateArg("remote", name, value);
9715
9716
          if (control -> LocalDataCompressionLevel > 0)
9717
          {
9718
            control -> LocalDataCompression = 1;
9719
          }
9720
          else
9721
          {
9722
            control -> LocalDataCompression = 0;
9723
          }
9724
        }
9725
      }
9726
9727
      hasData = 1;
9728
    }
9729
    else if (strcasecmp(name, "flush") == 0)
9730
    {
9731
      //
9732
      // This option has no effect in recent
9733
      // versions.
9734
      //
9735
9736
      #ifdef DEBUG
9737
      *logofs << "Loop: Ignoring obsolete remote option '"
9738
              << name << "' with value '" << value
9739
              << "'.\n" << logofs_flush;
9740
      #endif
9741
    }
9742
    else
9743
    {
9744
      #ifdef WARNING
9745
      *logofs << "Loop: WARNING! Ignoring unknown remote option '"
9746
              << name << "' with value '" << value << "'.\n"
9747
              << logofs_flush;
9748
      #endif
9749
9750
      cerr << "Warning" << ": Ignoring unknown remote option '"
9751
           << name << "' with value '" << value << "'.\n";
9752
    }
9753
9754
    name = strtok(NULL, "=");
9755
9756
  } // End of while (name) ...
9757
9758
  //
9759
  // If we are client side, we need remote 'stream'
9760
  // and 'data' options. If we are server, we need
9761
  // all the above plus 'link' and some others.
9762
  //
9763
9764
  char missing[DEFAULT_STRING_LENGTH];
9765
9766
  *missing = '\0';
9767
9768
  if (control -> ProxyMode == proxy_client)
9769
  {
9770
    if (hasStream == 0)
9771
    {
9772
      strcpy(missing, "stream");
9773
    }
9774
    else if (hasData == 0)
9775
    {
9776
      strcpy(missing, "data");
9777
    }
9778
  }
9779
  else
9780
  {
9781
    //
9782
    // Don't complain if the optional 'flush',
9783
    // 'render' and 'taint' options are not
9784
    // provided.
9785
    //
9786
9787
    if (hasLink == 0)
9788
    {
9789
      strcpy(missing, "link");
9790
    }
9791
    else if (hasCache == 0)
9792
    {
9793
      strcpy(missing, "cache");
9794
    }
9795
    else if (hasPack == 0)
9796
    {
9797
      strcpy(missing, "pack");
9798
    }
9799
    else if (hasDelta == 0)
9800
    {
9801
      strcpy(missing, "delta");
9802
    }
9803
    else if (hasStream == 0)
9804
    {
9805
      strcpy(missing, "stream");
9806
    }
9807
    else if (hasData == 0)
9808
    {
9809
      strcpy(missing, "data");
9810
    }
9811
    else if (hasType == 0)
9812
    {
9813
      strcpy(missing, "type");
9814
    }
9815
    else if (hasImages == 0)
9816
    {
9817
      strcpy(missing, "images");
9818
    }
9819
  }
9820
9821
  if (WE_PROVIDE_CREDENTIALS == 0)
9822
  {
9823
    //
9824
    // Can be that user doesn't have requested to
9825
    // check the authorization cookie provided by
9826
    // the connecting peer.
9827
    //
9828
9829
    if (hasCookie == 0 && *authCookie != '\0')
9830
    {
9831
      strcpy(missing, "cookie");
9832
    }
9833
  }
9834
9835
  if (*missing != '\0')
9836
  {
9837
    #ifdef PANIC
9838
    *logofs << "Loop: PANIC! The remote peer didn't specify the option '"
9839
            << missing << "'.\n" << logofs_flush;
9840
    #endif
9841
9842
    cerr << "Error" << ": The remote peer didn't specify the option '"
9843
         << missing << "'.\n";
9844
9845
    return -1;
9846
  }
9847
9848
  return 1;
9849
}
9850
9851
//
9852
// Parse the cookie provided by the NX proxy
9853
// connection forwarder.
9854
//
9855
9856
int ParseForwarderOptions(char *opts)
9857
{
9858
  #ifdef TEST
9859
  *logofs << "Loop: Going to parse the forwarder options "
9860
          << "string '" << opts << "'.\n"
9861
          << logofs_flush;
9862
  #endif
9863
9864
  char *name;
9865
  char *value;
9866
9867
  int hasCookie = 0;
9868
9869
  //
9870
  // Get rid of the terminating space.
9871
  //
9872
9873
  if (*(opts + strlen(opts) - 1) == ' ')
9874
  {
9875
    *(opts + strlen(opts) - 1) = '\0';
9876
  }
9877
9878
  name = strtok(opts, "=");
9879
9880
  while (name)
9881
  {
9882
    value = strtok(NULL, ",");
9883
9884
    if (CheckArg("forwarder", name, value) < 0)
9885
    {
9886
      return -1;
9887
    }
9888
9889
    if (strcasecmp(name, "cookie") == 0)
9890
    {
9891
      if (strncasecmp(authCookie, value, strlen(authCookie)) != 0)
9892
      {
9893
        #ifdef PANIC
9894
        *logofs << "Loop: PANIC! The NX forwarder cookie '" << value
9895
                << "' doesn't match '" << authCookie << "'.\n"
9896
                << logofs_flush;
9897
        #endif
9898
9899
        cerr << "Error" << ": The NX forwarder cookie '" << value
9900
             << "' doesn't match '" << authCookie << "'.\n";
9901
9902
        return -1;
9903
      }
9904
9905
      hasCookie = 1;
9906
    }
9907
    else
9908
    {
9909
      #ifdef WARNING
9910
      *logofs << "Loop: WARNING! Ignoring unknown forwarder option '"
9911
              << name << "' with value '" << value << "'.\n"
9912
              << logofs_flush;
9913
      #endif
9914
9915
      cerr << "Warning" << ": Ignoring unknown forwarder option '"
9916
           << name << "' with value '" << value << "'.\n";
9917
    }
9918
9919
    name = strtok(NULL, "=");
9920
9921
  } // End of while (name) ...
9922
9923
  if (hasCookie == 0)
9924
  {
9925
    #ifdef PANIC
9926
    *logofs << "Loop: PANIC! The NX forwarder didn't provide "
9927
            << "the authentication cookie.\n" << logofs_flush;
9928
    #endif
9929
9930
    cerr << "Error" << ": The NX forwarder didn't provide "
9931
         << "the authentication cookie.\n";
9932
9933
    return -1;
9934
  }
9935
9936
  return 1;
9937
}
9938
9939
int SetCore()
9940
{
9941
  #ifdef COREDUMPS
9942
9943
  rlimit rlim;
9944
9945
  if (getrlimit(RLIMIT_CORE, &rlim))
9946
  {
9947
    #ifdef TEST
9948
    *logofs << "Cannot read RLIMIT_CORE. Error is '"
9949
            << ESTR() << "'.\n" << logofs_flush;
9950
    #endif
9951
9952
    return -1;
9953
  }
9954
9955
  if (rlim.rlim_cur < rlim.rlim_max)
9956
  {
9957
    rlim.rlim_cur = rlim.rlim_max;
9958
9959
    if (setrlimit(RLIMIT_CORE, &rlim))
9960
    {
9961
      #ifdef TEST
9962
      *logofs << "Loop: Cannot read RLIMIT_CORE. Error is '"
9963
              << ESTR() << "'.\n" << logofs_flush;
9964
      #endif
9965
9966
      return -2;
9967
    }
9968
  }
9969
9970
  #ifdef TEST
9971
  *logofs << "Loop: Set RLIMIT_CORE to "<< rlim.rlim_max
9972
          << ".\n" << logofs_flush;
9973
  #endif
9974
9975
  #endif // #ifdef COREDUMPS
9976
9977
  return 1;
9978
}
9979
9980
char *GetLastCache(char *listBuffer, const char *searchPath)
9981
{
9982
  if (listBuffer == NULL || searchPath == NULL ||
9983
          strncmp(listBuffer, "cachelist=", strlen("cachelist=")) != 0)
9984
  {
9985
    #ifdef TEST
9986
    *logofs << "Loop: Invalid parameters '" << listBuffer << "' and '"
9987
            << (searchPath != NULL ? searchPath : "")
9988
            << "'. Can't select any cache.\n" << logofs_flush;
9989
    #endif
9990
9991
    return NULL;
9992
  }
9993
9994
  char *selectedName = new char[MD5_LENGTH * 2 + 3];
9995
9996
  *selectedName = '\0';
9997
9998
  char *localPrefix;
9999
  char *remotePrefix;
10000
10001
  if (control -> ProxyMode == proxy_client)
10002
  {
10003
    localPrefix  = "C-";
10004
    remotePrefix = "S-";
10005
  }
10006
  else
10007
  {
10008
    localPrefix  = "S-";
10009
    remotePrefix = "C-";
10010
  }
10011
10012
  //
10013
  // Get rid of prefix.
10014
  //
10015
10016
  listBuffer += strlen("cachelist=");
10017
10018
  char *fileName;
10019
10020
  fileName = strtok(listBuffer, ",");
10021
10022
  //
10023
  // It is "/path/to/file" + "/" + "C-" + 32 + "\0".
10024
  //
10025
10026
  char fullPath[strlen(searchPath) + MD5_LENGTH * 2 + 4];
10027
10028
  time_t selectedTime = 0;
10029
10030
  struct stat fileStat;
10031
10032
  while (fileName)
10033
  {
10034
    if (strncmp(fileName, "none", strlen("none")) == 0)
10035
    {
10036
      #ifdef TEST
10037
      *logofs << "Loop: No cache files seem to be available.\n"
10038
              << logofs_flush;
10039
      #endif
10040
10041
      delete [] selectedName;
10042
10043
      return NULL;
10044
    }
10045
    else if (strlen(fileName) != MD5_LENGTH * 2 + 2 ||
10046
                 strncmp(fileName, remotePrefix, 2) != 0)
10047
    {
10048
      #ifdef PANIC
10049
      *logofs << "Loop: PANIC! Bad cache file name '"
10050
               << fileName << "'.\n" << logofs_flush;
10051
      #endif
10052
10053
      cerr << "Error" << ": Bad cache file name '"
10054
           << fileName << "'.\n";
10055
10056
      delete [] selectedName;
10057
10058
      HandleCleanup();
10059
    }
10060
10061
    #ifdef TEST
10062
    *logofs << "Loop: Parsing remote cache name '"
10063
            << fileName << "'.\n" << logofs_flush;
10064
    #endif
10065
10066
    //
10067
    // Prefix, received as "S-", becomes
10068
    // "C-" and viceversa.
10069
    //
10070
10071
    *fileName = *localPrefix;
10072
10073
    strcpy(fullPath, searchPath);
10074
    strcat(fullPath, "/");
10075
    strcat(fullPath, fileName);
10076
10077
    if (stat(fullPath, &fileStat) == 0)
10078
    {
10079
      #ifdef TEST
10080
      *logofs << "Loop: Found a matching cache '"
10081
              << fullPath << "'.\n" << logofs_flush;
10082
      #endif
10083
10084
      if (fileStat.st_mtime >= selectedTime)
10085
      {
10086
        strcpy(selectedName, fileName);
10087
10088
        selectedTime = fileStat.st_mtime;
10089
      }
10090
    }
10091
    #ifdef TEST
10092
    else
10093
    {
10094
      *logofs << "Loop: Can't get stats of file '"
10095
              << fullPath << "'.\n" << logofs_flush;
10096
    }
10097
    #endif
10098
10099
    fileName = strtok(NULL, ",");
10100
  }
10101
10102
  if (*selectedName != '\0')
10103
  {
10104
    return selectedName;
10105
  }
10106
  else
10107
  {
10108
    delete [] selectedName;
10109
10110
    return NULL;
10111
  }
10112
}
10113
10114
char *GetTempPath()
10115
{
10116
  if (*tempDir == '\0')
10117
  {
10118
    //
10119
    // Check the NX_TEMP environment, first,
10120
    // then the TEMP variable.
10121
    //
10122
10123
    const char *tempEnv = getenv("NX_TEMP");
10124
10125
    if (tempEnv == NULL || *tempEnv == '\0')
10126
    {
10127
      #ifdef TEST
10128
      *logofs << "Loop: WARNING! No environment for NX_TEMP.\n"
10129
              << logofs_flush;
10130
      #endif
10131
10132
      tempEnv = getenv("TEMP");
10133
10134
      if (tempEnv == NULL || *tempEnv == '\0')
10135
      {
10136
        #ifdef TEST
10137
        *logofs << "Loop: WARNING! No environment for TEMP.\n"
10138
                << logofs_flush;
10139
        #endif
10140
10141
        tempEnv = "/tmp";
10142
      }
10143
    }
10144
10145
    if (strlen(tempEnv) > DEFAULT_STRING_LENGTH - 1)
10146
    {
10147
      #ifdef PANIC
10148
      *logofs << "Loop: PANIC! Invalid value for the NX "
10149
              << "temporary directory '" << tempEnv
10150
              << "'.\n" << logofs_flush;
10151
      #endif
10152
10153
      cerr << "Error" << ": Invalid value for the NX "
10154
           << "temporary directory '" << tempEnv
10155
           << "'.\n";
10156
10157
      HandleCleanup();
10158
    }
10159
10160
    strcpy(tempDir, tempEnv);
10161
10162
    #ifdef TEST
10163
    *logofs << "Loop: Assuming temporary NX directory '"
10164
            << tempDir << "'.\n" << logofs_flush;
10165
    #endif
10166
  }
10167
10168
  char *tempPath = new char[strlen(tempDir) + 1];
10169
10170
  if (tempPath == NULL)
10171
  {
10172
    #ifdef PANIC
10173
    *logofs << "Loop: PANIC! Can't allocate memory "
10174
            << "for the temp path.\n" << logofs_flush;
10175
    #endif
10176
10177
    cerr << "Error" << ": Can't allocate memory "
10178
         << "for the temp path.\n";
10179
10180
    HandleCleanup();
10181
  }
10182
10183
  strcpy(tempPath, tempDir);
10184
10185
  return tempPath;
10186
}
10187
10188
char *GetClientPath()
10189
{
10190
  if (*clientDir == '\0')
10191
  {
10192
    //
10193
    // Check the NX_CLIENT environment.
10194
    //
10195
10196
    const char *clientEnv = getenv("NX_CLIENT");
10197
10198
    if (clientEnv == NULL || *clientEnv == '\0')
10199
    {
10200
      #ifdef TEST
10201
      *logofs << "Loop: WARNING! No environment for NX_CLIENT.\n"
10202
              << logofs_flush;
10203
      #endif
10204
10205
      //
10206
      // Try to guess the location of the client.
10207
      //
10208
10209
      clientEnv = "/usr/NX/bin/nxclient";
10210
10211
      #ifdef __APPLE__
10212
10213
      clientEnv = "/Applications/NX Client for OSX.app/Contents/MacOS/nxclient";
10214
10215
      #endif
10216
10217
      #ifdef __CYGWIN32__
10218
10219
      clientEnv = "C:\\Program Files\\NX Client for Windows\\nxclient";
10220
10221
      #endif
10222
    }
10223
10224
    if (strlen(clientEnv) > DEFAULT_STRING_LENGTH - 1)
10225
    {
10226
      #ifdef PANIC
10227
      *logofs << "Loop: PANIC! Invalid value for the NX "
10228
              << "client directory '" << clientEnv
10229
              << "'.\n" << logofs_flush;
10230
      #endif
10231
10232
      cerr << "Error" << ": Invalid value for the NX "
10233
           << "client directory '" << clientEnv
10234
           << "'.\n";
10235
10236
      HandleCleanup();
10237
    }
10238
10239
    strcpy(clientDir, clientEnv);
10240
10241
    #ifdef TEST
10242
    *logofs << "Loop: Assuming NX client location '"
10243
            << clientDir << "'.\n" << logofs_flush;
10244
    #endif
10245
  }
10246
10247
  char *clientPath = new char[strlen(clientDir) + 1];
10248
10249
  if (clientPath == NULL)
10250
  {
10251
    #ifdef PANIC
10252
    *logofs << "Loop: PANIC! Can't allocate memory "
10253
            << "for the client path.\n" << logofs_flush;
10254
    #endif
10255
10256
    cerr << "Error" << ": Can't allocate memory "
10257
         << "for the client path.\n";
10258
10259
    HandleCleanup();
10260
  }
10261
10262
  strcpy(clientPath, clientDir);
10263
10264
  return clientPath;
10265
}
10266
10267
char *GetSystemPath()
10268
{
10269
  if (*systemDir == '\0')
10270
  {
10271
    //
10272
    // Check the NX_SYSTEM environment.
10273
    //
10274
10275
    const char *systemEnv = getenv("NX_SYSTEM");
10276
10277
    if (systemEnv == NULL || *systemEnv == '\0')
10278
    {
10279
      #ifdef TEST
10280
      *logofs << "Loop: WARNING! No environment for NX_SYSTEM.\n"
10281
              << logofs_flush;
10282
      #endif
10283
10284
      systemEnv = "/usr/NX";
10285
    }
10286
10287
    if (strlen(systemEnv) > DEFAULT_STRING_LENGTH - 1)
10288
    {
10289
      #ifdef PANIC
10290
      *logofs << "Loop: PANIC! Invalid value for the NX "
10291
              << "system directory '" << systemEnv
10292
              << "'.\n" << logofs_flush;
10293
      #endif
10294
10295
      cerr << "Error" << ": Invalid value for the NX "
10296
           << "system directory '" << systemEnv
10297
           << "'.\n";
10298
10299
      HandleCleanup();
10300
    }
10301
10302
    strcpy(systemDir, systemEnv);
10303
10304
    #ifdef TEST
10305
    *logofs << "Loop: Assuming system NX directory '"
10306
            << systemDir << "'.\n" << logofs_flush;
10307
    #endif
10308
  }
10309
10310
  char *systemPath = new char[strlen(systemDir) + 1];
10311
10312
  if (systemPath == NULL)
10313
  {
10314
    #ifdef PANIC
10315
    *logofs << "Loop: PANIC! Can't allocate memory "
10316
            << "for the system path.\n" << logofs_flush;
10317
    #endif
10318
10319
    cerr << "Error" << ": Can't allocate memory "
10320
         << "for the system path.\n";
10321
10322
    HandleCleanup();
10323
  }
10324
10325
  strcpy(systemPath, systemDir);
10326
10327
  return systemPath;
10328
}
10329
10330
char *GetHomePath()
10331
{
10332
  if (*homeDir == '\0')
10333
  {
10334
    //
10335
    // Check the NX_HOME environment.
10336
    //
10337
10338
    const char *homeEnv = getenv("NX_HOME");
10339
10340
    if (homeEnv == NULL || *homeEnv == '\0')
10341
    {
10342
      #ifdef TEST
10343
      *logofs << "Loop: WARNING! No environment for NX_HOME.\n"
10344
              << logofs_flush;
10345
      #endif
10346
10347
      homeEnv = getenv("HOME");
10348
10349
      if (homeEnv == NULL || *homeEnv == '\0')
10350
      {
10351
        #ifdef PANIC
10352
        *logofs << "Loop: PANIC! No environment for HOME.\n"
10353
                << logofs_flush;
10354
        #endif
10355
10356
        cerr << "Error" << ": No environment for HOME.\n";
10357
10358
        HandleCleanup();
10359
      }
10360
    }
10361
10362
    if (strlen(homeEnv) > DEFAULT_STRING_LENGTH - 1)
10363
    {
10364
      #ifdef PANIC
10365
      *logofs << "Loop: PANIC! Invalid value for the NX "
10366
              << "home directory '" << homeEnv
10367
              << "'.\n" << logofs_flush;
10368
      #endif
10369
10370
      cerr << "Error" << ": Invalid value for the NX "
10371
           << "home directory '" << homeEnv
10372
           << "'.\n";
10373
10374
      HandleCleanup();
10375
    }
10376
10377
    strcpy(homeDir, homeEnv);
10378
10379
    #ifdef TEST
10380
    *logofs << "Loop: Assuming NX user's home directory '"
10381
            << homeDir << "'.\n" << logofs_flush;
10382
    #endif
10383
  }
10384
10385
  char *homePath = new char[strlen(homeDir) + 1];
10386
10387
  if (homePath == NULL)
10388
  {
10389
    #ifdef PANIC
10390
    *logofs << "Loop: PANIC! Can't allocate memory "
10391
            << "for the home path.\n" << logofs_flush;
10392
    #endif
10393
10394
    cerr << "Error" << ": Can't allocate memory "
10395
         << "for the home path.\n";
10396
10397
    HandleCleanup();
10398
  }
10399
10400
  strcpy(homePath, homeDir);
10401
10402
  return homePath;
10403
}
10404
10405
char *GetRootPath()
10406
{
10407
  if (*rootDir == '\0')
10408
  {
10409
    //
10410
    // Check the NX_ROOT environment.
10411
    //
10412
10413
    const char *rootEnv = getenv("NX_ROOT");
10414
10415
    if (rootEnv == NULL || *rootEnv == '\0')
10416
    {
10417
      #ifdef TEST
10418
      *logofs << "Loop: WARNING! No environment for NX_ROOT.\n"
10419
              << logofs_flush;
10420
      #endif
10421
10422
      //
10423
      // We will determine the root NX directory
10424
      // based on the NX_HOME or HOME directory
10425
      // settings.
10426
      //
10427
10428
      const char *homeEnv = GetHomePath();
10429
10430
      if (strlen(homeEnv) > DEFAULT_STRING_LENGTH -
10431
              strlen("/.nx") - 1)
10432
      {
10433
        #ifdef PANIC
10434
        *logofs << "Loop: PANIC! Invalid value for the NX "
10435
                << "home directory '" << homeEnv
10436
                << "'.\n" << logofs_flush;
10437
        #endif
10438
10439
        cerr << "Error" << ": Invalid value for the NX "
10440
             << "home directory '" << homeEnv
10441
             << "'.\n";
10442
10443
        HandleCleanup();
10444
      }
10445
10446
      #ifdef TEST
10447
      *logofs << "Loop: Assuming NX root directory in "
10448
              << "the user's home '" << homeEnv
10449
              << "'.\n" << logofs_flush;
10450
      #endif
10451
10452
      strcpy(rootDir, homeEnv);
10453
      strcat(rootDir, "/.nx");
10454
10455
      delete [] homeEnv;
10456
10457
      //
10458
      // Create the NX root directory.
10459
      //
10460
10461
      struct stat dirStat;
10462
10463
      if ((stat(rootDir, &dirStat) == -1) && (EGET() == ENOENT))
10464
      {
10465
        if (mkdir(rootDir, 0700) < 0 && (EGET() != EEXIST))
10466
        {
10467
          #ifdef PANIC
10468
          *logofs << "Loop: PANIC! Can't create directory '"
10469
                  << rootDir << ". Error is " << EGET() << " '"
10470
                  << ESTR() << "'.\n" << logofs_flush;
10471
          #endif
10472
10473
          cerr << "Error" << ": Can't create directory '"
10474
               << rootDir << ". Error is " << EGET() << " '"
10475
               << ESTR() << "'.\n";
10476
10477
          HandleCleanup();
10478
        }
10479
      }
10480
    }
10481
    else
10482
    {
10483
      if (strlen(rootEnv) > DEFAULT_STRING_LENGTH - 1)
10484
      {
10485
        #ifdef PANIC
10486
        *logofs << "Loop: PANIC! Invalid value for the NX "
10487
                << "root directory '" << rootEnv
10488
                << "'.\n" << logofs_flush;
10489
        #endif
10490
10491
        cerr << "Error" << ": Invalid value for the NX "
10492
             << "root directory '" << rootEnv
10493
             << "'.\n";
10494
10495
        HandleCleanup();
10496
      }
10497
10498
      strcpy(rootDir, rootEnv);
10499
    }
10500
        
10501
    #ifdef TEST
10502
    *logofs << "Loop: Assuming NX root directory '"
10503
            << rootDir << "'.\n" << logofs_flush;
10504
    #endif
10505
  }
10506
10507
  char *rootPath = new char[strlen(rootDir) + 1];
10508
10509
  if (rootPath == NULL)
10510
  {
10511
    #ifdef PANIC
10512
    *logofs << "Loop: PANIC! Can't allocate memory "
10513
            << "for the root path.\n" << logofs_flush;
10514
    #endif
10515
10516
    cerr << "Error" << ": Can't allocate memory "
10517
         << "for the root path.\n";
10518
10519
    HandleCleanup();
10520
  }
10521
10522
  strcpy(rootPath, rootDir);
10523
10524
  return rootPath;
10525
}
10526
10527
char *GetCachePath()
10528
{
10529
  char *rootPath = GetRootPath();
10530
10531
  char *cachePath;
10532
10533
  if (*sessionType != '\0')
10534
  {
10535
    cachePath = new char[strlen(rootPath) + strlen("/cache-") +
10536
                             strlen(sessionType) + 1];
10537
  }
10538
  else
10539
  {
10540
    cachePath = new char[strlen(rootPath) + strlen("/cache") + 1];
10541
  }
10542
10543
  strcpy(cachePath, rootPath);
10544
10545
  if (*sessionType != '\0')
10546
  {
10547
    strcat(cachePath, "/cache-");
10548
10549
    strcat(cachePath, sessionType);
10550
  }
10551
  else
10552
  {
10553
    strcat(cachePath, "/cache");
10554
  }
10555
10556
  //
10557
  // Create the cache directory if needed.
10558
  //
10559
10560
  struct stat dirStat;
10561
10562
  if ((stat(cachePath, &dirStat) == -1) && (EGET() == ENOENT))
10563
  {
10564
    if (mkdir(cachePath, 0700) < 0 && (EGET() != EEXIST))
10565
    {
10566
      #ifdef PANIC
10567
      *logofs << "Loop: PANIC! Can't create directory '" << cachePath
10568
              << ". Error is " << EGET() << " '" << ESTR() << "'.\n"
10569
              << logofs_flush;
10570
      #endif
10571
10572
      cerr << "Error" << ": Can't create directory '" << cachePath
10573
           << ". Error is " << EGET() << " '" << ESTR() << "'.\n";
10574
10575
      delete [] rootPath;
10576
      delete [] cachePath;
10577
10578
      return NULL;
10579
    }
10580
  }
10581
10582
  delete [] rootPath;
10583
10584
  return cachePath;
10585
}
10586
10587
char *GetImagesPath()
10588
{
10589
  char *rootPath = GetRootPath();
10590
10591
  char *imagesPath = new char[strlen(rootPath) + strlen("/images") + 1];
10592
10593
  strcpy(imagesPath, rootPath);
10594
10595
  strcat(imagesPath, "/images");
10596
10597
  //
10598
  // Create the cache directory if needed.
10599
  //
10600
10601
  struct stat dirStat;
10602
10603
  if ((stat(imagesPath, &dirStat) == -1) && (EGET() == ENOENT))
10604
  {
10605
    if (mkdir(imagesPath, 0700) < 0 && (EGET() != EEXIST))
10606
    {
10607
      #ifdef PANIC
10608
      *logofs << "Loop: PANIC! Can't create directory '" << imagesPath
10609
              << ". Error is " << EGET() << " '" << ESTR() << "'.\n"
10610
              << logofs_flush;
10611
      #endif
10612
10613
      cerr << "Error" << ": Can't create directory '" << imagesPath
10614
           << ". Error is " << EGET() << " '" << ESTR() << "'.\n";
10615
10616
      delete [] rootPath;
10617
      delete [] imagesPath;
10618
10619
      return NULL;
10620
    }
10621
  }
10622
10623
  //
10624
  // Create 16 directories in the path to
10625
  // hold the images whose name begins with
10626
  // the corresponding hexadecimal digit.
10627
  //
10628
10629
  char *digitPath = new char[strlen(imagesPath) + 5];
10630
10631
  strcpy(digitPath, imagesPath);
10632
10633
  //
10634
  // Image paths have format "[path][/I-c][\0]",
10635
  // where c is the first digit of the checksum.
10636
  //
10637
10638
  for (char digit = 0; digit < 16; digit++)
10639
  {
10640
    sprintf(digitPath + strlen(imagesPath), "/I-%01X", digit);
10641
10642
    if ((stat(digitPath, &dirStat) == -1) && (EGET() == ENOENT))
10643
    {
10644
      if (mkdir(digitPath, 0700) < 0 && (EGET() != EEXIST))
10645
      {
10646
        #ifdef PANIC
10647
        *logofs << "Loop: PANIC! Can't create directory '" << digitPath
10648
                << ". Error is " << EGET() << " '" << ESTR() << "'.\n"
10649
                << logofs_flush;
10650
        #endif
10651
10652
        cerr << "Error" << ": Can't create directory '" << digitPath
10653
             << ". Error is " << EGET() << " '" << ESTR() << "'.\n";
10654
10655
        delete [] rootPath;
10656
        delete [] imagesPath;
10657
        delete [] digitPath;
10658
10659
        return NULL;
10660
      }
10661
    }
10662
  }
10663
10664
  delete [] rootPath;
10665
  delete [] digitPath;
10666
10667
  return imagesPath;
10668
}
10669
10670
char *GetSessionPath()
10671
{
10672
  if (*sessionDir == '\0')
10673
  {
10674
    char *rootPath = GetRootPath();
10675
10676
    strcpy(sessionDir, rootPath);
10677
10678
    if (control -> ProxyMode == proxy_client)
10679
    {
10680
      strcat(sessionDir, "/C-");
10681
    }
10682
    else
10683
    {
10684
      strcat(sessionDir, "/S-");
10685
    }
10686
10687
    if (*sessionId == '\0')
10688
    {
10689
      char port[DEFAULT_STRING_LENGTH];
10690
10691
      sprintf(port, "%d", proxyPort);
10692
10693
      strcpy(sessionId, port);
10694
    }
10695
10696
    strcat(sessionDir, sessionId);
10697
10698
    struct stat dirStat;
10699
10700
    if ((stat(sessionDir, &dirStat) == -1) && (EGET() == ENOENT))
10701
    {
10702
      if (mkdir(sessionDir, 0700) < 0 && (EGET() != EEXIST))
10703
      {
10704
        #ifdef PANIC
10705
        *logofs << "Loop: PANIC! Can't create directory '" << sessionDir
10706
                << ". Error is " << EGET() << " '" << ESTR() << "'.\n"
10707
                << logofs_flush;
10708
        #endif
10709
10710
        cerr << "Error" << ": Can't create directory '" << sessionDir
10711
             << ". Error is " << EGET() << " '" << ESTR() << "'.\n";
10712
10713
        delete [] rootPath;
10714
10715
        return NULL;
10716
      }
10717
    }
10718
10719
    #ifdef TEST
10720
    *logofs << "Loop: Root of NX session is '" << sessionDir
10721
            << "'.\n" << logofs_flush;
10722
    #endif
10723
10724
    delete [] rootPath;
10725
  }
10726
10727
  char *sessionPath = new char[strlen(sessionDir) + 1];
10728
10729
  strcpy(sessionPath, sessionDir);
10730
10731
  return sessionPath;
10732
}
10733
10734
//
10735
// Identify requested link characteristics
10736
// and set control parameters accordingly.
10737
//
10738
10739
int ParseLinkOption(const char *opt)
10740
{
10741
  //
10742
  // Normalize the user input.
10743
  //
10744
10745
  if (strcasecmp(opt, "modem") == 0 ||
10746
          strcasecmp(opt, "33k") == 0 ||
10747
              strcasecmp(opt, "56k") == 0)
10748
  {
10749
    strcpy(linkSpeedName, "MODEM");
10750
  }
10751
  else if (strcasecmp(opt, "isdn")  == 0 ||
10752
               strcasecmp(opt, "64k")  == 0 ||
10753
                   strcasecmp(opt, "128k") == 0)
10754
  {
10755
    strcpy(linkSpeedName, "ISDN");
10756
  }
10757
  else if (strcasecmp(opt, "adsl") == 0 ||
10758
               strcasecmp(opt, "256k") == 0 ||
10759
                   strcasecmp(opt, "640k") == 0)
10760
  {
10761
    strcpy(linkSpeedName, "ADSL");
10762
  }
10763
  else if (strcasecmp(opt, "wan")  == 0 ||
10764
               strcasecmp(opt, "1m")  == 0 ||
10765
                   strcasecmp(opt, "2m")  == 0 ||
10766
                       strcasecmp(opt, "34m") == 0)
10767
  {
10768
    strcpy(linkSpeedName, "WAN");
10769
  }
10770
  else if (strcasecmp(opt, "lan")   == 0 ||
10771
               strcasecmp(opt, "10m")   == 0 ||
10772
                   strcasecmp(opt, "100m")  == 0 ||
10773
                       strcasecmp(opt, "local") == 0)
10774
  {
10775
    strcpy(linkSpeedName, "LAN");
10776
  }
10777
10778
  if (strcasecmp(linkSpeedName, "modem") != 0 &&
10779
          strcasecmp(linkSpeedName, "isdn")  != 0 &&
10780
              strcasecmp(linkSpeedName, "adsl")  != 0 &&
10781
                  strcasecmp(linkSpeedName, "wan")   != 0 &&
10782
                      strcasecmp(linkSpeedName, "lan")   != 0)
10783
  {
10784
    return -1;
10785
  }
10786
10787
  return 1;
10788
}
10789
10790
int ParsePackOption(const char *opt)
10791
{
10792
  #ifdef DEBUG
10793
  *logofs << "Loop: Pack method is " << packMethod
10794
          << " quality is " << packQuality << ".\n"
10795
          << logofs_flush;
10796
  #endif
10797
10798
  #ifdef DEBUG
10799
  *logofs << "Loop: Parsing pack method '" << opt
10800
          << "'.\n" << logofs_flush;
10801
  #endif
10802
10803
  if (strcasecmp(opt, "0") == 0 ||
10804
          strcasecmp(opt, "none") == 0 ||
10805
              strcasecmp(opt, "nopack") == 0 ||
10806
                  strcasecmp(opt, "no-pack") == 0)
10807
  {
10808
    packMethod = PACK_NONE;
10809
  }
10810
  else if (strcasecmp(opt, "8") == 0)
10811
  {
10812
    packMethod = PACK_MASKED_8_COLORS;
10813
  }
10814
  else if (strcasecmp(opt, "64") == 0)
10815
  {
10816
    packMethod = PACK_MASKED_64_COLORS;
10817
  }
10818
  else if (strcasecmp(opt, "256") == 0)
10819
  {
10820
    packMethod = PACK_MASKED_256_COLORS;
10821
  }
10822
  else if (strcasecmp(opt, "512") == 0)
10823
  {
10824
    packMethod = PACK_MASKED_512_COLORS;
10825
  }
10826
  else if (strcasecmp(opt, "4k") == 0)
10827
  {
10828
    packMethod = PACK_MASKED_4K_COLORS;
10829
  }
10830
  else if (strcasecmp(opt, "32k") == 0)
10831
  {
10832
    packMethod = PACK_MASKED_32K_COLORS;
10833
  }
10834
  else if (strcasecmp(opt, "64k") == 0)
10835
  {
10836
    packMethod = PACK_MASKED_64K_COLORS;
10837
  }
10838
  else if (strcasecmp(opt, "256k") == 0)
10839
  {
10840
    packMethod = PACK_MASKED_256K_COLORS;
10841
  }
10842
  else if (strcasecmp(opt, "2m") == 0)
10843
  {
10844
    packMethod = PACK_MASKED_2M_COLORS;
10845
  }
10846
  else if (strcasecmp(opt, "16m") == 0)
10847
  {
10848
    packMethod = PACK_MASKED_16M_COLORS;
10849
  }
10850
  else if (strncasecmp(opt, "8-jpeg", strlen("8-jpeg")) == 0)
10851
  {
10852
    packMethod = PACK_JPEG_8_COLORS;
10853
  }
10854
  else if (strncasecmp(opt, "64-jpeg", strlen("64-jpeg")) == 0)
10855
  {
10856
    packMethod = PACK_JPEG_64_COLORS;
10857
  }
10858
  else if (strncasecmp(opt, "256-jpeg", strlen("256-jpeg")) == 0)
10859
  {
10860
    packMethod = PACK_JPEG_256_COLORS;
10861
  }
10862
  else if (strncasecmp(opt, "512-jpeg", strlen("512-jpeg")) == 0)
10863
  {
10864
    packMethod = PACK_JPEG_512_COLORS;
10865
  }
10866
  else if (strncasecmp(opt, "4k-jpeg", strlen("4k-jpeg")) == 0)
10867
  {
10868
    packMethod = PACK_JPEG_4K_COLORS;
10869
  }
10870
  else if (strncasecmp(opt, "32k-jpeg", strlen("32k-jpeg")) == 0)
10871
  {
10872
    packMethod = PACK_JPEG_32K_COLORS;
10873
  }
10874
  else if (strncasecmp(opt, "64k-jpeg", strlen("64k-jpeg")) == 0)
10875
  {
10876
    packMethod = PACK_JPEG_64K_COLORS;
10877
  }
10878
  else if (strncasecmp(opt, "256k-jpeg", strlen("256k-jpeg")) == 0)
10879
  {
10880
    packMethod = PACK_JPEG_256K_COLORS;
10881
  }
10882
  else if (strncasecmp(opt, "2m-jpeg", strlen("2m-jpeg")) == 0)
10883
  {
10884
    packMethod = PACK_JPEG_2M_COLORS;
10885
  }
10886
  else if (strncasecmp(opt, "16m-jpeg", strlen("16m-jpeg")) == 0)
10887
  {
10888
    packMethod = PACK_JPEG_16M_COLORS;
10889
  }
10890
  else if (strncasecmp(opt, "8-png", strlen("8-png")) == 0)
10891
  {
10892
    packMethod = PACK_PNG_8_COLORS;
10893
  }
10894
  else if (strncasecmp(opt, "64-png", strlen("64-png")) == 0)
10895
  {
10896
    packMethod = PACK_PNG_64_COLORS;
10897
  }
10898
  else if (strncasecmp(opt, "256-png", strlen("256-png")) == 0)
10899
  {
10900
    packMethod = PACK_PNG_256_COLORS;
10901
  }
10902
  else if (strncasecmp(opt, "512-png", strlen("512-png")) == 0)
10903
  {
10904
    packMethod = PACK_PNG_512_COLORS;
10905
  }
10906
  else if (strncasecmp(opt, "4k-png", strlen("4k-png")) == 0)
10907
  {
10908
    packMethod = PACK_PNG_4K_COLORS;
10909
  }
10910
  else if (strncasecmp(opt, "32k-png", strlen("32k-png")) == 0)
10911
  {
10912
    packMethod = PACK_PNG_32K_COLORS;
10913
  }
10914
  else if (strncasecmp(opt, "64k-png", strlen("64k-png")) == 0)
10915
  {
10916
    packMethod = PACK_PNG_64K_COLORS;
10917
  }
10918
  else if (strncasecmp(opt, "256k-png", strlen("256k-png")) == 0)
10919
  {
10920
    packMethod = PACK_PNG_256K_COLORS;
10921
  }
10922
  else if (strncasecmp(opt, "2m-png", strlen("2m-png")) == 0)
10923
  {
10924
    packMethod = PACK_PNG_2M_COLORS;
10925
  }
10926
  else if (strncasecmp(opt, "16m-png", strlen("16m-png")) == 0)
10927
  {
10928
    packMethod = PACK_PNG_16M_COLORS;
10929
  }
10930
  else if (strncasecmp(opt, "16m-rgb", strlen("16m-rgb")) == 0 ||
10931
               strncasecmp(opt, "rgb", strlen("rgb")) == 0)
10932
  {
10933
    packMethod = PACK_RGB_16M_COLORS;
10934
  }
10935
  else if (strncasecmp(opt, "16m-rle", strlen("16m-rle")) == 0 ||
10936
               strncasecmp(opt, "rle", strlen("rle")) == 0)
10937
  {
10938
    packMethod = PACK_RLE_16M_COLORS;
10939
  }
10940
  else if (strncasecmp(opt, "16m-bitmap", strlen("16m-bitmap")) == 0 ||
10941
               strncasecmp(opt, "bitmap", strlen("bitmap")) == 0)
10942
  {
10943
    packMethod = PACK_BITMAP_16M_COLORS;
10944
  }
10945
  else if (strncasecmp(opt, "lossy", strlen("lossy")) == 0)
10946
  {
10947
    packMethod = PACK_LOSSY;
10948
  }
10949
  else if (strncasecmp(opt, "lossless", strlen("lossless")) == 0)
10950
  {
10951
    packMethod = PACK_LOSSLESS;
10952
  }
10953
  else if (strncasecmp(opt, "adaptive", strlen("adaptive")) == 0)
10954
  {
10955
    packMethod = PACK_ADAPTIVE;
10956
  }
10957
  else
10958
  {
10959
    return -1;
10960
  }
10961
10962
  if (packMethod == PACK_NONE)
10963
  {
10964
    strcpy(packMethodName, "none");
10965
  }
10966
  else
10967
  {
10968
    strcpy(packMethodName, opt);
10969
  }
10970
10971
  if (packMethod == PACK_RGB_16M_COLORS ||
10972
          packMethod == PACK_RLE_16M_COLORS ||
10973
              packMethod == PACK_BITMAP_16M_COLORS ||
10974
                  (packMethod >= PACK_JPEG_8_COLORS &&
10975
                      packMethod <= PACK_JPEG_16M_COLORS) ||
10976
                          (packMethod >= PACK_PNG_8_COLORS &&
10977
                              packMethod <= PACK_PNG_16M_COLORS) ||
10978
                                  packMethod == PACK_LOSSY ||
10979
                                      packMethod == PACK_LOSSLESS ||
10980
                                          packMethod == PACK_ADAPTIVE)
10981
  {
10982
    char *dash = rindex(opt, '-');
10983
10984
    if (dash != NULL && strlen(dash) == 2 &&
10985
            *(dash + 1) >= '0' && *(dash + 1) <= '9')
10986
    {
10987
      packQuality = atoi(dash + 1);
10988
10989
      #ifdef DEBUG
10990
      *logofs << "Loop: Using pack quality '"
10991
              << packQuality << "'.\n" << logofs_flush;
10992
      #endif
10993
    }
10994
  }
10995
  else
10996
  {
10997
    packQuality = 0;
10998
  }
10999
11000
  return 1;
11001
}
11002
11003
int ParsePackMethod(const int method, const int quality)
11004
{
11005
  switch (method)
11006
  {
11007
    case PACK_NONE:
11008
    {
11009
      strcpy(packMethodName, "none");
11010
11011
      break;
11012
    }
11013
    case PACK_MASKED_8_COLORS:
11014
    {
11015
      strcpy(packMethodName, "8");
11016
11017
      break;
11018
    }
11019
    case PACK_MASKED_64_COLORS:
11020
    {
11021
      strcpy(packMethodName, "64");
11022
11023
      break;
11024
    }
11025
    case PACK_MASKED_256_COLORS:
11026
    {
11027
      strcpy(packMethodName, "256");
11028
11029
      break;
11030
    }
11031
    case PACK_MASKED_512_COLORS:
11032
    {
11033
      strcpy(packMethodName, "512");
11034
11035
      break;
11036
    }
11037
    case PACK_MASKED_4K_COLORS:
11038
    {
11039
      strcpy(packMethodName, "4k");
11040
11041
      break;
11042
    }
11043
    case PACK_MASKED_32K_COLORS:
11044
    {
11045
      strcpy(packMethodName, "32k");
11046
11047
      break;
11048
    }
11049
    case PACK_MASKED_64K_COLORS:
11050
    {
11051
      strcpy(packMethodName, "64k");
11052
11053
      break;
11054
    }
11055
    case PACK_MASKED_256K_COLORS:
11056
    {
11057
      strcpy(packMethodName, "256k");
11058
11059
      break;
11060
    }
11061
    case PACK_MASKED_2M_COLORS:
11062
    {
11063
      strcpy(packMethodName, "2m");
11064
11065
      break;
11066
    }
11067
    case PACK_MASKED_16M_COLORS:
11068
    {
11069
      strcpy(packMethodName, "16m");
11070
11071
      break;
11072
    }
11073
    case PACK_JPEG_8_COLORS:
11074
    {
11075
      strcpy(packMethodName, "8-jpeg");
11076
11077
      break;
11078
    }
11079
    case PACK_JPEG_64_COLORS:
11080
    {
11081
      strcpy(packMethodName, "64-jpeg");
11082
11083
      break;
11084
    }
11085
    case PACK_JPEG_256_COLORS:
11086
    {
11087
      strcpy(packMethodName, "256-jpeg");
11088
11089
      break;
11090
    }
11091
    case PACK_JPEG_512_COLORS:
11092
    {
11093
      strcpy(packMethodName, "512-jpeg");
11094
11095
      break;
11096
    }
11097
    case PACK_JPEG_4K_COLORS:
11098
    {
11099
      strcpy(packMethodName, "4k-jpeg");
11100
11101
      break;
11102
    }
11103
    case PACK_JPEG_32K_COLORS:
11104
    {
11105
      strcpy(packMethodName, "32k-jpeg");
11106
11107
      break;
11108
    }
11109
    case PACK_JPEG_64K_COLORS:
11110
    {
11111
      strcpy(packMethodName, "64k-jpeg");
11112
11113
      break;
11114
    }
11115
    case PACK_JPEG_256K_COLORS:
11116
    {
11117
      strcpy(packMethodName, "256k-jpeg");
11118
11119
      break;
11120
    }
11121
    case PACK_JPEG_2M_COLORS:
11122
    {
11123
      strcpy(packMethodName, "2m-jpeg");
11124
11125
      break;
11126
    }
11127
    case PACK_JPEG_16M_COLORS:
11128
    {
11129
      strcpy(packMethodName, "16m-jpeg");
11130
11131
      break;
11132
    }
11133
    case PACK_PNG_8_COLORS:
11134
    {
11135
      strcpy(packMethodName, "8-png");
11136
11137
      break;
11138
    }
11139
    case PACK_PNG_64_COLORS:
11140
    {
11141
      strcpy(packMethodName, "64-png");
11142
11143
      break;
11144
    }
11145
    case PACK_PNG_256_COLORS:
11146
    {
11147
      strcpy(packMethodName, "256-png");
11148
11149
      break;
11150
    }
11151
    case PACK_PNG_512_COLORS:
11152
    {
11153
      strcpy(packMethodName, "512-png");
11154
11155
      break;
11156
    }
11157
    case PACK_PNG_4K_COLORS:
11158
    {
11159
      strcpy(packMethodName, "4k-png");
11160
11161
      break;
11162
    }
11163
    case PACK_PNG_32K_COLORS:
11164
    {
11165
      strcpy(packMethodName, "32k-png");
11166
11167
      break;
11168
    }
11169
    case PACK_PNG_64K_COLORS:
11170
    {
11171
      strcpy(packMethodName, "64k-png");
11172
11173
      break;
11174
    }
11175
    case PACK_PNG_256K_COLORS:
11176
    {
11177
      strcpy(packMethodName, "256k-png");
11178
11179
      break;
11180
    }
11181
    case PACK_PNG_2M_COLORS:
11182
    {
11183
      strcpy(packMethodName, "2m-png");
11184
11185
      break;
11186
    }
11187
    case PACK_PNG_16M_COLORS:
11188
    {
11189
      strcpy(packMethodName, "16m-png");
11190
11191
      break;
11192
    }
11193
    case PACK_RGB_16M_COLORS:
11194
    {
11195
      strcpy(packMethodName, "16m-rgb");
11196
11197
      break;
11198
    }
11199
    case PACK_RLE_16M_COLORS:
11200
    {
11201
      strcpy(packMethodName, "16m-rle");
11202
11203
      break;
11204
    }
11205
    case PACK_BITMAP_16M_COLORS:
11206
    {
11207
      strcpy(packMethodName, "16m-bitmap");
11208
11209
      break;
11210
    }
11211
    case PACK_LOSSY:
11212
    {
11213
      strcpy(packMethodName, "lossy");
11214
11215
      break;
11216
    }
11217
    case PACK_LOSSLESS:
11218
    {
11219
      strcpy(packMethodName, "lossless");
11220
11221
      break;
11222
    }
11223
    case PACK_ADAPTIVE:
11224
    {
11225
      strcpy(packMethodName, "adaptive");
11226
11227
      break;
11228
    }
11229
    default:
11230
    {
11231
      return -1;
11232
    }
11233
  }
11234
11235
  if (quality < 0 || quality > 9)
11236
  {
11237
    return -1;
11238
  }
11239
11240
  if (packMethod == PACK_RGB_16M_COLORS ||
11241
          packMethod == PACK_RLE_16M_COLORS ||
11242
              packMethod == PACK_BITMAP_16M_COLORS ||
11243
                  (packMethod >= PACK_JPEG_8_COLORS &&
11244
                      packMethod <= PACK_JPEG_16M_COLORS) ||
11245
                          (packMethod >= PACK_PNG_8_COLORS &&
11246
                              packMethod <= PACK_PNG_16M_COLORS) ||
11247
                                  packMethod == PACK_LOSSY ||
11248
                                      packMethod == PACK_LOSSLESS ||
11249
                                          packMethod == PACK_ADAPTIVE)
11250
  {
11251
    sprintf(packMethodName + strlen(packMethodName),
11252
                "-%d", quality);
11253
  }
11254
11255
  packMethod  = method;
11256
  packQuality = quality;
11257
11258
  control -> PackMethod  = packMethod;
11259
  control -> PackQuality = packQuality;
11260
11261
  return 1;
11262
}
11263
11264
int SetDirectories()
11265
{
11266
  //
11267
  // Determine the location of the user's NX
11268
  // directory and the other relevant paths.
11269
  // The functions below will check the pa-
11270
  // rameters passed to the program and will
11271
  // query the environment, if needed.
11272
  //
11273
11274
  control -> HomePath   = GetHomePath();
11275
  control -> RootPath   = GetRootPath();
11276
  control -> SystemPath = GetSystemPath();
11277
  control -> TempPath   = GetTempPath();
11278
  control -> ClientPath = GetClientPath();
11279
11280
  return 1;
11281
}
11282
11283
int SetLogs()
11284
{
11285
  //
11286
  // So far we used stderr (or stdout under
11287
  // WIN32). Now use the files selected by
11288
  // the user.
11289
  //
11290
11291
  if (*statsFileName == '\0')
11292
  {
11293
    strcpy(statsFileName, "stats");
11294
11295
    #ifdef TEST
11296
    *logofs << "Loop: Assuming default statistics file '"
11297
            << statsFileName << "'.\n" << logofs_flush;
11298
    #endif
11299
  }
11300
  #ifdef TEST
11301
  else
11302
  {
11303
    *logofs << "Loop: Name selected for statistics is '"
11304
            << statsFileName << "'.\n" << logofs_flush;
11305
  }
11306
  #endif
11307
11308
  if (OpenLogFile(statsFileName, statofs) < 0)
11309
  {
11310
    HandleCleanup();
11311
  }
11312
11313
  #ifndef MIXED
11314
11315
  if (*errorsFileName == '\0')
11316
  {
11317
    strcpy(errorsFileName, "errors");
11318
11319
    #ifdef TEST
11320
    *logofs << "Loop: Assuming default log file name '"
11321
            << errorsFileName << "'.\n" << logofs_flush;
11322
    #endif
11323
  }
11324
  #ifdef TEST
11325
  else
11326
  {
11327
    *logofs << "Loop: Name selected for log file is '"
11328
            << errorsFileName << "'.\n" << logofs_flush;
11329
  }
11330
  #endif
11331
11332
  //
11333
  // Share the bebug output with the nxssh binder
11334
  // process. The file must be made writable by
11335
  // everybody because the nxssh process is run by
11336
  // nxserver as the nx user.
11337
  //
11338
11339
  #ifdef BINDER
11340
11341
  strcpy(errorsFileName, "/tmp/errors");
11342
11343
  ostream *tmpfs = new ofstream(errorsFileName, ios::out);
11344
11345
  delete tmpfs;
11346
11347
  chmod(errorsFileName, S_IRUSR | S_IWUSR | S_IRGRP |
11348
            S_IWGRP | S_IROTH | S_IWOTH);
11349
11350
  #endif
11351
                
11352
  if (OpenLogFile(errorsFileName, logofs) < 0)
11353
  {
11354
    HandleCleanup();
11355
  }
11356
11357
  //
11358
  // By default the session log is the standard error
11359
  // of the process. It is anyway required to set the
11360
  // option when running inside SSH, otherwise the
11361
  // output will go to the same file as the SSH log,
11362
  // depending where the NX client has redirected the
11363
  // output.
11364
  //
11365
11366
  if (*sessionFileName != '\0')
11367
  {
11368
    #ifdef TEST
11369
    *logofs << "Loop: Name selected for session file is '"
11370
            << sessionFileName << "'.\n" << logofs_flush;
11371
    #endif
11372
11373
    if (errofs != NULL)
11374
    {
11375
      #ifdef WARNING
11376
      *logofs << "Loop: WARNING! Unexpected value for stream errofs.\n"
11377
              << logofs_flush;
11378
      #endif
11379
11380
      cerr << "Warning" << ": Unexpected value for stream errofs.\n";
11381
    }
11382
11383
    if (errsbuf != NULL)
11384
    {
11385
      #ifdef WARNING
11386
      *logofs << "Loop: WARNING! Unexpected value for buffer errsbuf.\n"
11387
              << logofs_flush;
11388
      #endif
11389
11390
      cerr << "Warning" << ": Unexpected value for buffer errsbuf.\n";
11391
    }
11392
11393
    errofs  = NULL;
11394
    errsbuf = NULL;
11395
11396
    if (OpenLogFile(sessionFileName, errofs) < 0)
11397
    {
11398
      HandleCleanup();
11399
    }
11400
11401
    //
11402
    // Redirect the standard error to the file.
11403
    //
11404
11405
    errsbuf = cerr.rdbuf(errofs -> rdbuf());
11406
  }
11407
11408
  #endif
11409
11410
  return 1;
11411
}
11412
11413
int SetPorts()
11414
{
11415
  //
11416
  // Depending on the proxy side, we need to determine on which
11417
  // port to listen for the given protocol or to which port we
11418
  // will have to forward the connection. Three possibilities
11419
  // are given for each supported protocol:
11420
  //
11421
  // Port <= 0: Disable port forwarding.
11422
  // Port == 1: Use the default port.
11423
  // Port >  1: Use the specified port.
11424
  //
11425
  // At the connectiong side the user should always explicitly
11426
  // set the ports where the connections will be forwarded. This
11427
  // is both for security reasons and because, when running both
11428
  // proxies on the same host, there is a concrete possibility
11429
  // that, by using the default ports, the connection will be
11430
  // forwarded to the same port where the peer proxy is listen-
11431
  // ing, causing a loop.
11432
  //
11433
11434
  if (cupsPort <= 0)
11435
  {
11436
    #ifdef TEST
11437
    *logofs << "Loop: Disabling cups connections.\n"
11438
            << logofs_flush;
11439
    #endif
11440
11441
    cupsPort = 0;
11442
11443
    useCupsSocket = 0;
11444
  }
11445
  else
11446
  {
11447
    if (control -> ProxyMode == proxy_client)
11448
    {
11449
      if (cupsPort == 1)
11450
      {
11451
        cupsPort = DEFAULT_NX_CUPS_PORT_OFFSET + proxyPort;
11452
      }
11453
11454
      useCupsSocket = 1;
11455
    }
11456
    else
11457
    {
11458
      if (cupsPort == 1)
11459
      {
11460
        //
11461
        // Use the well-known 631/tcp port of the
11462
        // Internet Printing Protocol.
11463
        //
11464
11465
        cupsPort = 631;
11466
      }
11467
11468
      useCupsSocket = 0;
11469
    }
11470
11471
    #ifdef TEST
11472
    *logofs << "Loop: Using cups port '" << cupsPort
11473
            << "'.\n" << logofs_flush;
11474
    #endif
11475
  }
11476
11477
  if (auxPort <= 0)
11478
  {
11479
    #ifdef TEST
11480
    *logofs << "Loop: Disabling auxiliary X11 connections.\n"
11481
            << logofs_flush;
11482
    #endif
11483
11484
    auxPort = 0;
11485
11486
    useAuxSocket = 0;
11487
  }
11488
  else
11489
  {
11490
    if (control -> ProxyMode == proxy_client)
11491
    {
11492
      if (auxPort == 1)
11493
      {
11494
        auxPort = DEFAULT_NX_AUX_PORT_OFFSET + proxyPort;
11495
      }
11496
11497
      useAuxSocket = 1;
11498
    }
11499
    else
11500
    {
11501
      //
11502
      // Auxiliary X connections are always forwarded
11503
      // to the display where the session is running.
11504
      // The only value accepted is 1.
11505
      //
11506
11507
      if (auxPort != 1)
11508
      {
11509
        #ifdef WARNING
11510
        *logofs << "Loop: WARNING! Overriding auxiliary X11 "
11511
                << "port with new value '" << 1 << "'.\n"
11512
                << logofs_flush;
11513
        #endif
11514
11515
        cerr << "Warning" << ": Overriding auxiliary X11 "
11516
             << "port with new value '" << 1 << "'.\n";
11517
11518
        auxPort = 1;
11519
      }
11520
11521
      useAuxSocket = 0;
11522
    }
11523
11524
    #ifdef TEST
11525
    *logofs << "Loop: Using auxiliary X11 port '" << auxPort
11526
            << "'.\n" << logofs_flush;
11527
    #endif
11528
  }
11529
11530
  if (smbPort <= 0)
11531
  {
11532
    #ifdef TEST
11533
    *logofs << "Loop: Disabling SMB connections.\n"
11534
            << logofs_flush;
11535
    #endif
11536
11537
    smbPort = 0;
11538
11539
    useSmbSocket = 0;
11540
  }
11541
  else
11542
  {
11543
    if (control -> ProxyMode == proxy_client)
11544
    {
11545
      if (smbPort == 1)
11546
      {
11547
        smbPort = DEFAULT_NX_SMB_PORT_OFFSET + proxyPort;
11548
      }
11549
11550
      useSmbSocket = 1;
11551
    }
11552
    else
11553
    {
11554
      if (smbPort == 1)
11555
      {
11556
        //
11557
        // Assume the 139/tcp port used for SMB
11558
        // over NetBIOS over TCP.
11559
        //
11560
11561
        smbPort = 139;
11562
      }
11563
11564
      useSmbSocket = 0;
11565
    }
11566
11567
    #ifdef TEST
11568
    *logofs << "Loop: Using SMB port '" << smbPort
11569
            << "'.\n" << logofs_flush;
11570
    #endif
11571
  }
11572
11573
  if (mediaPort <= 0)
11574
  {
11575
    #ifdef TEST
11576
    *logofs << "Loop: Disabling multimedia connections.\n"
11577
            << logofs_flush;
11578
    #endif
11579
11580
    mediaPort = 0;
11581
11582
    useMediaSocket = 0;
11583
  }
11584
  else
11585
  {
11586
    if (control -> ProxyMode == proxy_client)
11587
    {
11588
      if (mediaPort == 1)
11589
      {
11590
        mediaPort = DEFAULT_NX_MEDIA_PORT_OFFSET + proxyPort;
11591
      }
11592
11593
      useMediaSocket = 1;
11594
    }
11595
    else
11596
    {
11597
      if (mediaPort == 1)
11598
      {
11599
        //
11600
        // We don't have a well-known port to
11601
        // be used for media connections.
11602
        //
11603
11604
        #ifdef PANIC
11605
        *logofs << "Loop: PANIC! No port specified for multimedia connections.\n"
11606
                << logofs_flush;
11607
        #endif
11608
11609
        cerr << "Error" << ": No port specified for multimedia connections.\n";
11610
11611
        HandleCleanup();
11612
      }
11613
11614
      useMediaSocket = 0;
11615
    }
11616
11617
    #ifdef TEST
11618
    *logofs << "Loop: Using multimedia port '" << mediaPort
11619
            << "'.\n" << logofs_flush;
11620
    #endif
11621
  }
11622
11623
  if (httpPort <= 0)
11624
  {
11625
    #ifdef TEST
11626
    *logofs << "Loop: Disabling HTTP connections.\n"
11627
            << logofs_flush;
11628
    #endif
11629
11630
    httpPort = 0;
11631
11632
    useHttpSocket = 0;
11633
  }
11634
  else
11635
  {
11636
    if (control -> ProxyMode == proxy_client)
11637
    {
11638
      if (httpPort == 1)
11639
      {
11640
        httpPort = DEFAULT_NX_HTTP_PORT_OFFSET + proxyPort;
11641
      }
11642
11643
      useHttpSocket = 1;
11644
    }
11645
    else
11646
    {
11647
      if (httpPort == 1)
11648
      {
11649
        //
11650
        // Use the well-known 80/tcp port.
11651
        //
11652
11653
        httpPort = 80;
11654
      }
11655
11656
      useHttpSocket = 0;
11657
    }
11658
11659
    #ifdef TEST
11660
    *logofs << "Loop: Using HTTP port '" << httpPort
11661
            << "'.\n" << logofs_flush;
11662
    #endif
11663
  }
11664
11665
  if (ParseFontPath(fontPort) <= 0)
11666
  {
11667
    #ifdef TEST
11668
    *logofs << "Loop: Disabling font server connections.\n"
11669
            << logofs_flush;
11670
    #endif
11671
11672
    *fontPort = '\0';
11673
11674
    useFontSocket = 0;
11675
  }
11676
  else
11677
  {
11678
    //
11679
    // We don't know yet if the remote proxy supports
11680
    // the font server connections. If needed, we will
11681
    // disable the font server connections at later
11682
    // time.
11683
    //
11684
11685
    if (control -> ProxyMode == proxy_server)
11686
    {
11687
      useFontSocket = 1;
11688
    }
11689
    else
11690
    {
11691
      useFontSocket = 0;
11692
    }
11693
11694
    #ifdef TEST
11695
    *logofs << "Loop: Using font server port '" << fontPort
11696
            << "'.\n" << logofs_flush;
11697
    #endif
11698
  }
11699
11700
  if (slavePort <= 0)
11701
  {
11702
    #ifdef TEST
11703
    *logofs << "Loop: Disabling slave connections.\n"
11704
            << logofs_flush;
11705
    #endif
11706
11707
    slavePort = 0;
11708
11709
    useSlaveSocket = 0;
11710
  }
11711
  else
11712
  {
11713
    //
11714
    // File transfer connections can
11715
    // be originated by both sides.
11716
    //
11717
11718
    if (slavePort == 1)
11719
    {
11720
      if (control -> ProxyMode == proxy_client)
11721
      {
11722
        slavePort = DEFAULT_NX_SLAVE_PORT_CLIENT_OFFSET + proxyPort;
11723
      }
11724
      else
11725
      {
11726
        slavePort = DEFAULT_NX_SLAVE_PORT_SERVER_OFFSET + proxyPort;
11727
      }
11728
    }
11729
11730
    useSlaveSocket = 1;
11731
11732
    #ifdef TEST
11733
    *logofs << "Loop: Using slave port '" << slavePort
11734
            << "'.\n" << logofs_flush;
11735
    #endif
11736
  }
11737
11738
  return 1;
11739
}
11740
11741
int SetDescriptors()
11742
{
11743
  unsigned int limit = 0;
11744
11745
  #ifdef RLIMIT_NOFILE
11746
11747
  rlimit limits;
11748
11749
  if (getrlimit(RLIMIT_NOFILE, &limits) == 0)
11750
  {
11751
    if (limits.rlim_max == RLIM_INFINITY)
11752
    {
11753
      limit = 0;
11754
    }
11755
    else
11756
    {
11757
      limit = (unsigned int) limits.rlim_max;
11758
    }
11759
  }
11760
11761
  #endif
11762
11763
  #ifdef _SC_OPEN_MAX
11764
11765
  if (limit == 0)
11766
  {
11767
    limit = sysconf(_SC_OPEN_MAX);
11768
  }
11769
11770
  #endif
11771
11772
  #ifdef FD_SETSIZE
11773
11774
  if (limit > FD_SETSIZE)
11775
  {
11776
    limit = FD_SETSIZE;
11777
  }
11778
11779
  #endif
11780
11781
  #ifdef RLIMIT_NOFILE
11782
11783
  if (limits.rlim_cur < limit)
11784
  {
11785
    limits.rlim_cur = limit;
11786
11787
    setrlimit(RLIMIT_NOFILE, &limits);
11788
  }
11789
11790
  #endif
11791
11792
  if (limit == 0)
11793
  {
11794
    #ifdef PANIC
11795
    *logofs << "Loop: PANIC! Cannot determine number of available "
11796
            << "file descriptors.\n" << logofs_flush;
11797
    #endif
11798
11799
    cerr << "Error" << ": Cannot determine number of available "
11800
         << "file descriptors.\n";
11801
11802
    return -1;
11803
  }
11804
11805
  return 1;
11806
}
11807
11808
//
11809
// Find the directory containing the caches
11810
// matching the session type.
11811
//
11812
11813
int SetCaches()
11814
{
11815
  if ((control -> PersistentCachePath = GetCachePath()) == NULL)
11816
  {
11817
    #ifdef PANIC
11818
    *logofs << "Loop: PANIC! Error getting or creating the cache path.\n"
11819
            << logofs_flush;
11820
    #endif
11821
11822
    cerr << "Error" << ": Error getting or creating the cache path.\n";
11823
11824
    HandleCleanup();
11825
  }
11826
11827
  #ifdef TEST
11828
  *logofs << "Loop: Path of cache files is '" << control -> PersistentCachePath
11829
          << "'.\n" << logofs_flush;
11830
  #endif
11831
11832
  return 1;
11833
}
11834
11835
//
11836
// Initialize all configuration parameters.
11837
//
11838
11839
int SetParameters()
11840
{
11841
  //
11842
  // Find out the type of session.
11843
  //
11844
11845
  SetSession();
11846
11847
  //
11848
  // Initialize the network and compression
11849
  // parameters according to the settings
11850
  // suggested by the user.
11851
  //
11852
11853
  SetLink();
11854
11855
  //
11856
  // Set compression according to link speed.
11857
  //
11858
11859
  SetCompression();
11860
11861
  //
11862
  // Be sure that we have a literal for current
11863
  // cache size. Value will reflect control's
11864
  // default unless we already parsed a 'cache'
11865
  // option. Server side has no control on size
11866
  // of cache but is informed at session nego-
11867
  // tiation about how much memory is going to
11868
  // be used.
11869
  //
11870
11871
  SetStorage();
11872
11873
  //
11874
  // Set size of shared memory segments.
11875
  //
11876
11877
  SetShmem();
11878
11879
  //
11880
  // Make adjustments to cache based
11881
  // on the pack method.
11882
  //
11883
11884
  SetPack();
11885
11886
  //
11887
  // Set disk-based image cache.
11888
  //
11889
11890
  SetImages();
11891
11892
  //
11893
  // Set CPU and bandwidth limits.
11894
  //
11895
11896
  SetLimits();
11897
11898
  return 1;
11899
}
11900
11901
//
11902
// According to session literal determine
11903
// the type of traffic that is going to be
11904
// transported. Literals should be better
11905
// standardized in future NX versions.
11906
//
11907
11908
int SetSession()
11909
{
11910
  if (strncmp(sessionType, "agent", strlen("agent")) == 0 ||
11911
          strncmp(sessionType, "desktop", strlen("desktop")) == 0 ||
11912
              strncmp(sessionType, "rootless", strlen("rootless")) == 0 ||
11913
                  strncmp(sessionType, "console", strlen("console")) == 0 ||
11914
                      strncmp(sessionType, "default", strlen("default")) == 0 ||
11915
                          strncmp(sessionType, "gnome", strlen("gnome")) == 0 ||
11916
                              strncmp(sessionType, "kde", strlen("kde")) == 0 ||
11917
                                  strncmp(sessionType, "cde", strlen("cde")) == 0 ||
11918
                                      strncmp(sessionType, "xdm", strlen("xdm")) == 0)
11919
  {
11920
    control -> SessionMode = session_agent;
11921
  }
11922
  else if (strncmp(sessionType, "win", strlen("win")) == 0 ||
11923
               strncmp(sessionType, "vnc", strlen("vnc")) == 0)
11924
  {
11925
    control -> SessionMode = session_agent;
11926
  }
11927
  else if (strncmp(sessionType, "shadow", strlen("shadow")) == 0)
11928
  {
11929
    control -> SessionMode = session_shadow;
11930
  }
11931
  else if (strncmp(sessionType, "proxy", strlen("proxy")) == 0 ||
11932
               strncmp(sessionType, "application", strlen("application")) == 0 ||
11933
                   strncmp(sessionType, "raw", strlen("raw")) == 0)
11934
  {
11935
    control -> SessionMode = session_proxy;
11936
  }
11937
  else
11938
  {
11939
    //
11940
    // If the session type is not passed or
11941
    // it is not among the recognized strings,
11942
    // we assume that the proxy is connected
11943
    // to the agent.
11944
    //
11945
11946
    if (*sessionType != '\0' &&
11947
            (control -> isProtoStep8() == 1 ||
11948
                strncmp(sessionType, "unix-", strlen("unix-")) != 0))
11949
    {
11950
      #ifdef WARNING
11951
      *logofs << "Loop: WARNING! Unrecognized session type '"
11952
              << sessionType << "'. Assuming agent session.\n"
11953
              << logofs_flush;
11954
      #endif
11955
11956
      cerr << "Warning" << ": Unrecognized session type '"
11957
           << sessionType << "'. Assuming agent session.\n";
11958
    }
11959
11960
    control -> SessionMode = session_agent;
11961
  }
11962
11963
  #if defined(TEST) || defined(INFO)
11964
  *logofs << "Loop: Assuming session type '"
11965
          << DumpSession(control -> SessionMode) << "' with "
11966
          << "string '" << sessionType << "'.\n"
11967
          << logofs_flush;
11968
  #endif
11969
11970
  //
11971
  // By default the policy is immediate. Agents
11972
  // will set a different policy, if they like.
11973
  // Anyway we need to check if the user has
11974
  // provided a custom flush policy.
11975
  //
11976
11977
  if (usePolicy != -1)
11978
  {
11979
    if (usePolicy > 0)
11980
    {
11981
      control -> FlushPolicy = policy_deferred;
11982
    }
11983
    else
11984
    {
11985
      control -> FlushPolicy = policy_immediate;
11986
    }
11987
11988
    #if defined(TEST) || defined(INFO)
11989
    *logofs << "Loop: WARNING! Forcing flush policy to '"
11990
            << DumpPolicy(control -> FlushPolicy)
11991
            << ".\n" << logofs_flush;
11992
    #endif
11993
  }
11994
  else
11995
  {
11996
    control -> FlushPolicy = policy_immediate;
11997
11998
    #if defined(TEST) || defined(INFO)
11999
    *logofs << "Loop: Setting initial flush policy to '"
12000
            << DumpPolicy(control -> FlushPolicy)
12001
            << "'.\n" << logofs_flush;
12002
    #endif
12003
  }
12004
12005
  //
12006
  // Check if the proxy library is run inside
12007
  // another program providing encryption, as
12008
  // it is the case of the SSH client.
12009
  //
12010
12011
  if (useEncryption != -1)
12012
  {
12013
    if (useEncryption > 0)
12014
    {
12015
      control -> LinkEncrypted = 1;
12016
    }
12017
    else
12018
    {
12019
      control -> LinkEncrypted = 0;
12020
    }
12021
  }
12022
12023
  if (control -> LinkEncrypted == 1)
12024
  {
12025
    #if defined(TEST) || defined(INFO)
12026
    *logofs << "Loop: Proxy running as part of an "
12027
            << "encrypting client.\n"
12028
            << logofs_flush;
12029
    #endif
12030
  }
12031
  else
12032
  {
12033
    #if defined(TEST) || defined(INFO)
12034
    *logofs << "Loop: Assuming proxy running as a "
12035
            << "standalone program.\n"
12036
            << logofs_flush;
12037
    #endif
12038
  }
12039
12040
  //
12041
  // Check if the system administrator has
12042
  // enabled the respawn of the client at
12043
  // the end of session.
12044
  //
12045
12046
  if (control -> ProxyMode == proxy_server)
12047
  {
12048
    struct stat fileStat;
12049
12050
    char fileName[DEFAULT_STRING_LENGTH];
12051
12052
    snprintf(fileName, DEFAULT_STRING_LENGTH - 1,
12053
                 "%s/share/noexit", control -> SystemPath);
12054
12055
    *(fileName + DEFAULT_STRING_LENGTH - 1) = '\0';
12056
12057
    if (stat(fileName, &fileStat) == 0)
12058
    {
12059
      #ifdef TEST
12060
      *logofs << "Loop: Enabling respawn of client at session shutdown.\n"
12061
              << logofs_flush;
12062
      #endif
12063
12064
      control -> EnableRestartOnShutdown = 1;
12065
    }
12066
  }
12067
12068
  return 1;
12069
}
12070
12071
int SetStorage()
12072
{
12073
  //
12074
  // If differential compression is disabled
12075
  // we don't need a cache at all.
12076
  //
12077
12078
  if (control -> LocalDeltaCompression == 0)
12079
  {
12080
    control -> ClientTotalStorageSize = 0;
12081
    control -> ServerTotalStorageSize = 0;
12082
  }
12083
12084
  //
12085
  // Set a a cache size literal.
12086
  //
12087
12088
  int size = control -> getUpperStorageSize();
12089
12090
  if (size / 1024 > 0)
12091
  {
12092
    sprintf(cacheSizeName, "%dk", size / 1024);
12093
  }
12094
  else
12095
  { 
12096
    sprintf(cacheSizeName, "%d", size);
12097
  }
12098
12099
  if (control -> ProxyMode == proxy_client)
12100
  {
12101
    control -> LocalTotalStorageSize =
12102
        control -> ClientTotalStorageSize;
12103
12104
    control -> RemoteTotalStorageSize =
12105
        control -> ServerTotalStorageSize;
12106
  }
12107
  else
12108
  {
12109
    control -> LocalTotalStorageSize =
12110
        control -> ServerTotalStorageSize;
12111
12112
    control -> RemoteTotalStorageSize =
12113
        control -> ClientTotalStorageSize;
12114
  }
12115
12116
  #ifdef DEBUG
12117
  *logofs << "Loop: Storage size limit is "
12118
          << control -> ClientTotalStorageSize
12119
          << " at client and "
12120
          << control -> ServerTotalStorageSize
12121
          << " at server.\n"
12122
          << logofs_flush;
12123
  #endif
12124
12125
  #ifdef DEBUG
12126
  *logofs << "Loop: Storage local limit set to "
12127
          << control -> LocalTotalStorageSize
12128
          << " remote limit set to "
12129
          << control -> RemoteTotalStorageSize
12130
          << ".\n" << logofs_flush;
12131
  #endif
12132
12133
  //
12134
  // Never reserve for split store more than
12135
  // half the memory available for messages.
12136
  //
12137
12138
  if (size > 0 && control ->
12139
          SplitTotalStorageSize > size / 2)
12140
  {
12141
    #ifdef TEST
12142
    *logofs << "Loop: Reducing size of split store to "
12143
            << size / 2 << " bytes.\n"
12144
            << logofs_flush;
12145
    #endif
12146
12147
    control -> SplitTotalStorageSize = size / 2;
12148
  }
12149
12150
  //
12151
  // Don't load render from persistent
12152
  // cache if extension is hidden or
12153
  // not supported by agent.
12154
  //
12155
12156
  if (control -> HideRender == 1)
12157
  {
12158
    #ifdef TEST
12159
    *logofs << "Loop: Not loading render extension "
12160
            << "from persistent cache.\n"
12161
            << logofs_flush;
12162
    #endif
12163
12164
    control -> PersistentCacheLoadRender = 0;
12165
  }
12166
12167
  return 1;
12168
}
12169
12170
int SetShmem()
12171
{
12172
  //
12173
  // If not set, adjust the size of the shared
12174
  // memory segment according to size of the
12175
  // message cache.
12176
  //
12177
12178
  if (*shsegSizeName == '\0')
12179
  {
12180
    int size = control -> getUpperStorageSize();
12181
12182
    const int mega = 1048576;
12183
12184
    if (size > 0)
12185
    {
12186
      if (size <= 1 * mega)
12187
      {
12188
        size = 0;
12189
      }
12190
      else if (size <= 2 * mega)
12191
      {
12192
        size = 524288;
12193
      }
12194
      else if (size < 4 * mega)
12195
      {
12196
        size = 1048576;
12197
      }
12198
      else
12199
      {
12200
        size = size / 4;
12201
      }
12202
12203
      if (size > 4194304)
12204
      {
12205
        size = 4194304;
12206
      }
12207
12208
      control -> ShmemClientSize = size;
12209
      control -> ShmemServerSize = size;
12210
    }
12211
    else
12212
    {
12213
      //
12214
      // The delta compression is disabled.
12215
      // Use a default segment size of 2 MB.
12216
      //
12217
12218
      control -> ShmemServerSize = 2 * mega;
12219
    }
12220
  }
12221
12222
  //
12223
  // Client side shared memory support is
12224
  // not useful and not implemented.
12225
  //
12226
12227
  if (control -> ShmemServerSize >= 524288)
12228
  {
12229
    control -> ShmemServer = 1;
12230
12231
    #if defined(TEST) || defined(INFO)
12232
    *logofs << "Loop: Set initial shared memory size "
12233
            << "to " << control -> ShmemServerSize
12234
            << " bytes.\n" << logofs_flush;
12235
    #endif
12236
  }
12237
  else
12238
  {
12239
    #if defined(TEST) || defined(INFO)
12240
    *logofs << "Loop: Disabled use of the shared memory "
12241
            << "extension.\n" << logofs_flush;
12242
    #endif
12243
12244
    control -> ShmemServer = 0;
12245
  }
12246
12247
  return 1;
12248
}
12249
12250
//
12251
// Adjust the pack method according to the
12252
// type of the session.
12253
//
12254
12255
int SetPack()
12256
{
12257
  #ifdef TEST
12258
  *logofs << "Loop: Setting pack with initial method "
12259
          << packMethod << " and quality " << packQuality
12260
          << ".\n" << logofs_flush;
12261
  #endif
12262
12263
  //
12264
  // Check if this is a proxy session and, in
12265
  // this case, set the pack method to none.
12266
  // Packed images are not supported by plain
12267
  // X applications.
12268
  //
12269
12270
  if (control -> SessionMode == session_proxy)
12271
  {
12272
    #ifdef TEST
12273
    *logofs << "Loop: WARNING! Disabling pack with proxy session.\n"
12274
            << logofs_flush;
12275
    #endif
12276
12277
    packMethod = PACK_NONE;
12278
  }
12279
12280
  //
12281
  // Adjust the internal settings according
12282
  // to the newly selected pack method.
12283
  //
12284
12285
  ParsePackMethod(packMethod, packQuality);
12286
12287
  //
12288
  // Don't load messages from persistent
12289
  // cache if packed images are disabled.
12290
  //
12291
12292
  if (control -> PackMethod == PACK_NONE)
12293
  {
12294
    control -> PersistentCacheLoadPacked = 0;
12295
12296
    #ifdef TEST
12297
    *logofs << "Loop: Not loading packed images "
12298
            << "from persistent cache.\n"
12299
            << logofs_flush;
12300
    #endif
12301
  }
12302
12303
  return 1;
12304
}
12305
12306
//
12307
// Set the disk-based image cache parameters
12308
// according to the user's wishes.
12309
//
12310
12311
int SetImages()
12312
{
12313
  //
12314
  // Be sure we disable the image cache if we
12315
  // are connecting to plain X clients.
12316
  //
12317
12318
  if (control -> SessionMode == session_proxy)
12319
  {
12320
    #ifdef TEST
12321
    *logofs << "Loop: Disabling image cache with "
12322
            << "session '" << DumpSession(control ->
12323
               SessionMode) << "'.\n" << logofs_flush;
12324
    #endif
12325
12326
    sprintf(imagesSizeName, "0");
12327
12328
    control -> ImageCacheEnableLoad = 0;
12329
    control -> ImageCacheEnableSave = 0;
12330
12331
    return 1;
12332
  }
12333
12334
  int size = control -> ImageCacheDiskLimit;
12335
12336
  if (size / 1024 > 0)
12337
  {
12338
    sprintf(imagesSizeName, "%dk", size / 1024);
12339
  }
12340
  else
12341
  {
12342
    sprintf(imagesSizeName, "%d", size);
12343
  }
12344
12345
  if (size > 0)
12346
  {
12347
    control -> ImageCacheEnableLoad = 1;
12348
    control -> ImageCacheEnableSave = 1;
12349
12350
    if (control -> ProxyMode == proxy_server)
12351
    {
12352
      if ((control -> ImageCachePath = GetImagesPath()) == NULL)
12353
      {
12354
        #ifdef PANIC
12355
        *logofs << "Loop: PANIC! Error getting or creating image cache path.\n"
12356
                << logofs_flush;
12357
        #endif
12358
12359
        cerr << "Error" << ": Error getting or creating image cache path.\n";
12360
12361
        HandleCleanup();
12362
      }
12363
12364
      #ifdef TEST
12365
      *logofs << "Loop: Path of image cache files is '" << control -> ImageCachePath
12366
              << "'.\n" << logofs_flush;
12367
      #endif
12368
    }
12369
  }
12370
  else
12371
  {
12372
    #ifdef TEST
12373
    *logofs << "Loop: Disabling the persistent image cache.\n"
12374
            << logofs_flush;
12375
    #endif
12376
12377
    control -> ImageCacheEnableLoad = 0;
12378
    control -> ImageCacheEnableSave = 0;
12379
  }
12380
12381
  return 1;
12382
}
12383
12384
int SetVersion()
12385
{
12386
  //
12387
  // Normalize the different proxy versions.
12388
  //
12389
12390
  int local = (control -> LocalVersionMajor << 24) |
12391
                  (control -> LocalVersionMinor << 16) |
12392
                      control -> LocalVersionPatch;
12393
12394
  int remote = (control -> RemoteVersionMajor << 24) |
12395
                   (control -> RemoteVersionMinor << 16) |
12396
                       control -> RemoteVersionPatch;
12397
12398
  int major = -1;
12399
  int minor = -1;
12400
  int patch = -1;
12401
12402
  if (control -> RemoteVersionMajor <= 1)
12403
  {
12404
    //
12405
    // The remote proxy uses a different
12406
    // logic to determine the version so
12407
    // we default to the compatibility
12408
    // version.
12409
    //
12410
12411
    major = control -> CompatVersionMajor;
12412
    minor = control -> CompatVersionMinor;
12413
    patch = control -> CompatVersionPatch;
12414
12415
    #ifdef TEST
12416
    *logofs << "Loop: Using compatibility version '"
12417
            << major << "." << minor << "." << patch
12418
            << "'.\n" << logofs_flush;
12419
    #endif
12420
  }
12421
  else if (control -> LocalVersionMajor >
12422
               control -> RemoteVersionMajor)
12423
  {
12424
    //
12425
    // We use a more recent version. Let's
12426
    // negotiate the version based on the
12427
    // version supported by the remote.
12428
    //
12429
12430
    major = control -> RemoteVersionMajor;
12431
    minor = control -> RemoteVersionMinor;
12432
    patch = control -> RemoteVersionPatch;
12433
12434
    #ifdef TEST
12435
    *logofs << "Loop: Using remote version '"
12436
            << major << "." << minor << "." << patch
12437
            << "'.\n" << logofs_flush;
12438
    #endif
12439
  }
12440
  else
12441
  {
12442
    //
12443
    // We support a major version that is
12444
    // equal or older than the remote. We
12445
    // assume the smaller version between
12446
    // the two, including the minor and
12447
    // the patch numbers.
12448
    //
12449
12450
    if (local > remote)
12451
    {
12452
      major = control -> RemoteVersionMajor;
12453
      minor = control -> RemoteVersionMinor;
12454
      patch = control -> RemoteVersionPatch;
12455
12456
      #ifdef TEST
12457
      *logofs << "Loop: Using remote version '"
12458
              << major << "." << minor << "." << patch
12459
              << "'.\n" << logofs_flush;
12460
      #endif
12461
    }
12462
    else
12463
    {
12464
      major = control -> LocalVersionMajor;
12465
      minor = control -> LocalVersionMinor;
12466
      patch = control -> LocalVersionPatch;
12467
12468
      #ifdef TEST
12469
      *logofs << "Loop: Using local version '"
12470
              << major << "." << minor << "." << patch
12471
              << "'.\n" << logofs_flush;
12472
      #endif
12473
    }
12474
  }
12475
12476
  //
12477
  // Handle the 1.5.0 versions. The protocol
12478
  // step 6 is the minimum supported version.
12479
  //
12480
12481
  int step = 0;
12482
12483
  if (major == 1)
12484
  {
12485
    if (minor == 5)
12486
    {
12487
      step = 6;
12488
    }
12489
  }
12490
  else if (major == 2)
12491
  {
12492
    step = 7;
12493
  }
12494
  else if (major == 3)
12495
  {
12496
    if (minor >= 2)
12497
    {
12498
      step = 10;
12499
    }
12500
    else if (minor > 0 || patch > 0)
12501
    {
12502
      step = 9;
12503
    }
12504
    else
12505
    {
12506
      step = 8;
12507
    }
12508
  }
12509
  else if (major > 3)
12510
  {
12511
    step = 10;
12512
  }
12513
12514
  if (step == 0)
12515
  {
12516
    #ifdef PANIC
12517
    *logofs << "Loop: PANIC! Incompatible remote version "
12518
            << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor
12519
            << "." << control -> RemoteVersionPatch << " with local version "
12520
            << control -> LocalVersionMajor << "." << control -> LocalVersionMinor
12521
            << "." << control -> LocalVersionPatch << ".\n" << logofs_flush;
12522
    #endif
12523
12524
    cerr << "Error" << ": Incompatible remote version "
12525
         << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor
12526
         << "." << control -> RemoteVersionPatch << " with local version "
12527
         << control -> LocalVersionMajor << "." << control -> LocalVersionMinor
12528
         << "." << control -> LocalVersionPatch << ".\n";
12529
12530
    return -1;
12531
  }
12532
12533
  #ifdef TEST
12534
  *logofs << "Loop: Using NX protocol step "
12535
          << step << ".\n" << logofs_flush;
12536
  #endif
12537
12538
  control -> setProtoStep(step);
12539
12540
  //
12541
  // Ignore the differences in patch version
12542
  // and print a warning if the local version
12543
  // is different or obsolete compared to
12544
  // the remote.
12545
  //
12546
12547
  local  &= 0xffff0000;
12548
  remote &= 0xffff0000;
12549
12550
  if (local != remote)
12551
  {
12552
    #ifdef WARNING
12553
    *logofs << "Loop: WARNING! Connected to remote version "
12554
            << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor
12555
            << "." << control -> RemoteVersionPatch << " with local version "
12556
            << control -> LocalVersionMajor << "." << control -> LocalVersionMinor
12557
            << "." << control -> LocalVersionPatch << ".\n" << logofs_flush;
12558
    #endif
12559
12560
    cerr << "Warning" << ": Connected to remote version "
12561
         << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor
12562
         << "." << control -> RemoteVersionPatch << " with local version "
12563
         << control -> LocalVersionMajor << "." << control -> LocalVersionMinor
12564
         << "." << control -> LocalVersionPatch << ".\n" << logofs_flush;
12565
  }
12566
12567
  if (local < remote)
12568
  {
12569
    cerr << "Warning" << ": Consider checking http://www.nomachine.com/ for updates.\n";
12570
  }
12571
12572
  //
12573
  // Now that we are aware of the remote
12574
  // version, let's adjust the options to
12575
  // be compatible with the remote proxy.
12576
  //
12577
12578
  if (control -> ProxyMode == proxy_client)
12579
  {
12580
    if (control -> isProtoStep8() == 0)
12581
    {
12582
      if (strncmp(sessionType, "shadow", strlen("shadow")) == 0 ||
12583
              strncmp(sessionType, "application", strlen("application")) == 0 ||
12584
                  strncmp(sessionType, "console", strlen("console")) == 0 ||
12585
                      strncmp(sessionType, "default", strlen("default")) == 0 ||
12586
                          strncmp(sessionType, "gnome", strlen("gnome")) == 0 ||
12587
                              strncmp(sessionType, "kde", strlen("kde")) == 0 ||
12588
                                  strncmp(sessionType, "cde", strlen("cde")) == 0 ||
12589
                                      strncmp(sessionType, "xdm", strlen("xdm")) == 0)
12590
12591
      {
12592
        #if defined(TEST) || defined(INFO)
12593
        *logofs << "Loop: WARNING! Prepending 'unix-' to the "
12594
                << "name of the session.\n" << logofs_flush;
12595
        #endif
12596
12597
        char buffer[DEFAULT_STRING_LENGTH];
12598
12599
        snprintf(buffer, DEFAULT_STRING_LENGTH - 1, "unix-%s", sessionType);
12600
12601
        strcpy(sessionType, buffer);
12602
      }
12603
    }
12604
12605
    //
12606
    // Check if the remote is able to handle
12607
    // the selected pack method.
12608
    //
12609
12610
    if (control -> isProtoStep8() == 0)
12611
    {
12612
      if (packMethod == PACK_ADAPTIVE || packMethod == PACK_LOSSY)
12613
      {
12614
        #ifdef TEST
12615
        *logofs << "Loop: WARNING! Assuming a lossy encoding with "
12616
                << "an old proxy version.\n" << logofs_flush;
12617
        #endif
12618
12619
        packMethod = PACK_JPEG_16M_COLORS;
12620
      }
12621
      else if (packMethod == PACK_LOSSLESS)
12622
      {
12623
        #ifdef TEST
12624
        *logofs << "Loop: WARNING! Assuming a lossless encoding with "
12625
                << "an old proxy version.\n" << logofs_flush;
12626
        #endif
12627
12628
        if (control -> isProtoStep7() == 1)
12629
        {
12630
          packMethod = PACK_RLE_16M_COLORS;
12631
        }
12632
        else
12633
        {
12634
          packMethod = PACK_PNG_16M_COLORS;
12635
        }
12636
      }
12637
    }
12638
12639
    //
12640
    // If the remote doesn't support the
12641
    // selected method use something that
12642
    // is compatible.
12643
    //
12644
12645
    if ((packMethod == PACK_RGB_16M_COLORS ||
12646
            packMethod == PACK_RLE_16M_COLORS ||
12647
                packMethod == PACK_BITMAP_16M_COLORS) &&
12648
                    control -> isProtoStep7() == 0)
12649
    {
12650
      #ifdef TEST
12651
      *logofs << "Loop: WARNING! Setting the pack method to '"
12652
              << PACK_PNG_16M_COLORS << "' with '" << packMethod
12653
              << "' unsupported.\n" << logofs_flush;
12654
      #endif
12655
12656
      packMethod  = PACK_PNG_16M_COLORS;
12657
      packQuality = 9;
12658
    }
12659
    else if (packMethod == PACK_BITMAP_16M_COLORS &&
12660
                 control -> isProtoStep8() == 0)
12661
    {
12662
      #ifdef TEST
12663
      *logofs << "Loop: WARNING! Setting the pack method to '"
12664
              << PACK_RLE_16M_COLORS << "' with '" << packMethod
12665
              << "' unsupported.\n" << logofs_flush;
12666
      #endif
12667
12668
      packMethod  = PACK_RLE_16M_COLORS;
12669
      packQuality = 9;
12670
    }
12671
12672
    //
12673
    // Update the pack method name.
12674
    //
12675
12676
    ParsePackMethod(packMethod, packQuality);
12677
  }
12678
12679
  //
12680
  // At the moment the image cache is not used by the
12681
  // agent but we need to take care of the compatibi-
12682
  // lity with old versions. Proxy versions older than
12683
  // the 3.0.0 assume that it is enabled and will send
12684
  // specific bits as part of the encoding. Conversely,
12685
  // it is advisable to disable the cache right now.
12686
  // By not enabling the image cache, the house-keep-
12687
  // ing process will only take care of cleaning up
12688
  // the "cache-" directories.
12689
  //
12690
12691
  if (control -> isProtoStep8() == 1)
12692
  {
12693
    #ifdef TEST
12694
    *logofs << "Loop: Disabling image cache with protocol "
12695
            << "step '" << control -> getProtoStep()
12696
            << "'.\n"  << logofs_flush;
12697
    #endif
12698
12699
    sprintf(imagesSizeName, "0");
12700
12701
    control -> ImageCacheEnableLoad = 0;
12702
    control -> ImageCacheEnableSave = 0;
12703
  }
12704
12705
  return 1;
12706
}
12707
12708
//
12709
// Identify the requested link settings
12710
// and update the control parameters
12711
// accordingly.
12712
//
12713
12714
int SetLink()
12715
{
12716
  #ifdef TEST
12717
  *logofs << "Loop: Setting link with initial value "
12718
          << linkSpeedName << ".\n" << logofs_flush;
12719
  #endif
12720
12721
  if (*linkSpeedName == '\0')
12722
  {
12723
    strcpy(linkSpeedName, "lan");
12724
  }
12725
  
12726
  #ifdef TEST
12727
  *logofs << "Loop: Link speed is " << linkSpeedName
12728
          << ".\n" << logofs_flush;
12729
  #endif
12730
12731
  if (strcasecmp(linkSpeedName, "modem") == 0)
12732
  {
12733
    SetLinkModem();
12734
  }
12735
  else if (strcasecmp(linkSpeedName, "isdn") == 0)
12736
  {
12737
    SetLinkIsdn();
12738
  }
12739
  else if (strcasecmp(linkSpeedName, "adsl") == 0)
12740
  {
12741
    SetLinkAdsl();
12742
  }
12743
  else if (strcasecmp(linkSpeedName, "wan") == 0)
12744
  {
12745
    SetLinkWan();
12746
  }
12747
  else if (strcasecmp(linkSpeedName, "lan") == 0)
12748
  {
12749
    SetLinkLan();
12750
  }
12751
  else
12752
  {
12753
    return -1;
12754
  }
12755
12756
  //
12757
  // Set TCP_NODELAY according to the user's
12758
  // wishes.
12759
  //
12760
12761
  if (useNoDelay != -1)
12762
  {
12763
    control -> OptionProxyClientNoDelay = useNoDelay;
12764
    control -> OptionProxyServerNoDelay = useNoDelay;
12765
  }
12766
12767
  //
12768
  // Select the image compression method.
12769
  //
12770
12771
  if (packMethod == -1)
12772
  {
12773
    packMethod = control -> PackMethod;
12774
  }
12775
12776
  if (packQuality == -1)
12777
  {
12778
    packQuality = control -> PackQuality;
12779
  }
12780
12781
  if (ParsePackMethod(packMethod, packQuality) < 0)
12782
  {
12783
    #ifdef PANIC
12784
    *logofs << "Loop: PANIC! Unrecognized pack method id "
12785
            << packMethod << " with quality " << packQuality
12786
            << ".\n" << logofs_flush;
12787
    #endif
12788
12789
    cerr << "Error" << ": Unrecognized pack method id "
12790
         << packMethod << " with quality " << packQuality
12791
         << ".\n";
12792
12793
    HandleCleanup();
12794
  }
12795
12796
  //
12797
  // Check if the user disabled the ability
12798
  // to generate simple replies at the client
12799
  // side.
12800
  //
12801
12802
  if (control -> SessionMode == session_proxy)
12803
  {
12804
    if (useTaint != -1)
12805
    {
12806
      control -> TaintReplies = (useTaint == 1);
12807
    }
12808
    else
12809
    {
12810
      #ifdef WARNING
12811
      *logofs << "Loop: WARNING! Forcing taint of replies "
12812
              << "with a proxy session.\n"
12813
              << logofs_flush;
12814
      #endif
12815
12816
      control -> TaintReplies = 1;
12817
    }
12818
  }
12819
  else
12820
  {
12821
    //
12822
    // There is no need to taint the
12823
    // replies if we have an agent.
12824
    //
12825
12826
    control -> TaintReplies = 0;
12827
  }
12828
12829
  //
12830
  // Be sure that the requests needing a reply
12831
  // are flushed immediately. Normal X clients
12832
  // use so many replies to make the queuing
12833
  // completely useless.
12834
  //
12835
12836
  if (control -> SessionMode == session_proxy)
12837
  {
12838
    #ifdef WARNING
12839
    *logofs << "Loop: WARNING! Forcing flush on priority "
12840
            << "with a proxy session.\n"
12841
            << logofs_flush;
12842
    #endif
12843
12844
    control -> FlushPriority = 1;
12845
  }
12846
12847
  return 1;
12848
}
12849
12850
//
12851
// Parameters for MODEM 28.8/33.6/56 Kbps.
12852
//
12853
12854
int SetLinkModem()
12855
{
12856
  #ifdef TEST
12857
  *logofs << "Loop: Setting parameters for MODEM.\n"
12858
          << logofs_flush;
12859
  #endif
12860
12861
  control -> LinkMode = LINK_TYPE_MODEM;
12862
12863
  control -> TokenSize  = 256;
12864
  control -> TokenLimit = 24;
12865
12866
  control -> SplitMode             = 1;
12867
  control -> SplitTotalSize        = 128;
12868
  control -> SplitTotalStorageSize = 1048576;
12869
12870
  control -> SplitTimeout   = 50;
12871
  control -> MotionTimeout  = 50;
12872
  control -> IdleTimeout    = 50;
12873
12874
  control -> PackMethod  = PACK_ADAPTIVE;
12875
  control -> PackQuality = 3;
12876
12877
  return 1;
12878
}
12879
12880
//
12881
// Parameters for ISDN 64/128 Kbps.
12882
//
12883
12884
int SetLinkIsdn()
12885
{
12886
  #ifdef TEST
12887
  *logofs << "Loop: Setting parameters for ISDN.\n"
12888
          << logofs_flush;
12889
  #endif
12890
12891
  control -> LinkMode = LINK_TYPE_ISDN;
12892
12893
  control -> TokenSize  = 384;
12894
  control -> TokenLimit = 24;
12895
12896
  control -> SplitMode             = 1;
12897
  control -> SplitTotalSize        = 128;
12898
  control -> SplitTotalStorageSize = 1048576;
12899
12900
  control -> SplitTimeout   = 50;
12901
  control -> MotionTimeout  = 20;
12902
  control -> IdleTimeout    = 50;
12903
12904
  control -> PackMethod  = PACK_ADAPTIVE;
12905
  control -> PackQuality = 5;
12906
12907
  return 1;
12908
}
12909
12910
//
12911
// Parameters for ADSL 256 Kbps.
12912
//
12913
12914
int SetLinkAdsl()
12915
{
12916
  #ifdef TEST
12917
  *logofs << "Loop: Setting parameters for ADSL.\n"
12918
          << logofs_flush;
12919
  #endif
12920
12921
  control -> LinkMode = LINK_TYPE_ADSL;
12922
12923
  control -> TokenSize  = 512;
12924
  control -> TokenLimit = 24;
12925
12926
  control -> SplitMode             = 1;
12927
  control -> SplitTotalSize        = 128;
12928
  control -> SplitTotalStorageSize = 1048576;
12929
12930
  control -> SplitTimeout   = 50;
12931
  control -> MotionTimeout  = 10;
12932
  control -> IdleTimeout    = 50;
12933
12934
  control -> PackMethod  = PACK_ADAPTIVE;
12935
  control -> PackQuality = 7;
12936
12937
  return 1;
12938
}
12939
12940
//
12941
// Parameters for XDSL/FDDI/ATM 1/2/34 Mbps WAN.
12942
//
12943
12944
int SetLinkWan()
12945
{
12946
  #ifdef TEST
12947
  *logofs << "Loop: Setting parameters for WAN.\n"
12948
          << logofs_flush;
12949
  #endif
12950
12951
  control -> LinkMode = LINK_TYPE_WAN;
12952
12953
  control -> TokenSize  = 768;
12954
  control -> TokenLimit = 24;
12955
12956
  control -> SplitMode             = 1;
12957
  control -> SplitTotalSize        = 128;
12958
  control -> SplitTotalStorageSize = 1048576;
12959
12960
  control -> SplitTimeout   = 50;
12961
  control -> MotionTimeout  = 5;
12962
  control -> IdleTimeout    = 50;
12963
12964
  control -> PackMethod  = PACK_ADAPTIVE;
12965
  control -> PackQuality = 9;
12966
12967
  return 1;
12968
}
12969
12970
//
12971
// Parameters for LAN 10/100 Mbps.
12972
//
12973
12974
int SetLinkLan()
12975
{
12976
  #ifdef TEST
12977
  *logofs << "Loop: Setting parameters for LAN.\n"
12978
          << logofs_flush;
12979
  #endif
12980
12981
  control -> LinkMode = LINK_TYPE_LAN;
12982
12983
  control -> TokenSize  = 1536;
12984
  control -> TokenLimit = 24;
12985
12986
  control -> SplitMode             = 1;
12987
  control -> SplitTotalSize        = 128;
12988
  control -> SplitTotalStorageSize = 1048576;
12989
12990
  control -> SplitTimeout   = 50;
12991
  control -> MotionTimeout  = 0;
12992
  control -> IdleTimeout    = 50;
12993
12994
  control -> PackMethod  = PACK_ADAPTIVE;
12995
  control -> PackQuality = 9;
12996
12997
  return 1;
12998
}
12999
13000
//
13001
// Identify the requested link type and set
13002
// the control parameters accordingly.
13003
//
13004
13005
int SetCompression()
13006
{
13007
  if (strcasecmp(linkSpeedName, "modem") == 0)
13008
  {
13009
    SetCompressionModem();
13010
  }
13011
  else if (strcasecmp(linkSpeedName, "isdn") == 0)
13012
  {
13013
    SetCompressionIsdn();
13014
  }
13015
  else if (strcasecmp(linkSpeedName, "adsl") == 0)
13016
  {
13017
    SetCompressionAdsl();
13018
  }
13019
  else if (strcasecmp(linkSpeedName, "wan") == 0)
13020
  {
13021
    SetCompressionWan();
13022
  }
13023
  else if (strcasecmp(linkSpeedName, "lan") == 0)
13024
  {
13025
    SetCompressionLan();
13026
  }
13027
  else
13028
  {
13029
    return -1;
13030
  }
13031
13032
  if (control -> LocalDeltaCompression < 0)
13033
  {
13034
    control -> LocalDeltaCompression = 1;
13035
  }
13036
13037
  //
13038
  // If we didn't set remote delta compression
13039
  // (as it should always be the case at client
13040
  // side) assume value of local side.
13041
  //
13042
13043
  if (control -> RemoteDeltaCompression < 0)
13044
  {
13045
    control -> RemoteDeltaCompression =
13046
        control -> LocalDeltaCompression;
13047
  }
13048
13049
  //
13050
  // If we didn't set remote compression levels
13051
  // assume values of local side.
13052
  //
13053
13054
  if (control -> RemoteStreamCompression < 0)
13055
  {
13056
    control -> RemoteStreamCompressionLevel =
13057
        control -> LocalStreamCompressionLevel;
13058
13059
    if (control -> RemoteStreamCompressionLevel > 0)
13060
    {
13061
      control -> RemoteStreamCompression = 1;
13062
    }
13063
    else
13064
    {
13065
      control -> RemoteStreamCompression = 0;
13066
    }
13067
  }
13068
13069
  if (control -> RemoteDataCompression < 0)
13070
  {
13071
    control -> RemoteDataCompressionLevel =
13072
        control -> LocalDataCompressionLevel;
13073
13074
    if (control -> RemoteDataCompressionLevel > 0)
13075
    {
13076
      control -> RemoteDataCompression = 1;
13077
    }
13078
    else
13079
    {
13080
      control -> RemoteDataCompression = 0;
13081
    }
13082
  }
13083
13084
  return 1;
13085
}
13086
13087
//
13088
// Compression for MODEM.
13089
//
13090
13091
int SetCompressionModem()
13092
{
13093
  if (control -> LocalDataCompression < 0)
13094
  {
13095
    control -> LocalDataCompression      = 1;
13096
    control -> LocalDataCompressionLevel = 1;
13097
  }
13098
13099
  if (control -> LocalDataCompressionThreshold < 0)
13100
  {
13101
    control -> LocalDataCompressionThreshold = 32;
13102
  }
13103
13104
  if (control -> LocalStreamCompression < 0)
13105
  {
13106
    control -> LocalStreamCompression      = 1;
13107
    control -> LocalStreamCompressionLevel = 9;
13108
  }
13109
13110
  return 1;
13111
}
13112
13113
//
13114
// Compression for ISDN.
13115
//
13116
13117
int SetCompressionIsdn()
13118
{
13119
  if (control -> LocalDataCompression < 0)
13120
  {
13121
    control -> LocalDataCompression      = 1;
13122
    control -> LocalDataCompressionLevel = 1;
13123
  }
13124
13125
  if (control -> LocalDataCompressionThreshold < 0)
13126
  {
13127
    control -> LocalDataCompressionThreshold = 32;
13128
  }
13129
13130
  if (control -> LocalStreamCompression < 0)
13131
  {
13132
    control -> LocalStreamCompression      = 1;
13133
    control -> LocalStreamCompressionLevel = 6;
13134
  }
13135
13136
  return 1;
13137
}
13138
13139
//
13140
// Compression for ADSL.
13141
//
13142
13143
int SetCompressionAdsl()
13144
{
13145
  if (control -> LocalDataCompression < 0)
13146
  {
13147
    control -> LocalDataCompression      = 1;
13148
    control -> LocalDataCompressionLevel = 1;
13149
  }
13150
13151
  if (control -> LocalDataCompressionThreshold < 0)
13152
  {
13153
    control -> LocalDataCompressionThreshold = 32;
13154
  }
13155
13156
  if (control -> LocalStreamCompression < 0)
13157
  {
13158
    control -> LocalStreamCompression      = 1;
13159
    control -> LocalStreamCompressionLevel = 4;
13160
  }
13161
13162
  return 1;
13163
}
13164
13165
//
13166
// Compression for WAN.
13167
//
13168
13169
int SetCompressionWan()
13170
{
13171
  if (control -> LocalDataCompression < 0)
13172
  {
13173
    control -> LocalDataCompression      = 1;
13174
    control -> LocalDataCompressionLevel = 1;
13175
  }
13176
13177
  if (control -> LocalDataCompressionThreshold < 0)
13178
  {
13179
    control -> LocalDataCompressionThreshold = 32;
13180
  }
13181
13182
  if (control -> LocalStreamCompression < 0)
13183
  {
13184
    control -> LocalStreamCompression      = 1;
13185
    control -> LocalStreamCompressionLevel = 1;
13186
  }
13187
13188
  return 1;
13189
}
13190
13191
//
13192
// Compression for LAN.
13193
//
13194
13195
int SetCompressionLan()
13196
{
13197
  //
13198
  // Disable delta compression if not
13199
  // explicitly enabled.
13200
  //
13201
13202
  if (control -> LocalDeltaCompression < 0)
13203
  {
13204
    control -> LocalDeltaCompression = 0;
13205
  }
13206
13207
  if (control -> LocalDataCompression < 0)
13208
  {
13209
    control -> LocalDataCompression      = 0;
13210
    control -> LocalDataCompressionLevel = 0;
13211
  }
13212
13213
  if (control -> LocalDataCompressionThreshold < 0)
13214
  {
13215
    control -> LocalDataCompressionThreshold = 0;
13216
  }
13217
13218
  if (control -> LocalStreamCompression < 0)
13219
  {
13220
    control -> LocalStreamCompression      = 0;
13221
    control -> LocalStreamCompressionLevel = 0;
13222
  }
13223
13224
  return 1;
13225
}
13226
13227
int SetLimits()
13228
{
13229
  //
13230
  // Check if the user requested strict
13231
  // control flow parameters.
13232
  //
13233
13234
  if (useStrict == 1)
13235
  {
13236
    #if defined(TEST) || defined(INFO)
13237
    *logofs << "Loop: LIMIT! Decreasing the token limit "
13238
            << "to " << control -> TokenLimit / 2
13239
            << " with option 'strict'.\n"
13240
            << logofs_flush;
13241
    #endif
13242
13243
    control -> TokenLimit /= 2;
13244
  }
13245
13246
  #ifdef STRICT
13247
13248
  control -> TokenLimit = 1;
13249
13250
  #if defined(TEST) || defined(INFO)
13251
  *logofs << "Loop: WARNING! LIMIT! Setting the token limit "
13252
          << "to " << control -> TokenLimit
13253
          << " to simulate the proxy congestion.\n"
13254
          << logofs_flush;
13255
  #endif
13256
13257
  #endif
13258
13259
  //
13260
  // Reduce the size of the log file.
13261
  //
13262
13263
  #ifdef QUOTA
13264
13265
  control -> FileSizeLimit = 8388608;
13266
13267
  #endif
13268
13269
  //
13270
  // Check the bitrate limits.
13271
  //
13272
13273
  if (control -> LocalBitrateLimit == -1)
13274
  {
13275
    if (control -> ProxyMode == proxy_client)
13276
    {
13277
      control -> LocalBitrateLimit =
13278
          control -> ClientBitrateLimit;
13279
    }
13280
    else
13281
    {
13282
      control -> LocalBitrateLimit =
13283
          control -> ServerBitrateLimit;
13284
    }
13285
  }
13286
13287
  #if defined(TEST) || defined(INFO)
13288
  *logofs << "Loop: LIMIT! Setting client bitrate limit "
13289
          << "to " << control -> ClientBitrateLimit
13290
          << " server bitrate limit to " << control ->
13291
             ServerBitrateLimit << " with local limit "
13292
          << control -> LocalBitrateLimit << ".\n"
13293
          << logofs_flush;
13294
  #endif
13295
13296
  return 1;
13297
}
13298
13299
//
13300
// These functions are used to parse literal
13301
// values provided by the user and set the
13302
// control parameters accordingly.
13303
//
13304
13305
int ParseCacheOption(const char *opt)
13306
{
13307
  int size = ParseArg("", "cache", opt);
13308
13309
  if (size < 0)
13310
  {
13311
    #ifdef PANIC
13312
    *logofs << "Loop: PANIC! Invalid value '"
13313
            << opt << "' for option 'cache'.\n"
13314
            << logofs_flush;
13315
    #endif
13316
13317
    cerr << "Error" << ": Invalid value '"
13318
         << opt << "' for option 'cache'.\n";
13319
13320
    return -1;
13321
  }
13322
13323
  #ifdef TEST
13324
  *logofs << "Loop: Setting size of cache to "
13325
          << size << " bytes.\n" << logofs_flush;
13326
  #endif
13327
13328
  control -> ClientTotalStorageSize = size;
13329
  control -> ServerTotalStorageSize = size;
13330
13331
  strcpy(cacheSizeName, opt);
13332
13333
  if (size == 0)
13334
  {
13335
    #ifdef WARNING
13336
    *logofs << "Loop: WARNING! Disabling NX delta compression.\n"
13337
            << logofs_flush;
13338
    #endif
13339
13340
    control -> LocalDeltaCompression = 0;
13341
13342
    #ifdef WARNING
13343
    *logofs << "Loop: WARNING! Disabling use of NX persistent cache.\n"
13344
            << logofs_flush;
13345
    #endif
13346
13347
    control -> PersistentCacheEnableLoad = 0;
13348
    control -> PersistentCacheEnableSave = 0;
13349
  }
13350
13351
  return 1;
13352
}
13353
13354
int ParseImagesOption(const char *opt)
13355
{
13356
  int size = ParseArg("", "images", opt);
13357
13358
  if (size < 0)
13359
  {
13360
    #ifdef PANIC
13361
    *logofs << "Loop: PANIC! Invalid value '"
13362
            << opt << "' for option 'images'.\n"
13363
            << logofs_flush;
13364
    #endif
13365
13366
    cerr << "Error" << ": Invalid value '"
13367
         << opt << "' for option 'images'.\n";
13368
13369
    return -1;
13370
  }
13371
13372
  #ifdef TEST
13373
  *logofs << "Loop: Setting size of images cache to "
13374
          << size << " bytes.\n" << logofs_flush;
13375
  #endif
13376
13377
  control -> ImageCacheDiskLimit = size;
13378
13379
  strcpy(imagesSizeName, opt);
13380
13381
  return 1;
13382
}
13383
13384
int ParseShmemOption(const char *opt)
13385
{
13386
  int size = ParseArg("", "shseg", opt);
13387
13388
  if (size < 0)
13389
  {
13390
    #ifdef PANIC
13391
    *logofs << "Loop: PANIC! Invalid value '"
13392
            << opt << "' for option 'shseg'.\n"
13393
            << logofs_flush;
13394
    #endif
13395
13396
    cerr << "Error" << ": Invalid value '"
13397
         << opt << "' for option 'shseg'.\n";
13398
13399
    return -1;
13400
  }
13401
13402
  control -> ShmemClientSize = size;
13403
  control -> ShmemServerSize = size;
13404
13405
  #if defined(TEST) || defined(INFO)
13406
  *logofs << "Loop: Set shared memory size to "
13407
          << control -> ShmemServerSize << " bytes.\n"
13408
          << logofs_flush;
13409
  #endif
13410
13411
  strcpy(shsegSizeName, opt);
13412
13413
  return 1;
13414
}
13415
13416
int ParseBitrateOption(const char *opt)
13417
{
13418
  int bitrate = ParseArg("", "limit", opt);
13419
13420
  if (bitrate < 0)
13421
  {
13422
    #ifdef PANIC
13423
    *logofs << "Loop: PANIC! Invalid value '"
13424
            << opt << "' for option 'limit'.\n"
13425
            << logofs_flush;
13426
    #endif
13427
13428
    cerr << "Error" << ": Invalid value '"
13429
         << opt << "' for option 'limit'.\n";
13430
13431
    return -1;
13432
  }
13433
13434
  strcpy(bitrateLimitName, opt);
13435
13436
  if (bitrate == 0)
13437
  {
13438
    #ifdef TEST
13439
    *logofs << "Loop: Disabling bitrate limit on proxy link.\n"
13440
            << logofs_flush;
13441
    #endif
13442
13443
    control -> LocalBitrateLimit = 0;
13444
  }
13445
  else
13446
  {
13447
    #ifdef TEST
13448
    *logofs << "Loop: Setting bitrate to " << bitrate
13449
            << " bits per second.\n" << logofs_flush;
13450
    #endif
13451
13452
    //
13453
    // Internal representation is in bytes
13454
    // per second.
13455
    //
13456
13457
    control -> LocalBitrateLimit = bitrate >> 3;
13458
  }
13459
13460
  return 1;
13461
}
13462
13463
int ParseHostOption(const char *opt, char *host, int &port)
13464
{
13465
  #ifdef TEST
13466
  *logofs << "Loop: Trying to parse options string '" << opt
13467
          << "' as a remote NX host.\n" << logofs_flush;
13468
  #endif
13469
13470
  if (opt == NULL || *opt == '\0')
13471
  {
13472
    #ifdef PANIC
13473
    *logofs << "Loop: PANIC! No host parameter provided.\n"
13474
            << logofs_flush;
13475
    #endif
13476
13477
    return 0;
13478
  }
13479
  else if (strlen(opt) >= DEFAULT_STRING_LENGTH)
13480
  {
13481
    #ifdef PANIC
13482
    *logofs << "Loop: PANIC! Host parameter exceeds length of "
13483
            << DEFAULT_STRING_LENGTH << " characters.\n"
13484
            << logofs_flush;
13485
    #endif
13486
13487
    return 0;
13488
  }
13489
13490
  //
13491
  // Look for a host name followed
13492
  // by a colon followed by port.
13493
  //
13494
13495
  int newPort = port;
13496
13497
  const char *separator = rindex(opt, ':');
13498
13499
  if (separator != NULL)
13500
  {
13501
    const char *check = separator + 1;
13502
13503
    while (*check != '\0' && *check != ',' &&
13504
               *check != '=' && isdigit(*check) != 0)
13505
    {
13506
      check++;
13507
    }
13508
13509
    newPort = atoi(separator + 1);
13510
13511
    if (newPort < 0 || *check != '\0')
13512
    {
13513
      #ifdef TEST
13514
      *logofs << "Loop: Can't identify remote NX port in string '"
13515
              << separator << "'.\n" << logofs_flush;
13516
      #endif
13517
13518
      return 0;
13519
    }
13520
  }
13521
  else if (newPort < 0)
13522
  {
13523
    //
13524
    // Complain if port was not passed
13525
    // by other means.
13526
    //
13527
13528
    #ifdef TEST
13529
    *logofs << "Loop: Can't identify remote NX port in string '"
13530
            << opt << "'.\n" << logofs_flush;
13531
    #endif
13532
13533
    return 0;
13534
  }
13535
  else
13536
  {
13537
    separator = opt + strlen(opt);
13538
  }
13539
13540
  char newHost[DEFAULT_STRING_LENGTH] = { 0 };
13541
13542
  strncpy(newHost, opt, strlen(opt) - strlen(separator));
13543
13544
  *(newHost + strlen(opt) - strlen(separator)) = '\0';
13545
13546
  const char *check = newHost;
13547
13548
  while (*check != '\0' && *check != ',' &&
13549
             *check != '=')
13550
  {
13551
    check++;
13552
  }
13553
13554
  if (*check != '\0')
13555
  {
13556
    #ifdef TEST
13557
    *logofs << "Loop: Can't identify remote NX host in string '"
13558
            << newHost << "'.\n" << logofs_flush;
13559
    #endif
13560
13561
    return 0;
13562
  }
13563
  else if (*acceptHost != '\0')
13564
  {
13565
    #ifdef PANIC
13566
    *logofs << "Loop: PANIC! Can't manage to connect and accept connections "
13567
            << "at the same time.\n" << logofs_flush;
13568
13569
    *logofs << "Loop: PANIC! Refusing remote NX host with string '"
13570
            << opt << "'.\n" << logofs_flush;
13571
    #endif
13572
13573
    cerr << "Error" << ": Can't manage to connect and accept connections "
13574
         << "at the same time.\n";
13575
13576
    cerr << "Error" << ": Refusing remote NX host with string '"
13577
         << opt << "'.\n";
13578
13579
    return -1;
13580
  }
13581
13582
  if (*host != '\0' && strcmp(host, newHost) != 0)
13583
  {
13584
    #ifdef WARNING
13585
    *logofs << "Loop: WARNING! Overriding remote NX host '"
13586
            << host << "' with new value '" << newHost
13587
            << "'.\n" << logofs_flush;
13588
    #endif
13589
  }
13590
13591
  strcpy(host, newHost);
13592
13593
  if (port != -1 && port != newPort)
13594
  {
13595
    #ifdef WARNING
13596
    *logofs << "Loop: WARNING! Overriding remote NX port '"
13597
            << port << "' with new value '" << newPort
13598
            << "'.\n" << logofs_flush;
13599
    #endif
13600
  }
13601
13602
  #ifdef TEST
13603
  *logofs << "Loop: Parsed options string '" << opt
13604
          << "' with host '" << newHost << "' and port '"
13605
          << newPort << "'.\n" << logofs_flush;
13606
  #endif
13607
13608
  port = newPort;
13609
13610
  return 1;
13611
}
13612
13613
int ParseFontPath(char *path)
13614
{
13615
  char oldPath[DEFAULT_STRING_LENGTH];
13616
13617
  strcpy(oldPath, path);
13618
13619
  if (path == NULL || *path == '\0' || strcmp(path, "0") == 0)
13620
  {
13621
    return 0;
13622
  }
13623
13624
  #ifdef TEST
13625
  *logofs << "Loop: Parsing font server option '" << path
13626
          << "'.\n" << logofs_flush;
13627
  #endif
13628
13629
  //
13630
  // Convert the value to our default port.
13631
  //
13632
13633
  if (strcmp(fontPort, "1") == 0)
13634
  {
13635
    if (control -> ProxyMode == proxy_server)
13636
    {
13637
      snprintf(fontPort, DEFAULT_STRING_LENGTH - 1, "%d",
13638
                   DEFAULT_NX_FONT_PORT_OFFSET + proxyPort);
13639
    }
13640
    else
13641
    {
13642
      //
13643
      // Let the client use the well-known
13644
      // "unix/:7100" font path.
13645
      //
13646
13647
      snprintf(fontPort, DEFAULT_STRING_LENGTH - 1, "unix/:7100");
13648
    }
13649
  }
13650
13651
  //
13652
  // Check if a simple numaric value was given.
13653
  //
13654
13655
  if (atoi(path) > 0)
13656
  {
13657
    #ifdef TEST
13658
    *logofs << "Loop: Assuming numeric TCP port '" << atoi(path)
13659
            << "' for font server.\n" << logofs_flush;
13660
    #endif
13661
13662
    return 1;
13663
  }
13664
13665
  //
13666
  // Let's assume that a port specification "unix/:7100"
13667
  // corresponds to "$TEMP/.font-unix/fs7100" and a port
13668
  // "unix/:-1" corresponds to "$TEMP/.font-unix/fs-1".
13669
  //
13670
13671
  if (strncmp("unix/:", path, 6) == 0)
13672
  {
13673
    snprintf(path, DEFAULT_STRING_LENGTH - 1, "%s/.font-unix/fs%s",
13674
                 control -> TempPath, oldPath + 6);
13675
13676
    *(path + DEFAULT_STRING_LENGTH - 1) = '\0';
13677
13678
    #ifdef TEST
13679
    *logofs << "Loop: Assuming Unix socket '" << path
13680
            << "' for font server.\n" << logofs_flush;
13681
    #endif
13682
  }
13683
  else if (strncmp("tcp/:", path, 5) == 0)
13684
  {
13685
    snprintf(path, DEFAULT_STRING_LENGTH - 1, "%d", atoi(oldPath + 5));
13686
13687
    *(path + DEFAULT_STRING_LENGTH - 1) = '\0';
13688
13689
    if (atoi(path) <= 0)
13690
    {
13691
      goto ParseFontPathError;
13692
    }
13693
13694
    #ifdef TEST
13695
    *logofs << "Loop: Assuming TCP port '" << atoi(path)
13696
            << "' for font server.\n" << logofs_flush;
13697
    #endif
13698
  }
13699
  else
13700
  {
13701
    //
13702
    // Accept an absolute file path as
13703
    // a valid Unix socket.
13704
    //
13705
13706
    if (*path != '/')
13707
    {
13708
      goto ParseFontPathError;
13709
    }
13710
13711
    #ifdef TEST
13712
    *logofs << "Loop: Assuming Unix socket '" << path
13713
            << "' for font server.\n" << logofs_flush;
13714
    #endif
13715
  }
13716
13717
  return 1;
13718
13719
ParseFontPathError:
13720
13721
  #ifdef TEST
13722
  *logofs << "Loop: Unable to determine the font server "
13723
          << "port in string '" << path << "'.\n"
13724
          << logofs_flush;
13725
  #endif
13726
13727
  return -1;
13728
}
13729
13730
int ParseListenOption(int &address)
13731
{
13732
  if (*listenHost == '\0')
13733
  {
13734
    //
13735
    // On the X client side listen on any address.
13736
    // On the X server side listen to the forwarder
13737
    // on localhost.
13738
    //
13739
13740
    if (control -> ProxyMode == proxy_server)
13741
    {
13742
      address = (int) inet_addr("127.0.0.1");
13743
    }
13744
    else
13745
    {
13746
      address = htonl(INADDR_ANY);
13747
    }
13748
  }
13749
  else
13750
  {
13751
    address = inet_addr(listenHost);
13752
  }
13753
13754
  return 1;
13755
}
13756
13757
int OpenLogFile(char *name, ostream *&stream)
13758
{
13759
  if (name == NULL || *name == '\0')
13760
  {
13761
    #ifdef TEST
13762
    *logofs << "Loop: WARNING! No name provided for output. Using standard error.\n"
13763
            << logofs_flush;
13764
    #endif
13765
13766
    if (stream == NULL)
13767
    {
13768
      stream = &cerr;
13769
    }
13770
13771
    return 1;
13772
  }
13773
13774
  if (stream == NULL || stream == &cerr)
13775
  {
13776
    if (*name != '/' && *name != '.')
13777
    {
13778
      char *filePath = GetSessionPath();
13779
13780
      if (filePath == NULL)
13781
      {
13782
        #ifdef PANIC
13783
        *logofs << "Loop: PANIC! Cannot determine directory of NX session file.\n"
13784
                << logofs_flush;
13785
        #endif
13786
13787
        cerr << "Error" << ": Cannot determine directory of NX session file.\n";
13788
13789
        return -1;
13790
      }
13791
13792
      if (strlen(filePath) + strlen("/") +
13793
              strlen(name) + 1 > DEFAULT_STRING_LENGTH)
13794
      {
13795
        #ifdef PANIC
13796
        *logofs << "Loop: PANIC! Full name of NX file '" << name
13797
                << " would exceed length of " << DEFAULT_STRING_LENGTH
13798
                << " characters.\n" << logofs_flush;
13799
        #endif
13800
13801
        cerr << "Error" << ": Full name of NX file '" << name
13802
             << " would exceed length of " << DEFAULT_STRING_LENGTH
13803
             << " characters.\n";
13804
13805
        return -1;
13806
      }
13807
13808
      char *file = new char[strlen(filePath) + strlen("/") +
13809
                                strlen(name) + 1];
13810
13811
      //
13812
      // Transform name in a fully qualified name.
13813
      //
13814
13815
      strcpy(file, filePath);
13816
      strcat(file, "/");
13817
      strcat(file, name);
13818
13819
      strcpy(name, file);
13820
13821
      delete [] filePath;
13822
      delete [] file;
13823
    }
13824
13825
    mode_t fileMode = umask(0077);
13826
13827
    for (;;)
13828
    {
13829
      if ((stream = new ofstream(name, ios::app)) != NULL)
13830
      {
13831
        break;
13832
      }
13833
13834
      usleep(200000);
13835
    }
13836
13837
    umask(fileMode);
13838
  }
13839
  else
13840
  {
13841
    #ifdef PANIC
13842
    *logofs << "Loop: PANIC! Bad stream provided for output.\n"
13843
            << logofs_flush;
13844
    #endif
13845
13846
    cerr << "Error" << ": Bad stream provided for output.\n";
13847
13848
    return -1;
13849
  }
13850
13851
  return 1;
13852
}
13853
13854
int ReopenLogFile(char *name, ostream *&stream, int limit)
13855
{
13856
  if (*name != '\0' && limit >= 0)
13857
  {
13858
    struct stat fileStat;
13859
13860
    if (limit > 0)
13861
    {
13862
      //
13863
      // This is used for the log file, if the
13864
      // size exceeds the limit.
13865
      //
13866
13867
      if (stat(name, &fileStat) != 0)
13868
      {
13869
        #ifdef WARNING
13870
        *logofs << "Loop: WARNING! Can't get stats of file '"
13871
                << name  << "'. Error is " << EGET() 
13872
                << " '" << ESTR() << "'.\n" << logofs_flush;
13873
        #endif
13874
13875
        return 0;
13876
      }
13877
      else if (fileStat.st_size < (long) limit)
13878
      {
13879
        return 0;
13880
      }
13881
    }
13882
13883
    #ifdef TEST
13884
    *logofs << "Loop: Deleting file '" << name
13885
            << "' with size " << fileStat.st_size
13886
            << ".\n" << logofs_flush;
13887
    #endif
13888
13889
    //
13890
    // Create a new stream over the previous
13891
    // file. Trying to delete the file fails
13892
    // to work on recent Cygwin installs.
13893
    //
13894
13895
    *stream << flush;
13896
13897
    delete stream;
13898
13899
    mode_t fileMode = umask(0077);
13900
13901
    for (;;)
13902
    {
13903
      if ((stream = new ofstream(name, ios::out)) != NULL)
13904
      {
13905
        break;
13906
      }
13907
13908
      usleep(200000);
13909
    }
13910
13911
    umask(fileMode);
13912
13913
    #ifdef TEST
13914
    *logofs << "Loop: Reopened file '" << name
13915
            << "'.\n" << logofs_flush;
13916
    #endif
13917
  }
13918
13919
  return 1;
13920
}
13921
13922
void PrintProcessInfo()
13923
{
13924
  if (agent == NULL)
13925
  {
13926
    cerr << "\nNXPROXY - Version " << control -> LocalVersionMajor
13927
         << "." << control -> LocalVersionMinor << "."
13928
         << control -> LocalVersionPatch << "\n\n";
13929
13930
    cerr << "Copyright (C) 2001, 2007 NoMachine.\n"
13931
         << "See http://www.nomachine.com/ for more information.\n\n";
13932
  }
13933
13934
  //
13935
  // People get confused by the fact that client
13936
  // mode is running on NX server and viceversa.
13937
  // Let's adopt an user-friendly naming conven-
13938
  // tion here.
13939
  //
13940
13941
  cerr << "Info: Proxy running in "
13942
       << (control -> ProxyMode == proxy_client ? "server" : "client")
13943
       << " mode with pid '" << getpid() << "'.\n";
13944
13945
  if (agent == NULL)
13946
  {
13947
    cerr << "Session" << ": Starting session at '"
13948
         << strTimestamp() << "'.\n";
13949
  }
13950
13951
  #ifdef TEST
13952
13953
  if (*errorsFileName != '\0')
13954
  {
13955
    cerr << "Info" << ": Using errors file '" << errorsFileName << "'.\n";
13956
  }
13957
13958
  if (*statsFileName != '\0')
13959
  {
13960
    cerr << "Info" << ": Using stats file '" << statsFileName << "'.\n";
13961
  }
13962
13963
  #endif
13964
}
13965
13966
void PrintConnectionInfo()
13967
{
13968
  cerr << "Info" << ": Using "
13969
       << linkSpeedName << " link parameters "
13970
       << control -> TokenSize
13971
       << "/" << control -> TokenLimit
13972
       << "/" << control -> FlushPolicy + 1
13973
       << "/" << control -> FlushPriority
13974
       << ".\n";
13975
13976
  if (control -> ProxyMode == proxy_client)
13977
  {
13978
    cerr << "Info" << ": Using agent parameters "
13979
         << control -> PingTimeout
13980
         << "/" << control -> MotionTimeout
13981
         << "/" << control -> IdleTimeout
13982
         << "/" << control -> TaintReplies
13983
         << "/" << control -> HideRender
13984
         << ".\n";
13985
  }
13986
13987
  if (control -> LocalDeltaCompression == 1)
13988
  {
13989
    cerr << "Info" << ": Using cache parameters "
13990
         << control -> MinimumMessageSize
13991
         << "/" << control -> MaximumMessageSize / 1024 << "KB"
13992
         << "/" << control -> ClientTotalStorageSize / 1024 << "KB"
13993
         << "/" << control -> ServerTotalStorageSize / 1024 << "KB"
13994
         << ".\n";
13995
  }
13996
13997
  if (control -> ImageCacheEnableLoad == 1 ||
13998
          control -> ImageCacheEnableSave == 1)
13999
  {
14000
    cerr << "Info" << ": Using image streaming parameters "
14001
         << control -> SplitTimeout
14002
         << "/" << control -> SplitTotalSize
14003
         << "/" << control -> SplitTotalStorageSize / 1024 << "KB"
14004
         << "/" << control -> SplitDataThreshold
14005
         << "/" << control -> SplitDataPacketLimit
14006
         << ".\n";
14007
14008
    cerr << "Info" << ": Using image cache parameters "
14009
         << control -> ImageCacheEnableLoad
14010
         << "/" << control -> ImageCacheEnableSave
14011
         << "/" << control -> ImageCacheDiskLimit / 1024 << "KB"
14012
         << ".\n";
14013
  }
14014
14015
  cerr << "Info" << ": Using pack method '"
14016
       << packMethodName << "' with session '"
14017
       << sessionType << "'.\n";
14018
14019
  if (*productName != '\0')
14020
  {
14021
    cerr << "Info" << ": Using product '" << productName
14022
         << "'.\n" << logofs_flush;
14023
  }
14024
14025
  if (control -> LocalDeltaCompression == 0)
14026
  {
14027
    cerr << "Info" << ": Not using NX delta compression.\n";
14028
  }
14029
14030
  if (control -> LocalDataCompression == 1 ||
14031
          control -> RemoteDataCompression == 1)
14032
  {
14033
    cerr << "Info" << ": Using ZLIB data compression "
14034
         << control -> LocalDataCompressionLevel
14035
         << "/" << control -> RemoteDataCompressionLevel
14036
         << "/" << control -> LocalDataCompressionThreshold
14037
         << ".\n";
14038
  }
14039
  else
14040
  {
14041
    cerr << "Info" << ": Not using ZLIB data compression.\n";
14042
  }
14043
14044
  if (control -> LocalStreamCompression == 1 ||
14045
          control -> RemoteStreamCompression == 1)
14046
  {
14047
    cerr << "Info" << ": Using ZLIB stream compression "
14048
         << control -> LocalStreamCompressionLevel
14049
         << "/" << control -> RemoteStreamCompressionLevel
14050
         << ".\n";
14051
  }
14052
  else
14053
  {
14054
    cerr << "Info" << ": Not using ZLIB stream compression.\n";
14055
  }
14056
14057
  if (control -> LocalBitrateLimit > 0)
14058
  {
14059
    cerr << "Info" << ": Using bandwidth limit of "
14060
         << bitrateLimitName << " bits per second.\n";
14061
  }
14062
14063
  if (control -> PersistentCacheName != NULL)
14064
  {
14065
    cerr << "Info" << ": Using cache file '"
14066
         << control -> PersistentCachePath << "/"
14067
         << control -> PersistentCacheName << "'.\n";
14068
  }
14069
  else
14070
  {
14071
    if (control -> PersistentCacheEnableLoad == 0 ||
14072
            control -> LocalDeltaCompression == 0)
14073
    {
14074
      cerr << "Info" << ": Not using a persistent cache.\n";
14075
    }
14076
    else
14077
    {
14078
      cerr << "Info" << ": No suitable cache file found.\n";
14079
    }
14080
  }
14081
14082
  if (control -> ProxyMode == proxy_client &&
14083
          useUnixSocket > 0 || useTcpSocket > 0 ||
14084
              useAgentSocket > 0)
14085
  {
14086
    cerr << "Info" << ": Listening to X11 connections "
14087
         << "on display ':" << xPort << "'.\n";
14088
  }
14089
  else if (control -> ProxyMode == proxy_server)
14090
  {
14091
    cerr << "Info" << ": Forwarding X11 connections "
14092
         << "to display '" << displayHost << "'.\n";
14093
  }
14094
14095
  if (control -> ProxyMode == proxy_client &&
14096
          useCupsSocket > 0 && cupsPort > 0)
14097
  {
14098
    cerr << "Info" << ": Listening to CUPS connections "
14099
         << "on port '" << cupsPort << "'.\n";
14100
  }
14101
  else if (control -> ProxyMode == proxy_server &&
14102
               cupsPort > 0)
14103
  {
14104
    cerr << "Info" << ": Forwarding CUPS connections "
14105
         << "to port '" << cupsPort << "'.\n";
14106
  }
14107
14108
  if (control -> ProxyMode == proxy_client &&
14109
          useAuxSocket > 0 && auxPort > 0)
14110
  {
14111
    cerr << "Info" << ": Listening to auxiliary X11 connections "
14112
         << "on port '" << auxPort << "'.\n";
14113
  }
14114
  else if (control -> ProxyMode == proxy_server &&
14115
               auxPort > 0)
14116
  {
14117
    cerr << "Info" << ": Forwarding auxiliary X11 connections "
14118
         << "to display '" << displayHost << "'.\n";
14119
  }
14120
14121
  if (control -> ProxyMode == proxy_client &&
14122
          useSmbSocket > 0 && smbPort > 0)
14123
  {
14124
    cerr << "Info" << ": Listening to SMB connections "
14125
         << "on port '" << smbPort << "'.\n";
14126
  }
14127
  else if (control -> ProxyMode == proxy_server &&
14128
               smbPort > 0)
14129
  {
14130
    cerr << "Info" << ": Forwarding SMB connections "
14131
         << "to port '" << smbPort << "'.\n";
14132
  }
14133
14134
  if (control -> ProxyMode == proxy_client &&
14135
          useMediaSocket > 0 && mediaPort > 0)
14136
  {
14137
    cerr << "Info" << ": Listening to multimedia connections "
14138
         << "on port '" << mediaPort << "'.\n";
14139
  }
14140
  else if (control -> ProxyMode == proxy_server &&
14141
               mediaPort > 0)
14142
  {
14143
    cerr << "Info" << ": Forwarding multimedia connections "
14144
         << "to port '" << mediaPort << "'.\n";
14145
  }
14146
14147
  if (control -> ProxyMode == proxy_client &&
14148
          useHttpSocket > 0 && httpPort > 0)
14149
  {
14150
    cerr << "Info" << ": Listening to HTTP connections "
14151
         << "on port '" << httpPort << "'.\n";
14152
  }
14153
  else if (control -> ProxyMode == proxy_server &&
14154
               httpPort > 0)
14155
  {
14156
    cerr << "Info" << ": Forwarding HTTP connections "
14157
         << "to port '" << httpPort << "'.\n";
14158
  }
14159
14160
  if (control -> ProxyMode == proxy_server &&
14161
          useFontSocket > 0 && *fontPort != '\0')
14162
  {
14163
    cerr << "Info" << ": Listening to font server connections "
14164
         << "on port '" << fontPort << "'.\n";
14165
  }
14166
  else if (control -> ProxyMode == proxy_client &&
14167
               *fontPort != '\0')
14168
  {
14169
    cerr << "Info" << ": Forwarding font server connections "
14170
         << "to port '" << fontPort << "'.\n";
14171
  }
14172
14173
  if (useSlaveSocket > 0 && slavePort > 0)
14174
  {
14175
    cerr << "Info" << ": Listening to slave connections "
14176
         << "on port '" << slavePort << "'.\n";
14177
  }
14178
}
14179
14180
void PrintVersionInfo()
14181
{
14182
  cerr << "NXPROXY - " << "Version "
14183
       << control -> LocalVersionMajor << "."
14184
       << control -> LocalVersionMinor << "."
14185
       << control -> LocalVersionPatch;
14186
14187
  cerr << endl;
14188
}
14189
14190
void PrintCopyrightInfo()
14191
{
14192
  cerr << endl;
14193
14194
  PrintVersionInfo();
14195
14196
  cerr << endl;
14197
14198
  cerr << GetCopyrightInfo();
14199
14200
  //
14201
  // Print third party's copyright info.
14202
  //
14203
14204
  cerr << endl;
14205
14206
  cerr << GetOtherCopyrightInfo();
14207
14208
  cerr << endl;
14209
}
14210
14211
void PrintOptionIgnored(const char *type, const char *name, const char *value)
14212
{
14213
  if (control -> ProxyMode == proxy_server)
14214
  {
14215
    #ifdef WARNING
14216
    *logofs << "Loop: WARNING! Ignoring " << type
14217
            << " option '" << name << "' with value '"
14218
            << value << "' at " << "NX client side.\n"
14219
            << logofs_flush;
14220
    #endif
14221
14222
    cerr << "Warning" << ": Ignoring " << type
14223
         << " option '" << name << "' with value '"
14224
         << value << "' at " << "NX client side.\n";
14225
  }
14226
  else
14227
  {
14228
    #ifdef WARNING
14229
    *logofs << "Loop: WARNING! Ignoring " << type
14230
            << " option '" << name << "' with value '"
14231
            << value << "' at " << "NX server side.\n"
14232
            << logofs_flush;
14233
    #endif
14234
14235
    cerr << "Warning" << ": Ignoring " << type
14236
         << " option '" << name << "' with value '"
14237
         << value << "' at " << "NX server side.\n";
14238
  }
14239
}
14240
14241
const char *GetOptions(const char *options)
14242
{
14243
  if (options != NULL)
14244
  {
14245
    if (strncasecmp(options, "nx/nx,", 6) != 0 &&
14246
            strncasecmp(options, "nx,", 3) != 0 &&
14247
                strncasecmp(options, "nx:", 3) != 0)
14248
    {
14249
      #ifdef TEST
14250
      *logofs << "Loop: PANIC! Display options string '" << options
14251
              << "' must start with 'nx' or 'nx/nx' prefix.\n"
14252
              << logofs_flush;
14253
      #endif
14254
14255
      cerr << "Error" << ": Display options string '" << options
14256
           << "' must start with 'nx' or 'nx/nx' prefix.\n";
14257
14258
      HandleCleanup();
14259
    }
14260
  }
14261
  else
14262
  {
14263
    options = getenv("DISPLAY");
14264
  }
14265
14266
  return options;
14267
}
14268
14269
const char *GetArg(int &argi, int argc, const char **argv)
14270
{
14271
  //
14272
  // Skip "-" and flag character.
14273
  //
14274
14275
  const char *arg = argv[argi] + 2;
14276
14277
  if (*arg == 0)
14278
  {
14279
    if (argi + 1 == argc)
14280
    {
14281
      return NULL;
14282
    }
14283
    else
14284
    {
14285
      argi++;
14286
14287
      return (*argv[argi] == '-' ? NULL : argv[argi]);
14288
    }
14289
  }
14290
  else
14291
  {
14292
    return (*arg == '-' ? NULL : arg);
14293
  }
14294
}
14295
14296
int CheckArg(const char *type, const char *name, const char *value)
14297
{
14298
  #ifdef TEST
14299
  *logofs << "Loop: Parsing " << type << " option '" << name
14300
          << "' with value '" << (value ? value : "(null)")
14301
          << "'.\n" << logofs_flush;
14302
  #endif
14303
14304
  if (value == NULL || strstr(value, "=") != NULL)
14305
  {
14306
    #ifdef PANIC
14307
    *logofs << "Loop: PANIC! Error in " << type << " option '"
14308
            << name << "'. No value found.\n"
14309
            << logofs_flush;
14310
    #endif
14311
14312
    cerr << "Error" << ": Error in " << type << " option '"
14313
         << name << "'. No value found.\n";
14314
14315
    return -1;
14316
  }
14317
  else if (strstr(name, ",") != NULL)
14318
  {
14319
    #ifdef PANIC
14320
    *logofs << "Loop: PANIC! Parse error at " << type << " option '"
14321
            << name << "'.\n" << logofs_flush;
14322
    #endif
14323
14324
    cerr << "Error" << ": Parse error at " << type << " option '"
14325
         << name << "'.\n";
14326
14327
    return -1;
14328
  }
14329
  else if (strlen(value) >= DEFAULT_STRING_LENGTH)
14330
  {
14331
    #ifdef PANIC
14332
    *logofs << "Loop: PANIC! Value '" << value << "' of "
14333
            << type << " option '" << name << "' exceeds length of "
14334
            << DEFAULT_STRING_LENGTH << " characters.\n"
14335
            << logofs_flush;
14336
    #endif
14337
14338
    cerr << "Error" << ": Value '" << value << "' of "
14339
         << type << " option '" << name << "' exceeds length of "
14340
         << DEFAULT_STRING_LENGTH << " characters.\n";
14341
14342
    return -1;
14343
  }
14344
14345
  return 1;
14346
}
14347
14348
int ParseArg(const char *type, const char *name, const char *value)
14349
{
14350
  if (strcasecmp(value, "0") == 0)
14351
  {
14352
    return 0;
14353
  }
14354
14355
  //
14356
  // Find the base factor.
14357
  //
14358
14359
  double base;
14360
14361
  const char *id = value + strlen(value) - 1;
14362
14363
  if (strcasecmp(id, "g") == 0)
14364
  {
14365
    base = 1024 * 1024 * 1024;
14366
  }
14367
  else if (strcasecmp(id, "m") == 0)
14368
  {
14369
    base = 1024 * 1024;
14370
  }
14371
  else if (strcasecmp(id, "k") == 0)
14372
  {
14373
    base = 1024;
14374
  }
14375
  else if (strcasecmp(id, "b") == 0 || isdigit(*id) == 1)
14376
  {
14377
    base = 1;
14378
  }
14379
  else
14380
  {
14381
    return -1;
14382
  }
14383
14384
  char *string = new char[strlen(value)];
14385
14386
  strncpy(string, value, strlen(value) - 1);
14387
14388
  *(string + (strlen(value) - 1)) = '\0';
14389
14390
  #ifdef TEST
14391
14392
  *logofs << "Loop: Parsing integer option '" << name
14393
          << "' from string '" << string << "' with base set to ";
14394
14395
  switch (tolower(*id))
14396
  {
14397
    case 'k':
14398
    case 'm':
14399
    case 'g':
14400
    {
14401
      *logofs << (char) toupper(*id);
14402
    }
14403
    break;
14404
  }
14405
14406
  *logofs << ".\n" << logofs_flush;
14407
14408
  #endif
14409
14410
  double result = atof(string) * base;
14411
14412
  if (result < 0 || result > (((unsigned) -1) >> 1))
14413
  {
14414
    delete [] string;
14415
14416
    return -1;
14417
  }
14418
14419
  delete [] string;
14420
14421
  #ifdef TEST
14422
  *logofs << "Loop: Integer option parsed to '"
14423
          << (int) result << "'.\n" << logofs_flush;
14424
  #endif
14425
14426
  return (int) result;
14427
}
14428
14429
int ValidateArg(const char *type, const char *name, const char *value)
14430
{
14431
  int number = atoi(value);
14432
14433
  if (number < 0)
14434
  {
14435
    #ifdef PANIC
14436
    *logofs << "Loop: PANIC! Invalid " << type
14437
            << " option '" << name << "' with value '"
14438
            << value << "'.\n" << logofs_flush;
14439
    #endif
14440
14441
    cerr << "Error" << ": Invalid " << type
14442
         << " option '" << name << "' with value '"
14443
         << value << "'.\n";
14444
14445
    HandleCleanup();
14446
  }
14447
14448
  return number;
14449
} 
14450
14451
int LowercaseArg(const char *type, const char *name, char *value)
14452
{
14453
  char *next = value;
14454
14455
  while (*next != '\0')
14456
  {
14457
    *next = tolower(*next);
14458
14459
    next++;
14460
  }
14461
14462
  return 1;
14463
}
14464
14465
int CheckSignal(int signal)
14466
{
14467
  //
14468
  // Return 1 if the signal needs to be handled
14469
  // by the proxy, 2 if the signal just needs to
14470
  // be blocked to avoid interrupting a system
14471
  // call.
14472
  //
14473
14474
  switch (signal)
14475
  {
14476
    case SIGCHLD:
14477
    case SIGUSR1:
14478
    case SIGUSR2:
14479
    case SIGHUP:
14480
    case SIGINT:
14481
    case SIGTERM:
14482
    case SIGPIPE:
14483
    case SIGALRM:
14484
    {
14485
      return 1;
14486
    }
14487
    case SIGVTALRM:
14488
    case SIGWINCH:
14489
    case SIGIO:
14490
    case SIGTSTP:
14491
    case SIGTTIN:
14492
    case SIGTTOU:
14493
    {
14494
      return 2;
14495
    }
14496
    default:
14497
    {
14498
      #ifdef __CYGWIN32__
14499
14500
      //
14501
      // This signal can be raised by the Cygwin
14502
      // library.
14503
      //
14504
14505
      if (signal == 12)
14506
      {
14507
        return 1;
14508
      }
14509
14510
      #endif
14511
14512
      return 0;
14513
    }
14514
  }
14515
}
14516
14517
static void PrintUsageInfo(const char *option, int error)
14518
{
14519
  if (error == 1)
14520
  {
14521
    cerr << "Error" << ": Invalid command line option '" << option << "'.\n";
14522
  }
14523
14524
  cerr << GetUsageInfo();
14525
14526
  if (error == 1)
14527
  {
14528
    cerr << "Error" << ": NX transport initialization failed.\n";
14529
  }
14530
}
14531
14532
static void handleCheckSessionInLoop()
14533
{
14534
  //
14535
  // Check if we completed the shutdown procedure
14536
  // and the remote confirmed the shutdown. The
14537
  // tear down should be always initiated by the
14538
  // agent, but the X server side may unilateral-
14539
  // ly shut down the link without our permission.
14540
  //
14541
14542
  if (proxy -> getShutdown() > 0)
14543
  {
14544
    #ifdef TEST
14545
    *logofs << "Loop: End of NX transport requested "
14546
            << "by remote.\n" << logofs_flush;
14547
    #endif
14548
14549
    handleTerminatingInLoop();
14550
14551
    if (control -> ProxyMode == proxy_server)
14552
    {
14553
      #ifdef TEST
14554
      *logofs << "Loop: Bytes received so far are "
14555
              << (unsigned long long) statistics -> getBytesIn()
14556
              << ".\n" << logofs_flush;
14557
      #endif
14558
14559
      if (statistics -> getBytesIn() < 1024)
14560
      {
14561
        cerr << "Info" << ": Your session was closed before reaching "
14562
             << "a usable state.\n";
14563
        cerr << "Info" << ": This can be due to the local X server "
14564
             << "refusing access to the client.\n";
14565
        cerr << "Info" << ": Please check authorization provided "
14566
             << "by the remote X application.\n";
14567
      }
14568
    }
14569
14570
    #ifdef TEST
14571
    *logofs << "Loop: Shutting down the NX transport.\n"
14572
            << logofs_flush;
14573
    #endif
14574
 
14575
    HandleCleanup();
14576
  }
14577
  else if (proxy -> handlePing() < 0)
14578
  {
14579
    #ifdef TEST
14580
    *logofs << "Loop: Failure handling the ping for "
14581
            << "proxy FD#" << proxyFD << ".\n"
14582
            << logofs_flush;
14583
    #endif
14584
14585
    HandleShutdown();
14586
  }
14587
14588
  //
14589
  // Check if the watchdog has exited and we didn't
14590
  // get the SIGCHLD. This can happen if the parent
14591
  // has overridden our signal handlers.
14592
  //
14593
14594
  if (IsRunning(lastWatchdog) && CheckProcess(lastWatchdog, "watchdog") == 0)
14595
  {
14596
    #ifdef WARNING
14597
    *logofs << "Loop: WARNING! Watchdog is gone unnoticed. "
14598
            << "Setting the last signal to SIGTERM.\n"
14599
            << logofs_flush;
14600
    #endif
14601
14602
    lastSignal = SIGTERM;
14603
14604
    #ifdef WARNING
14605
    *logofs << "Loop: WARNING! Resetting pid of last "
14606
            << "watchdog process.\n" << logofs_flush;
14607
    #endif
14608
14609
    SetNotRunning(lastWatchdog);
14610
  }
14611
14612
  //
14613
  // Let the client proxy find out if the agent's
14614
  // channel is gone. This is the normal shutdown
14615
  // procedure in the case of an internal connect-
14616
  // ion to the agent.
14617
  // 
14618
14619
  int cleanup = 0;
14620
14621
  if (control -> ProxyMode == proxy_client &&
14622
          agent != NULL && proxy -> getType(agentFD[1]) ==
14623
              channel_none && lastKill == 0 && lastDestroy == 1)
14624
  {
14625
    #ifdef TEST
14626
    *logofs << "Loop: End of NX transport requested "
14627
            << "by agent.\n" << logofs_flush;
14628
    #endif
14629
14630
    #ifdef TEST
14631
    *logofs << "Loop: Bytes sent so far are "
14632
            << (unsigned long long) statistics -> getBytesOut()
14633
            << ".\n" << logofs_flush;
14634
    #endif
14635
14636
    if (statistics -> getBytesOut() < 1024)
14637
    {
14638
      cerr << "Info" << ": Your session has died before reaching "
14639
           << "an usable state.\n";
14640
      cerr << "Info" << ": This can be due to the remote X server "
14641
           << "refusing access to the client.\n";
14642
      cerr << "Info" << ": Please check the authorization provided "
14643
           << "by your X application.\n";
14644
    }
14645
14646
    cleanup = 1;
14647
  }
14648
14649
  //
14650
  // Check if the user requested the end of the
14651
  // session by sending a signal to the proxy.
14652
  // All signals are handled in the main loop
14653
  // so we need to reset the value to get ready
14654
  // for the next iteration.
14655
  //
14656
14657
  int signal = 0;
14658
14659
  if (lastSignal != 0)
14660
  {
14661
    switch (lastSignal)
14662
    {
14663
      case SIGCHLD:
14664
      case SIGUSR1:
14665
      case SIGUSR2:
14666
      {
14667
        break;
14668
      }
14669
      default:
14670
      {
14671
        signal = lastSignal;
14672
14673
        cleanup = 1;
14674
14675
        break;
14676
      }
14677
    }
14678
14679
    lastSignal = 0;
14680
  }
14681
14682
  if (cleanup == 1)
14683
  {
14684
    //
14685
    // The first time termination signal is received
14686
    // disable all further connections, close down any
14687
    // X channel and wait for a second signal.
14688
    //
14689
14690
    if (lastKill == 0)
14691
    {
14692
      //
14693
      // Don't print a message if cleanup is
14694
      // due to normal termination of agent.
14695
      //
14696
14697
      if (signal != 0)
14698
      {
14699
        #ifdef TEST
14700
        *logofs << "Loop: End of NX transport requested by signal '"
14701
                << signal << "' '" << DumpSignal(signal)
14702
                << "'.\n" << logofs_flush;
14703
        #endif
14704
14705
        handleTerminatingInLoop();
14706
      }
14707
14708
      //
14709
      // Disable any further connection.
14710
      //
14711
14712
      CleanupListeners();
14713
14714
      //
14715
      // Close all the remaining X channels and
14716
      // let proxies save their persistent cache
14717
      // on disk.
14718
      //
14719
14720
      CleanupConnections();
14721
14722
      //
14723
      // We'll need to wait for the X channels
14724
      // to be shut down before waiting for the
14725
      // cleanup signal.
14726
      //
14727
14728
      lastKill = 1;
14729
    }
14730
    else if (lastKill == 2)
14731
    {
14732
      #ifdef TEST
14733
      *logofs << "Loop: Shutting down the NX transport.\n"
14734
              << logofs_flush;
14735
      #endif
14736
14737
      proxy -> handleShutdown();
14738
14739
      HandleCleanup();
14740
    }
14741
  }
14742
14743
  if (lastKill == 1 && proxy -> getChannels(channel_x11) == 0)
14744
  {
14745
    //
14746
    // Save the message stores to the
14747
    // persistent cache.
14748
    //
14749
14750
    proxy -> handleSave();
14751
14752
    //
14753
    // Run a watchdog process so we can finally
14754
    // give up at the time the watchdog exits.
14755
    //
14756
14757
    if (IsNotRunning(lastWatchdog))
14758
    {
14759
      int timeout = control -> CleanupTimeout;
14760
14761
      if (timeout > 0)
14762
      {
14763
        if (proxy -> getChannels() == 0)
14764
        {
14765
          timeout = 500;
14766
        }
14767
14768
        #ifdef TEST
14769
        *logofs << "Loop: Starting watchdog process with timeout "
14770
                << "of " << timeout << " Ms.\n"
14771
                << logofs_flush;
14772
        #endif
14773
      }
14774
      #ifdef TEST
14775
      else
14776
      {
14777
        *logofs << "Loop: Starting watchdog process without "
14778
                << "a timeout.\n" << logofs_flush;
14779
      }
14780
      #endif
14781
14782
      lastWatchdog = NXTransWatchdog(timeout);
14783
14784
      if (IsFailed(lastWatchdog))
14785
      {
14786
        #ifdef PANIC
14787
        *logofs << "Loop: PANIC! Can't start the NX watchdog "
14788
                << "process in shutdown.\n" << logofs_flush;
14789
        #endif
14790
14791
        cerr << "Error" << ": Can't start the NX watchdog "
14792
             << "process in shutdown.\n";
14793
14794
        HandleCleanup();
14795
      }
14796
      #ifdef TEST
14797
      else
14798
      {
14799
        *logofs << "Loop: Watchdog started with pid '"
14800
                << lastWatchdog << "'.\n" << logofs_flush;
14801
      }
14802
      #endif
14803
    }
14804
    else
14805
    {
14806
      #ifdef PANIC
14807
      *logofs << "Loop: PANIC! Previous watchdog detected "
14808
              << "in shutdown with pid '" << lastWatchdog
14809
              << "'.\n" << logofs_flush;
14810
      #endif
14811
14812
      cerr << "Error" << ": Previous watchdog detected "
14813
           << "in shutdown with pid '" << lastWatchdog
14814
           << "'.\n";
14815
14816
      HandleCleanup();
14817
    }
14818
14819
    if (control -> CleanupTimeout > 0)
14820
    {
14821
      #ifdef TEST
14822
      *logofs << "Loop: Waiting the cleanup timeout to complete.\n"
14823
              << logofs_flush;
14824
      #endif
14825
14826
      cerr << "Info" << ": Waiting the cleanup timeout to complete.\n";
14827
    }
14828
    else
14829
    {
14830
      //
14831
      // The NX server will kill the watchdog
14832
      // process after having shut down the
14833
      // service channels.
14834
      //
14835
14836
      cerr << "Info" << ": Watchdog running with pid '" << lastWatchdog
14837
           << "'.\n";
14838
14839
      #ifdef TEST
14840
      *logofs << "Loop: Waiting the watchdog process to complete.\n"
14841
              << logofs_flush;
14842
      #endif
14843
14844
      cerr << "Info" << ": Waiting the watchdog process to complete.\n";
14845
    }
14846
14847
    lastKill = 2;
14848
  }
14849
}
14850
14851
static void handleCheckBitrateInLoop()
14852
{
14853
  static long int slept = 0;
14854
14855
  #ifdef TEST
14856
  *logofs << "Loop: Bitrate is " << statistics -> getBitrateInShortFrame()
14857
          << " B/s and " << statistics -> getBitrateInLongFrame()
14858
          << " B/s in " << control -> ShortBitrateTimeFrame / 1000
14859
          << "/" << control -> LongBitrateTimeFrame / 1000
14860
          << " seconds timeframes.\n" << logofs_flush;
14861
  #endif
14862
14863
  //
14864
  // This can be improved. We may not jump out
14865
  // of the select often enough to guarantee
14866
  // the necessary accuracy.
14867
  //
14868
14869
  if (control -> LocalBitrateLimit > 0)
14870
  {
14871
    #ifdef TEST
14872
    *logofs << "Loop: Calculating bandwidth usage with limit "
14873
            << control -> LocalBitrateLimit << ".\n"
14874
            << logofs_flush;
14875
    #endif
14876
14877
    int reference = (statistics -> getBitrateInLongFrame() +
14878
                         statistics -> getBitrateInShortFrame()) / 2;
14879
14880
    if (reference > control -> LocalBitrateLimit)
14881
    {
14882
      double ratio = ((double) reference) /
14883
                         ((double) control -> LocalBitrateLimit);
14884
14885
      if (ratio > 1.2)
14886
      {
14887
        ratio = 1.2;
14888
      }
14889
14890
      slept += (unsigned int) (pow(50000, ratio) / 1000);
14891
14892
      if (slept > 2000)
14893
      {
14894
        #ifdef WARNING
14895
        *logofs << "Loop: WARNING! Sleeping due to "
14896
                << "reference bitrate of " << reference
14897
                << " B/s.\n" << logofs_flush;
14898
        #endif
14899
14900
        cerr << "Warning" << ": Sleeping due to "
14901
             << "reference bitrate of " << reference
14902
             << " B/s.\n";
14903
14904
        slept %= 2000;
14905
      }
14906
14907
      T_timestamp idleTs = getNewTimestamp();
14908
14909
      usleep((unsigned int) pow(50000, ratio));
14910
14911
      int diffTs = diffTimestamp(idleTs, getNewTimestamp());
14912
14913
      statistics -> addIdleTime(diffTs);
14914
14915
      statistics -> subReadTime(diffTs);
14916
    }
14917
  }
14918
}
14919
14920
#if defined(TEST) || defined(INFO)
14921
14922
static void handleCheckStateInLoop(int &setFDs)
14923
{
14924
  int fdLength;
14925
  int fdPending;
14926
  int fdSplits;
14927
14928
  for (int j = 0; j < setFDs; j++)
14929
  {
14930
    if (j != proxyFD)
14931
    {
14932
      fdPending = proxy -> getPending(j);
14933
14934
      if (fdPending > 0)
14935
      {
14936
        #ifdef PANIC
14937
        *logofs << "Loop: PANIC! Buffer for descriptor FD#"
14938
                << j << " has pending bytes to read.\n"
14939
                << logofs_flush;
14940
        #endif
14941
14942
        HandleCleanup();
14943
      }
14944
14945
      fdLength = proxy -> getLength(j);
14946
14947
      if (fdLength > 0)
14948
      {
14949
        #ifdef TEST
14950
        *logofs << "Loop: WARNING! Buffer for descriptor FD#"
14951
                << j << " has " << fdLength << " bytes to write.\n"
14952
                << logofs_flush;
14953
        #endif
14954
      }
14955
    }
14956
  }
14957
14958
  fdPending = proxy -> getPending(proxyFD);
14959
14960
  if (fdPending > 0)
14961
  {
14962
    #ifdef PANIC
14963
    *logofs << "Loop: PANIC! Buffer for proxy descriptor FD#"
14964
            << proxyFD << " has pending bytes to read.\n"
14965
            << logofs_flush;
14966
    #endif
14967
14968
    HandleCleanup();
14969
  }
14970
14971
  fdLength = proxy -> getFlushable(proxyFD);
14972
14973
  if (fdLength > 0)
14974
  {
14975
    if (control -> FlushPolicy == policy_immediate &&
14976
            proxy -> getBlocked(proxyFD) == 0)
14977
    {
14978
      #ifdef PANIC
14979
      *logofs << "Loop: PANIC! Buffer for proxy descriptor FD#"
14980
              << proxyFD << " has " << fdLength << " bytes "
14981
              << "to write with policy 'immediate'.\n"
14982
              << logofs_flush;
14983
      #endif
14984
14985
      HandleCleanup();
14986
    }
14987
    else
14988
    {
14989
      #ifdef TEST
14990
      *logofs << "Loop: WARNING! Buffer for proxy descriptor FD#"
14991
              << proxyFD << " has " << fdLength << " bytes "
14992
              << "to write.\n" << logofs_flush;
14993
      #endif
14994
    }
14995
  }
14996
14997
  fdSplits = proxy -> getSplitSize();
14998
14999
  if (fdSplits > 0)
15000
  {
15001
    #ifdef WARNING
15002
    *logofs << "Loop: WARNING! Proxy descriptor FD#" << proxyFD
15003
            << " has " << fdSplits << " splits to send.\n"
15004
            << logofs_flush;
15005
    #endif
15006
  }
15007
}
15008
15009
static void handleCheckSelectInLoop(int &setFDs, fd_set &readSet,
15010
                                        fd_set &writeSet, T_timestamp selectTs)
15011
{
15012
  #if defined(TEST) || defined(INFO)
15013
  *logofs << "Loop: Maximum descriptors is ["
15014
          << setFDs << "] at " << strMsTimestamp()
15015
          << ".\n" << logofs_flush;
15016
  #endif
15017
15018
  int i;
15019
15020
  if (setFDs > 0)
15021
  {
15022
    i = 0;
15023
15024
    #if defined(TEST) || defined(INFO)
15025
    *logofs << "Loop: Selected for read are ";
15026
    #endif
15027
15028
    for (int j = 0; j < setFDs; j++)
15029
    {
15030
      if (FD_ISSET(j, &readSet))
15031
      {
15032
        #if defined(TEST) || defined(INFO)
15033
        *logofs << "[" << j << "]" << logofs_flush;
15034
        #endif
15035
15036
        i++;
15037
      }
15038
    }
15039
15040
    if (i > 0)
15041
    {
15042
      #if defined(TEST) || defined(INFO)
15043
      *logofs << ".\n" << logofs_flush;
15044
      #endif
15045
    }
15046
    else
15047
    {
15048
      #if defined(TEST) || defined(INFO)
15049
      *logofs << "[none].\n" << logofs_flush;
15050
      #endif
15051
    }
15052
15053
    i = 0;
15054
15055
    #if defined(TEST) || defined(INFO)
15056
    *logofs << "Loop: Selected for write are ";
15057
    #endif
15058
15059
    for (int j = 0; j < setFDs; j++)
15060
    {
15061
      if (FD_ISSET(j, &writeSet))
15062
      {
15063
        #if defined(TEST) || defined(INFO)
15064
        *logofs << "[" << j << "]" << logofs_flush;
15065
        #endif
15066
15067
        i++;
15068
      }
15069
    }
15070
15071
    if (i > 0)
15072
    {
15073
      #if defined(TEST) || defined(INFO)
15074
      *logofs << ".\n" << logofs_flush;
15075
      #endif
15076
    }
15077
    else
15078
    {
15079
      #if defined(TEST) || defined(INFO)
15080
      *logofs << "[none].\n" << logofs_flush;
15081
      #endif
15082
    }
15083
  }
15084
15085
  #if defined(TEST) || defined(INFO)
15086
  *logofs << "Loop: Select timeout is "
15087
          << selectTs.tv_sec << " S and "
15088
          << (double) selectTs.tv_usec / 1000
15089
          << " Ms.\n" << logofs_flush;
15090
  #endif
15091
}
15092
15093
static void handleCheckResultInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet,
15094
                                        fd_set &writeSet, struct timeval &selectTs,
15095
                                            struct timeval &startTs)
15096
{
15097
  int diffTs = diffTimestamp(startTs, getNewTimestamp());
15098
15099
  #if defined(TEST) || defined(INFO)
15100
15101
  if (diffTs >= (control -> PingTimeout -
15102
                     (control -> LatencyTimeout * 4)))
15103
  {
15104
    *logofs << "Loop: Select result is [" << resultFDs
15105
            << "] at " << strMsTimestamp() << " with no "
15106
            << "communication within " << diffTs
15107
            << " Ms.\n" << logofs_flush;
15108
  }
15109
  else
15110
  {
15111
    *logofs << "Loop: Select result is [" << resultFDs
15112
            << "] error is [" << errorFDs << "] at "
15113
            << strMsTimestamp() << " after " << diffTs
15114
            << " Ms.\n" << logofs_flush;
15115
  }
15116
15117
  #endif
15118
15119
  int i;
15120
15121
  if (resultFDs > 0)
15122
  {
15123
    i = 0;
15124
15125
    #if defined(TEST) || defined(INFO)
15126
    *logofs << "Loop: Selected for read are ";
15127
    #endif
15128
15129
    for (int j = 0; j < setFDs; j++)
15130
    {
15131
      if (FD_ISSET(j, &readSet))
15132
      {
15133
        #if defined(TEST) || defined(INFO)
15134
        *logofs << "[" << j << "]" << logofs_flush;
15135
        #endif
15136
15137
        i++;
15138
      }
15139
    }
15140
15141
    if (i > 0)
15142
    {
15143
      #if defined(TEST) || defined(INFO)
15144
      *logofs << ".\n" << logofs_flush;
15145
      #endif
15146
    }
15147
    else
15148
    {
15149
      #if defined(TEST) || defined(INFO)
15150
      *logofs << "[none].\n" << logofs_flush;
15151
      #endif
15152
    }
15153
15154
    i = 0;
15155
15156
    #if defined(TEST) || defined(INFO)
15157
    *logofs << "Loop: Selected for write are ";
15158
    #endif
15159
15160
    for (int j = 0; j < setFDs; j++)
15161
    {
15162
      if (FD_ISSET(j, &writeSet))
15163
      {
15164
        #if defined(TEST) || defined(INFO)
15165
        *logofs << "[" << j << "]" << logofs_flush;
15166
        #endif
15167
15168
        i++;
15169
      }
15170
    }
15171
15172
    if (i > 0)
15173
    {
15174
      #if defined(TEST) || defined(INFO)
15175
      *logofs << ".\n" << logofs_flush;
15176
      #endif
15177
    }
15178
    else
15179
    {
15180
      #if defined(TEST) || defined(INFO)
15181
      *logofs << "[none].\n" << logofs_flush;
15182
      #endif
15183
    }
15184
  }
15185
}
15186
15187
#endif
15188
15189
static void handleCheckSessionInConnect()
15190
{
15191
  #ifdef TEST
15192
  *logofs << "Loop: Going to check session in connect.\n"
15193
          << logofs_flush;
15194
  #endif
15195
15196
  if (control -> ProxyMode == proxy_client)
15197
  {
15198
    HandleAlert(FAILED_PROXY_CONNECTION_CLIENT_ALERT, 1);
15199
  }
15200
  else if (IsNotRunning(lastDialog))
15201
  {
15202
    HandleAlert(FAILED_PROXY_CONNECTION_SERVER_ALERT, 1);
15203
  }
15204
15205
  handleAlertInLoop();
15206
}
15207
15208
static void handleStatisticsInLoop()
15209
{
15210
  if (lastSignal == 0)
15211
  {
15212
    return;
15213
  }
15214
15215
  int mode = NO_STATS;
15216
15217
  if (control -> EnableStatistics == 1)
15218
  {
15219
    if (lastSignal == SIGUSR1)
15220
    {
15221
      //
15222
      // Print overall statistics.
15223
      //
15224
15225
      mode = TOTAL_STATS;
15226
    }
15227
    else if (lastSignal == SIGUSR2)
15228
    {
15229
      //
15230
      // Print partial statistics.
15231
      //
15232
15233
      mode = PARTIAL_STATS;
15234
    }
15235
15236
    if (mode == TOTAL_STATS || mode == PARTIAL_STATS)
15237
    {
15238
      #ifdef TEST
15239
      *logofs << "Loop: Going to request proxy statistics "
15240
              << "with signal '" << DumpSignal(lastSignal)
15241
              << "'.\n" << logofs_flush;
15242
      #endif
15243
15244
      if (proxy != NULL)
15245
      {
15246
        if (ReopenLogFile(statsFileName, statofs, 0) < 0)
15247
        {
15248
          HandleCleanup();
15249
        }
15250
15251
        proxy -> handleStatistics(mode, statofs);
15252
      }
15253
    }
15254
  }
15255
}
15256
15257
static void handleNegotiationInLoop(int &setFDs, fd_set &readSet,
15258
                                        fd_set &writeSet, T_timestamp &selectTs)
15259
{
15260
  int yield = 0;
15261
15262
  while (yield == 0)
15263
  {
15264
    #ifdef TEST
15265
    *logofs << "Loop: Going to run a new negotiation loop "
15266
            << "with stage " << control -> ProxyStage
15267
            << " at " << strMsTimestamp() << ".\n"
15268
            << logofs_flush;
15269
    #endif
15270
15271
    switch (control -> ProxyStage)
15272
    {
15273
      case stage_undefined:
15274
      {
15275
        #ifdef TEST
15276
        *logofs << "Loop: Handling negotiation with '"
15277
                << "stage_undefined" << "'.\n"
15278
                << logofs_flush;
15279
        #endif
15280
15281
        control -> ProxyStage = stage_initializing;
15282
15283
        break;
15284
      }
15285
      case stage_initializing:
15286
      {
15287
        #ifdef TEST
15288
        *logofs << "Loop: Handling negotiation with '"
15289
                << "stage_initializing" << "'.\n"
15290
                << logofs_flush;
15291
        #endif
15292
15293
        InitBeforeNegotiation();
15294
15295
        control -> ProxyStage = stage_connecting;
15296
15297
        break;
15298
      }
15299
      case stage_connecting:
15300
      {
15301
        #ifdef TEST
15302
        *logofs << "Loop: Handling negotiation with '"
15303
                << "stage_connecting" << "'.\n"
15304
                << logofs_flush;
15305
        #endif
15306
15307
        SetupProxyConnection();
15308
15309
        control -> ProxyStage = stage_connected;
15310
15311
        break;
15312
      }
15313
      case stage_connected:
15314
      {
15315
        #ifdef TEST
15316
        *logofs << "Loop: Handling negotiation with '"
15317
                << "stage_connected" << "'.\n"
15318
                << logofs_flush;
15319
        #endif
15320
15321
        //
15322
        // Server side proxy must always be the one that
15323
        // sends its version and options first, so, in
15324
        // some way, client side can be the the one that
15325
        // has the last word on the matter.
15326
        //
15327
15328
        if (control -> ProxyMode == proxy_server)
15329
        {
15330
          //
15331
          // Check if we have been listening for a
15332
          // forwarder. In this case it will have to
15333
          // authenticate itself.
15334
          //
15335
15336
          if (WE_LISTEN_FORWARDER)
15337
          {
15338
            control -> ProxyStage = stage_waiting_forwarder_version;
15339
15340
            break;
15341
          }
15342
15343
          control -> ProxyStage = stage_sending_proxy_options;
15344
        }
15345
        else
15346
        {
15347
          //
15348
          // The X client side is the side that has to wait
15349
          // for the authorization cookie and any remote
15350
          // option.
15351
          //
15352
15353
          control -> ProxyStage = stage_waiting_proxy_version;
15354
        }
15355
15356
        break;
15357
      }
15358
      case stage_sending_proxy_options:
15359
      {
15360
        #ifdef TEST
15361
        *logofs << "Loop: Handling negotiation with '"
15362
                << "stage_sending_proxy_options" << "'.\n"
15363
                << logofs_flush;
15364
        #endif
15365
15366
        if (SendProxyOptions(proxyFD) < 0)
15367
        {
15368
          goto handleNegotiationInLoopError;
15369
        }
15370
15371
        if (control -> ProxyMode == proxy_server)
15372
        {
15373
          control -> ProxyStage = stage_waiting_proxy_version;
15374
        }
15375
        else
15376
        {
15377
          control -> ProxyStage = stage_sending_proxy_caches;
15378
        }
15379
15380
        break;
15381
      }
15382
      case stage_waiting_forwarder_version:
15383
      {
15384
        #ifdef TEST
15385
        *logofs << "Loop: Handling negotiation with '"
15386
                << "stage_waiting_forwarder_version" << "'.\n"
15387
                << logofs_flush;
15388
        #endif
15389
15390
        int result = ReadForwarderVersion(proxyFD);
15391
15392
        if (result == 0)
15393
        {
15394
          yield = 1;
15395
        }
15396
        else if (result == 1)
15397
        {
15398
          control -> ProxyStage = stage_waiting_forwarder_options;
15399
        }
15400
        else
15401
        {
15402
          goto handleNegotiationInLoopError;
15403
        }
15404
15405
        break;
15406
      }
15407
      case stage_waiting_forwarder_options:
15408
      {
15409
        #ifdef TEST
15410
        *logofs << "Loop: Handling negotiation with '"
15411
                << "stage_waiting_forwarder_options" << "'.\n"
15412
                << logofs_flush;
15413
        #endif
15414
15415
        int result = ReadForwarderOptions(proxyFD);
15416
15417
        if (result == 0)
15418
        {
15419
          yield = 1;
15420
        }
15421
        else if (result == 1)
15422
        {
15423
          control -> ProxyStage = stage_sending_proxy_options;
15424
        }
15425
        else
15426
        {
15427
          goto handleNegotiationInLoopError;
15428
        }
15429
15430
        break;
15431
      }
15432
      case stage_waiting_proxy_version:
15433
      {
15434
        #ifdef TEST
15435
        *logofs << "Loop: Handling negotiation with '"
15436
                << "stage_waiting_proxy_version" << "'.\n"
15437
                << logofs_flush;
15438
        #endif
15439
15440
        int result = ReadProxyVersion(proxyFD);
15441
15442
        if (result == 0)
15443
        {
15444
          yield = 1;
15445
        }
15446
        else if (result == 1)
15447
        {
15448
          control -> ProxyStage = stage_waiting_proxy_options;
15449
        }
15450
        else
15451
        {
15452
          goto handleNegotiationInLoopError;
15453
        }
15454
15455
        break;
15456
      }
15457
      case stage_waiting_proxy_options:
15458
      {
15459
        #ifdef TEST
15460
        *logofs << "Loop: Handling negotiation with '"
15461
                << "stage_waiting_proxy_options" << "'.\n"
15462
                << logofs_flush;
15463
        #endif
15464
15465
        int result = ReadProxyOptions(proxyFD);
15466
15467
        if (result == 0)
15468
        {
15469
          yield = 1;
15470
        }
15471
        else if (result == 1)
15472
        {
15473
          if (control -> ProxyMode == proxy_server)
15474
          {
15475
            control -> ProxyStage = stage_waiting_proxy_caches;
15476
          }
15477
          else
15478
          {
15479
            control -> ProxyStage = stage_sending_proxy_options;
15480
          }
15481
        }
15482
        else
15483
        {
15484
          goto handleNegotiationInLoopError;
15485
        }
15486
15487
        break;
15488
      }
15489
      case stage_sending_proxy_caches:
15490
      {
15491
        #ifdef TEST
15492
        *logofs << "Loop: Handling negotiation with '"
15493
                << "stage_sending_proxy_caches" << "'.\n"
15494
                << logofs_flush;
15495
        #endif
15496
15497
        if (SendProxyCaches(proxyFD) < 0)
15498
        {
15499
          goto handleNegotiationInLoopError;
15500
        }
15501
15502
        if (control -> ProxyMode == proxy_server)
15503
        {
15504
          control -> ProxyStage = stage_operational;
15505
        }
15506
        else
15507
        {
15508
          control -> ProxyStage = stage_waiting_proxy_caches;
15509
        }
15510
15511
        break;
15512
      }
15513
      case stage_waiting_proxy_caches:
15514
      {
15515
        #ifdef TEST
15516
        *logofs << "Loop: Handling negotiation with '"
15517
                << "stage_waiting_proxy_caches" << "'.\n"
15518
                << logofs_flush;
15519
        #endif
15520
15521
        int result = ReadProxyCaches(proxyFD);
15522
15523
        if (result == 0)
15524
        {
15525
          yield = 1;
15526
        }
15527
        else if (result == 1)
15528
        {
15529
          if (control -> ProxyMode == proxy_server)
15530
          {
15531
            control -> ProxyStage = stage_sending_proxy_caches;
15532
          }
15533
          else
15534
          {
15535
            control -> ProxyStage = stage_operational;
15536
          }
15537
        }
15538
        else
15539
        {
15540
          goto handleNegotiationInLoopError;
15541
        }
15542
15543
        break;
15544
      }
15545
      case stage_operational:
15546
      {
15547
        #ifdef TEST
15548
        *logofs << "Loop: Handling negotiation with '"
15549
                << "stage_operational" << "'.\n"
15550
                << logofs_flush;
15551
        #endif
15552
15553
        InitAfterNegotiation();
15554
15555
        yield = 1;
15556
15557
        break;
15558
      }
15559
      default:
15560
      {
15561
        #ifdef PANIC
15562
        *logofs << "Loop: PANIC! Unmanaged case '" << control -> ProxyStage
15563
                << "' while handling negotiation.\n" << logofs_flush;
15564
        #endif
15565
15566
        cerr << "Error" << ": Unmanaged case '" << control -> ProxyStage
15567
             << "' while handling negotiation.\n";
15568
15569
        HandleCleanup();
15570
      }
15571
    }
15572
  }
15573
15574
  //
15575
  // Check if the user requested the end of
15576
  // the session.
15577
  //
15578
  
15579
  if (CheckAbort() != 0)
15580
  {
15581
    HandleCleanup();
15582
  }
15583
15584
  //
15585
  // Select the proxy descriptor so that we
15586
  // can proceed negotiating the session.
15587
  //
15588
15589
  FD_SET(proxyFD, &readSet);
15590
15591
  if (proxyFD >= setFDs)
15592
  {
15593
    setFDs = proxyFD + 1;
15594
  }
15595
15596
  setMinTimestamp(selectTs, control -> PingTimeout);
15597
15598
  #ifdef TEST
15599
  *logofs << "Loop: Selected proxy FD#" << proxyFD << " in negotiation "
15600
          << "phase with timeout of " << selectTs.tv_sec << " S and "
15601
          << selectTs.tv_usec << " Ms.\n" << logofs_flush;
15602
  #endif
15603
15604
  return;
15605
15606
handleNegotiationInLoopError:
15607
15608
  #ifdef PANIC
15609
  *logofs << "Loop: PANIC! Failure negotiating the session in stage '"
15610
          << control -> ProxyStage << "'.\n" << logofs_flush;
15611
  #endif
15612
15613
  cerr << "Error" << ": Failure negotiating the session in stage '"
15614
       << control -> ProxyStage << "'.\n";
15615
15616
15617
  if (control -> ProxyMode == proxy_server &&
15618
          control -> ProxyStage == stage_waiting_proxy_version)
15619
  {
15620
    #ifdef PANIC
15621
    *logofs << "Loop: PANIC! Wrong version or invalid session "
15622
            << "authentication cookie.\n" << logofs_flush;
15623
    #endif
15624
15625
    cerr << "Error" << ": Wrong version or invalid session "
15626
         << "authentication cookie.\n";
15627
  }
15628
15629
  handleTerminatingInLoop();
15630
15631
  HandleCleanup();
15632
}
15633
15634
static void handleTerminatingInLoop()
15635
{
15636
  if (getpid() == lastProxy)
15637
  {
15638
    if (control -> ProxyStage < stage_terminating)
15639
    {
15640
      if (agent == NULL)
15641
      {
15642
        cerr << "Session" << ": Terminating session at '"
15643
             << strTimestamp() << "'.\n";
15644
      }
15645
15646
      control -> ProxyStage = stage_terminating;
15647
    }
15648
  }
15649
}
15650
15651
static void handleTerminatedInLoop()
15652
{
15653
  if (getpid() == lastProxy)
15654
  {
15655
    if (control -> ProxyStage < stage_terminated)
15656
    {
15657
      if (agent == NULL)
15658
      {
15659
        cerr << "Session" << ": Session terminated at '"
15660
             << strTimestamp() << "'.\n";
15661
      }
15662
15663
      control -> ProxyStage = stage_terminated;
15664
    }
15665
  }
15666
}
15667
15668
static void handleAlertInLoop()
15669
{
15670
  if (lastAlert.code == 0)
15671
  {
15672
    return;
15673
  }
15674
15675
  if (lastAlert.local == 0 &&
15676
          (lastAlert.code > LAST_PROTO_STEP_6_ALERT &&
15677
               control -> isProtoStep7() == 0))
15678
  {
15679
    //
15680
    // The remote proxy would be unable
15681
    // to handle the alert.
15682
    //
15683
15684
    #ifdef WARNING
15685
    *logofs << "Loop: WARNING! Ignoring unsupported alert "
15686
            << "with code '" << lastAlert.code << "'.\n"
15687
            << logofs_flush;
15688
    #endif
15689
  }
15690
  else if (lastAlert.local == 0)
15691
  {
15692
    if (proxy != NULL)
15693
    {
15694
      #if defined(TEST) || defined(INFO)
15695
      *logofs << "Loop: Requesting a remote alert with code '"
15696
              << lastAlert.code << "'.\n" << logofs_flush;
15697
      #endif
15698
15699
      if (proxy -> handleAlert(lastAlert.code) < 0)
15700
      {
15701
        HandleShutdown();
15702
      }
15703
    }
15704
  }
15705
  else
15706
  {
15707
    #if defined(TEST) || defined(INFO)
15708
    *logofs << "Loop: Handling a local alert with code '"
15709
            << lastAlert.code << "'.\n" << logofs_flush;
15710
    #endif
15711
15712
    if (control -> ProxyMode == proxy_client)
15713
    {
15714
      //
15715
      // If we are at X client side and server
15716
      // proxy is not responding, we don't have
15717
      // any possibility to interact with user.
15718
      //
15719
15720
      if (lastAlert.code != CLOSE_DEAD_PROXY_CONNECTION_CLIENT_ALERT &&
15721
              lastAlert.code != RESTART_DEAD_PROXY_CONNECTION_CLIENT_ALERT &&
15722
                  lastAlert.code != FAILED_PROXY_CONNECTION_CLIENT_ALERT)
15723
      {
15724
        //
15725
        // Let the server proxy show the dialog.
15726
        //
15727
15728
        if (proxy != NULL &&
15729
                proxy -> handleAlert(lastAlert.code) < 0)
15730
        {
15731
          HandleShutdown();
15732
        }
15733
      }
15734
    }
15735
    else
15736
    {
15737
      char caption[DEFAULT_STRING_LENGTH];
15738
15739
      strcpy(caption, ALERT_CAPTION_PREFIX);
15740
15741
      int length = strlen(sessionId);
15742
15743
      //
15744
      // Get rid of the trailing MD5 from session id.
15745
      //
15746
15747
      if (length > (MD5_LENGTH * 2 + 1) &&
15748
              *(sessionId + (length - (MD5_LENGTH * 2 + 1))) == '-')
15749
      {
15750
        strncat(caption, sessionId, length - (MD5_LENGTH * 2 + 1));
15751
      }
15752
      else
15753
      {
15754
        strcat(caption, sessionId);
15755
      }
15756
15757
      //
15758
      // Use the display to which we are forwarding
15759
      // the remote X connections.
15760
      // 
15761
15762
      char *display = displayHost;
15763
15764
      int replace = 1;
15765
      int local   = 1;
15766
15767
      char *message;
15768
      char *type;
15769
15770
      switch (lastAlert.code)
15771
      {
15772
        case CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT:
15773
        {
15774
          message = CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT_STRING;
15775
          type    = CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT_TYPE;
15776
15777
          break;
15778
        }
15779
        case CLOSE_DEAD_X_CONNECTION_SERVER_ALERT:
15780
        {
15781
          message = CLOSE_DEAD_X_CONNECTION_SERVER_ALERT_STRING;
15782
          type    = CLOSE_DEAD_X_CONNECTION_SERVER_ALERT_TYPE;
15783
15784
          break;
15785
        }
15786
        case CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT:
15787
        {
15788
          message = CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT_STRING;
15789
          type    = CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT_TYPE;
15790
15791
          break;
15792
        }
15793
        case RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT:
15794
        {
15795
          message = RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT_STRING;
15796
          type    = RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT_TYPE;
15797
15798
          break;
15799
        }
15800
        case CLOSE_UNRESPONSIVE_X_SERVER_ALERT:
15801
        {
15802
          message = CLOSE_UNRESPONSIVE_X_SERVER_ALERT_STRING;
15803
          type    = CLOSE_UNRESPONSIVE_X_SERVER_ALERT_TYPE;
15804
15805
          break;
15806
        }
15807
        case WRONG_PROXY_VERSION_ALERT:
15808
        {
15809
          message = WRONG_PROXY_VERSION_ALERT_STRING;
15810
          type    = WRONG_PROXY_VERSION_ALERT_TYPE;
15811
15812
          break;
15813
        }
15814
        case FAILED_PROXY_CONNECTION_SERVER_ALERT:
15815
        {
15816
          message = FAILED_PROXY_CONNECTION_SERVER_ALERT_STRING;
15817
          type    = FAILED_PROXY_CONNECTION_SERVER_ALERT_TYPE;
15818
15819
          break;
15820
        }
15821
        case MISSING_PROXY_CACHE_ALERT:
15822
        {
15823
          message = MISSING_PROXY_CACHE_ALERT_STRING;
15824
          type    = MISSING_PROXY_CACHE_ALERT_TYPE;
15825
15826
          break;
15827
        }
15828
        case ABORT_PROXY_CONNECTION_ALERT:
15829
        {
15830
          message = ABORT_PROXY_CONNECTION_ALERT_STRING;
15831
          type    = ABORT_PROXY_CONNECTION_ALERT_TYPE;
15832
15833
          break;
15834
        }
15835
        case DISPLACE_MESSAGE_ALERT:
15836
        {
15837
          message = DISPLACE_MESSAGE_ALERT_STRING;
15838
          type    = DISPLACE_MESSAGE_ALERT_TYPE;
15839
15840
          break;
15841
        }
15842
        case GREETING_MESSAGE_ALERT:
15843
        {
15844
          message = GREETING_MESSAGE_ALERT_STRING;
15845
          type    = GREETING_MESSAGE_ALERT_TYPE;
15846
15847
          break;
15848
        }
15849
        case START_RESUME_SESSION_ALERT:
15850
        {
15851
          message = START_RESUME_SESSION_ALERT_STRING;
15852
          type    = START_RESUME_SESSION_ALERT_TYPE;
15853
15854
          break;
15855
        }
15856
        case FAILED_RESUME_DISPLAY_ALERT:
15857
        {
15858
          message = FAILED_RESUME_DISPLAY_ALERT_STRING;
15859
          type    = FAILED_RESUME_DISPLAY_ALERT_TYPE;
15860
15861
          break;
15862
        }
15863
        case FAILED_RESUME_DISPLAY_BROKEN_ALERT:
15864
        {
15865
          message = FAILED_RESUME_DISPLAY_BROKEN_STRING;
15866
          type    = FAILED_RESUME_DISPLAY_BROKEN_TYPE;
15867
15868
          break;
15869
        }
15870
        case FAILED_RESUME_VISUALS_ALERT:
15871
        {
15872
          message = FAILED_RESUME_VISUALS_ALERT_STRING;
15873
          type    = FAILED_RESUME_VISUALS_ALERT_TYPE;
15874
15875
          break;
15876
        }
15877
        case FAILED_RESUME_COLORMAPS_ALERT:
15878
        {
15879
          message = FAILED_RESUME_COLORMAPS_ALERT_STRING;
15880
          type    = FAILED_RESUME_COLORMAPS_ALERT_TYPE;
15881
15882
          break;
15883
        }
15884
        case FAILED_RESUME_PIXMAPS_ALERT:
15885
        {
15886
          message = FAILED_RESUME_PIXMAPS_ALERT_STRING;
15887
          type    = FAILED_RESUME_PIXMAPS_ALERT_TYPE;
15888
15889
          break;
15890
        }
15891
        case FAILED_RESUME_DEPTHS_ALERT:
15892
        {
15893
          message = FAILED_RESUME_DEPTHS_ALERT_STRING;
15894
          type    = FAILED_RESUME_DEPTHS_ALERT_TYPE;
15895
15896
          break;
15897
        }
15898
        case FAILED_RESUME_RENDER_ALERT:
15899
        {
15900
          message = FAILED_RESUME_RENDER_ALERT_STRING;
15901
          type    = FAILED_RESUME_RENDER_ALERT_TYPE;
15902
15903
          break;
15904
        }
15905
        case FAILED_RESUME_FONTS_ALERT:
15906
        {
15907
          message = FAILED_RESUME_FONTS_ALERT_STRING;
15908
          type    = FAILED_RESUME_FONTS_ALERT_TYPE;
15909
15910
          break;
15911
        }
15912
        case INTERNAL_ERROR_ALERT:
15913
        {
15914
          message = INTERNAL_ERROR_ALERT_STRING;
15915
          type    = INTERNAL_ERROR_ALERT_TYPE;
15916
15917
          break;
15918
        }
15919
        case ABORT_PROXY_NEGOTIATION_ALERT:
15920
        {
15921
          message = ABORT_PROXY_NEGOTIATION_ALERT_STRING;
15922
          type    = ABORT_PROXY_NEGOTIATION_ALERT_TYPE;
15923
15924
          break;
15925
        }
15926
        case ABORT_PROXY_SHUTDOWN_ALERT:
15927
        {
15928
          message = ABORT_PROXY_SHUTDOWN_ALERT_STRING;
15929
          type    = ABORT_PROXY_SHUTDOWN_ALERT_TYPE;
15930
15931
          break;
15932
        }
15933
        case FAILED_XDMCP_CONNECTION_ALERT:
15934
        {
15935
          message = FAILED_XDMCP_CONNECTION_ALERT_STRING;
15936
          type    = FAILED_XDMCP_CONNECTION_ALERT_TYPE;
15937
15938
          break;
15939
        }
15940
        default:
15941
        {
15942
          if (lastAlert.code > LAST_PROTO_STEP_7_ALERT)
15943
          {
15944
            #ifdef WARNING
15945
            *logofs << "Loop: WARNING! An unrecognized alert type '"
15946
                    << lastAlert.code << "' was requested.\n"
15947
                    << logofs_flush;
15948
            #endif
15949
15950
            cerr << "Warning" << ": An unrecognized alert type '"
15951
                 << lastAlert.code << "' was requested.\n";
15952
          }
15953
          #ifdef WARNING
15954
          else
15955
          {
15956
            *logofs << "Loop: WARNING! Ignoring obsolete alert type '"
15957
                    << lastAlert.code << "'.\n" << logofs_flush;
15958
          }
15959
          #endif
15960
15961
          message = NULL;
15962
          type    = NULL;
15963
15964
          replace = 0;
15965
15966
          break;
15967
        }
15968
      }
15969
15970
      if (replace == 1 && IsRunning(lastDialog))
15971
      {
15972
        #if defined(TEST) || defined(INFO)
15973
        *logofs << "Loop: Killing the previous dialog with pid '"
15974
                << lastDialog << "'.\n" << logofs_flush;
15975
        #endif
15976
15977
        //
15978
        // The client ignores the TERM signal
15979
        // on Windows.
15980
        //
15981
15982
        #ifdef __CYGWIN32__
15983
15984
        KillProcess(lastDialog, "dialog", SIGKILL, 0);
15985
15986
        #else
15987
15988
        KillProcess(lastDialog, "dialog", SIGTERM, 0);
15989
15990
        #endif
15991
15992
        SetNotRunning(lastDialog);
15993
15994
        if (proxy != NULL)
15995
        {
15996
          proxy -> handleResetAlert();
15997
        }
15998
      }
15999
16000
      if (message != NULL && type != NULL)
16001
      {
16002
        lastDialog = NXTransDialog(caption, message, 0, type, local, display);
16003
16004
        if (IsFailed(lastDialog))
16005
        {
16006
          #ifdef PANIC
16007
          *logofs << "Loop: PANIC! Can't start the NX dialog process.\n"
16008
                  << logofs_flush;
16009
          #endif
16010
16011
          SetNotRunning(lastDialog);
16012
        }
16013
        #if defined(TEST) || defined(INFO)
16014
        else
16015
        {
16016
          *logofs << "Loop: Dialog started with pid '"
16017
                  << lastDialog << "'.\n" << logofs_flush;
16018
        }
16019
        #endif
16020
      }
16021
      #if defined(TEST) || defined(INFO)
16022
      else
16023
      {
16024
        *logofs << "Loop: No new dialog required for code '"
16025
                << lastAlert.code << "'.\n" << logofs_flush;
16026
      }
16027
      #endif
16028
    }
16029
  }
16030
16031
  //
16032
  // Reset state.
16033
  //
16034
16035
  lastAlert.code  = 0;
16036
  lastAlert.local = 0;
16037
}
16038
16039
static inline void handleSetAgentInLoop(int &setFDs, fd_set &readSet,
16040
                                            fd_set &writeSet, struct timeval &selectTs)
16041
{
16042
  #ifdef TEST
16043
  *logofs << "Loop: Preparing the masks for the agent descriptors.\n"
16044
          << logofs_flush;
16045
  #endif
16046
16047
  agent -> saveChannelState();
16048
16049
  agent -> saveReadMask(&readSet);
16050
  agent -> saveWriteMask(&writeSet);
16051
16052
  if (control -> ProxyStage >= stage_operational)
16053
  {
16054
    if (agent -> remoteCanRead(&readSet) ||
16055
            agent -> remoteCanWrite(&writeSet) ||
16056
                agent -> localCanRead() ||
16057
                    agent -> proxyCanRead())
16058
    {
16059
      #ifdef TEST
16060
      *logofs << "Loop: Setting a null timeout with agent descriptors ready.\n"
16061
              << logofs_flush;
16062
      #endif
16063
16064
      //
16065
      // Force a null timeout so we'll bail out
16066
      // of the select immediately. We will ac-
16067
      // comodate the result code later.
16068
      //
16069
16070
      selectTs.tv_sec  = 0;
16071
      selectTs.tv_usec = 0;
16072
    }
16073
  }
16074
16075
  #ifdef TEST
16076
  *logofs << "Loop: Clearing the read and write agent descriptors.\n"
16077
          << logofs_flush;
16078
  #endif
16079
16080
  agent -> clearReadMask(&readSet);
16081
  agent -> clearWriteMask(&writeSet);
16082
}
16083
16084
static inline void handleAgentInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet,
16085
                                         fd_set &writeSet, struct timeval &selectTs)
16086
{
16087
  #if defined(TEST) || defined(INFO)
16088
  *logofs << "Loop: Setting proxy and local agent descriptors.\n"
16089
          << logofs_flush;
16090
  #endif
16091
16092
  //
16093
  // Check if I/O is possible on the local
16094
  // agent or the proxy descriptor.
16095
  //
16096
  
16097
  if (resultFDs >= 0)
16098
  {
16099
    //
16100
    // Save if the proxy can read from the
16101
    // the agent descriptor.
16102
    //
16103
16104
    agent -> saveChannelState();
16105
16106
    #if defined(TEST) || defined(INFO)
16107
    *logofs << "Loop: Values were resultFDs " << resultFDs
16108
            << " errorFDs " << errorFDs << " setFDs "
16109
            << setFDs << ".\n" << logofs_flush;
16110
    #endif
16111
16112
    if (agent -> localCanRead() == 1)
16113
    {
16114
      #if defined(TEST) || defined(INFO)
16115
      *logofs << "Loop: Setting agent descriptor FD#" << agent ->
16116
                 getLocalFd() << " as ready to read.\n"
16117
              << logofs_flush;
16118
      #endif
16119
16120
      agent -> setLocalRead(&readSet, &resultFDs);
16121
    }
16122
16123
    #if defined(TEST) || defined(INFO)
16124
16125
    if (agent -> proxyCanRead(&readSet) == 0 &&
16126
            agent -> proxyCanRead() == 1)
16127
    {
16128
      *logofs << "Loop: WARNING! Can read from proxy FD#"
16129
              << proxyFD << " but the descriptor "
16130
              << "is not selected.\n" << logofs_flush;
16131
    }
16132
16133
    if (agent -> proxyCanRead(&readSet) == 1)
16134
    {
16135
      *logofs << "Loop: Setting proxy descriptor FD#" << agent ->
16136
                 getProxyFd() << " as ready to read.\n"
16137
              << logofs_flush;
16138
    }
16139
16140
    #endif
16141
16142
    #if defined(TEST) || defined(INFO)
16143
    *logofs << "Loop: Values are now resultFDs " << resultFDs
16144
            << " errorFDs " << errorFDs << " setFDs "
16145
            << setFDs << ".\n" << logofs_flush;
16146
    #endif
16147
  }
16148
}
16149
16150
static inline void handleAgentLateInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet,
16151
                                             fd_set &writeSet, struct timeval &selectTs)
16152
{
16153
  #if defined(TEST) || defined(INFO)
16154
  *logofs << "Loop: Setting remote agent descriptors.\n"
16155
          << logofs_flush;
16156
  #endif
16157
16158
  //
16159
  // We reset the masks before calling our select.
16160
  // We now set the descriptors that are ready but
16161
  // only if they were set in the original mask.
16162
  // We do this after having executed our loop as
16163
  // we may have produced more data and the agent
16164
  // descriptors may have become readable or writ-
16165
  // able in the meanwhile.
16166
  //
16167
  
16168
  if (resultFDs >= 0)
16169
  {
16170
    //
16171
    // Save if the proxy can read from the
16172
    // the agent descriptor.
16173
    //
16174
16175
    agent -> saveChannelState();
16176
16177
    #if defined(TEST) || defined(INFO)
16178
    *logofs << "Loop: Values were resultFDs " << resultFDs
16179
            << " errorFDs " << errorFDs << " setFDs "
16180
            << setFDs << ".\n" << logofs_flush;
16181
    #endif
16182
16183
    if (agent -> remoteCanRead(agent ->
16184
            getSavedReadMask()) == 1)
16185
    {
16186
      #if defined(TEST) || defined(INFO)
16187
      *logofs << "Loop: Setting agent descriptor FD#" << agent ->
16188
                 getRemoteFd() << " as ready to read.\n"
16189
              << logofs_flush;
16190
      #endif
16191
16192
      agent -> setRemoteRead(&readSet, &resultFDs);
16193
    }
16194
16195
    if (agent -> remoteCanWrite(agent ->
16196
            getSavedWriteMask()) == 1)
16197
    {
16198
      #if defined(TEST) || defined(INFO)
16199
      *logofs << "Loop: Setting agent descriptor FD#" << agent ->
16200
                 getRemoteFd() << " as ready to write.\n"
16201
              << logofs_flush;
16202
      #endif
16203
16204
      agent -> setRemoteWrite(&writeSet, &resultFDs);
16205
    }
16206
16207
    #if defined(TEST) || defined(INFO)
16208
    *logofs << "Loop: Values are now resultFDs " << resultFDs
16209
            << " errorFDs " << errorFDs << " setFDs "
16210
            << setFDs << ".\n" << logofs_flush;
16211
    #endif
16212
  }
16213
}
16214
16215
static inline void handleReadableInLoop(int &resultFDs, fd_set &readSet)
16216
{
16217
  if (resultFDs > 0)
16218
  {
16219
    T_channel_type type = channel_none;
16220
16221
    char *label = NULL;
16222
    int domain  = -1;
16223
    int fd      = -1;
16224
16225
    if (tcpFD != -1 && FD_ISSET(tcpFD, &readSet))
16226
    {
16227
      type   = channel_x11;
16228
      label  = "X";
16229
      domain = AF_INET;
16230
      fd     = tcpFD;
16231
16232
      resultFDs--;
16233
    }
16234
16235
    if (unixFD != -1 && FD_ISSET(unixFD, &readSet))
16236
    {
16237
      type   = channel_x11;
16238
      label  = "X";
16239
      domain = AF_UNIX;
16240
      fd     = unixFD;
16241
16242
      resultFDs--;
16243
    }
16244
16245
    if (cupsFD != -1 && FD_ISSET(cupsFD, &readSet))
16246
    {
16247
      type   = channel_cups;
16248
      label  = "CUPS";
16249
      domain = AF_INET;
16250
      fd     = cupsFD;
16251
16252
      resultFDs--;
16253
    }
16254
16255
    if (auxFD != -1 && FD_ISSET(auxFD, &readSet))
16256
    {
16257
      //
16258
      // Starting from version 1.5.0 we create real X
16259
      // connections for the keyboard channel, so they
16260
      // can use the fake authorization cookie. This
16261
      // means that there is not such a thing like a
16262
      // channel_aux anymore.
16263
      //
16264
16265
      type   = channel_x11;
16266
      label  = "auxiliary X11";
16267
      domain = AF_INET;
16268
      fd     = auxFD;
16269
16270
      resultFDs--;
16271
    }
16272
16273
    if (smbFD != -1 && FD_ISSET(smbFD, &readSet))
16274
    {
16275
      type   = channel_smb;
16276
      label  = "SMB";
16277
      domain = AF_INET;
16278
      fd     = smbFD;
16279
16280
      resultFDs--;
16281
    }
16282
16283
    if (mediaFD != -1 && FD_ISSET(mediaFD, &readSet))
16284
    {
16285
      type   = channel_media;
16286
      label  = "media";
16287
      domain = AF_INET;
16288
      fd     = mediaFD;
16289
16290
      resultFDs--;
16291
    }
16292
16293
    if (httpFD != -1 && FD_ISSET(httpFD, &readSet))
16294
    {
16295
      type   = channel_http;
16296
      label  = "HTTP";
16297
      domain = AF_INET;
16298
      fd     = httpFD;
16299
16300
      resultFDs--;
16301
    }
16302
16303
    if (fontFD != -1 && FD_ISSET(fontFD, &readSet))
16304
    {
16305
      type   = channel_font;
16306
      label  = "font server";
16307
      domain = AF_INET;
16308
      fd     = fontFD;
16309
16310
      resultFDs--;
16311
    }
16312
16313
    if (slaveFD != -1 && FD_ISSET(slaveFD, &readSet))
16314
    {
16315
      type   = channel_slave;
16316
      label  = "slave";
16317
      domain = AF_INET;
16318
      fd     = slaveFD;
16319
16320
      resultFDs--;
16321
    }
16322
16323
    if (type != channel_none)
16324
    {
16325
      int newFD = AcceptConnection(fd, domain, label);
16326
16327
      if (newFD != -1)
16328
      {
16329
        if (proxy -> handleNewConnection(type, newFD) < 0)
16330
        {
16331
          #ifdef PANIC
16332
          *logofs << "Loop: PANIC! Error creating new " << label
16333
                  << " connection.\n" << logofs_flush;
16334
          #endif
16335
16336
          cerr << "Error" << ": Error creating new " << label
16337
               << " connection.\n";
16338
16339
          close(newFD);
16340
16341
          //
16342
          // Don't kill the proxy in the case of an error.
16343
          //
16344
          // HandleCleanup();
16345
          //
16346
        }
16347
        else if (proxy -> getReadable(newFD) > 0)
16348
        {
16349
          //
16350
          // Add the descriptor, so we can try
16351
          // to read immediately.
16352
          //
16353
16354
          #ifdef TEST
16355
          *logofs << "Loop: Trying to read immediately "
16356
                  << "from descriptor FD#" << newFD
16357
                  << ".\n" << logofs_flush;
16358
          #endif
16359
16360
          FD_SET(newFD, &readSet);
16361
16362
          resultFDs++;
16363
        }
16364
        #ifdef TEST
16365
        else
16366
        {
16367
          *logofs << "Loop: Nothing to read immediately "
16368
                  << "from descriptor FD#" << newFD
16369
                  << ".\n" << logofs_flush;
16370
        }
16371
        #endif
16372
      }
16373
    }
16374
  }
16375
16376
  #ifdef DEBUG
16377
  *logofs << "Loop: Going to check the readable descriptors.\n"
16378
          << logofs_flush;
16379
  #endif
16380
16381
  if (proxy -> handleRead(resultFDs, readSet) < 0)
16382
  {
16383
    #ifdef TEST
16384
    *logofs << "Loop: Failure reading from descriptors "
16385
            << "for proxy FD#" << proxyFD << ".\n"
16386
            << logofs_flush;
16387
    #endif
16388
16389
    HandleShutdown();
16390
  }
16391
}
16392
16393
static inline void handleWritableInLoop(int &resultFDs, fd_set &writeSet)
16394
{
16395
  #ifdef DEBUG
16396
  *logofs << "Loop: Going to check the writable descriptors.\n"
16397
          << logofs_flush;
16398
  #endif
16399
16400
  if (resultFDs > 0 && proxy -> handleFlush(resultFDs, writeSet) < 0)
16401
  {
16402
    #ifdef TEST
16403
    *logofs << "Loop: Failure writing to descriptors "
16404
            << "for proxy FD#" << proxyFD << ".\n"
16405
            << logofs_flush;
16406
    #endif
16407
16408
    HandleShutdown();
16409
  }
16410
}
16411
16412
static inline void handleFlushInLoop()
16413
{
16414
  #ifdef DEBUG
16415
  *logofs << "Loop: Going to flush any data to the proxy.\n"
16416
          << logofs_flush;
16417
  #endif
16418
16419
  if (agent == NULL || control ->
16420
          FlushPolicy == policy_immediate)
16421
  {
16422
    #if defined(TEST) || defined(INFO)
16423
16424
    if (usePolicy == -1 && control ->
16425
            ProxyMode == proxy_client)
16426
    {
16427
      *logofs << "Loop: WARNING! Flushing the proxy link "
16428
              << "on behalf of the agent.\n" << logofs_flush;
16429
    }
16430
16431
    #endif
16432
16433
    if (proxy -> handleFlush() < 0)
16434
    {
16435
      #ifdef TEST
16436
      *logofs << "Loop: Failure flushing the proxy FD#"
16437
              << proxyFD << ".\n" << logofs_flush;
16438
      #endif
16439
16440
      HandleShutdown();
16441
    }
16442
  }
16443
}
16444
16445
static inline void handleRotateInLoop()
16446
{
16447
  #ifdef DEBUG
16448
  *logofs << "Loop: Going to rotate channels "
16449
          << "for proxy FD#" << proxyFD << ".\n"
16450
          << logofs_flush;
16451
  #endif
16452
16453
  proxy -> handleRotate();
16454
}
16455
16456
static inline void handleEventsInLoop()
16457
{
16458
  #ifdef DEBUG
16459
  *logofs << "Loop: Going to check channel events "
16460
          << "for proxy FD#" << proxyFD << ".\n"
16461
          << logofs_flush;
16462
  #endif
16463
16464
  if (proxy -> handleEvents() < 0)
16465
  {
16466
    #ifdef TEST
16467
    *logofs << "Loop: Failure handling channel events "
16468
            << "for proxy FD#" << proxyFD << ".\n"
16469
            << logofs_flush;
16470
    #endif
16471
16472
    HandleShutdown();
16473
  }
16474
}
16475
16476
static void handleLogReopenInLoop(T_timestamp &logsTs, T_timestamp &nowTs)
16477
{
16478
  //
16479
  // If need to limit the size of the
16480
  // log file, check the size at each
16481
  // loop.
16482
  //
16483
16484
  #ifndef QUOTA
16485
16486
  if (diffTimestamp(logsTs, nowTs) > control -> FileSizeCheckTimeout)
16487
16488
  #endif
16489
  {
16490
    #ifdef DEBUG
16491
    *logofs << "Loop: Checking size of log file '"
16492
            << errorsFileName << "'.\n" << logofs_flush;
16493
    #endif
16494
16495
    #ifndef MIXED
16496
16497
    if (ReopenLogFile(errorsFileName, logofs, control -> FileSizeLimit) < 0)
16498
    {
16499
      HandleShutdown();
16500
    }
16501
16502
    #endif
16503
16504
    //
16505
    // Reset to current timestamp.
16506
    //
16507
16508
    logsTs = nowTs;
16509
  }
16510
}
16511
16512
static inline void handleSetReadInLoop(fd_set &readSet, int &setFDs, struct timeval &selectTs)
16513
{
16514
  proxy -> setReadDescriptors(&readSet, setFDs, selectTs);
16515
}
16516
16517
static inline void handleSetWriteInLoop(fd_set &writeSet, int &setFDs, struct timeval &selectTs)
16518
{
16519
  proxy -> setWriteDescriptors(&writeSet, setFDs, selectTs);
16520
}
16521
16522
static void handleSetListenersInLoop(fd_set &readSet, int &setFDs)
16523
{
16524
  //
16525
  // Set descriptors of listening sockets.
16526
  //
16527
16528
  if (control -> ProxyMode == proxy_client)
16529
  {
16530
    if (useTcpSocket == 1)
16531
    {
16532
      FD_SET(tcpFD, &readSet);
16533
16534
      if (tcpFD >= setFDs)
16535
      {
16536
        setFDs = tcpFD + 1;
16537
      }
16538
16539
      #ifdef DEBUG
16540
      *logofs << "Loop: Selected listener tcpFD " << tcpFD
16541
              << " with setFDs " << setFDs << ".\n"
16542
              << logofs_flush;
16543
      #endif
16544
    }
16545
16546
    if (useUnixSocket == 1)
16547
    {
16548
      FD_SET(unixFD, &readSet);
16549
16550
      if (unixFD >= setFDs)
16551
      {
16552
        setFDs = unixFD + 1;
16553
      }
16554
16555
      #ifdef DEBUG
16556
      *logofs << "Loop: Selected listener unixFD " << unixFD
16557
              << " with setFDs " << setFDs << ".\n"
16558
              << logofs_flush;
16559
      #endif
16560
    }
16561
16562
    if (useCupsSocket == 1)
16563
    {
16564
      FD_SET(cupsFD, &readSet);
16565
16566
      if (cupsFD >= setFDs)
16567
      {
16568
        setFDs = cupsFD + 1;
16569
      }
16570
16571
      #ifdef DEBUG
16572
      *logofs << "Loop: Selected listener cupsFD " << cupsFD
16573
              << " with setFDs " << setFDs << ".\n"
16574
              << logofs_flush;
16575
      #endif
16576
    }
16577
16578
    if (useAuxSocket == 1)
16579
    {
16580
      FD_SET(auxFD, &readSet);
16581
16582
      if (auxFD >= setFDs)
16583
      {
16584
        setFDs = auxFD + 1;
16585
      }
16586
16587
      #ifdef DEBUG
16588
      *logofs << "Loop: Selected listener auxFD " << auxFD
16589
              << " with setFDs " << setFDs << ".\n"
16590
              << logofs_flush;
16591
      #endif
16592
    }
16593
16594
    if (useSmbSocket == 1)
16595
    {
16596
      FD_SET(smbFD, &readSet);
16597
16598
      if (smbFD >= setFDs)
16599
      {
16600
        setFDs = smbFD + 1;
16601
      }
16602
16603
      #ifdef DEBUG
16604
      *logofs << "Loop: Selected listener smbFD " << smbFD
16605
              << " with setFDs " << setFDs << ".\n"
16606
              << logofs_flush;
16607
      #endif
16608
    }
16609
16610
    if (useMediaSocket == 1)
16611
    {
16612
      FD_SET(mediaFD, &readSet);
16613
16614
      if (mediaFD >= setFDs)
16615
      {
16616
        setFDs = mediaFD + 1;
16617
      }
16618
16619
      #ifdef DEBUG
16620
      *logofs << "Loop: Selected listener mediaFD " << mediaFD
16621
              << " with setFDs " << setFDs << ".\n"
16622
              << logofs_flush;
16623
      #endif
16624
    }
16625
16626
    if (useHttpSocket == 1)
16627
    {
16628
      FD_SET(httpFD, &readSet);
16629
16630
      if (httpFD >= setFDs)
16631
      {
16632
        setFDs = httpFD + 1;
16633
      }
16634
16635
      #ifdef DEBUG
16636
      *logofs << "Loop: Selected listener httpFD " << httpFD
16637
              << " with setFDs " << setFDs << ".\n"
16638
              << logofs_flush;
16639
      #endif
16640
    }
16641
  }
16642
  else
16643
  {
16644
    if (useFontSocket == 1)
16645
    {
16646
      FD_SET(fontFD, &readSet);
16647
16648
      if (fontFD >= setFDs)
16649
      {
16650
        setFDs = fontFD + 1;
16651
      }
16652
16653
      #ifdef DEBUG
16654
      *logofs << "Loop: Selected listener fontFD " << fontFD
16655
              << " with setFDs " << setFDs << ".\n"
16656
              << logofs_flush;
16657
      #endif
16658
    }
16659
  }
16660
16661
  if (useSlaveSocket == 1)
16662
  {
16663
    FD_SET(slaveFD, &readSet);
16664
16665
    if (slaveFD >= setFDs)
16666
    {
16667
      setFDs = slaveFD + 1;
16668
    }
16669
16670
    #ifdef DEBUG
16671
    *logofs << "Loop: Selected listener slaveFD " << slaveFD
16672
            << " with setFDs " << setFDs << ".\n"
16673
            << logofs_flush;
16674
    #endif
16675
  }
16676
}