void addClntThrdCD::run( void * ) { HAB thab = WinInitialize( 0 ); HMQ hmq = WinCreateMsgQueue( thab , 0 ); // Attempt to create a new socket VSocket *tmpsock; tmpsock = new VSocket; if (tmpsock!=NULL) { // Connect out to the specified host on the VNCviewer listen port // To be really good, we should allow a display number here but // for now we'll just assume we're connecting to display zero tmpsock->Create(); if (tmpsock->Connect(m_host, m_port)) { // Add the new client to this server m_server->AddClient(tmpsock, TRUE, TRUE); } else { // Print up an error message WinMessageBox( HWND_DESKTOP , HWND_DESKTOP , (PSZ)"Failed to connect to listening VNC viewer", (PSZ)"Outgoing Connection", 10001 , MB_ICONEXCLAMATION | MB_OK ); delete tmpsock; } } WinDestroyMsgQueue( hmq ); WinTerminate( thab ); }
void vncDesktopThread::PollWindow(rfb::Region2D &rgn, HWND hwnd) { // Are we set to low-load polling? if (m_server->PollOnEventOnly()) { // Yes, so only poll if the remote user has done something if (!m_server->RemoteEventReceived()) { return; } } // Does the client want us to poll only console windows? if (m_desktop->m_server->PollConsoleOnly()) { char classname[20]; // Yes, so check that this is a console window... if (GetClassName(hwnd, classname, sizeof(classname))) { if ((strcmp(classname, "tty") != 0) && (strcmp(classname, "ConsoleWindowClass") != 0)) { return; } } } RECT rect; // Get the rectangle if (GetWindowRect(hwnd, &rect)) { rfb::Rect wrect = rfb::Rect(rect).intersect(m_desktop->m_bmrect); if (!wrect.is_empty()) { rgn = rgn.union_(rfb::Region2D(wrect)); } } }
// Code to be executed by the thread void *vncSockConnectThread::run_undetached(void * arg) { vnclog.Print(LL_STATE, VNCLOG("started socket connection thread\n")); // Go into a loop, listening for connections on the given socket while (!m_shutdown) { // Accept an incoming connection VSocket *new_socket; if (!m_socket->TryAccept(&new_socket, 100)) break; if (new_socket != NULL) { vnclog.Print(LL_CLIENTS, VNCLOG("accepted connection from %s\n"), new_socket->GetPeerName()); // Successful accept - start the client unauthenticated m_server->AddClient(new_socket, FALSE, FALSE); } } vnclog.Print(LL_STATE, VNCLOG("quitting socket connection thread\n")); return NULL; }
void vncClientThread::run(void *arg) { // All this thread does is go into a socket-recieve loop, // waiting for stuff on the given socket // IMPORTANT : ALWAYS call RemoveClient on the server before quitting // this thread. vnclog.Print(LL_CLIENTS, VNCLOG("client connected : %s (%hd)\n"), m_client->GetClientName(), m_client->GetClientId()); // Save the handle to the thread's original desktop HDESK home_desktop = GetThreadDesktop(GetCurrentThreadId()); // To avoid people connecting and then halting the connection, set a timeout if (!m_socket->SetTimeout(30000)) vnclog.Print(LL_INTERR, VNCLOG("failed to set socket timeout(%d)\n"), GetLastError()); // Initially blacklist the client so that excess connections from it get dropped m_server->AddAuthHostsBlacklist(m_client->GetClientName()); // LOCK INITIAL SETUP // All clients have the m_protocol_ready flag set to FALSE initially, to prevent // updates and suchlike interfering with the initial protocol negotiations. // GET PROTOCOL VERSION if (!InitVersion()) { m_server->RemoveClient(m_client->GetClientId()); return; } vnclog.Print(LL_INTINFO, VNCLOG("negotiated version\n")); // AUTHENTICATE LINK if (!InitAuthenticate()) { m_server->RemoveClient(m_client->GetClientId()); return; } // Authenticated OK - remove from blacklist and remove timeout m_server->RemAuthHostsBlacklist(m_client->GetClientName()); m_socket->SetTimeout(m_server->AutoIdleDisconnectTimeout()*1000); vnclog.Print(LL_INTINFO, VNCLOG("authenticated connection\n")); // INIT PIXEL FORMAT // Get the screen format m_client->m_fullscreen = m_client->m_encodemgr.GetSize(); // 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, "WinVNC"); } // Send the server format message to the client rfbServerInitMsg server_ini; server_ini.format = m_client->m_encodemgr.m_buffer->GetLocalFormat(); // Endian swaps server_ini.framebufferWidth = Swap16IfLE(m_client->m_fullscreen.br.x); server_ini.framebufferHeight = Swap16IfLE(m_client->m_fullscreen.br.y); server_ini.format.redMax = Swap16IfLE(server_ini.format.redMax); server_ini.format.greenMax = Swap16IfLE(server_ini.format.greenMax); server_ini.format.blueMax = Swap16IfLE(server_ini.format.blueMax); server_ini.nameLength = Swap32IfLE(strlen(desktopname)); if (!m_socket->SendExact((char *)&server_ini, sizeof(server_ini))) { m_server->RemoveClient(m_client->GetClientId()); return; } if (!m_socket->SendExact(desktopname, strlen(desktopname))) { m_server->RemoveClient(m_client->GetClientId()); return; } vnclog.Print(LL_INTINFO, VNCLOG("sent pixel format to client\n")); // UNLOCK INITIAL SETUP // Initial negotiation is complete, so set the protocol ready flag m_client->EnableProtocol(); // Add a fullscreen update to the client's update list { omni_mutex_lock l(m_client->GetUpdateLock()); m_client->m_update_tracker.add_changed(m_client->m_fullscreen); } // Clear the CapsLock and NumLock keys if (m_client->m_keyboardenabled) { ClearKeyState(VK_CAPITAL); // *** JNW - removed because people complain it's wrong //ClearKeyState(VK_NUMLOCK); ClearKeyState(VK_SCROLL); } // MAIN LOOP // Set the input thread to a high priority set_priority(omni_thread::PRIORITY_HIGH); BOOL connected = TRUE; while (connected) { rfbClientToServerMsg msg; // Ensure that we're running in the correct desktop if (!vncService::InputDesktopSelected()) if (!vncService::SelectDesktop(NULL)) break; // Try to read a message ID if (!m_socket->ReadExact((char *)&msg.type, sizeof(msg.type))) { connected = FALSE; break; } // What to do is determined by the message id switch(msg.type) { case rfbSetPixelFormat: // Read the rest of the message: if (!m_socket->ReadExact(((char *) &msg)+1, sz_rfbSetPixelFormatMsg-1)) { connected = FALSE; break; } // Swap the relevant bits. msg.spf.format.redMax = Swap16IfLE(msg.spf.format.redMax); msg.spf.format.greenMax = Swap16IfLE(msg.spf.format.greenMax); msg.spf.format.blueMax = Swap16IfLE(msg.spf.format.blueMax); // Prevent updates while the pixel format is changed m_client->DisableProtocol(); // Tell the buffer object of the change if (!m_client->m_encodemgr.SetClientFormat(msg.spf.format)) { vnclog.Print(LL_CONNERR, VNCLOG("remote pixel format invalid\n")); connected = FALSE; } // Set the palette-changed flag, just in case... m_client->m_palettechanged = TRUE; // Re-enable updates m_client->EnableProtocol(); break; case rfbSetEncodings: // Read the rest of the message: if (!m_socket->ReadExact(((char *) &msg)+1, sz_rfbSetEncodingsMsg-1)) { connected = FALSE; break; } // Prevent updates while the encoder is changed m_client->DisableProtocol(); // Read in the preferred encodings msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings); { int x; BOOL encoding_set = FALSE; // By default, don't use copyrect! m_client->m_update_tracker.enable_copyrect(false); for (x=0; x<msg.se.nEncodings; x++) { CARD32 encoding; // Read an encoding in if (!m_socket->ReadExact((char *)&encoding, sizeof(encoding))) { connected = FALSE; break; } // Is this the CopyRect encoding (a special case)? if (Swap32IfLE(encoding) == rfbEncodingCopyRect) { m_client->m_update_tracker.enable_copyrect(true); continue; } // Have we already found a suitable encoding? if (!encoding_set) { // No, so try the buffer to see if this encoding will work... if (m_client->m_encodemgr.SetEncoding(Swap32IfLE(encoding))) encoding_set = TRUE; } } // If no encoding worked then default to RAW! if (!encoding_set) { vnclog.Print(LL_INTINFO, VNCLOG("defaulting to raw encoder\n")); if (!m_client->m_encodemgr.SetEncoding(Swap32IfLE(rfbEncodingRaw))) { vnclog.Print(LL_INTERR, VNCLOG("failed to select raw encoder!\n")); connected = FALSE; } } } // Re-enable updates m_client->EnableProtocol(); break; case rfbFramebufferUpdateRequest: // Read the rest of the message: if (!m_socket->ReadExact(((char *) &msg)+1, sz_rfbFramebufferUpdateRequestMsg-1)) { connected = FALSE; break; } { rfb::Rect update; // Get the specified rectangle as the region to send updates for. update.tl.x = Swap16IfLE(msg.fur.x); update.tl.y = Swap16IfLE(msg.fur.y); update.br.x = update.tl.x + Swap16IfLE(msg.fur.w); update.br.y = update.tl.y + Swap16IfLE(msg.fur.h); rfb::Region2D update_rgn = update; if (update_rgn.is_empty()) { vnclog.Print(LL_INTERR, VNCLOG("FATAL! client update region is empty!\n")); connected = FALSE; break; } { omni_mutex_lock l(m_client->GetUpdateLock()); // Add the requested area to the incremental update cliprect m_client->m_incr_rgn = m_client->m_incr_rgn.union_(update_rgn); // Is this request for a full update? if (!msg.fur.incremental) { // Yes, so add the region to the update tracker m_client->m_update_tracker.add_changed(update_rgn); // Tell the desktop grabber to fetch the region's latest state m_client->m_encodemgr.m_buffer->m_desktop->QueueRect(update); } // Kick the update thread (and create it if not there already) m_client->TriggerUpdateThread(); } } break; case rfbKeyEvent: // Read the rest of the message: if (m_socket->ReadExact(((char *) &msg)+1, sz_rfbKeyEventMsg-1)) { if (m_client->m_keyboardenabled) { msg.ke.key = Swap32IfLE(msg.ke.key); // Get the keymapper to do the work vncKeymap::keyEvent(msg.ke.key, msg.ke.down); m_client->m_remoteevent = TRUE; } } break; case rfbPointerEvent: // Read the rest of the message: if (m_socket->ReadExact(((char *) &msg)+1, sz_rfbPointerEventMsg-1)) { if (m_client->m_pointerenabled) { // Convert the coords to Big Endian msg.pe.x = Swap16IfLE(msg.pe.x); msg.pe.y = Swap16IfLE(msg.pe.y); // Work out the flags for this event DWORD flags = MOUSEEVENTF_ABSOLUTE; long data = 0; if (msg.pe.x != m_client->m_ptrevent.x || msg.pe.y != m_client->m_ptrevent.y) flags |= MOUSEEVENTF_MOVE; if ( (msg.pe.buttonMask & rfbButton1Mask) != (m_client->m_ptrevent.buttonMask & rfbButton1Mask) ) { if (GetSystemMetrics(SM_SWAPBUTTON)) flags |= (msg.pe.buttonMask & rfbButton1Mask) ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; else flags |= (msg.pe.buttonMask & rfbButton1Mask) ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; } if ( (msg.pe.buttonMask & rfbButton2Mask) != (m_client->m_ptrevent.buttonMask & rfbButton2Mask) ) { flags |= (msg.pe.buttonMask & rfbButton2Mask) ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP; } if ( (msg.pe.buttonMask & rfbButton3Mask) != (m_client->m_ptrevent.buttonMask & rfbButton3Mask) ) { if (GetSystemMetrics(SM_SWAPBUTTON)) flags |= (msg.pe.buttonMask & rfbButton3Mask) ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; else flags |= (msg.pe.buttonMask & rfbButton3Mask) ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; } // Mouse wheel support if (msg.pe.buttonMask & rfbWheelUpMask) { flags |= MOUSEEVENTF_WHEEL; data = WHEEL_DELTA; } if (msg.pe.buttonMask & rfbWheelDownMask) { flags |= MOUSEEVENTF_WHEEL; data = -WHEEL_DELTA; } // Generate coordinate values unsigned long x = (msg.pe.x * 65535) / (m_client->m_fullscreen.br.x); unsigned long y = (msg.pe.y * 65535) / (m_client->m_fullscreen.br.y); // Do the pointer event ::mouse_event(flags, (DWORD) x, (DWORD) y, data, 0); // Save the old position m_client->m_ptrevent = msg.pe; // Flag that a remote event occurred m_client->m_remoteevent = TRUE; // Tell the desktop hook system to grab the screen... m_client->m_encodemgr.m_buffer->m_desktop->TriggerUpdate(); } } break; case rfbClientCutText: // Read the rest of the message: if (m_socket->ReadExact(((char *) &msg)+1, sz_rfbClientCutTextMsg-1)) { // Allocate storage for the text const UINT length = Swap32IfLE(msg.cct.length); char *text = new char [length+1]; if (text == NULL) break; text[length] = 0; // Read in the text if (!m_socket->ReadExact(text, length)) { delete [] text; break; } // Get the server to update the local clipboard m_server->UpdateLocalClipText(text); // Free the clip text we read delete [] text; } break; default: // Unknown message, so fail! connected = FALSE; } } // Move into the thread's original desktop vncService::SelectHDESK(home_desktop); // Quit this thread. This will automatically delete the thread and the // associated client. vnclog.Print(LL_CLIENTS, VNCLOG("client disconnected : %s (%hd)\n"), m_client->GetClientName(), m_client->GetClientId()); // Disable the protocol to ensure that the update thread // is not accessing the desktop and buffer objects m_client->DisableProtocol(); // Finally, it's safe to kill the update thread here if (m_client->m_updatethread) { m_client->m_updatethread->Kill(); m_client->m_updatethread->join(NULL); } // Remove the client from the server // This may result in the desktop and buffer being destroyed // It also guarantees that the client will not be passed further // updates m_server->RemoveClient(m_client->GetClientId()); }
BOOL vncClientThread::InitAuthenticate() { // Retrieve the local password char password[MAXPWLEN]; m_server->GetPassword(password); vncPasswd::ToText plain(password); // Verify the peer host name against the AuthHosts string vncServer::AcceptQueryReject verified; if (m_auth) { verified = vncServer::aqrAccept; } else { verified = m_server->VerifyHost(m_socket->GetPeerName()); } // If necessary, query the connection with a timed dialog if (verified == vncServer::aqrQuery) { vncAcceptDialog *acceptDlg = new vncAcceptDialog(m_server->QueryTimeout(), m_socket->GetPeerName()); if ((acceptDlg == 0) || (!(acceptDlg->DoDialog()))) verified = vncServer::aqrReject; } if (verified == vncServer::aqrReject) { CARD32 auth_val = Swap32IfLE(rfbConnFailed); char *errmsg = "Your connection has been rejected."; CARD32 errlen = Swap32IfLE(strlen(errmsg)); if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val))) return FALSE; if (!m_socket->SendExact((char *)&errlen, sizeof(errlen))) return FALSE; m_socket->SendExact(errmsg, strlen(errmsg)); return FALSE; } // By default we disallow passwordless workstations! if ((strlen(plain) == 0) && m_server->AuthRequired()) { vnclog.Print(LL_CONNERR, VNCLOG("no password specified for server - client rejected\n")); // Send an error message to the client CARD32 auth_val = Swap32IfLE(rfbConnFailed); char *errmsg = "This server does not have a valid password enabled. " "Until a password is set, incoming connections cannot be accepted."; CARD32 errlen = Swap32IfLE(strlen(errmsg)); if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val))) return FALSE; if (!m_socket->SendExact((char *)&errlen, sizeof(errlen))) return FALSE; m_socket->SendExact(errmsg, strlen(errmsg)); return FALSE; } // By default we filter out local loop connections, because they're pointless if (!m_server->LoopbackOk()) { char *localname = strdup(m_socket->GetSockName()); char *remotename = strdup(m_socket->GetPeerName()); // Check that the local & remote names are different! if ((localname != NULL) && (remotename != NULL)) { BOOL ok = strcmp(localname, remotename) != 0; if (localname != NULL) free(localname); if (remotename != NULL) free(remotename); if (!ok) { vnclog.Print(LL_CONNERR, VNCLOG("loopback connection attempted - client rejected\n")); // Send an error message to the client CARD32 auth_val = Swap32IfLE(rfbConnFailed); char *errmsg = "Local loop-back connections are disabled."; CARD32 errlen = Swap32IfLE(strlen(errmsg)); if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val))) return FALSE; if (!m_socket->SendExact((char *)&errlen, sizeof(errlen))) return FALSE; m_socket->SendExact(errmsg, strlen(errmsg)); return FALSE; } } } // Authenticate the connection, if required if (m_auth || (strlen(plain) == 0)) { // Send no-auth-required message CARD32 auth_val = Swap32IfLE(rfbNoAuth); if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val))) return FALSE; } else { // Send auth-required message CARD32 auth_val = Swap32IfLE(rfbVncAuth); if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val))) return FALSE; BOOL auth_ok = TRUE; { // Now create a 16-byte challenge char challenge[16]; vncRandomBytes((BYTE *)&challenge); // Send the challenge to the client if (!m_socket->SendExact(challenge, sizeof(challenge))) return FALSE; // Read the response char response[16]; if (!m_socket->ReadExact(response, sizeof(response)))\ return FALSE; // Encrypt the challenge bytes vncEncryptBytes((BYTE *)&challenge, plain); // Compare them to the response for (int i=0; i<sizeof(challenge); i++) { if (challenge[i] != response[i]) { auth_ok = FALSE; break; } } } // Did the authentication work? CARD32 authmsg; if (!auth_ok) { vnclog.Print(LL_CONNERR, VNCLOG("authentication failed\n")); authmsg = Swap32IfLE(rfbVncAuthFailed); m_socket->SendExact((char *)&authmsg, sizeof(authmsg)); return FALSE; } else { // Tell the client we're ok authmsg = Swap32IfLE(rfbVncAuthOK); if (!m_socket->SendExact((char *)&authmsg, sizeof(authmsg))) return FALSE; } } // Read the client's initialisation message rfbClientInitMsg client_ini; if (!m_socket->ReadExact((char *)&client_ini, sz_rfbClientInitMsg)) return FALSE; // If the client wishes to have exclusive access then remove other clients if (!client_ini.shared && !m_shared) { // Which client takes priority, existing or incoming? if (m_server->ConnectPriority() < 1) { // Incoming vnclog.Print(LL_INTINFO, VNCLOG("non-shared connection - disconnecting old clients\n")); m_server->KillAuthClients(); } else if (m_server->ConnectPriority() > 1) { // Existing if (m_server->AuthClientCount() > 0) { vnclog.Print(LL_CLIENTS, VNCLOG("connections already exist - client rejected\n")); return FALSE; } } } // Tell the server that this client is ok return m_server->Authenticated(m_client->GetClientId()); }
void * vncDesktopThread::run_undetached(void *arg) { // Save the thread's "home" desktop, under NT (no effect under 9x) HDESK home_desktop = GetThreadDesktop(GetCurrentThreadId()); // Attempt to initialise and return success or failure if (!m_desktop->Startup()) { vncService::SelectHDESK(home_desktop); ReturnVal(FALSE); return NULL; } // Grab the initial display contents // *** m_desktop->m_buffer.GrabRegion(m_desktop->m_bmrect); // *** m_desktop->m_buffer.Clear(m_desktop->m_bmrect); // Succeeded to initialise ok ReturnVal(TRUE); // START PROCESSING DESKTOP MESSAGES // We set a flag inside the desktop handler here, to indicate it's now safe // to handle clipboard messages m_desktop->SetClipboardActive(TRUE); // All changes in the state of the display are stored in a local // UpdateTracker object, and are flushed to the vncServer whenever // client updates are about to be triggered rfb::SimpleUpdateTracker clipped_updates; rfb::ClippedUpdateTracker updates(clipped_updates, m_desktop->m_bmrect); clipped_updates.enable_copyrect(true); // Incoming update messages are collated into a single region cache // The region cache areas are checked for changes before an update // is triggered, and the changed areas are passed to the UpdateTracker rfb::Region2D rgncache = m_desktop->m_bmrect; // The previous cursor position is stored, to allow us to erase the // old instance whenever it moves. rfb::Point oldcursorpos; // Set the hook thread to a high priority // *** set_priority(omni_thread::PRIORITY_HIGH); BOOL idle_skip = TRUE; ULONG idle_skip_count = 0; MSG msg; while (TRUE) { if (!PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) { // // - MESSAGE QUEUE EMPTY // Whenever the message queue becomes empty, we check to see whether // there are updates to be passed to clients. if (idle_skip) { idle_skip = FALSE; if (idle_skip_count++ < 4) { Sleep(5); continue; } } idle_skip_count = 0; // Clear the triggered flag m_desktop->m_update_triggered = FALSE; // // CHECK SCREEN FORMAT // First, we must check that the screen hasnt changed too much. if (m_desktop->m_displaychanged || !vncService::InputDesktopSelected()) { rfbServerInitMsg oldscrinfo = m_desktop->m_scrinfo; m_desktop->m_displaychanged = FALSE; // Attempt to close the old hooks if (!m_desktop->Shutdown()) { m_server->KillAuthClients(); break; } // Now attempt to re-install them! if (!m_desktop->Startup()) { m_server->KillAuthClients(); break; } // Check that the screen info hasn't changed //vnclog.Print(LL_INTINFO, VNCLOG("SCR: old screen format %dx%dx%d\n"), // oldscrinfo.framebufferWidth, // oldscrinfo.framebufferHeight, // oldscrinfo.format.bitsPerPixel); //vnclog.Print(LL_INTINFO, VNCLOG("SCR: new screen format %dx%dx%d\n"), // m_desktop->m_scrinfo.framebufferWidth, // m_desktop->m_scrinfo.framebufferHeight, // m_desktop->m_scrinfo.format.bitsPerPixel); if ((m_desktop->m_scrinfo.framebufferWidth != oldscrinfo.framebufferWidth) || (m_desktop->m_scrinfo.framebufferHeight != oldscrinfo.framebufferHeight)) { m_server->KillAuthClients(); break; } else if (memcmp(&m_desktop->m_scrinfo.format, &oldscrinfo.format, sizeof(rfbPixelFormat)) != 0) { m_server->UpdateLocalFormat(); } // Adjust the UpdateTracker clip region updates.set_clip_region(m_desktop->m_bmrect); // Add a full screen update to all the clients rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_bmrect)); m_server->UpdatePalette(); } // // CALCULATE CHANGES // if (m_desktop->m_server->UpdateWanted()) { // POLL PROBLEM AREAS // We add specific areas of the screen to the region cache, // causing them to be fetched for processing. if (m_desktop->m_server->PollFullScreen()) { rfb::Rect rect = m_desktop->m_qtrscreen; rect = rect.translate(rfb::Point(0, m_desktop->m_pollingcycle * m_desktop->m_qtrscreen.br.y)); rgncache = rgncache.union_(rfb::Region2D(rect)); m_desktop->m_pollingcycle = (m_desktop->m_pollingcycle + 1) % 4; } if (m_desktop->m_server->PollForeground()) { // Get the window rectangle for the currently selected window HWND hwnd = GetForegroundWindow(); if (hwnd != NULL) PollWindow(rgncache, hwnd); } if (m_desktop->m_server->PollUnderCursor()) { // Find the mouse position POINT mousepos; if (GetCursorPos(&mousepos)) { // Find the window under the mouse HWND hwnd = WindowFromPoint(mousepos); if (hwnd != NULL) PollWindow(rgncache, hwnd); } } // PROCESS THE MOUSE POINTER // Some of the hard work is done in clients, some here // This code fetches the desktop under the old pointer position // but the client is responsible for actually encoding and sending // it when required. // This code also renders the pointer and saves the rendered position // Clients include this when rendering updates. // The code is complicated in this way because we wish to avoid // rendering parts of the screen the mouse moved through between // client updates, since in practice they will probably not have changed. // Re-render the mouse's old location if it's moved BOOL cursormoved = FALSE; POINT cursorpos; if (GetCursorPos(&cursorpos) && ((cursorpos.x != oldcursorpos.x) || (cursorpos.y != oldcursorpos.y))) { cursormoved = TRUE; oldcursorpos = rfb::Point(cursorpos); } if (cursormoved) { if (!m_desktop->m_cursorpos.is_empty()) rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_cursorpos)); } { // Prevent any clients from accessing the Buffer omni_mutex_lock l(m_desktop->m_update_lock); // CHECK FOR COPYRECTS // This actually just checks where the Foreground window is m_desktop->CalcCopyRects(updates); // GRAB THE DISPLAY // Fetch data from the display to our display cache. m_desktop->m_buffer.GrabRegion(rgncache); // Render the mouse m_desktop->m_buffer.GrabMouse(); if (cursormoved) { // Inform clients that it has moved m_desktop->m_server->UpdateMouse(); // Get the buffer to fetch the pointer bitmap if (!m_desktop->m_cursorpos.is_empty()) rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_cursorpos)); } // SCAN THE CHANGED REGION FOR ACTUAL CHANGES // The hooks return hints as to areas that may have changed. // We check the suggested areas, and just send the ones that // have actually changed. // Note that we deliberately don't check the copyrect destination // here, to reduce the overhead & the likelihood of corrupting the // backbuffer contents. rfb::Region2D checkrgn = rgncache.subtract(clipped_updates.get_copied_region()); rgncache = clipped_updates.get_copied_region(); rfb::Region2D changedrgn; m_desktop->m_buffer.CheckRegion(changedrgn, checkrgn); // FLUSH UPDATES TO CLIENTS // Add the bits that have really changed to their update regions // Note that the cursor is NOT included - they must do that // themselves, for the reasons above. // This call implicitly kicks clients to update themselves updates.add_changed(changedrgn); clipped_updates.get_update(m_server->GetUpdateTracker()); } // Clear the update tracker and region cache clipped_updates.clear(); } // Now wait for more messages to be queued if (!WaitMessage()) { //vnclog.Print(LL_INTERR, VNCLOG("WaitMessage() failed\n")); break; } } else if (msg.message == RFB_SCREEN_UPDATE) { // Process an incoming update event // An area of the screen has changed rfb::Rect rect; rect.tl = rfb::Point((SHORT)LOWORD(msg.wParam), (SHORT)HIWORD(msg.wParam)); rect.br = rfb::Point((SHORT)LOWORD(msg.lParam), (SHORT)HIWORD(msg.lParam)); rect = rect.intersect(m_desktop->m_bmrect); if (!rect.is_empty()) { rgncache = rgncache.union_(rfb::Region2D(rect)); } idle_skip = TRUE; } else if (msg.message == RFB_MOUSE_UPDATE) { // Process an incoming mouse event // Save the cursor ID m_desktop->SetCursor((HCURSOR) msg.wParam); idle_skip = TRUE; } else if (msg.message == WM_QUIT) { break; } else { // Process any other messages normally DispatchMessage(&msg); idle_skip = TRUE; } } m_desktop->SetClipboardActive(FALSE); //vnclog.Print(LL_INTINFO, VNCLOG("quitting desktop server thread\n")); // Clear all the hooks and close windows, etc. m_desktop->Shutdown(); // Clear the shift modifier keys, now that there are no remote clients vncKeymap::ClearShiftKeys(); // Switch back into our home desktop, under NT (no effect under 9x) vncService::SelectHDESK(home_desktop); return NULL; }
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 ", (char*)&filename); delete [] line; if ((result == 0) || (result == EOF)) return; vnclog.Print(LL_CLIENTS, VNCLOG("file %s requested\n"), filename); // Read in the rest of the browser's request data and discard... BOOL emptyline=TRUE; for (;;) { char c; if (!socket->ReadExact(&c, 1)) return; if (c=='\n') { if (emptyline) break; emptyline = TRUE; } else if (c >= ' ') { emptyline = FALSE; } } vnclog.Print(LL_INTINFO, VNCLOG("parameters read\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; } // Switch, dependent upon the filename: if (strcmp(filename, "/") == 0) { char indexpage[2048 + MAX_COMPUTERNAME_LENGTH + 1]; vnclog.Print(LL_CLIENTS, VNCLOG("sending main page\n")); // Send the OK notification message to the client if (!socket->SendExact(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]; if (GetCompName(desktopname, MAX_COMPUTERNAME_LENGTH)) { // Make the name lowercase for (int x=0; x<strlen(desktopname); x++) { desktopname[x] = tolower(desktopname[x]); } } else { strcpy(desktopname, szAppName); } // Send the java applet page sprintf(indexpage, HTTP_FMT_INDEX, desktopname, width, height+32, m_server->GetPort() ); } else { // 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; } // 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) { VOID *resourceptr = NULL; vnclog.Print(LL_INTINFO, VNCLOG("requested file recognised\n")); // Load the resource APIRET rc = DosGetResource(NULLHANDLE, filemapping[x].type, filemapping[x].resourceID, &resourceptr); if ( (rc != 0) || (resourceptr==NULL) ) return; vnclog.Print(LL_INTINFO, VNCLOG("sending file...\n")); // Send the OK message if (!socket->SendExact(HTTP_MSG_OK, strlen(HTTP_MSG_OK))) { DosFreeResource( resourceptr ); return; } // Now send the entirety of the data to the client if (!socket->SendExact( (const char *)resourceptr, filemapping[x].rsize)) { DosFreeResource( resourceptr ); return; } vnclog.Print(LL_INTINFO, VNCLOG("file successfully sent\n")); DosFreeResource( resourceptr ); return; } } // Send the NoSuchFile notification message to the client if (!socket->SendExact(HTTP_MSG_NOSUCHFILE, strlen(HTTP_MSG_NOSUCHFILE))) return; }