vnchttpconnect.cpp

来自「Web VNC samples delphi」· C++ 代码 · 共 851 行 · 第 1/2 页

CPP
851
字号
//  Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
//  Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
//
//  This file is part of the VNC system.
//
//  The VNC system 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 program 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 program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
//  USA.
//
// TightVNC distribution homepage on the Web: http://www.tightvnc.com/
//
// If the source code for the VNC system is not available from the place 
// whence you received this file, check http://www.uk.research.att.com/vnc or contact
// the authors on vnc@uk.research.att.com for information on obtaining it.


// vncHTTPConnect.cpp

// Implementation of the HTTP server class

#include "stdhdrs.h"
#include "VSocket.h"
#include "vncHTTPConnect.h"
#include "vncServer.h"
#include <omnithread.h>
#include <stdio.h>
#include <string.h>
#include "resource.h"
extern "C" {
#include "libjpeg/jpeglib.h"
}
#define XK_MISCELLANY
#include "keysymdef.h"

// HTTP messages / message formats
const char HTTP_MSG_OK[] = "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n";

const char HTTP_FMT_INDEX[] =
"<HTML>\n"
"  <HEAD><TITLE>TightVNC desktop [%.256s]</TITLE></HEAD>\n"
"  <BODY>\n"
"    <APPLET CODE=VncViewer.class ARCHIVE=VncViewer.jar WIDTH=%d HEIGHT=%d>\n"
"      <PARAM NAME=\"PORT\" VALUE=\"%d\">\n"
"%.1024s"
"    </APPLET><BR>\n"
"    <A HREF=\"http://www.tightvnc.com/\">www.TightVNC.com</A>\n"
"  </BODY>\n"
"</HTML>\n";

const char HTTP_MSG_NOSOCKCONN [] =
"<HTML>\n"
"  <HEAD><TITLE>TightVNC desktop</TITLE></HEAD>\n"
"  <BODY>\n"
"    <H1>Connections Disabled</H1>\n"
"    The requested desktop is not configured to accept incoming connections.\n"
"  </BODY>\n"
"</HTML>\n";

const char HTTP_MSG_BADPARAMS [] =
"<HTML>\n"
"  <HEAD><TITLE>TightVNC desktop</TITLE></HEAD>\n"
"  <BODY>\n"
"    <H1>Bad Parameters</H1>\n"
"    The sequence of applet parameters specified within the URL is invalid.\n"
"  </BODY>\n"
"</HTML>\n";

const char HTTP_MSG_NOSUCHFILE [] =
"HTTP/1.0 404 Not Found\n\n"
"<HTML>\n"
"  <HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
"  <BODY>\n"
"    <H1>Not Found</H1>\n"
"    The requested file could not be found.\n"
"  </BODY>\n"
"</HTML>\n";

// Filename to resource ID mappings for the Java class files:
typedef struct _FileToResourceMap {
	char *filename;
	char *type;
	int resourceID;
} FileMap;

const FileMap filemapping [] = {
	{"/VncViewer.jar", "JavaArchive", IDR_VNCVIEWER_JAR},
	{"/AuthPanel.class", "JavaClass", IDR_AUTHPANEL_CLASS},
	{"/ClipboardFrame.class", "JavaClass", IDR_CLIPBOARDFRAME_CLASS},
	{"/DesCipher.class", "JavaClass", IDR_DESCIPHER_CLASS},
	{"/OptionsFrame.class", "JavaClass", IDR_OPTIONSFRAME_CLASS},
	{"/RfbProto.class", "JavaClass", IDR_RFBPROTO_CLASS},
	{"/VncCanvas.class", "JavaClass", IDR_VNCCANVAS_CLASS},
	{"/VncCanvas2.class", "JavaClass", IDR_VNCCANVAS2_CLASS},
	{"/VncViewer.class", "JavaClass", IDR_VNCVIEWER_CLASS},
	{"/ButtonPanel.class", "JavaClass", IDR_BUTTONPANEL_CLASS},
	{"/RecordingFrame.class", "JavaClass", IDR_RECFRAME_CLASS},
	{"/SessionRecorder.class", "JavaClass", IDR_SESSIONREC_CLASS},
	{"/ReloginPanel.class", "JavaClass", IDR_RELOGINPANEL_CLASS},
	{"/SocketFactory.class", "JavaClass", IDR_SOCKFACTORY_CLASS},
	{"/CapabilityInfo.class", "JavaClass", IDR_CAPINFO_CLASS},
	{"/CapsContainer.class", "JavaClass", IDR_CAPSCONTAINER_CLASS},
	{"/InStream.class", "JavaClass", IDR_INSTREAM_CLASS},
	{"/MemInStream.class", "JavaClass", IDR_MEMINSTREAM_CLASS},
	{"/ZlibInStream.class", "JavaClass", IDR_ZLIBINSTREAM_CLASS},
};
const int filemappingsize		= 19;

#define WINDOW_LIST_MAX 1024
static HWND windowList[WINDOW_LIST_MAX];
static int windowListCount;

BOOL CALLBACK wndEnumProc(HWND hWnd, LPARAM lParam) {
  if (windowListCount >= WINDOW_LIST_MAX) return FALSE;
  windowList[windowListCount++] = hWnd;
  return TRUE;
}

//
// Connection thread -- one per each client connection.
//

class vncHTTPConnectThread : public omni_thread
{
public:
	// Init routine
	virtual BOOL Init(VSocket *socket, vncServer *server, BOOL allow_params);

	// Code to be executed by the thread
	virtual void run(void *arg);

	// Routines to handle HTTP requests
	virtual void DoHTTP(VSocket *socket);
	virtual BOOL ParseParams(const char *request, char *result, int max_bytes);
	BOOL ValidateString(char *str);
	virtual char *ReadLine(VSocket *socket, char delimiter, int max);

protected:
	// Fields used internally
	vncServer	*m_server;
	VSocket		*m_socket;
	BOOL		m_allow_params;
};

// Method implementations
BOOL vncHTTPConnectThread::Init(VSocket *socket, vncServer *server,
								BOOL allow_params)
{
	m_server = server;
	m_socket = socket;
	m_allow_params = allow_params;

	// Start the thread
	start();

	return TRUE;
}

// Code to be executed by the thread
void vncHTTPConnectThread::run(void *arg)
{
	vnclog.Print(LL_INTINFO, VNCLOG("started HTTP client thread\n"));

	// Perform the transaction
	DoHTTP(m_socket);

  m_socket->Close();

	// And close the client
	delete m_socket;

	vnclog.Print(LL_INTINFO, VNCLOG("quitting HTTP client thread\n"));
}

void vncHTTPConnectThread::DoHTTP(VSocket *socket)
{
	char filename[1024];
	char *line;

	// Read in the HTTP header
	if ((line = ReadLine(socket, '\n', 1024)) == NULL)
		return;

	// Scan the header for the filename and free the storage
	int result = sscanf(line, "GET %s HTTP/", filename);
	delete [] line;
	if (result != 1)
		return;

	vnclog.Print(LL_CLIENTS, VNCLOG("file %s requested\n"), filename);

	// Read in the rest of the browser's request data and discard...
	BOOL newline = TRUE;

  char * str, * str2;
	char c;
	for (;;) {
		if (!socket->ReadExact(&c, 1))
			return;
		if (c == '\n') {
			if (newline)
				break;
			newline = TRUE;
		} else {
			if (c >= ' ')
				newline = FALSE;
		}
	}

	vnclog.Print(LL_INTINFO, VNCLOG("HTTP headers skipped\n"));

    if (filename[0] != '/') {
		vnclog.Print(LL_CONNERR, VNCLOG("filename didn't begin with '/'\n"));
		socket->SendExact(HTTP_MSG_NOSUCHFILE, strlen(HTTP_MSG_NOSUCHFILE));
		return;
	}

	static int width=0, height=0, depth=0;
  static vncDesktop * v_desktop = NULL;
  if (!v_desktop) {
    v_desktop = new vncDesktop();
    m_server->m_desktop = v_desktop;
    v_desktop->Init(m_server);
    v_desktop->CheckUpdates();
  }
  if (!width) {
		m_server->GetScreenInfo(width, height, depth);
  }
	// Switch, dependent upon the filename:
	if (filename[1] == '\0' || filename[1] == '?')
	{
		char indexpage[2048];
    int prefwidth = 320;
    
    if (filename[1] == '?' && (line = strstr(filename + 1, "pagewidth="))) {
      line += strlen("pagewidth=");
      sscanf(line, "%d", &prefwidth);
    }

		// Compose the index page
		if (m_server->SockConnected())
		{

			// Get the screen's dimensions

			vnclog.Print(LL_INTINFO, VNCLOG("requested file recognised as index file\n"));

			FILE * index = fopen("res/webvnc.html", "r");
      if (!index) return;


      vnclog.Print(LL_INTINFO, VNCLOG("sending file...\n"));

      str = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\nConnection: close\r\n\r\n";

			// Send the OK message
			if (!socket->SendExact(str, strlen(str)))
				return;

      while (!feof(index)) {
        int len;
        len = fread(indexpage, 1, 2047, index);
        indexpage[len] = 0;
        if (str = strstr(indexpage, "__W__")) {
          _snprintf(str, 5, "%05d", prefwidth);
        }
        socket->SendExact(indexpage, len);
      }
      fclose(index);
		}
		else
		{
		  // Send the OK notification message to the client
		  if (!socket->SendExact(HTTP_MSG_OK, strlen(HTTP_MSG_OK)))
			  return;
			// Send a "sorry, not allowed" page
			sprintf(indexpage, HTTP_MSG_NOSOCKCONN);
		  // Send the page
		  if (socket->SendExact(indexpage, strlen(indexpage)))
			  vnclog.Print(LL_INTINFO, VNCLOG("sent page\n"));

		}

		return;
	}
  
  static unsigned long cookie = 0;
  static const int tileSize = 300;

  str = "HTTP/1.1 200 OK\r\nConnection: close\r\n";
  socket->SendExact(str, strlen(str));
  char gbuf[1024];
  DWORD m_flags;
  static char * imgbuffer = NULL;
  char * scanlinebuffer = NULL;
  rectlist rects;

  int cookiecheck;
  int validated = 0;
  char * parmstart = filename + 1;
  if (sscanf(filename, "/%x/", &cookiecheck) && cookiecheck == cookie) {
    validated = 1;
    parmstart = strchr(filename + 1, '/') + 1;
  }

  switch(parmstart[0]) {
    case 'i':
      //Initialize - log in and give back screen parameters
      //Grab password from URL (url like /ipassword)
      str = parmstart + 1;
      char passbytes[MAXPWLEN];
      memset(passbytes, 0, MAXPWLEN);
      if (strlen(str) > 8) str[8] = 0;
      memcpy(passbytes, str, strlen(str));
      vncEncryptPasswd("", passbytes);
      char passbytes2[MAXPWLEN];
      m_server->GetPassword(passbytes2);
      str2 = vncDecryptPasswd(passbytes2);
      if (!strcmp(str, str2)) {
        str = "Content-type: text/plain\r\n\r\n";
        socket->SendExact(str, strlen(str));
        srand(time(NULL));
        cookie = rand() + (rand() << 8) + (rand() << 16) + (rand() << 24);
        _snprintf(gbuf, 1024, "%d,%d,%d,%08X", width, height, tileSize, cookie);
        socket->SendExact(gbuf, strlen(gbuf));
      }
      else {
        str = "Content-type: text/plain\r\n\r\n0,0,0,00000000";
        socket->SendExact(str, strlen(str));
      }
      break;
    case 'c':
      if (!validated) return;
      //Control request - delay until changed tiles show up!
      str = "Content-type: text/plain\r\n\r\n";
      socket->SendExact(str, strlen(str));
      v_desktop->CheckUpdates();
      time_t lastAMsent;
      lastAMsent = time(NULL);
      while (!(v_desktop->m_last_changed_rgn.Rectangles(rects))) {
        Sleep(100);
        v_desktop->CheckUpdates();
        if (time(NULL) - lastAMsent > 10) {
          _snprintf(gbuf, 1024, "0,0,%d,%d;", width, height);
          return;
        }
      }
      bool * changedArray;
      int tilewidth;
      int tileheight;
      tilewidth = (width + (tileSize - 1)) / tileSize;
      tileheight = (height + (tileSize - 1)) / tileSize;
      while (!rects.empty()) {
        RECT rec = rects.front();
        rec.left -= v_desktop->m_bmrect.left;
        rec.top -= v_desktop->m_bmrect.top;
        rec.right -= v_desktop->m_bmrect.left;
        rec.bottom -= v_desktop->m_bmrect.top;
        _snprintf(gbuf, 1024, "%d,%d,%d,%d;", rec.left, rec.top, rec.right, rec.bottom);
        socket->SendExact(gbuf, strlen(gbuf));
        rects.pop_front();
      }
      break;
    case 'm':
      if (!validated) return;
      //Mouse clickey
      int mbtn, mousex, mousey;
      sscanf(parmstart + 1, "%d,%d,%d", &mbtn, &mousex, &mousey);
      m_flags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
      mousex += v_desktop->m_bmrect.left;
      mousey += v_desktop->m_bmrect.top;
      mousex = mousex * 65536 / v_desktop->m_bmrect.right;
      mousey = mousey * 65536 / v_desktop->m_bmrect.bottom;
      if (mbtn == 0) {
        mouse_event(m_flags, mousex, mousey, 0, NULL);
      }
      if (mbtn >= 1 && mbtn <= 3) {
        if (mbtn == 1) mouse_event(m_flags | MOUSEEVENTF_LEFTDOWN, mousex, mousey, 0, NULL);
        if (mbtn == 2) mouse_event(m_flags | MOUSEEVENTF_MIDDLEDOWN, mousex, mousey, 0, NULL);
        if (mbtn == 3) mouse_event(m_flags | MOUSEEVENTF_RIGHTDOWN, mousex, mousey, 0, NULL);
        Sleep(5);
        if (mbtn == 1) mouse_event(m_flags | MOUSEEVENTF_LEFTUP, mousex, mousey, 0, NULL);
        if (mbtn == 2) mouse_event(m_flags | MOUSEEVENTF_MIDDLEUP, mousex, mousey, 0, NULL);
        if (mbtn == 3) mouse_event(m_flags | MOUSEEVENTF_RIGHTUP, mousex, mousey, 0, NULL);
      }
      if (mbtn == 4) {
        mouse_event(m_flags | MOUSEEVENTF_WHEEL, mousex, mousey, 120, NULL);
      }
      if (mbtn == 5) {
        mouse_event(m_flags | MOUSEEVENTF_WHEEL, mousex, mousey, -120, NULL);
      }
      if (mbtn == 6) {
        mouse_event(m_flags | MOUSEEVENTF_LEFTDOWN, mousex, mousey, 0, NULL);
        Sleep(5);
        mouse_event(m_flags | MOUSEEVENTF_LEFTUP, mousex, mousey, 0, NULL);
        Sleep(5);
        mouse_event(m_flags | MOUSEEVENTF_LEFTDOWN, mousex, mousey, 0, NULL);
        Sleep(5);
        mouse_event(m_flags | MOUSEEVENTF_LEFTUP, mousex, mousey, 0, NULL);
      }
      if (mbtn == 7) {
        mouse_event(m_flags | MOUSEEVENTF_LEFTDOWN, mousex, mousey, 0, NULL);
      }
      if (mbtn == 8) {
        mouse_event(m_flags | MOUSEEVENTF_LEFTUP, mousex, mousey, 0, NULL);
      }
      str = "Content-type: text/html\r\nContent-length: 6\r\n\r\nThanks";
      socket->SendExact(str, strlen(str));
      break;
    case 'f':
      if (!validated) return;
      //Fetch tile
      int fetchx, fetchy, offsetx, offsety;
      FILE * outfile;
      RECT rect;
      jpeg_compress_struct cinfo;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?