📄 rfbserver.c
字号:
/* * rfbserver.c - deal with server-side of the RFB protocol. *//* * Copyright (C) 2000-2006 Constantin Kaplinsky. All Rights Reserved. * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. * Copyright (C) 1999 AT&T Laboratories Cambridge. 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. *//* Use ``#define CORBA'' to enable CORBA control interface */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pwd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include "windowstr.h"#include "rfb.h"#include "input.h"#include "mipointer.h"#include "sprite.h"#ifdef CORBA#include <vncserverctrl.h>#endifchar updateBuf[UPDATE_BUF_SIZE];int ublen;rfbClientPtr rfbClientHead = NULL;rfbClientPtr pointerClient = NULL; /* Mutex for pointer events */Bool rfbAlwaysShared = FALSE;Bool rfbNeverShared = FALSE;Bool rfbDontDisconnect = FALSE;Bool rfbViewOnly = FALSE; /* run server in view only mode - Ehud Karni SW */static rfbClientPtr rfbNewClient(int sock);static void rfbProcessClientProtocolVersion(rfbClientPtr cl);static void rfbProcessClientInitMessage(rfbClientPtr cl);static void rfbSendInteractionCaps(rfbClientPtr cl);static void rfbProcessClientNormalMessage(rfbClientPtr cl);static Bool rfbSendCopyRegion(rfbClientPtr cl, RegionPtr reg, int dx, int dy);static Bool rfbSendLastRectMarker(rfbClientPtr cl);/* * rfbNewClientConnection is called from sockets.c when a new connection * comes in. */voidrfbNewClientConnection(sock) int sock;{ rfbClientPtr cl; cl = rfbNewClient(sock);#ifdef CORBA if (cl != NULL) newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1);#endif}/* * rfbReverseConnection is called by the CORBA stuff to make an outward * connection to a "listening" RFB client. */rfbClientPtrrfbReverseConnection(host, port) char *host; int port;{ int sock; rfbClientPtr cl; if ((sock = rfbConnect(host, port)) < 0) return (rfbClientPtr)NULL; cl = rfbNewClient(sock); if (cl) { cl->reverseConnection = TRUE; } return cl;}/* * rfbNewClient is called when a new connection has been made by whatever * means. */static rfbClientPtrrfbNewClient(sock) int sock;{ rfbProtocolVersionMsg pv; rfbClientPtr cl; BoxRec box; struct sockaddr_in addr; int addrlen = sizeof(struct sockaddr_in); int i; if (rfbClientHead == NULL) { /* no other clients - make sure we don't think any keys are pressed */ KbdReleaseAllKeys(); } else { rfbLog(" (other clients"); for (cl = rfbClientHead; cl; cl = cl->next) { fprintf(stderr," %s",cl->host); } fprintf(stderr,")\n"); } cl = (rfbClientPtr)xalloc(sizeof(rfbClientRec)); cl->sock = sock; getpeername(sock, (struct sockaddr *)&addr, &addrlen); cl->host = strdup(inet_ntoa(addr.sin_addr)); cl->login = NULL; /* Dispatch client input to rfbProcessClientProtocolVersion(). */ cl->state = RFB_PROTOCOL_VERSION; cl->viewOnly = FALSE; cl->reverseConnection = FALSE; cl->readyForSetColourMapEntries = FALSE; cl->useCopyRect = FALSE; cl->preferredEncoding = rfbEncodingRaw; cl->correMaxWidth = 48; cl->correMaxHeight = 48; REGION_INIT(pScreen,&cl->copyRegion,NullBox,0); cl->copyDX = 0; cl->copyDY = 0; box.x1 = box.y1 = 0; box.x2 = rfbScreen.width; box.y2 = rfbScreen.height; REGION_INIT(pScreen,&cl->modifiedRegion,&box,0); REGION_INIT(pScreen,&cl->requestedRegion,NullBox,0); cl->deferredUpdateScheduled = FALSE; cl->deferredUpdateTimer = NULL; cl->format = rfbServerFormat; cl->translateFn = rfbTranslateNone; cl->translateLookupTable = NULL; cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION; cl->tightQualityLevel = -1; for (i = 0; i < 4; i++) cl->zsActive[i] = FALSE; cl->enableCursorShapeUpdates = FALSE; cl->enableCursorPosUpdates = FALSE; cl->enableLastRectEncoding = FALSE; cl->next = rfbClientHead; rfbClientHead = cl; rfbResetStats(cl); cl->compStreamInited = FALSE; cl->compStream.total_in = 0; cl->compStream.total_out = 0; cl->compStream.zalloc = Z_NULL; cl->compStream.zfree = Z_NULL; cl->compStream.opaque = Z_NULL; cl->zlibCompressLevel = 5; sprintf(pv, rfbProtocolVersionFormat, 3, 8); if (WriteExact(sock, pv, sz_rfbProtocolVersionMsg) < 0) { rfbLogPerror("rfbNewClient: write"); rfbCloseSock(sock); return NULL; } return cl;}/* * rfbClientConnectionGone is called from sockets.c just after a connection * has gone away. */voidrfbClientConnectionGone(sock) int sock;{ rfbClientPtr cl, prev; int i; for (prev = NULL, cl = rfbClientHead; cl; prev = cl, cl = cl->next) { if (sock == cl->sock) break; } if (!cl) { rfbLog("rfbClientConnectionGone: unknown socket %d\n",sock); return; } if (cl->login != NULL) { rfbLog("Client %s (%s) gone\n", cl->login, cl->host); free(cl->login); } else { rfbLog("Client %s gone\n", cl->host); } free(cl->host); /* Release the compression state structures if any. */ if ( cl->compStreamInited == TRUE ) { deflateEnd( &(cl->compStream) ); } for (i = 0; i < 4; i++) { if (cl->zsActive[i]) deflateEnd(&cl->zsStruct[i]); } if (pointerClient == cl) pointerClient = NULL;#ifdef CORBA destroyConnection(cl);#endif if (prev) prev->next = cl->next; else rfbClientHead = cl->next; REGION_UNINIT(pScreen,&cl->copyRegion); REGION_UNINIT(pScreen,&cl->modifiedRegion); TimerFree(cl->deferredUpdateTimer); rfbPrintStats(cl); if (cl->translateLookupTable) free(cl->translateLookupTable); xfree(cl);}/* * rfbProcessClientMessage is called when there is data to read from a client. */voidrfbProcessClientMessage(sock) int sock;{ rfbClientPtr cl; for (cl = rfbClientHead; cl; cl = cl->next) { if (sock == cl->sock) break; } if (!cl) { rfbLog("rfbProcessClientMessage: unknown socket %d\n",sock); rfbCloseSock(sock); return; }#ifdef CORBA if (isClosePending(cl)) { rfbLog("Closing connection to client %s\n", cl->host); rfbCloseSock(sock); return; }#endif switch (cl->state) { case RFB_PROTOCOL_VERSION: rfbProcessClientProtocolVersion(cl); break; case RFB_SECURITY_TYPE: /* protocol versions 3.7 and above */ rfbProcessClientSecurityType(cl); break; case RFB_TUNNELING_TYPE: /* protocol versions 3.7t, 3.8t */ rfbProcessClientTunnelingType(cl); break; case RFB_AUTH_TYPE: /* protocol versions 3.7t, 3.8t */ rfbProcessClientAuthType(cl); break; case RFB_AUTHENTICATION: rfbVncAuthProcessResponse(cl); break; case RFB_INITIALISATION: rfbProcessClientInitMessage(cl); break; default: rfbProcessClientNormalMessage(cl); }}/* * rfbProcessClientProtocolVersion is called when the client sends its * protocol version. */static voidrfbProcessClientProtocolVersion(cl) rfbClientPtr cl;{ rfbProtocolVersionMsg pv; int n, major, minor; Bool mismatch; if ((n = ReadExact(cl->sock, pv, sz_rfbProtocolVersionMsg)) <= 0) { if (n == 0) rfbLog("rfbProcessClientProtocolVersion: client gone\n"); else rfbLogPerror("rfbProcessClientProtocolVersion: read"); rfbCloseSock(cl->sock); return; } pv[sz_rfbProtocolVersionMsg] = 0; if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) { rfbLog("rfbProcessClientProtocolVersion: not a valid RFB client\n"); rfbCloseSock(cl->sock); return; } if (major != 3) { rfbLog("Unsupported protocol version %d.%d\n", major, minor); rfbCloseSock(cl->sock); return; } /* Always use one of the three standard versions of the RFB protocol. */ cl->protocol_minor_ver = minor; if (minor > 8) { /* buggy client */ cl->protocol_minor_ver = 8; } else if (minor > 3 && minor < 7) { /* non-standard client */ cl->protocol_minor_ver = 3; } else if (minor < 3) { /* ancient client */ cl->protocol_minor_ver = 3; } if (cl->protocol_minor_ver != minor) { rfbLog("Non-standard protocol version 3.%d, using 3.%d instead\n", minor, cl->protocol_minor_ver); } else { rfbLog("Using protocol version 3.%d\n", cl->protocol_minor_ver); } /* TightVNC protocol extensions are not enabled yet. */ cl->protocol_tightvnc = FALSE; rfbAuthNewClient(cl);}/* * rfbProcessClientInitMessage is called when the client sends its * initialisation message. */static voidrfbProcessClientInitMessage(cl) rfbClientPtr cl;{ rfbClientInitMsg ci; char buf[256]; rfbServerInitMsg *si = (rfbServerInitMsg *)buf; struct passwd *user; int len, n; rfbClientPtr otherCl, nextCl; if ((n = ReadExact(cl->sock, (char *)&ci,sz_rfbClientInitMsg)) <= 0) { if (n == 0) rfbLog("rfbProcessClientInitMessage: client gone\n"); else rfbLogPerror("rfbProcessClientInitMessage: read"); rfbCloseSock(cl->sock); return; } si->framebufferWidth = Swap16IfLE(rfbScreen.width); si->framebufferHeight = Swap16IfLE(rfbScreen.height); si->format = rfbServerFormat; si->format.redMax = Swap16IfLE(si->format.redMax); si->format.greenMax = Swap16IfLE(si->format.greenMax); si->format.blueMax = Swap16IfLE(si->format.blueMax); user = getpwuid(getuid()); if (strlen(desktopName) > 128) /* sanity check on desktop name len */ desktopName[128] = 0; if (user) { sprintf(buf + sz_rfbServerInitMsg, "%s's %s desktop (%s:%s)", user->pw_name, desktopName, rfbThisHost, display); } else { sprintf(buf + sz_rfbServerInitMsg, "%s desktop (%s:%s)", desktopName, rfbThisHost, display); } len = strlen(buf + sz_rfbServerInitMsg); si->nameLength = Swap32IfLE(len); if (WriteExact(cl->sock, buf, sz_rfbServerInitMsg + len) < 0) { rfbLogPerror("rfbProcessClientInitMessage: write"); rfbCloseSock(cl->sock); return; } if (cl->protocol_tightvnc) rfbSendInteractionCaps(cl); /* protocol 3.7t */ /* Dispatch client input to rfbProcessClientNormalMessage(). */ cl->state = RFB_NORMAL; if (!cl->reverseConnection && (rfbNeverShared || (!rfbAlwaysShared && !ci.shared))) { if (rfbDontDisconnect) { for (otherCl = rfbClientHead; otherCl; otherCl = otherCl->next) { if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { rfbLog("-dontdisconnect: Not shared & existing client\n"); rfbLog(" refusing new client %s\n", cl->host); rfbCloseSock(cl->sock); return; } } } else { for (otherCl = rfbClientHead; otherCl; otherCl = nextCl) { nextCl = otherCl->next; if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { rfbLog("Not shared - closing connection to client %s\n", otherCl->host); rfbCloseSock(otherCl->sock); } } } }}/* * rfbSendInteractionCaps is called after sending the server * initialisation message, only if TightVNC protocol extensions were * enabled (protocol versions 3.7t, 3.8t). In this function, we send * the lists of supported protocol messages and encodings. *//* Update these constants on changing capability lists below! */#define N_SMSG_CAPS 0#define N_CMSG_CAPS 0#define N_ENC_CAPS 12voidrfbSendInteractionCaps(cl) rfbClientPtr cl;{ rfbInteractionCapsMsg intr_caps; rfbCapabilityInfo enc_list[N_ENC_CAPS]; int i; /* Fill in the header structure sent prior to capability lists. */ intr_caps.nServerMessageTypes = Swap16IfLE(N_SMSG_CAPS); intr_caps.nClientMessageTypes = Swap16IfLE(N_CMSG_CAPS); intr_caps.nEncodingTypes = Swap16IfLE(N_ENC_CAPS); intr_caps.pad = 0; /* Supported server->client message types. */ /* For future file transfer support: i = 0; SetCapInfo(&smsg_list[i++], rfbFileListData, rfbTightVncVendor); SetCapInfo(&smsg_list[i++], rfbFileDownloadData, rfbTightVncVendor); SetCapInfo(&smsg_list[i++], rfbFileUploadCancel, rfbTightVncVendor); SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed, rfbTightVncVendor); if (i != N_SMSG_CAPS) { rfbLog("rfbSendInteractionCaps: assertion failed, i != N_SMSG_CAPS\n"); rfbCloseSock(cl->sock); return; } */ /* Supported client->server message types. */ /* For future file transfer support: i = 0; SetCapInfo(&cmsg_list[i++], rfbFileListRequest, rfbTightVncVendor); SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest, rfbTightVncVendor); SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest, rfbTightVncVendor); SetCapInfo(&cmsg_list[i++], rfbFileUploadData, rfbTightVncVendor); SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel, rfbTightVncVendor); SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed, rfbTightVncVendor); if (i != N_CMSG_CAPS) { rfbLog("rfbSendInteractionCaps: assertion failed, i != N_CMSG_CAPS\n"); rfbCloseSock(cl->sock); return; } */ /* Encoding types. */ i = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -