📄 vnchttpconnect.cpp
字号:
// Copyright (C) 2006 Teamviewer GmbH. All Rights Reserved.
// Copyright (C) 2002 Ultr@VNC Team Members. All Rights Reserved.
// Copyright (C) 2000 Const Kaplinsky. All Rights Reserved.
// Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
// Copyright (C) 2006 Teamviewer GmbH. All Rights Reserved.
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
//
// This file is part of TeamViewer.
//
// TeamViewer 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.
//
// If the source code for TeamViewer is not available from the place
// whence you received this file, check http://www.teamviewer.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 "roGateway.h"
/* Old viewer - TODO: remove
// HTTP messages/message formats
const char HTTP_MSG_OK [] ="HTTP/1.0 200 OK\r\n\r\n";
const char HTTP_FMT_INDEX[] ="<HTML><TITLE>VNC desktop [%.256s]</TITLE>\n"
"<APPLET CODE=vncviewer.class ARCHIVE=vncviewer.jar WIDTH=%d HEIGHT=%d>\n"
"<param name=PORT value=%d></APPLET></HTML>\n";
const char HTTP_MSG_NOSOCKCONN [] ="<HTML><TITLE>Ultr@VNC desktop</TITLE>\n"
"<BODY>The requested desktop is not configured to accept incoming connections.</BODY>\n"
"</HTML>\n";
const char HTTP_MSG_NOSUCHFILE [] ="HTTP/1.0 404 Not found\r\n\r\n"
"<HEAD><TITLE>File Not Found</TITLE></HEAD>\n"
"<BODY><H1>The requested file could not be found</H1></BODY>\n";
*/
// HTTP messages / message formats
const char HTTP_MSG_OK[] = "HTTP/1.0 200 OK\r\n\r\n";
const char HTTP_FMT_INDEX[] =
"<HTML>\n"
" <HEAD><TITLE>TeamViewer Desktop [%.256s] - Get TeamViewer at www.teamviewer.com!</TITLE></HEAD>\n"
" <BODY>\n"
" <SPAN style='position: absolute; top:0px;left:0px'>\n" // sf@2002 - Hopefully supported by all recent browsers... to be checked.
" <APPLET CODEBASE='%s' CODE=VncViewer.class ARCHIVE=VncViewer.jar WIDTH=%d HEIGHT=%d>\r\n"
" <PARAM NAME=PORT VALUE=%d>\r\n"
" <PARAM NAME=TUNNELPORT VALUE=%d>\r\n"
" <PARAM NAME = 'Open New Window' VALUE='Yes'>\n"
" <PARAM NAME=DYNGATE VALUE='%s'>\r\n"
" <PARAM NAME=DYNGATEID VALUE='%d'>\r\n" // This line may NOT be modified, data is analysed by DynGate!
" <PARAM NAME=ENCODING VALUE=Tight>\r\n"
" <PARAM name='Show controls' value=No>\r\n"
" <PARAM name='View Only' value=Yes>\r\n"
" <param name='Cursor shape updates' value=Disable>\r\n" // Display Mouse Cursor
" </APPLET>"
" </SPAN>\n"
" </BODY>\n"
"</HTML>\n";
const char HTTP_MSG_NOSOCKCONN [] =
"<HTML>\n"
" <HEAD><TITLE>TeamViewer 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>TeamViewer 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;
/* Old viewer - TODO: remove
const FileMap filemapping [] ={
{"/vncviewer.jar", "JavaArchive", IDR_VNCVIEWER_JAR},
{"/authenticationPanel.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},
{"/vncviewer.class", "JavaClass", IDR_VNCVIEWER_CLASS},
{"/animatedMemoryImageSource.class", "JavaClass", IDR_ANIMMEMIMAGESRC_CLASS}
};
const int filemappingsize = 9;
*/
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},
{"/VncViewer.class", "JavaClass", IDR_VNCVIEWER_CLASS},
{"/ButtonPanel.class", "JavaClass", IDR_BUTTONPANEL_CLASS},
{"/RecordingFrame.class", "JavaClass", IDR_RECFRAME_CLASS},
{"/SessionRecorder.class", "JavaClass", IDR_SESSIONREC_CLASS},
{"/FTPFrame.class", "JavaClass", IDR_FTPFRAME_CLASS},
{"/TunnelReader.class", "JavaClass", IDR_TUNNELREADER_CLASS},
{"/TunnelWriter.class", "JavaClass", IDR_TUNNELWRITER_CLASS}
};
const int filemappingsize = 11;
#ifdef HTTP_SAMEPORT
// Added for HTTP-via-RFB. Allows us to handle an HTTP transaction
// without starting a separate thread.
class vncHTTPConnectThreadHelper {
public:
// Routines to handle HTTP requests
void Init(vncServer* svr) { m_server = svr; }
void DoHTTP(VSocket *socket);
char *ReadLine(VSocket *socket, char delimiter, int max);
protected:
vncServer *m_server;
};
#endif
#ifdef HTTP_SAMEPORT
class vncHTTPConnectThread : public omni_thread, public vncHTTPConnectThreadHelper
#else
// The function for the spawned thread to run
class vncHTTPConnectThread : public omni_thread
#endif
{
public:
// Init routine
virtual BOOL Init(VSocket *socket, vncServer *server);
// Code to be executed by the thread
virtual void *run_undetached(void * arg);
#ifndef HTTP_SAMEPORT
// Routines to handle HTTP requests
virtual void DoHTTP(VSocket *socket);
virtual char *ReadLine(VSocket *socket, char delimiter, int max);
#endif
// Fields used internally
BOOL m_shutdown;
protected:
#ifndef HTTP_SAMEPORT
vncServer *m_server;
#endif
VSocket *m_socket;
};
#ifdef HTTP_SAMEPORT
// Added for HTTP-via-RFB. This function is called when a connection is
// accepted on the RFB port. If the client sends an HTTP request we
// handle it here and return TRUE. Otherwise we return
// FALSE and the caller continues with the RFB handshake.
VBool maybeHandleHTTPRequest(VSocket* sock,vncServer* svr)
{
if (!sock->ReadSelect(2000)) return false;
// Client is sending data. Create a vncHTTPConnectThread to
// handle it.
vncHTTPConnectThreadHelper http;
http.Init(svr);
http.DoHTTP(sock);
sock->Shutdown();
sock->Close();
delete sock;
return true;
}
#endif
// Method implementations
BOOL vncHTTPConnectThread::Init(VSocket *socket, vncServer *server)
{
// Save the server pointer
m_server = server;
// Save the socket pointer
m_socket = socket;
// Start the thread
m_shutdown = FALSE;
start_undetached();
return TRUE;
}
// Code to be executed by the thread
void *vncHTTPConnectThread::run_undetached(void * arg)
{
vnclog.Print(LL_INTINFO, VNCLOG("started HTTP server thread"));
// Go into a loop, listening for connections on the given socket
while (!m_shutdown)
{
// Accept an incoming connection
VSocket *new_socket = m_socket->Accept();
if (new_socket == NULL)
break;
if (m_shutdown)
{
delete new_socket;
break;
}
vnclog.Print(LL_CLIENTS, VNCLOG("HTTP client connected"));
Sleep(250);
// Successful accept - perform the transaction
new_socket->SetTimeout(15000); //ms
DoHTTP(new_socket);
Sleep(500);
// And close the client
new_socket->Shutdown();
new_socket->Close();
delete new_socket;
}
vnclog.Print(LL_INTINFO, VNCLOG("quitting HTTP server thread"));
return NULL;
}
#ifdef HTTP_SAMEPORT
void vncHTTPConnectThreadHelper::DoHTTP(VSocket *socket)
#else
void vncHTTPConnectThread::DoHTTP(VSocket *socket)
#endif
{
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 ", (char*)&filename);
delete [] line;
if ((result == 0) || (result == EOF))
return;
vnclog.Print(LL_CLIENTS, VNCLOG("file %s requested"), filename);
// Read in the rest of the browser's request data and discard...
BOOL emptyline=TRUE;
for (;;)
{
char c;
if (!socket->ReadExactHTTP(&c, 1))
return;
if (c=='\n')
{
if (emptyline)
break;
emptyline = TRUE;
}
else
if (c >= ' ')
{
emptyline = FALSE;
}
}
vnclog.Print(LL_INTINFO, VNCLOG("parameters read"));
if (filename[0] != '/')
{
vnclog.Print(LL_CONNERR, VNCLOG("filename didn't begin with '/'"));
socket->SendExactHTTP(HTTP_MSG_NOSUCHFILE, strlen(HTTP_MSG_NOSUCHFILE));
return;
}
// Switch, dependent upon the filename:
if (strcmp(filename, "/") == 0)
{
char indexpage[2048 + MAX_COMPUTERNAME_LENGTH + 1];
vnclog.Print(LL_CLIENTS, VNCLOG("sending main page"));
// Send the OK notification message to the client
if (!socket->SendExactHTTP(HTTP_MSG_OK, strlen(HTTP_MSG_OK)))
return;
// Compose the index page
if (m_server->SockConnected())
{
int width, height, depth;
// Get the screen's dimensions
m_server->GetScreenInfo(width, height, depth);
// Get the name of this desktop
char desktopname[MAX_COMPUTERNAME_LENGTH+1];
DWORD desktopnamelen = MAX_COMPUTERNAME_LENGTH + 1;
if (GetComputerName(desktopname, &desktopnamelen))
{
// Make the name lowercase
for (int x=0; x<strlen(desktopname); x++)
{
desktopname[x] = tolower(desktopname[x]);
}
}
else
{
strcpy(desktopname, "TeamViewer");
}
// Is DynGate installed and active?
CroGateway *rgw = CroGateway::Instance();
if (rgw->GatewayInstalled() && rgw->GatewayRunning())
{
char codebase[50];
sprintf(codebase,"/tv/java/%d", rgw->NumericID());
// Send the java applet page for non-DynGate use
// Restricted to http-port
sprintf(indexpage, HTTP_FMT_INDEX,
desktopname, codebase, width, height+32,
-1, 80, "Yes", rgw->NumericID()
);
}
else
{
// Send the java applet page for non-DynGate use
sprintf(indexpage, HTTP_FMT_INDEX,
desktopname, "/", width, height+32,
m_server->GetPort(), -1, "No", 0
);
}
}
else
{
// Send a "sorry, not allowed" page
sprintf(indexpage, HTTP_MSG_NOSOCKCONN);
}
// Send the page
if (socket->SendExactHTTP(indexpage, strlen(indexpage)))
vnclog.Print(LL_INTINFO, VNCLOG("sent page"));
return;
}
// File requested was not the index so check the mappings
// list for a different file.
// Now search the mappings for the desired file
for (int x=0; x < filemappingsize; x++)
{
if (strcmp(filename, filemapping[x].filename) == 0)
{
HRSRC resource;
HGLOBAL resourcehan;
char *resourceptr;
int resourcesize;
vnclog.Print(LL_INTINFO, VNCLOG("requested file recognised"));
// Find the resource here
resource = FindResource(NULL,
MAKEINTRESOURCE(filemapping[x].resourceID),
filemapping[x].type
);
if (resource == NULL)
return;
// Get its size
resourcesize = SizeofResource(NULL, resource);
// Load the resource
resourcehan = LoadResource(NULL, resource);
if (resourcehan == NULL)
return;
// Lock the resource
resourceptr = (char *)LockResource(resourcehan);
if (resourceptr == NULL)
return;
vnclog.Print(LL_INTINFO, VNCLOG("sending file..."));
// Send the OK message
if (!socket->SendExactHTTP(HTTP_MSG_OK, strlen(HTTP_MSG_OK)))
return;
// Now send the entirety of the data to the client
if (!socket->SendExactHTTP(resourceptr, resourcesize))
return;
vnclog.Print(LL_INTINFO, VNCLOG("file successfully sent"));
return;
}
}
// Send the NoSuchFile notification message to the client
if (!socket->SendExactHTTP(HTTP_MSG_NOSUCHFILE, strlen(HTTP_MSG_NOSUCHFILE)))
return;
}
#ifdef HTTP_SAMEPORT
char *vncHTTPConnectThreadHelper::ReadLine(VSocket *socket, char delimiter, int max)
#else
char *vncHTTPConnectThread::ReadLine(VSocket *socket, char delimiter, int max)
#endif
{
// Allocate the maximum required buffer
char *buffer = new char[max+1];
int buffpos = 0;
// Read in data until a delimiter is read
for (;;)
{
char c;
if (!socket->ReadExactHTTP(&c, 1))
{
delete [] buffer;
return NULL;
}
if (c == delimiter)
{
buffer[buffpos] = 0;
return buffer;
}
buffer[buffpos] = c;
buffpos++;
if (buffpos == (max-1))
{
buffer[buffpos] = 0;
return buffer;
}
}
}
// The vncSockConnect class implementation
vncHTTPConnect::vncHTTPConnect()
{
m_thread = NULL;
}
vncHTTPConnect::~vncHTTPConnect()
{
m_socket.Shutdown();
// Join with our lovely thread
if (m_thread != NULL)
{
// *** This is a hack to force the listen thread out of the accept call,
// because Winsock accept semantics are broken.
((vncHTTPConnectThread *)m_thread)->m_shutdown = TRUE;
VSocket socket;
socket.Create();
//socket.Bind(0);
socket.Connect("localhost", m_port);
socket.Close();
void *returnval;
m_thread->join(&returnval);
m_thread = NULL;
m_socket.Close();
}
}
BOOL vncHTTPConnect::Init(vncServer *server, UINT port)
{
// Save the port id
m_port = port;
// Create the listening socket
if (!m_socket.Create())
return FALSE;
// Bind it
if (!m_socket.Bind(m_port, server->LoopbackOnly()))
return FALSE;
// Set it to listen
if (!m_socket.Listen())
return FALSE;
// Create the new thread
m_thread = new vncHTTPConnectThread;
if (m_thread == NULL)
return FALSE;
// And start it running
return ((vncHTTPConnectThread *)m_thread)->Init(&m_socket, server);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -