853 lines
21 KiB
C
853 lines
21 KiB
C
/**************************************************************************/
|
|
/* */
|
|
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
|
|
/* Copyright (c) 2008-2017 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
|
|
/* Copyright (c) 2011-2022 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
|
|
/* Copyright (c) 2014-2019 Mihai Moldovan <ionic@ionic.de> */
|
|
/* Copyright (c) 2014-2022 Ulrich Sibiller <uli42@gmx.de> */
|
|
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
|
|
/* */
|
|
/* NXAGENT, NX protocol compression and NX extensions to this software */
|
|
/* are copyright of the aforementioned persons and companies. */
|
|
/* */
|
|
/* Redistribution and use of the present software is allowed according */
|
|
/* to terms specified in the file LICENSE which comes in the source */
|
|
/* distribution. */
|
|
/* */
|
|
/* All rights reserved. */
|
|
/* */
|
|
/* NOTE: This software has received contributions from various other */
|
|
/* contributors, only the core maintainers and supporters are listed as */
|
|
/* copyright holders. Please contact us, if you feel you should be listed */
|
|
/* as copyright holder, as well. */
|
|
/* */
|
|
/**************************************************************************/
|
|
|
|
#include <signal.h>
|
|
|
|
#include "X.h"
|
|
#include "Xproto.h"
|
|
#include "Xpoll.h"
|
|
#include "mi.h"
|
|
#include "fb.h"
|
|
#include "inputstr.h"
|
|
|
|
#include "Agent.h"
|
|
#include "Atoms.h"
|
|
#include "Drawable.h"
|
|
#include "Client.h"
|
|
#include "Reconnect.h"
|
|
#include "Display.h"
|
|
#include "Dialog.h"
|
|
#include "Screen.h"
|
|
#include "Windows.h"
|
|
#include "Events.h"
|
|
#include "Dialog.h"
|
|
#include "Args.h"
|
|
#include "Font.h"
|
|
#include "GCs.h"
|
|
#include "Trap.h"
|
|
#include "Keyboard.h"
|
|
#include "Composite.h"
|
|
#include "Millis.h"
|
|
#include "Splash.h"
|
|
#include "Error.h"
|
|
#include "Keystroke.h"
|
|
#include "Utils.h"
|
|
#include "Init.h"
|
|
|
|
#ifdef XKB
|
|
#include "XKBsrv.h"
|
|
#endif
|
|
|
|
#include <nx/NX.h>
|
|
#include "compext/Compext.h"
|
|
#include <nx/NXalert.h>
|
|
|
|
/*
|
|
* Set here the required log level.
|
|
*/
|
|
|
|
#define PANIC
|
|
#define WARNING
|
|
#undef TEST
|
|
#undef DEBUG
|
|
|
|
#define NXAGENT_RECONNECT_DEFAULT_MESSAGE_SIZE 32
|
|
|
|
extern Bool nxagentReconnectAllCursor(void*);
|
|
extern Bool nxagentReconnectAllColormap(void*);
|
|
extern Bool nxagentReconnectAllWindows(void*);
|
|
extern Bool nxagentReconnectAllGlyphSet(void*);
|
|
extern Bool nxagentReconnectAllPictFormat(void*);
|
|
extern Bool nxagentReconnectAllPicture(void*);
|
|
|
|
extern Bool nxagentDisconnectAllPicture(void);
|
|
extern Bool nxagentDisconnectAllWindows(void);
|
|
extern void nxagentDisconnectAllCursor(void);
|
|
|
|
extern Bool nxagentReconnectFailedFonts(void*);
|
|
extern Bool nxagentInstallFontServerPath(void);
|
|
extern Bool nxagentUninstallFontServerPath(void);
|
|
|
|
extern void nxagentRemoveXConnection(void);
|
|
|
|
extern void nxagentInitPointerMap(void);
|
|
|
|
static char *nxagentGetReconnectError(void);
|
|
|
|
void nxagentInitializeRecLossyLevel(void);
|
|
|
|
static char *nxagentReconnectErrorMessage = NULL;
|
|
static int nxagentReconnectErrorId;
|
|
|
|
extern Bool nxagentRenderEnable;
|
|
|
|
extern char *nxagentKeyboard;
|
|
|
|
extern char *nxagentOptionsFilenameOrString;
|
|
|
|
enum SESSION_STATE nxagentSessionState = SESSION_STARTING;
|
|
|
|
struct nxagentExceptionStruct nxagentException = {0, 0};
|
|
|
|
enum RECONNECTION_STEP
|
|
{
|
|
DISPLAY_STEP = 0,
|
|
SCREEN_STEP,
|
|
FONT_STEP,
|
|
PIXMAP_STEP,
|
|
GC_STEP,
|
|
CURSOR_STEP,
|
|
COLORMAP_STEP,
|
|
WINDOW_STEP,
|
|
GLYPHSET_STEP,
|
|
PICTFORMAT_STEP,
|
|
PICTURE_STEP,
|
|
STEP_NONE
|
|
};
|
|
|
|
void *reconnectLossyLevel[STEP_NONE];
|
|
|
|
static enum RECONNECTION_STEP failedStep;
|
|
|
|
#include <limits.h>
|
|
|
|
/*
|
|
* Path of state File
|
|
*/
|
|
char stateFile[PATH_MAX] = {0};
|
|
|
|
|
|
void setStatePath(char* path)
|
|
{
|
|
snprintf(stateFile, PATH_MAX, "%s", path);
|
|
}
|
|
|
|
void saveAgentState(char* state)
|
|
{
|
|
if (strlen(stateFile))
|
|
{
|
|
FILE* fptr = fopen(stateFile, "w");
|
|
if (!fptr)
|
|
return;
|
|
fprintf(fptr, "%s", state);
|
|
fclose(fptr);
|
|
}
|
|
}
|
|
|
|
|
|
int nxagentHandleConnectionStates(void)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Handling Exception with "
|
|
"state [%s] and transport [%d] and generation [%ld].\n",
|
|
DECODE_SESSION_STATE(nxagentSessionState), NXTransRunning(NX_FD_ANY), serverGeneration);
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Entering with nxagentException.sigHup = [%d], "
|
|
"nxagentException.ioError = [%d]\n",
|
|
nxagentException.sigHup, nxagentException.ioError);
|
|
#endif
|
|
|
|
if (nxagentException.sigHup > 0)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Got SIGHUP in the exception flags.\n");
|
|
#endif
|
|
|
|
nxagentException.sigHup = 0;
|
|
|
|
if (nxagentSessionState == SESSION_UP)
|
|
{
|
|
if (nxagentOption(Persistent))
|
|
{
|
|
nxagentSessionState = SESSION_GOING_DOWN;
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Handling "
|
|
"signal [SIGHUP] by disconnecting the agent.\n");
|
|
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
nxagentTerminateSession();
|
|
}
|
|
}
|
|
else if (nxagentSessionState == SESSION_STARTING)
|
|
{
|
|
nxagentTerminateSession();
|
|
|
|
#ifdef WARNING
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Handling signal [SIGHUP] by terminating the agent.\n");
|
|
#endif
|
|
}
|
|
else if (nxagentSessionState == SESSION_DOWN &&
|
|
NXTransRunning(NX_FD_ANY) == 0)
|
|
{
|
|
nxagentSessionState = SESSION_GOING_UP;
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Handling signal [SIGHUP] by reconnecting the agent.\n");
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Handling signal with state [%s] and exception [%d].\n",
|
|
DECODE_SESSION_STATE(nxagentSessionState), dispatchException);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (nxagentNeedConnectionChange())
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Calling nxagentHandleConnectionChanges "
|
|
"with ioError [%d] sigHup [%d].\n", nxagentException.ioError, nxagentException.sigHup);
|
|
#endif
|
|
|
|
nxagentHandleConnectionChanges();
|
|
}
|
|
|
|
if (nxagentException.ioError > 0)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Got I/O error in the exception flags.\n");
|
|
#endif
|
|
/*
|
|
TODO: This should be reset only when the state became SESSION_DOWN.
|
|
*/
|
|
nxagentException.ioError = 0;
|
|
|
|
if (nxagentOption(Persistent) && nxagentSessionState != SESSION_STARTING)
|
|
{
|
|
if (nxagentSessionState == SESSION_UP)
|
|
{
|
|
if ((dispatchException & DE_TERMINATE) == 0)
|
|
{
|
|
fprintf(stderr, "Session: Display failure detected at '%s'.\n", GetTimeAsString());
|
|
|
|
fprintf(stderr, "Session: Suspending session at '%s'.\n", GetTimeAsString());
|
|
saveAgentState("SUSPENDING");
|
|
}
|
|
|
|
nxagentDisconnectSession();
|
|
}
|
|
else if (nxagentSessionState == SESSION_GOING_DOWN)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Got I/O error with session "
|
|
"[SESSION_GOING_DOWN].\n");
|
|
#endif
|
|
}
|
|
else if (nxagentSessionState == SESSION_GOING_UP)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Got I/O error with session "
|
|
"[SESSION_GOING_UP].\n");
|
|
#endif
|
|
|
|
nxagentSessionState = SESSION_GOING_DOWN;
|
|
|
|
nxagentSetReconnectError(FAILED_RESUME_DISPLAY_BROKEN_ALERT,
|
|
"Got I/O error during reconnect.");
|
|
|
|
nxagentChangeOption(Fullscreen, False);
|
|
|
|
return 1;
|
|
}
|
|
else if (nxagentSessionState == SESSION_DOWN)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Got I/O error with session "
|
|
"[SESSION_DOWN]. Ignoring.\n");
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentHandleConnectionStates: Got I/O error with session "
|
|
"[%d].\n", nxagentSessionState);
|
|
#endif
|
|
}
|
|
|
|
nxagentSessionState = SESSION_DOWN;
|
|
|
|
if ((dispatchException & DE_TERMINATE) == 0)
|
|
{
|
|
#ifdef NX_DEBUG_INPUT
|
|
fprintf(stderr, "Session: Session suspended at '%s' timestamp [%u].\n", GetTimeAsString(), GetTimeInMillis());
|
|
#else
|
|
fprintf(stderr, "Session: Session suspended at '%s'.\n", GetTimeAsString());
|
|
#endif
|
|
}
|
|
saveAgentState("SUSPENDED");
|
|
|
|
nxagentResetDisplayHandlers();
|
|
|
|
return 1;
|
|
}
|
|
|
|
fprintf(stderr, "Info: Disconnected from display '%s'.\n", nxagentDisplayName);
|
|
|
|
nxagentTerminateSession();
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void nxagentInitializeRecLossyLevel(void)
|
|
{
|
|
*(int *)reconnectLossyLevel[DISPLAY_STEP] = 0;
|
|
*(int *)reconnectLossyLevel[SCREEN_STEP] = 0;
|
|
*(int *)reconnectLossyLevel[FONT_STEP] = 0;
|
|
*(int *)reconnectLossyLevel[PIXMAP_STEP] = 0;
|
|
*(int *)reconnectLossyLevel[GC_STEP] = 0;
|
|
*(int *)reconnectLossyLevel[CURSOR_STEP] = 0;
|
|
*(int *)reconnectLossyLevel[COLORMAP_STEP] = 0;
|
|
*(int *)reconnectLossyLevel[WINDOW_STEP] = 0;
|
|
*(int *)reconnectLossyLevel[GLYPHSET_STEP] = 0;
|
|
*(int *)reconnectLossyLevel[PICTFORMAT_STEP] = 0;
|
|
*(int *)reconnectLossyLevel[PICTURE_STEP] = 0;
|
|
}
|
|
|
|
void nxagentInitReconnector(void)
|
|
{
|
|
nxagentReconnectTrap = False;
|
|
|
|
reconnectLossyLevel[DISPLAY_STEP] = malloc(sizeof(int));
|
|
reconnectLossyLevel[SCREEN_STEP] = malloc(sizeof(int));
|
|
reconnectLossyLevel[FONT_STEP] = malloc(sizeof(int));
|
|
reconnectLossyLevel[PIXMAP_STEP] = malloc(sizeof(int));
|
|
reconnectLossyLevel[GC_STEP] = malloc(sizeof(int));
|
|
reconnectLossyLevel[CURSOR_STEP] = malloc(sizeof(int));
|
|
reconnectLossyLevel[COLORMAP_STEP] = malloc(sizeof(int));
|
|
reconnectLossyLevel[WINDOW_STEP] = malloc(sizeof(int));
|
|
reconnectLossyLevel[GLYPHSET_STEP] = malloc(sizeof(int));
|
|
reconnectLossyLevel[PICTFORMAT_STEP] = malloc(sizeof(int));
|
|
reconnectLossyLevel[PICTURE_STEP] = malloc(sizeof(int));
|
|
}
|
|
|
|
void nxagentDisconnectSession(void)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentDisconnectSession: Disconnecting session with state [%s].\n",
|
|
DECODE_SESSION_STATE(nxagentSessionState));
|
|
#endif
|
|
|
|
nxagentFreeTimeoutTimer();
|
|
|
|
/*
|
|
* Force an I/O error on the display and wait until the NX transport
|
|
* is gone.
|
|
*/
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentDisconnectSession: Disconnecting the X display.\n");
|
|
#endif
|
|
|
|
nxagentWaitDisplay();
|
|
|
|
/*
|
|
* Prepare for the next reconnection.
|
|
*/
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentDisconnectSession: Disconnecting all X resources.\n");
|
|
#endif
|
|
|
|
nxagentInitializeRecLossyLevel();
|
|
|
|
nxagentBackupDisplayInfo();
|
|
|
|
if (nxagentOption(Rootless))
|
|
{
|
|
nxagentFreePropertyList();
|
|
}
|
|
|
|
if (nxagentRenderEnable)
|
|
{
|
|
nxagentDisconnectAllPicture();
|
|
}
|
|
|
|
nxagentEmptyAllBackingStoreRegions();
|
|
|
|
nxagentDisconnectAllWindows();
|
|
nxagentDisconnectAllCursor();
|
|
nxagentDisconnectAllPixmaps();
|
|
nxagentDisconnectAllGCs();
|
|
nxagentDisconnectDisplay();
|
|
|
|
nxagentWMIsRunning = False;
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentDisconnectSession: Disconnection completed. SigHup is [%d]. IoError is [%d].\n",
|
|
nxagentException.sigHup, nxagentException.ioError);
|
|
#endif
|
|
}
|
|
|
|
Bool nxagentReconnectSession(void)
|
|
{
|
|
char *nxagentOldKeyboard = NULL;
|
|
|
|
nxagentResizeDesktopAtStartup = False;
|
|
|
|
/*
|
|
* Propagate device settings if explicitly asked for.
|
|
*/
|
|
|
|
nxagentChangeOption(DeviceControl, nxagentOption(DeviceControlUserDefined));
|
|
|
|
/*
|
|
* We need to zero out every new XID created by the disconnected
|
|
* display.
|
|
*/
|
|
|
|
nxagentDisconnectSession();
|
|
|
|
/*
|
|
* Set this in order to let the screen function to behave
|
|
* differently at reconnection time.
|
|
*/
|
|
|
|
nxagentReconnectTrap = True;
|
|
|
|
nxagentSetReconnectError(0, NULL);
|
|
|
|
if (nxagentKeyboard != NULL)
|
|
{
|
|
nxagentOldKeyboard = strndup(nxagentKeyboard, strlen(nxagentKeyboard));
|
|
if (nxagentOldKeyboard == NULL)
|
|
{
|
|
/* 0 means reconnection failed */
|
|
return 0;
|
|
}
|
|
|
|
SAFE_free(nxagentKeyboard);
|
|
}
|
|
|
|
nxagentSaveOptions();
|
|
|
|
nxagentResetOptions();
|
|
|
|
nxagentProcessOptions(nxagentOptionsFilenameOrString);
|
|
|
|
|
|
if (!nxagentReconnectDisplay(reconnectLossyLevel[DISPLAY_STEP]))
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentReconnectSession: WARNING! Failed display reconnection.\n");
|
|
#endif
|
|
|
|
failedStep = DISPLAY_STEP;
|
|
goto nxagentReconnectError;
|
|
}
|
|
|
|
if (!nxagentReconnectScreen(reconnectLossyLevel[SCREEN_STEP]))
|
|
{
|
|
failedStep = SCREEN_STEP;
|
|
goto nxagentReconnectError;
|
|
}
|
|
|
|
nxagentDisconnectAllFonts();
|
|
|
|
nxagentListRemoteFonts("*", nxagentMaxFontNames);
|
|
|
|
if (!nxagentReconnectAllFonts(reconnectLossyLevel[FONT_STEP]))
|
|
{
|
|
if (!nxagentReconnectFailedFonts(reconnectLossyLevel[FONT_STEP]))
|
|
{
|
|
failedStep = FONT_STEP;
|
|
goto nxagentReconnectError;
|
|
}
|
|
else
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "nxagentReconnectSession: WARNING! Unable to retrieve all the fonts currently in use. "
|
|
"Missing fonts have been replaced.\n");
|
|
#endif
|
|
|
|
nxagentLaunchDialog(DIALOG_FONT_REPLACEMENT);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Map the main window and send a SetSelectionOwner request to
|
|
* notify of the agent start.
|
|
*/
|
|
|
|
nxagentMapDefaultWindows();
|
|
|
|
#ifdef NXAGENT_ONSTART
|
|
/*
|
|
* Ensure that the SetSelectionOwner request is sent through the
|
|
* link.
|
|
*/
|
|
|
|
XFlush(nxagentDisplay);
|
|
#endif
|
|
|
|
NXTransContinue(NULL);
|
|
|
|
nxagentEmptyBSPixmapList();
|
|
|
|
/* FIXME: nxagentReconnectAllPixmaps will always return 1 */
|
|
if (!nxagentReconnectAllPixmaps(reconnectLossyLevel[PIXMAP_STEP]))
|
|
{
|
|
failedStep = PIXMAP_STEP;
|
|
|
|
goto nxagentReconnectError;
|
|
}
|
|
|
|
if (!nxagentReconnectAllGCs(reconnectLossyLevel[GC_STEP]))
|
|
{
|
|
failedStep = GC_STEP;
|
|
goto nxagentReconnectError;
|
|
}
|
|
|
|
if (!nxagentReconnectAllColormap(reconnectLossyLevel[COLORMAP_STEP]))
|
|
{
|
|
failedStep = COLORMAP_STEP;
|
|
goto nxagentReconnectError;
|
|
}
|
|
|
|
if (!nxagentReconnectAllWindows(reconnectLossyLevel[WINDOW_STEP]))
|
|
{
|
|
failedStep = WINDOW_STEP;
|
|
goto nxagentReconnectError;
|
|
}
|
|
|
|
if (nxagentRenderEnable)
|
|
{
|
|
if (!nxagentReconnectAllGlyphSet(reconnectLossyLevel[GLYPHSET_STEP]))
|
|
{
|
|
failedStep = GLYPHSET_STEP;
|
|
goto nxagentReconnectError;
|
|
}
|
|
|
|
if (!nxagentReconnectAllPictFormat(reconnectLossyLevel[PICTFORMAT_STEP]))
|
|
{
|
|
failedStep = PICTFORMAT_STEP;
|
|
goto nxagentReconnectError;
|
|
}
|
|
|
|
if (!nxagentReconnectAllPicture(reconnectLossyLevel[PICTURE_STEP]))
|
|
{
|
|
failedStep = PICTURE_STEP;
|
|
goto nxagentReconnectError;
|
|
}
|
|
}
|
|
|
|
if (!nxagentReconnectAllCursor(reconnectLossyLevel[CURSOR_STEP]))
|
|
{
|
|
failedStep = CURSOR_STEP;
|
|
goto nxagentReconnectError;
|
|
}
|
|
|
|
if (!nxagentSetWindowCursors(reconnectLossyLevel[WINDOW_STEP]))
|
|
{
|
|
failedStep = WINDOW_STEP;
|
|
goto nxagentReconnectError;
|
|
}
|
|
|
|
/* Update remote XKB information */
|
|
nxagentGetRemoteXkbExtension();
|
|
|
|
/* if there's no keyboard definition in the options file
|
|
restore the previous value. */
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "%s: nxagentKeyboard [%s] nxagentOldKeyboard [%s]\n", __func__, nxagentKeyboard, nxagentOldKeyboard);
|
|
#endif
|
|
if (nxagentKeyboard == NULL)
|
|
{
|
|
nxagentKeyboard = nxagentOldKeyboard;
|
|
nxagentOldKeyboard = NULL;
|
|
}
|
|
|
|
/* Reset the keyboard only if we detect any changes. */
|
|
if (nxagentOption(ResetKeyboardAtResume))
|
|
{
|
|
if (nxagentKeyboard == NULL || nxagentOldKeyboard == NULL ||
|
|
strcmp(nxagentKeyboard, nxagentOldKeyboard) != 0 ||
|
|
strcmp(nxagentKeyboard, "query") == 0 ||
|
|
strcmp(nxagentKeyboard, "clone") == 0)
|
|
{
|
|
if (nxagentResetKeyboard() == 0)
|
|
{
|
|
#ifdef WARNING
|
|
if (nxagentVerbose)
|
|
{
|
|
fprintf(stderr, "%s: Failed to reset keyboard device.\n", __func__);
|
|
}
|
|
#endif
|
|
|
|
failedStep = WINDOW_STEP;
|
|
goto nxagentReconnectError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "%s: keyboard unchanged - skipping keyboard reset.\n", __func__);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
nxagentXkbState.Initialized = False;
|
|
|
|
SAFE_free(nxagentOldKeyboard);
|
|
|
|
nxagentInitPointerMap();
|
|
|
|
nxagentDeactivatePointerGrab();
|
|
|
|
nxagentWakeupByReconnect();
|
|
|
|
nxagentFreeGCList();
|
|
|
|
nxagentRedirectDefaultWindows();
|
|
|
|
if (nxagentResizeDesktopAtStartup || nxagentOption(Rootless) || nxagentOption(Xinerama))
|
|
{
|
|
nxagentChangeScreenConfig(0, nxagentOption(RootWidth),
|
|
nxagentOption(RootHeight), True);
|
|
|
|
nxagentResizeDesktopAtStartup = False;
|
|
}
|
|
|
|
nxagentReconnectTrap = False;
|
|
|
|
nxagentExposeArrayIsInitialized = False;
|
|
|
|
if (nxagentSessionState != SESSION_GOING_UP)
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "nxagentReconnectSession: WARNING! Unexpected session state [%s] while reconnecting.\n",
|
|
DECODE_SESSION_STATE(nxagentSessionState));
|
|
#endif
|
|
|
|
goto nxagentReconnectError;
|
|
}
|
|
|
|
/* Re-read keystrokes definitions in case the keystrokes file has
|
|
changed while being suspended */
|
|
nxagentInitKeystrokes(True);
|
|
|
|
#ifdef NX_DEBUG_INPUT
|
|
fprintf(stderr, "Session: Session resumed at '%s' timestamp [%u].\n", GetTimeAsString(), GetTimeInMillis());
|
|
#else
|
|
fprintf(stderr, "Session: Session resumed at '%s'.\n", GetTimeAsString());
|
|
#endif
|
|
saveAgentState("RUNNING");
|
|
|
|
nxagentRemoveSplashWindow();
|
|
|
|
/*
|
|
* We let the proxy flush the link on our behalf after having opened
|
|
* the display. We are now entering again the dispatcher so can
|
|
* flush the link explicitly.
|
|
*/
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentReconnectSession: Setting the NX flush policy to deferred.\n");
|
|
#endif
|
|
|
|
NXSetDisplayPolicy(nxagentDisplay, NXPolicyDeferred);
|
|
|
|
nxagentCleanupBackupDisplayInfo();
|
|
|
|
return 1;
|
|
|
|
nxagentReconnectError:
|
|
|
|
if (failedStep == DISPLAY_STEP)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentReconnectSession: Reconnection failed in display step. Restoring options.\n");
|
|
#endif
|
|
|
|
nxagentRestoreOptions();
|
|
}
|
|
else
|
|
{
|
|
nxagentCleanupBackupDisplayInfo();
|
|
}
|
|
|
|
if (*nxagentGetReconnectError() == '\0')
|
|
{
|
|
#ifdef WARNING
|
|
if (nxagentVerbose)
|
|
{
|
|
fprintf(stderr, "nxagentReconnectSession: WARNING! The reconnect error message is not set. Failed step is [%d].\n",
|
|
failedStep);
|
|
}
|
|
#endif
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentReconnectSession: Reconnection failed due to a display error.\n");
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentReconnectSession: Reconnection failed with reason '%s'\n",
|
|
nxagentGetReconnectError());
|
|
#endif
|
|
}
|
|
|
|
if (NXDisplayError(nxagentDisplay) == 0)
|
|
{
|
|
nxagentUnmapWindows();
|
|
|
|
nxagentFailedReconnectionDialog(nxagentReconnectErrorId, nxagentGetReconnectError());
|
|
}
|
|
#ifdef TEST
|
|
else
|
|
{
|
|
fprintf(stderr, "nxagentReconnectSession: Cannot launch the dialog without a valid display.\n");
|
|
}
|
|
#endif
|
|
|
|
if (failedStep == FONT_STEP)
|
|
{
|
|
*((int *) reconnectLossyLevel[FONT_STEP]) = 1;
|
|
}
|
|
|
|
if (nxagentDisplay == NULL)
|
|
{
|
|
nxagentDisconnectDisplay();
|
|
}
|
|
|
|
SAFE_free(nxagentOldKeyboard);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void nxagentSetReconnectError(int id, char *format, ...)
|
|
{
|
|
static int size = 0;
|
|
|
|
va_list ap;
|
|
int n;
|
|
|
|
if (format == NULL)
|
|
{
|
|
nxagentSetReconnectError(id, "");
|
|
|
|
return;
|
|
}
|
|
|
|
nxagentReconnectErrorId = id;
|
|
|
|
while (1)
|
|
{
|
|
va_start (ap, format);
|
|
|
|
n = vsnprintf(nxagentReconnectErrorMessage, size, format, ap);
|
|
|
|
va_end(ap);
|
|
|
|
if (n > -1 && n < size)
|
|
{
|
|
break;
|
|
}
|
|
if (n > -1)
|
|
{
|
|
size = n + 1;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The vsnprintf() in glibc 2.0.6 would return -1 when the
|
|
* output was truncated. See section NOTES on printf(3).
|
|
*/
|
|
|
|
size = (size ? size * 2 : NXAGENT_RECONNECT_DEFAULT_MESSAGE_SIZE);
|
|
}
|
|
|
|
char *tmp = realloc(nxagentReconnectErrorMessage, size);
|
|
|
|
if (tmp == NULL)
|
|
{
|
|
FatalError("realloc failed");
|
|
}
|
|
else
|
|
{
|
|
nxagentReconnectErrorMessage = tmp;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static char* nxagentGetReconnectError()
|
|
{
|
|
if (nxagentReconnectErrorMessage == NULL)
|
|
{
|
|
nxagentSetReconnectError(nxagentReconnectErrorId, "");
|
|
}
|
|
|
|
return nxagentReconnectErrorMessage;
|
|
}
|
|
|
|
void nxagentHandleConnectionChanges(void)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentHandleConnectionChanges: Called.\n");
|
|
#endif
|
|
|
|
if (nxagentSessionState == SESSION_GOING_DOWN)
|
|
{
|
|
fprintf(stderr, "Session: Suspending session at '%s'.\n", GetTimeAsString());
|
|
saveAgentState("SUSPENDING");
|
|
|
|
nxagentDisconnectSession();
|
|
}
|
|
else if (nxagentSessionState == SESSION_GOING_UP)
|
|
{
|
|
fprintf(stderr, "Session: Resuming session at '%s'.\n", GetTimeAsString());
|
|
saveAgentState("RESUMING");
|
|
|
|
if (nxagentReconnectSession())
|
|
{
|
|
nxagentSessionState = SESSION_UP;
|
|
}
|
|
else
|
|
{
|
|
nxagentSessionState = SESSION_GOING_DOWN;
|
|
|
|
fprintf(stderr, "Session: Display failure detected at '%s'.\n", GetTimeAsString());
|
|
|
|
fprintf(stderr, "Session: Suspending session at '%s'.\n", GetTimeAsString());
|
|
saveAgentState("SUSPENDING");
|
|
|
|
nxagentDisconnectSession();
|
|
}
|
|
}
|
|
}
|