int VNCServer::Client::Disconnect() { Debug(">VNCServer::Client::Disconnect [this:%p]\n",this); //Lock wait wait.Lock(); //If we did had a ws if (ws) { //Detach listeners ws->Detach(); //Remove ws data ws->SetUserData(NULL); //Close just in cae ws->ForceClose(); //Unset websocket ws = NULL; } //Unlock wait.Unlock(); //Cancel read wait wait.Cancel(); //Signal cond to exit update loop TSIGNAL(cl->updateCond); Debug("<VNCServer::Client::Disconnect [this:%p]\n",this); //OK return 1; }
void rfbCloseClient(rfbClientPtr cl) { rfbExtensionData* extension; for(extension=cl->extensions; extension; extension=extension->next) if(extension->extension->close) extension->extension->close(cl, extension->data); LOCK(cl->updateMutex); #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD if (cl->sock != -1) #endif { FD_CLR(cl->sock,&(cl->screen->allFds)); if(cl->sock==cl->screen->maxFd) while(cl->screen->maxFd>0 && !FD_ISSET(cl->screen->maxFd,&(cl->screen->allFds))) cl->screen->maxFd--; #ifndef __MINGW32__ shutdown(cl->sock,SHUT_RDWR); #endif closesocket(cl->sock); cl->sock = -1; } TSIGNAL(cl->updateCond); UNLOCK(cl->updateMutex); }
static void * clientInput(void *data) { rfbClientPtr cl = (rfbClientPtr)data; pthread_t output_thread; pthread_create(&output_thread, NULL, clientOutput, (void *)cl); while (1) { rfbProcessClientMessage(cl); if (cl->sock == -1) { /* Client has disconnected. */ break; } } /* Get rid of the output thread. */ LOCK(cl->updateMutex); TSIGNAL(cl->updateCond); UNLOCK(cl->updateMutex); IF_PTHREADS(pthread_join(output_thread, NULL)); rfbClientConnectionGone(cl); return NULL; }
static void * clientInput(void *data) { rfbClientPtr cl = (rfbClientPtr)data; pthread_t output_thread; pthread_create(&output_thread, NULL, clientOutput, (void *)cl); while (1) { fd_set rfds, wfds, efds; struct timeval tv; int n; if (cl->sock == -1) { /* Client has disconnected. */ break; } FD_ZERO(&rfds); FD_SET(cl->sock, &rfds); FD_ZERO(&efds); FD_SET(cl->sock, &efds); /* Are we transferring a file in the background? */ FD_ZERO(&wfds); if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1)) FD_SET(cl->sock, &wfds); tv.tv_sec = 60; /* 1 minute */ tv.tv_usec = 0; n = select(cl->sock + 1, &rfds, &wfds, &efds, &tv); if (n < 0) { rfbLogPerror("ReadExact: select"); break; } if (n == 0) /* timeout */ { rfbSendFileTransferChunk(cl); continue; } /* We have some space on the transmit queue, send some data */ if (FD_ISSET(cl->sock, &wfds)) rfbSendFileTransferChunk(cl); if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds)) rfbProcessClientMessage(cl); } /* Get rid of the output thread. */ LOCK(cl->updateMutex); TSIGNAL(cl->updateCond); UNLOCK(cl->updateMutex); IF_PTHREADS(pthread_join(output_thread, NULL)); rfbClientConnectionGone(cl); return NULL; }
void rfbMarkRegionAsModified(rfbScreenInfoPtr screen,sraRegionPtr modRegion) { rfbClientIteratorPtr iterator; rfbClientPtr cl; iterator=rfbGetClientIterator(screen); while((cl=rfbClientIteratorNext(iterator))) { LOCK(cl->updateMutex); sraRgnOr(cl->modifiedRegion,modRegion); TSIGNAL(cl->updateCond); UNLOCK(cl->updateMutex); } rfbReleaseClientIterator(iterator); }
void rfbNewFramebuffer(rfbScreenInfoPtr screen, char *framebuffer, int width, int height, int bitsPerSample, int samplesPerPixel, int bytesPerPixel) { rfbPixelFormat old_format; rfbBool format_changed = FALSE; rfbClientIteratorPtr iterator; rfbClientPtr cl; /* Update information in the screenInfo structure */ old_format = screen->serverFormat; if (width & 3) rfbErr("WARNING: New width (%d) is not a multiple of 4.\n", width); screen->width = width; screen->height = height; screen->bitsPerPixel = screen->depth = 8*bytesPerPixel; screen->paddedWidthInBytes = width*bytesPerPixel; rfbInitServerFormat(screen, bitsPerSample); if (memcmp(&screen->serverFormat, &old_format, sizeof(rfbPixelFormat)) != 0) { format_changed = TRUE; } screen->frameBuffer = framebuffer; /* Adjust pointer position if necessary */ if (screen->cursorX >= width) screen->cursorX = width - 1; if (screen->cursorY >= height) screen->cursorY = height - 1; /* For each client: */ iterator = rfbGetClientIterator(screen); while ((cl = rfbClientIteratorNext(iterator)) != NULL) { /* Re-install color translation tables if necessary */ if (format_changed) screen->setTranslateFunction(cl); /* Mark the screen contents as changed, and schedule sending NewFBSize message if supported by this client. */ LOCK(cl->updateMutex); sraRgnDestroy(cl->modifiedRegion); cl->modifiedRegion = sraRgnCreateRect(0, 0, width, height); sraRgnMakeEmpty(cl->copyRegion); cl->copyDX = 0; cl->copyDY = 0; if (cl->useNewFBSize) cl->newFBSizePending = TRUE; TSIGNAL(cl->updateCond); UNLOCK(cl->updateMutex); } rfbReleaseClientIterator(iterator); }
void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy) { rfbClientIteratorPtr iterator; rfbClientPtr cl; iterator=rfbGetClientIterator(rfbScreen); while((cl=rfbClientIteratorNext(iterator))) { LOCK(cl->updateMutex); if(cl->useCopyRect) { sraRegionPtr modifiedRegionBackup; if(!sraRgnEmpty(cl->copyRegion)) { if(cl->copyDX!=dx || cl->copyDY!=dy) { /* if a copyRegion was not yet executed, treat it as a * modifiedRegion. The idea: in this case it could be * source of the new copyRect or modified anyway. */ sraRgnOr(cl->modifiedRegion,cl->copyRegion); sraRgnMakeEmpty(cl->copyRegion); } else { /* we have to set the intersection of the source of the copy * and the old copy to modified. */ modifiedRegionBackup=sraRgnCreateRgn(copyRegion); sraRgnOffset(modifiedRegionBackup,-dx,-dy); sraRgnAnd(modifiedRegionBackup,cl->copyRegion); sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); sraRgnDestroy(modifiedRegionBackup); } } sraRgnOr(cl->copyRegion,copyRegion); cl->copyDX = dx; cl->copyDY = dy; /* if there were modified regions, which are now copied, * mark them as modified, because the source of these can be overlapped * either by new modified or now copied regions. */ modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion); sraRgnOffset(modifiedRegionBackup,dx,dy); sraRgnAnd(modifiedRegionBackup,cl->copyRegion); sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); sraRgnDestroy(modifiedRegionBackup); if(!cl->enableCursorShapeUpdates) { /* * n.b. (dx, dy) is the vector pointing in the direction the * copyrect displacement will take place. copyRegion is the * destination rectangle (say), not the source rectangle. */ sraRegionPtr cursorRegion; int x = cl->cursorX - cl->screen->cursor->xhot; int y = cl->cursorY - cl->screen->cursor->yhot; int w = cl->screen->cursor->width; int h = cl->screen->cursor->height; cursorRegion = sraRgnCreateRect(x, y, x + w, y + h); sraRgnAnd(cursorRegion, cl->copyRegion); if(!sraRgnEmpty(cursorRegion)) { /* * current cursor rect overlaps with the copy region *dest*, * mark it as modified since we won't copy-rect stuff to it. */ sraRgnOr(cl->modifiedRegion, cursorRegion); } sraRgnDestroy(cursorRegion); cursorRegion = sraRgnCreateRect(x, y, x + w, y + h); /* displace it to check for overlap with copy region source: */ sraRgnOffset(cursorRegion, dx, dy); sraRgnAnd(cursorRegion, cl->copyRegion); if(!sraRgnEmpty(cursorRegion)) { /* * current cursor rect overlaps with the copy region *source*, * mark the *displaced* cursorRegion as modified since we * won't copyrect stuff to it. */ sraRgnOr(cl->modifiedRegion, cursorRegion); } sraRgnDestroy(cursorRegion); } } else { sraRgnOr(cl->modifiedRegion,copyRegion); } TSIGNAL(cl->updateCond); UNLOCK(cl->updateMutex); } rfbReleaseClientIterator(iterator); }
void VNCServer::Client::Update() { //Signal cond TSIGNAL(cl->updateCond); }
void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy) { rfbClientIteratorPtr iterator; rfbClientPtr cl; rfbUndrawCursor(rfbScreen); iterator=rfbGetClientIterator(rfbScreen); while((cl=rfbClientIteratorNext(iterator))) { LOCK(cl->updateMutex); if(cl->useCopyRect) { sraRegionPtr modifiedRegionBackup; if(!sraRgnEmpty(cl->copyRegion)) { if(cl->copyDX!=dx || cl->copyDY!=dy) { /* if a copyRegion was not yet executed, treat it as a * modifiedRegion. The idea: in this case it could be * source of the new copyRect or modified anyway. */ sraRgnOr(cl->modifiedRegion,cl->copyRegion); sraRgnMakeEmpty(cl->copyRegion); } else { /* we have to set the intersection of the source of the copy * and the old copy to modified. */ modifiedRegionBackup=sraRgnCreateRgn(copyRegion); sraRgnOffset(modifiedRegionBackup,-dx,-dy); sraRgnAnd(modifiedRegionBackup,cl->copyRegion); sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); sraRgnDestroy(modifiedRegionBackup); } } sraRgnOr(cl->copyRegion,copyRegion); cl->copyDX = dx; cl->copyDY = dy; /* if there were modified regions, which are now copied, * mark them as modified, because the source of these can be overlapped * either by new modified or now copied regions. */ modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion); sraRgnOffset(modifiedRegionBackup,dx,dy); sraRgnAnd(modifiedRegionBackup,cl->copyRegion); sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); sraRgnDestroy(modifiedRegionBackup); #if 0 //TODO: is this needed? Or does it mess up deferring? /* while(!sraRgnEmpty(cl->copyRegion)) */ { #ifdef HAVE_PTHREADS if(!cl->screen->backgroundLoop) #endif { sraRegionPtr updateRegion = sraRgnCreateRgn(cl->modifiedRegion); sraRgnOr(updateRegion,cl->copyRegion); UNLOCK(cl->updateMutex); rfbSendFramebufferUpdate(cl,updateRegion); sraRgnDestroy(updateRegion); continue; } } #endif } else { sraRgnOr(cl->modifiedRegion,copyRegion); } TSIGNAL(cl->updateCond); UNLOCK(cl->updateMutex); } rfbReleaseClientIterator(iterator); }