diff options
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Args.c | 76 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Display.c | 323 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Options.c | 2 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Options.h | 17 | ||||
-rw-r--r-- | nxcomp/Loop.cpp | 3 | ||||
-rw-r--r-- | nxcomp/Misc.cpp | 4 |
6 files changed, 373 insertions, 52 deletions
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Args.c b/nx-X11/programs/Xserver/hw/nxagent/Args.c index 832595786..9e54c0073 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Args.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Args.c @@ -1405,6 +1405,82 @@ static void nxagentParseOptions(char *name, char *value) return; } + else if (!strcmp(name, "tolerancechecks")) + { + if (strcmp(value, "strict") == 0) + { + nxagentChangeOption(ReconnectTolerance, ToleranceChecksStrict); + } + else if (strcmp(value, "safe") == 0) + { + nxagentChangeOption(ReconnectTolerance, ToleranceChecksSafe); + } + else if (strcmp(value, "risky") == 0) + { + nxagentChangeOption(ReconnectTolerance, ToleranceChecksRisky); + } + else if (strcmp(value, "none") == 0) + { + nxagentChangeOption(ReconnectTolerance, ToleranceChecksBypass); + } + else + { + /* + * Check for a matching integer. Or any integer, really. + */ + long tolerance_parse = 0; + + errno = 0; + tolerance_parse = strtol(value, NULL, 10); + + if ((errno) && (0 == tolerance_parse)) + { + fprintf(stderr, "nxagentParseOptions: Unable to convert value [%s] of option [%s]. " + "Ignoring option.\n", + validateString(value), validateString(name)); + + return; + } + + if ((long) UINT_MAX < tolerance_parse) + { + tolerance_parse = UINT_MAX; + + fprintf(stderr, "nxagentParseOptions: Warning: value [%s] of option [%s] " + "out of range, clamped to [%u].\n", + validateString(value), validateString(name), tolerance_parse); + } + + if (0 > tolerance_parse) + { + tolerance_parse = 0; + + fprintf(stderr, "nxagentParseOptions: Warning: value [%s] of option [%s] " + "out of range, clamped to [%u].\n", + validateString(value), validateString(name), tolerance_parse); + } + + #ifdef TEST + switch (tolerance_parse) { + case ToleranceChecksStrict: + case ToleranceChecksSafe: + case ToleranceChecksRisky: + case ToleranceChecksBypass: + break; + default: + fprintf(stderr, "nxagentParseOptions: Warning: value [%s] of " + "option [%s] unknown, will be mapped to " + "\"Bypass\" [%u] value internally.\n", + validateString(value), validateString(name), + (unsigned int)ToleranceChecksBypass); + } + #endif + + nxagentChangeOption(ReconnectTolerance, tolerance_parse); + } + + return; + } else { #ifdef DEBUG diff --git a/nx-X11/programs/Xserver/hw/nxagent/Display.c b/nx-X11/programs/Xserver/hw/nxagent/Display.c index 5943fbf77..5d258fd44 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Display.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Display.c @@ -45,6 +45,7 @@ is" without express or implied warranty. #include <unistd.h> #include <time.h> #include <errno.h> +#include <stdbool.h> #include <nx-X11/X.h> #include <nx-X11/Xproto.h> @@ -178,7 +179,7 @@ static void nxagentInitDepths(void); static void nxagentInitPixmapFormats(void); static int nxagentCheckForDefaultDepthCompatibility(void); -static int nxagentCheckForDepthsCompatibility(int flexibility); +static int nxagentCheckForDepthsCompatibility(void); static int nxagentCheckForPixmapFormatsCompatibility(void); static int nxagentInitAndCheckVisuals(int flexibility); static int nxagentCheckForColormapsCompatibility(int flexibility); @@ -1346,6 +1347,7 @@ FIXME: Use of nxagentParentWindow is strongly deprecated. nxagentInitDepths(); nxagentInitPixmapFormats(); + (void) nxagentCheckForPixmapFormatsCompatibility(); /* * Create a pixmap for each depth matching the @@ -1726,8 +1728,6 @@ XXX: Some X server doesn't list 1 among available depths... } } #endif - - nxagentCheckForPixmapFormatsCompatibility(); } void nxagentSetDefaultDrawables() @@ -2175,10 +2175,40 @@ void nxagentDisconnectDisplay(void) static int nxagentCheckForDefaultDepthCompatibility() { + /* + * Depending on the (reconnect) tolerance checks value, this + * function checks stricter or looser: + * - Strict means that the old and new default depth values + * must match exactly. + * - Safe or Risky means that the default depth values might differ, + * but the new default depth value must be at least as + * high as the former default depth value. This is + * recommended, because it allows clients with a + * higher default depth value to still connect, but + * not lose functionality. + * - Bypass or higher means that all of these checks are + * essentially deactivated. This is probably a very + * bad idea. + */ + int dDepth; dDepth = DefaultDepth(nxagentDisplay, DefaultScreen(nxagentDisplay)); + const unsigned int tolerance = nxagentOption(ReconnectTolerance); + + if (ToleranceChecksBypass <= tolerance) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDefaultDepthCompatibility: WARNING! Not proceeding with any checks, " + "because tolerance [%u] higher than or equal [%u]. New default depth value " + "is [%d], former default depth value is [%d].\n", tolerance, + ToleranceChecksBypass, dDepth, nxagentDefaultDepthRecBackup); + #endif + + return 1; + } + if (nxagentDefaultDepthRecBackup == dDepth) { #ifdef TEST @@ -2188,142 +2218,326 @@ static int nxagentCheckForDefaultDepthCompatibility() return 1; } + else if ((ToleranceChecksSafe <= tolerance) && (nxagentDefaultDepthRecBackup < dDepth)) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDefaultDepthCompatibility: WARNING! New default depth [%d] " + "higher than the old default depth [%d] at tolerance [%u].\n", dDepth, + nxagentDefaultDepthRecBackup, tolerance); + #endif + + return 1; + } else { #ifdef WARNING fprintf(stderr, "nxagentCheckForDefaultDepthCompatibility: WARNING! New default depth [%d] " - "doesn't match with old default depth [%d].\n", dDepth, nxagentDefaultDepthRecBackup); + "doesn't match with old default depth [%d] at tolerance [%u].\n", dDepth, + nxagentDefaultDepthRecBackup, tolerance); #endif return 0; } } -static int nxagentCheckForDepthsCompatibility(int flexibility) +static int nxagentCheckForDepthsCompatibility() { - int i, j; - int matched; - int compatible; + /* + * Depending on the (reconnect) tolerance checks value, this + * function checks stricter or looser: + * - Strict means that the number of old and new depths must + * match exactly and every old depth value must be + * available in the new depth array. + * - Safe means that the number of depths might diverge, + * but all former depth must also be included in the + * new depth array. This is recommended, because + * it allows clients with more depths to still + * connect, but not lose functionality. + * - Risky means that the new depths array is allowed to be + * smaller than the old depths array, but at least + * one depth value must be included in both. + * This is potentially unsafe. + * - Bypass or higher means that all of these checks are + * essentially deactivated. This is a very bad idea. + */ - if (nxagentNumDepths != nxagentNumDepthsRecBackup) + const unsigned int tolerance = nxagentOption(ReconnectTolerance); + + if (ToleranceChecksBypass <= tolerance) { #ifdef WARNING - fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! Number of new available depths [%d] " - "doesn't match with old depths [%d].\n", nxagentNumDepths, - nxagentNumDepthsRecBackup); + fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! Not proceeding with any checks, " + "because tolerance [%u] higher than or equal [%u]. Number of newly available depths " + "is [%d], number of old depths is [%d].\n", tolerance, ToleranceChecksBypass, + nxagentNumDepths, nxagentNumDepthsRecBackup); + #endif + + return 1; + } + + if ((ToleranceChecksStrict == tolerance) && (nxagentNumDepths != nxagentNumDepthsRecBackup)) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! No tolerance allowed and " + "number of new available depths [%d] doesn't match with number of old " + "depths [%d].\n", nxagentNumDepths, + nxagentNumDepthsRecBackup); #endif return 0; } - compatible = 1; + if ((ToleranceChecksSafe == tolerance) && (nxagentNumDepths < nxagentNumDepthsRecBackup)) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! Tolerance [%u] not " + "high enough and number of new available depths [%d] " + "lower than number of old depths [%d].\n", tolerance, + nxagentNumDepths, nxagentNumDepthsRecBackup); + #endif + + return 0; + } + + /* + * By now the tolerance is either: + * - Strict and both depth numbers match + * - Safe and: + * o the number of old and new depths matches exactly, or + * o the number of old depths is lower than the number + * of new depths + * - Risky + */ + + bool compatible = true; + bool one_match = false; + bool matched = false; + int total_matches = 0; - for (i = 0; i < nxagentNumDepths; i++) + /* + * FIXME: within this loop, we try to match all "new" depths + * against the "old" depths. Depending upon the flexibility + * value, either all "new" depths must have a corresponding + * counterpart in the "old" array, or at least one value + * must be included in both. + * Is this safe enough though? + * Shouldn't we better try to match entries in the "old" + * depths array against the "new" depths array, such that + * we know that all "old" values are covered by "new" + * values? Or is it more important that "new" values are + * covered by "old" ones, with potentially more "old" + * values lingering around that cannot be displayed by the + * connected client? + * + * This section probably needs a revisit at some point in time. + */ + for (int i = 0; i < nxagentNumDepths; ++i) { - matched = 0; + matched = false; - for (j = 0; j < nxagentNumDepthsRecBackup; j++) + for (int j = 0; j < nxagentNumDepthsRecBackup; ++j) { if (nxagentDepths[i] == nxagentDepthsRecBackup[j]) { - matched = 1; + matched = true; + one_match = true; + ++total_matches; break; } } - if (matched == 0) + if ((ToleranceChecksRisky > tolerance) && (!matched)) { #ifdef WARNING - fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! Failed to match available depth [%d].\n", - nxagentDepths[i]); + fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! Tolerance [%u] too low and " + "failed to match available depth [%d].\n", tolerance, nxagentDepths[i]); #endif - compatible = 0; + compatible = false; break; } } + /* + * At Risky tolerance, only one match is necessary to be "compatible". + */ + if (ToleranceChecksRisky == tolerance) + { + compatible = one_match; + } + + int ret = (!(!compatible)); - if (compatible == 1) + if (compatible) { #ifdef TEST fprintf(stderr, "nxagentCheckForDepthsCompatibility: Internal depths match with " - "remote depths.\n"); + "remote depths at tolerance [%u].\n", tolerance); #endif + + if (total_matches != nxagentNumDepths) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDepthsCompatibility: only some [%d] of the new depths [%d] " + "match with old depths [%d] at tolerance [%u].\n", total_matches, nxagentNumDepths, + nxagentNumDepthsRecBackup, tolerance); + #endif + } } else { #ifdef WARNING - fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! New available depths don't match with " - "old depths.\n"); + fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! New available depths [%d] don't match " + "with old depths [%d] at tolerance [%u]. Only [%d] depth values matched.\n", + nxagentNumDepths, nxagentNumDepthsRecBackup, tolerance, total_matches); #endif } - return compatible; + return (ret); } static int nxagentCheckForPixmapFormatsCompatibility() { - int i, j; - int matched; - int compatible; + /* + * Depending on the (reconnect) tolerance checks value, this + * function checks stricter or looser: + * - Strict means that the number of internal and external + * pixmap formats must match exactly and every + * internal pixmap format must be available in the + * external pixmap format array. + * - Safe means that the number of pixmap formats might + * diverge, but all internal pixmap formats must + * also be included in the external pixmap formats + * array. This is recommended, because it allows + * clients with more pixmap formats to still connect, + * but not lose functionality. + * - Risky means that the internal pixmap formats array is + * allowed to be smaller than the external pixmap + * formats array, but at least one pixmap format must + * be included in both. This is potentially unsafe. + * - Bypass or higher means that all of these checks are + * essentially deactivated. This is a very bad idea. + */ - compatible = 1; + const unsigned int tolerance = nxagentOption(ReconnectTolerance); + + if (ToleranceChecksBypass <= tolerance) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: WARNING! Not proceeding with any checks, " + "because tolerance [%u] higher than or equal [%u]. Number of internally available " + "pixmap formats is [%d], number of externally available pixmap formats is [%d].\n", + tolerance, ToleranceChecksBypass, nxagentNumPixmapFormats, nxagentRemoteNumPixmapFormats); + #endif - if (nxagentNumPixmapFormats != nxagentRemoteNumPixmapFormats) + return 1; + } + + if ((ToleranceChecksStrict == tolerance) && (nxagentNumPixmapFormats != nxagentRemoteNumPixmapFormats)) { #ifdef DEBUG - fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: WARNING! Number of internal pixmap formats [%d] " - "doesn't match with remote formats [%d].\n", nxagentNumPixmapFormats, - nxagentRemoteNumPixmapFormats); + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: WARNING! No tolerance allowed and number " + "of internal pixmap formats [%d] doesn't match with number of remote formats [%d].\n", + nxagentNumPixmapFormats, nxagentRemoteNumPixmapFormats); #endif + + return 0; } - for (i = 0; i < nxagentNumPixmapFormats; i++) + if ((ToleranceChecksSafe == tolerance) && (nxagentNumPixmapFormats > nxagentRemoteNumPixmapFormats)) { - matched = 0; + #ifdef DEBUG + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: WARNING! Tolerance [%u] too low " + "and number of internal pixmap formats [%d] higher than number of external formats [%d].\n", + tolerance, nxagentNumPixmapFormats, nxagentRemoteNumPixmapFormats); + #endif + + return 0; + } + + /* + * By now the tolerance is either: + * - Strict + * - Safe and: + * o the number of internal and external pixmap formats + * matches exactly, or + * o the number of external pixmap formats is higher than + * the number of internal pixmap formats, + * - Risky + */ + + bool compatible = true; + bool one_match = false; + bool matched = false; + int total_matches = 0; + + for (int i = 0; i < nxagentNumPixmapFormats; ++i) + { + matched = false; - for (j = 0; j < nxagentRemoteNumPixmapFormats; j++) + for (int j = 0; j < nxagentRemoteNumPixmapFormats; ++j) { if (nxagentPixmapFormats[i].depth == nxagentRemotePixmapFormats[j].depth && nxagentPixmapFormats[i].bits_per_pixel == nxagentRemotePixmapFormats[j].bits_per_pixel && nxagentPixmapFormats[i].scanline_pad == nxagentRemotePixmapFormats[j].scanline_pad) { - matched = 1; + matched = true; + one_match = true; + ++total_matches; break; } } - if (matched == 0) + if ((ToleranceChecksRisky > tolerance) && (!matched)) { #ifdef WARNING - fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: WARNING! Failed to match internal " - "pixmap format depth [%d] bpp [%d] pad [%d].\n", nxagentPixmapFormats[i].depth, - nxagentPixmapFormats[i].bits_per_pixel, nxagentPixmapFormats[i].scanline_pad); + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: WARNING! Tolerance [%u] too low " + "and failed to match internal pixmap format (depth [%d] bpp [%d] pad [%d]).\n", + tolerance, nxagentPixmapFormats[i].depth, nxagentPixmapFormats[i].bits_per_pixel, + nxagentPixmapFormats[i].scanline_pad); #endif - compatible = 0; + compatible = false; } } - #ifdef TEST + int ret = !(!(compatible)); - if (compatible == 1) + if (compatible) { + #ifdef TEST fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: Internal pixmap formats match with " - "remote pixmap formats.\n"); - } + "remote pixmap formats at tolerance [%u].\n", tolerance); + #endif - #endif + if (total_matches != nxagentNumPixmapFormats) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: Only some [%d] of the internal " + "pixmap formats [%d] match with external pixmap formats [%d] at tolerance [%u].\n", + total_matches, nxagentNumPixmapFormats, nxagentRemoteNumPixmapFormats, tolerance); + #endif + } + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: WARNING! Internally available " + "pixmap formats [%d] don't match with external pixmap formats [%d] " + "at tolerance [%u]. Only [%d] depth values matched.\n", + nxagentNumPixmapFormats, nxagentRemoteNumPixmapFormats, tolerance, total_matches); + #endif + } - return compatible; + return (ret); } static int nxagentInitAndCheckVisuals(int flexibility) { + /* FIXME: does this also need work? */ XVisualInfo viTemplate; XVisualInfo *viList; XVisualInfo *newVisuals; @@ -2433,6 +2647,7 @@ FIXME: Should the visual be ignored in this case? static int nxagentCheckForColormapsCompatibility(int flexibility) { + /* FIXME: does this also need work? */ if (nxagentNumDefaultColormaps == nxagentNumDefaultColormapsRecBackup) { #ifdef TEST @@ -2592,7 +2807,7 @@ Bool nxagentReconnectDisplay(void *p0) reconnectDisplayState = GOT_DEPTH_LIST; - if (nxagentCheckForDepthsCompatibility(flexibility) == 0) + if (nxagentCheckForDepthsCompatibility() == 0) { nxagentSetReconnectError(FAILED_RESUME_DEPTHS_ALERT, "Couldn't restore all the required depths."); @@ -2626,6 +2841,14 @@ Bool nxagentReconnectDisplay(void *p0) nxagentInitPixmapFormats(); + if (nxagentCheckForPixmapFormatsCompatibility() == 0) + { + nxagentSetReconnectError(FAILED_RESUME_PIXMAPS_ALERT, + "Couldn't restore all the required pixmap formats."); + + return False; + } + reconnectDisplayState = GOT_PIXMAP_FORMAT_LIST; /* diff --git a/nx-X11/programs/Xserver/hw/nxagent/Options.c b/nx-X11/programs/Xserver/hw/nxagent/Options.c index 0a894f9a4..978f3ab95 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Options.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Options.c @@ -166,6 +166,8 @@ void nxagentInitOptions() nxagentOptions.Xinerama = 1; nxagentOptions.SleepTime = DEFAULT_SLEEP_TIME; + + nxagentOptions.ReconnectTolerance = DEFAULT_TOLERANCE; } /* diff --git a/nx-X11/programs/Xserver/hw/nxagent/Options.h b/nx-X11/programs/Xserver/hw/nxagent/Options.h index df6f8b65b..20616a90b 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Options.h +++ b/nx-X11/programs/Xserver/hw/nxagent/Options.h @@ -67,6 +67,17 @@ typedef enum _ClientOsType } ClientOsType; +typedef enum _ToleranceChecksMode +{ + ToleranceChecksStrict = 0, + ToleranceChecksSafe = 1, + ToleranceChecksRisky = 2, + ToleranceChecksBypass = 3 +} ToleranceChecksMode; + + +#define DEFAULT_TOLERANCE ToleranceChecksStrict + /* * Set of options affecting agent operations. */ @@ -414,6 +425,12 @@ typedef struct _AgentOptions unsigned int SleepTime; + /* + * Tolerance - tightens or loosens reconnect checks. + */ + + ToleranceChecksMode ReconnectTolerance; + } AgentOptionsRec; typedef AgentOptionsRec *AgentOptionsPtr; diff --git a/nxcomp/Loop.cpp b/nxcomp/Loop.cpp index c0951ee19..10026967a 100644 --- a/nxcomp/Loop.cpp +++ b/nxcomp/Loop.cpp @@ -9063,7 +9063,8 @@ int ParseEnvironmentOptions(const char *env, int force) strcasecmp(name, "clipboard") == 0 || strcasecmp(name, "streaming") == 0 || strcasecmp(name, "backingstore") == 0 || - strcasecmp(name, "sleep") == 0) + strcasecmp(name, "sleep") == 0 || + strcasecmp(name, "tolerancechecks") == 0) { #ifdef DEBUG *logofs << "Loop: Ignoring agent option '" << name diff --git a/nxcomp/Misc.cpp b/nxcomp/Misc.cpp index ca062ebed..c94dc8b9c 100644 --- a/nxcomp/Misc.cpp +++ b/nxcomp/Misc.cpp @@ -325,7 +325,9 @@ shadowmode=s\n\ defer=n\n\ tile=s\n\ menu=n\n\ -sleep=n These options are interpreted by the NX agent. They\n\ +sleep=n\n\ +tolerancecehcks=s\n\ + These options are interpreted by the NX agent. They\n\ are ignored by the proxy.\n\ \n\ Environment:\n\ |