?? vncextinit.cc
字號:
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */#include <stdio.h>extern "C" {#define class c_class#define NEED_EVENTS#include "X.h"#include "Xproto.h"#include "misc.h"#include "os.h"#include "dixstruct.h"#include "extnsionst.h"#include "scrnintstr.h"#include "selection.h"#define _VNCEXT_SERVER_#define _VNCEXT_PROTO_#include "vncExt.h"#undef class#undef xalloc}#include <rfb/Configuration.h>#include <rfb/Logger_stdio.h>#include <rfb/LogWriter.h>#include <rfb/util.h>#include <rfb/ServerCore.h>#include <rfb/SSecurityFactoryStandard.h>#include <rdr/HexOutStream.h>#include <rfb/LogWriter.h>#undef max#undef min#include <network/TcpSocket.h>#include "XserverDesktop.h"#include "vncHooks.h"#include "vncExtInit.h"extern "C" { extern void vncExtensionInit(); static void vncResetProc(ExtensionEntry* extEntry); static void vncBlockHandler(pointer data, OSTimePtr t, pointer readmask); static void vncWakeupHandler(pointer data, int nfds, pointer readmask); static void vncClientStateChange(CallbackListPtr*, pointer, pointer); static void SendSelectionChangeEvent(Atom selection); static int ProcVncExtDispatch(ClientPtr client); static int SProcVncExtDispatch(ClientPtr client); extern char *display; extern Selection *CurrentSelections; extern int NumCurrentSelections;}using namespace rfb;static rfb::LogWriter vlog("vncext");static unsigned long vncExtGeneration = 0;static bool initialised = false;static XserverDesktop* desktop[MAXSCREENS] = { 0, };void* vncFbptr[MAXSCREENS] = { 0, };static char* clientCutText = 0;static int clientCutTextLen = 0;static XserverDesktop* queryConnectDesktop = 0;static void* queryConnectId = 0;static int queryConnectTimeout = 0;static OsTimerPtr queryConnectTimer = 0;static struct VncInputSelect* vncInputSelectHead = 0;struct VncInputSelect { VncInputSelect(ClientPtr c, Window w, int m) : client(c), window(w), mask(m) { next = vncInputSelectHead; vncInputSelectHead = this; } ClientPtr client; Window window; int mask; VncInputSelect* next;};static int nPrevSelections = 0;static TimeStamp* prevSelectionTimes = 0;static int vncErrorBase = 0;static int vncEventBase = 0;static char* vncPasswdFile = 0;int vncInetdSock = -1;rfb::AliasParameter rfbauth("rfbauth", "Alias for PasswordFile", &SSecurityFactoryStandard::vncAuthPasswdFile);rfb::StringParameter httpDir("httpd", "Directory containing files to serve via HTTP", "");rfb::IntParameter httpPort("httpPort", "TCP port to listen for HTTP",0);rfb::AliasParameter rfbwait("rfbwait", "Alias for ClientWaitTimeMillis", &rfb::Server::clientWaitTimeMillis);rfb::IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",0);rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11");rfb::BoolParameter localhostOnly("localhost", "Only allow connections from localhost", false);void vncExtensionInit(){ if (vncExtGeneration == serverGeneration) { vlog.error("vncExtensionInit: called twice in same generation?"); return; } vncExtGeneration = serverGeneration; ExtensionEntry* extEntry = AddExtension(VNCEXTNAME, VncExtNumberEvents, VncExtNumberErrors, ProcVncExtDispatch, SProcVncExtDispatch, vncResetProc, StandardMinorOpcode); if (!extEntry) { ErrorF("vncExtInit: AddExtension failed\n"); return; } vncErrorBase = extEntry->errorBase; vncEventBase = extEntry->eventBase; vlog.info("VNC extension running!"); if (!AddCallback(&ClientStateCallback, vncClientStateChange, 0)) { FatalError("AddCallback failed\n"); } try { if (!initialised) { rfb::initStdIOLoggers(); initialised = true; } for (int scr = 0; scr < screenInfo.numScreens; scr++) { if (!desktop[scr]) { network::TcpListener* listener = 0; network::TcpListener* httpListener = 0; if (scr == 0 && vncInetdSock != -1) { if (network::TcpSocket::isSocket(vncInetdSock) && !network::TcpSocket::isConnected(vncInetdSock)) { listener = new network::TcpListener(0, 0, vncInetdSock, true); vlog.info("inetd wait"); } } else { int port = rfbport; if (port == 0) port = 5900 + atoi(display); port += 1000 * scr; listener = new network::TcpListener(port, localhostOnly); vlog.info("Listening for VNC connections on port %d",port); CharArray httpDirStr(httpDir.getData()); if (httpDirStr.buf[0]) { port = httpPort; if (port == 0) port = 5800 + atoi(display); port += 1000 * scr; httpListener = new network::TcpListener(port, localhostOnly); vlog.info("Listening for HTTP connections on port %d",port); } } CharArray desktopNameStr(desktopName.getData()); desktop[scr] = new XserverDesktop(screenInfo.screens[scr], listener, httpListener, desktopNameStr.buf, vncFbptr[scr]); vlog.info("created VNC server for screen %d", scr); if (scr == 0 && vncInetdSock != -1 && !listener) { network::Socket* sock = new network::TcpSocket(vncInetdSock); desktop[scr]->addClient(sock, false); vlog.info("added inetd sock"); } } else { desktop[scr]->serverReset(screenInfo.screens[scr]); } vncHooksInit(screenInfo.screens[scr], desktop[scr]); } RegisterBlockAndWakeupHandlers(vncBlockHandler, vncWakeupHandler, 0); } catch (rdr::Exception& e) { vlog.error("vncExtInit: %s",e.str()); }}static void vncResetProc(ExtensionEntry* extEntry){}//// vncBlockHandler - called just before the X server goes into select(). Call// on to the block handler for each desktop. Then check whether any of the// selections have changed, and if so, notify any interested X clients.//static void vncBlockHandler(pointer data, OSTimePtr timeout, pointer readmask){ fd_set* fds = (fd_set*)readmask; for (int scr = 0; scr < screenInfo.numScreens; scr++) { if (desktop[scr]) { desktop[scr]->blockHandler(fds); } } if (nPrevSelections != NumCurrentSelections) { prevSelectionTimes = (TimeStamp*)xnfrealloc(prevSelectionTimes, NumCurrentSelections * sizeof(TimeStamp)); for (int i = nPrevSelections; i < NumCurrentSelections; i++) { prevSelectionTimes[i].months = 0; prevSelectionTimes[i].milliseconds = 0; } nPrevSelections = NumCurrentSelections; } for (int i = 0; i < NumCurrentSelections; i++) { if (CurrentSelections[i].lastTimeChanged.months != prevSelectionTimes[i].months || CurrentSelections[i].lastTimeChanged.milliseconds != prevSelectionTimes[i].milliseconds) { SendSelectionChangeEvent(CurrentSelections[i].selection); prevSelectionTimes[i] = CurrentSelections[i].lastTimeChanged; } }}static void vncWakeupHandler(pointer data, int nfds, pointer readmask){ fd_set* fds = (fd_set*)readmask; for (int scr = 0; scr < screenInfo.numScreens; scr++) { if (desktop[scr]) { desktop[scr]->wakeupHandler(fds, nfds); } }}static void vncClientStateChange(CallbackListPtr*, pointer, pointer p){ ClientPtr client = ((NewClientInfoRec*)p)->client; if (client->clientState == ClientStateGone) { VncInputSelect** nextPtr = &vncInputSelectHead; for (VncInputSelect* cur = vncInputSelectHead; cur; cur = *nextPtr) { if (cur->client == client) { *nextPtr = cur->next; delete cur; continue; } nextPtr = &cur->next; } }}void vncBell(){ for (int scr = 0; scr < screenInfo.numScreens; scr++) { if (desktop[scr]) { desktop[scr]->bell(); } }}void vncClientGone(int fd){ if (fd == vncInetdSock) { fprintf(stderr,"inetdSock client gone\n"); GiveUp(0); }}void vncClientCutText(const char* str, int len){ delete [] clientCutText; clientCutText = new char[len]; memcpy(clientCutText, str, len); clientCutTextLen = len; xVncExtClientCutTextNotifyEvent ev; ev.type = vncEventBase + VncExtClientCutTextNotify; for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { if (cur->mask & VncExtClientCutTextMask) { ev.sequenceNumber = cur->client->sequence; ev.window = cur->window; ev.time = GetTimeInMillis(); if (cur->client->swapped) { int n; swaps(&ev.sequenceNumber, n); swapl(&ev.window, n); swapl(&ev.time, n); } WriteToClient(cur->client, sizeof(xVncExtClientCutTextNotifyEvent), (char *)&ev); } }}static CARD32 queryConnectTimerCallback(OsTimerPtr timer, CARD32 now, pointer arg){ if (queryConnectTimeout) queryConnectDesktop->approveConnection(queryConnectId, false, "The attempt to prompt the user to accept the connection failed"); // Re-notify clients, causing them to discover that we're done vncQueryConnect(queryConnectDesktop, queryConnectId); return 0;}void vncQueryConnect(XserverDesktop* desktop, void* opaqueId){ // Only one query can be processed at any one time if (queryConnectTimeout && ((desktop != queryConnectDesktop) || (opaqueId != queryConnectId))) { desktop->approveConnection(opaqueId, false, "Another connection is currently being queried."); return; } // Get the query timeout. If it's zero, there is no query. queryConnectTimeout = desktop->getQueryTimeout(opaqueId); queryConnectId = queryConnectTimeout ? opaqueId : 0; queryConnectDesktop = queryConnectTimeout ? desktop : 0; // Notify clients bool notified = false; xVncExtQueryConnectNotifyEvent ev; ev.type = vncEventBase + VncExtQueryConnectNotify; for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { if (cur->mask & VncExtQueryConnectMask) { ev.sequenceNumber = cur->client->sequence; ev.window = cur->window; if (cur->client->swapped) { int n; swaps(&ev.sequenceNumber, n); swapl(&ev.window, n); } WriteToClient(cur->client, sizeof(xVncExtQueryConnectNotifyEvent), (char *)&ev); notified = true; } } // If we're being asked to query a connection (rather than to cancel // a query), and haven't been able to notify clients then reject it. if (queryConnectTimeout && !notified) { queryConnectTimeout = 0; queryConnectId = 0; queryConnectDesktop = 0; desktop->approveConnection(opaqueId, false, "Unable to query the local user to accept the connection."); return; } // Set a timer so that if no-one ever responds, we will eventually // reject the connection // NB: We don't set a timer if sock is null, since that indicates // that pending queries should be cancelled. if (queryConnectDesktop) queryConnectTimer = TimerSet(queryConnectTimer, 0, queryConnectTimeout*2000, queryConnectTimerCallback, 0); else TimerCancel(queryConnectTimer);}static void SendSelectionChangeEvent(Atom selection){ xVncExtSelectionChangeNotifyEvent ev; ev.type = vncEventBase + VncExtSelectionChangeNotify; for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { if (cur->mask & VncExtSelectionChangeMask) { ev.sequenceNumber = cur->client->sequence; ev.window = cur->window; ev.selection = selection; if (cur->client->swapped) { int n; swaps(&ev.sequenceNumber, n); swapl(&ev.window, n); swapl(&ev.selection, n); } WriteToClient(cur->client, sizeof(xVncExtSelectionChangeNotifyEvent), (char *)&ev); } }}static int ProcVncExtSetParam(ClientPtr client){ REQUEST(xVncExtSetParamReq); REQUEST_FIXED_SIZE(xVncExtSetParamReq, stuff->paramLen); CharArray param(stuff->paramLen+1); strncpy(param.buf, (char*)&stuff[1], stuff->paramLen); param.buf[stuff->paramLen] = 0; xVncExtSetParamReply rep; int n; rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; rep.success = rfb::Configuration::setParam(param.buf); if (client->swapped) { swaps(&rep.sequenceNumber, n); swapl(&rep.length, n); } WriteToClient(client, sizeof(xVncExtSetParamReply), (char *)&rep); return (client->noClientException);}static int SProcVncExtSetParam(ClientPtr client){
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -