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

« back to all changes in this revision

Viewing changes to Loop.cpp

  • Committer: Marcelo Boveto Shima
  • Date: 2009-03-28 22:24:56 UTC
  • Revision ID: mshima@ufserv-20090328222456-rdtaq3oedfyq890c
Import nxcomp 3.3.0-3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}