void rfbScreenCleanup(rfbScreenInfoPtr screen) { rfbClientIteratorPtr i=rfbGetClientIterator(screen); rfbClientPtr cl,cl1=rfbClientIteratorNext(i); while(cl1) { cl=rfbClientIteratorNext(i); rfbClientConnectionGone(cl1); cl1=cl; } rfbReleaseClientIterator(i); #define FREE_IF(x) if(screen->x) free(screen->x) FREE_IF(colourMap.data.bytes); FREE_IF(underCursorBuffer); TINI_MUTEX(screen->cursorMutex); if(screen->cursor && screen->cursor->cleanup) rfbFreeCursor(screen->cursor); #ifdef LIBVNCSERVER_HAVE_LIBZ rfbZlibCleanup(screen); #ifdef LIBVNCSERVER_HAVE_LIBJPEG rfbTightCleanup(screen); #endif /* free all 'scaled' versions of this screen */ while (screen->scaledScreenNext!=NULL) { rfbScreenInfoPtr ptr; ptr = screen->scaledScreenNext; screen->scaledScreenNext = ptr->scaledScreenNext; free(ptr->frameBuffer); free(ptr); } #endif free(screen); }
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::encodeAndSend(int viewNum, int x0, int y0, int w, int h, const VncServer::ViewParameters ¶m, bool lastView) { //std::cerr << "encodeAndSend: view=" << viewNum << ", c=" << (void *)rgba(viewNum) << ", d=" << depth(viewNum) << std::endl; if (!m_resizeBlocked) { m_firstTile = true; } m_resizeBlocked = true; //vistle::StopWatch timer("encodeAndSend"); const int tileWidth = m_tileWidth, tileHeight = m_tileHeight; static int framecount=0; ++framecount; for (int y=y0; y<y0+h; y+=tileHeight) { for (int x=x0; x<x0+w; x+=tileWidth) { // depth auto dt = new(tbb::task::allocate_root()) EncodeTask(m_resultQueue, viewNum, x, y, std::min(tileWidth, x0+w-x), std::min(tileHeight, y0+h-y), depth(viewNum), m_imageParam, param); tbb::task::enqueue(*dt); ++m_queuedTiles; // color auto ct = new(tbb::task::allocate_root()) EncodeTask(m_resultQueue, viewNum, x, y, std::min(tileWidth, x0+w-x), std::min(tileHeight, y0+h-y), rgba(viewNum), m_imageParam, param); tbb::task::enqueue(*ct); ++m_queuedTiles; } } bool tileReady = false; do { VncServer::EncodeResult result; tileReady = false; if (m_resultQueue.try_pop(result)) { --m_queuedTiles; tileReady = true; if (result.message) { tileMsg &msg = *result.message; if (m_firstTile) { msg.flags |= rfbTileFirst; //std::cerr << "first tile: req=" << msg.requestNumber << std::endl; } m_firstTile = false; if (m_queuedTiles == 0 && lastView) { msg.flags |= rfbTileLast; //std::cerr << "last tile: req=" << msg.requestNumber << std::endl; } msg.frameNumber = framecount; rfbCheckFds(m_screen, 0); rfbHttpCheckFds(m_screen); rfbClientIteratorPtr i = rfbGetClientIterator(m_screen); while (rfbClientPtr cl = rfbClientIteratorNext(i)) { if (cl->clientData) { rfbUpdateClient(cl); if (rfbWriteExact(cl, (char *)&msg, sizeof(msg)) < 0) { rfbLogPerror("sendTileMessage: write header"); } if (result.payload && msg.size > 0) { if (rfbWriteExact(cl, result.payload, msg.size) < 0) { rfbLogPerror("sendTileMessage: write paylod"); } } } rfbUpdateClient(cl); } rfbReleaseClientIterator(i); } delete[] result.payload; delete result.message; } } while (m_queuedTiles > 0 && (tileReady || lastView)); if (lastView) { vassert(m_queuedTiles == 0); m_resizeBlocked = false; deferredResize(); } //sleep(1); }
int rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec) { int nfds; fd_set fds; struct timeval tv; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); char buf[6]; rfbClientIteratorPtr i; rfbClientPtr cl; int result = 0; if (!rfbScreen->inetdInitDone && rfbScreen->inetdSock != -1) { rfbNewClientConnection(rfbScreen,rfbScreen->inetdSock); rfbScreen->inetdInitDone = TRUE; } do { memcpy((char *)&fds, (char *)&(rfbScreen->allFds), sizeof(fd_set)); tv.tv_sec = 0; tv.tv_usec = usec; nfds = select(rfbScreen->maxFd + 1, &fds, NULL, NULL /* &fds */, &tv); if (nfds == 0) { /* timed out, check for async events */ i = rfbGetClientIterator(rfbScreen); while((cl = rfbClientIteratorNext(i))) { if (cl->onHold) continue; if (FD_ISSET(cl->sock, &(rfbScreen->allFds))) rfbSendFileTransferChunk(cl); } rfbReleaseClientIterator(i); return result; } if (nfds < 0) { #ifdef WIN32 errno = WSAGetLastError(); #endif if (errno != EINTR) rfbLogPerror("rfbCheckFds: select"); return -1; } result += nfds; if (rfbScreen->listenSock != -1 && FD_ISSET(rfbScreen->listenSock, &fds)) { if (!rfbProcessNewConnection(rfbScreen)) return -1; FD_CLR(rfbScreen->listenSock, &fds); if (--nfds == 0) return result; } if (rfbScreen->listen6Sock != -1 && FD_ISSET(rfbScreen->listen6Sock, &fds)) { if (!rfbProcessNewConnection(rfbScreen)) return -1; FD_CLR(rfbScreen->listen6Sock, &fds); if (--nfds == 0) return result; } if ((rfbScreen->udpSock != -1) && FD_ISSET(rfbScreen->udpSock, &fds)) { if(!rfbScreen->udpClient) rfbNewUDPClient(rfbScreen); if (recvfrom(rfbScreen->udpSock, buf, 1, MSG_PEEK, (struct sockaddr *)&addr, &addrlen) < 0) { rfbLogPerror("rfbCheckFds: UDP: recvfrom"); rfbDisconnectUDPSock(rfbScreen); rfbScreen->udpSockConnected = FALSE; } else { if (!rfbScreen->udpSockConnected || (memcmp(&addr, &rfbScreen->udpRemoteAddr, addrlen) != 0)) { /* new remote end */ rfbLog("rfbCheckFds: UDP: got connection\n"); memcpy(&rfbScreen->udpRemoteAddr, &addr, addrlen); rfbScreen->udpSockConnected = TRUE; if (connect(rfbScreen->udpSock, (struct sockaddr *)&addr, addrlen) < 0) { rfbLogPerror("rfbCheckFds: UDP: connect"); rfbDisconnectUDPSock(rfbScreen); return -1; } rfbNewUDPConnection(rfbScreen,rfbScreen->udpSock); } rfbProcessUDPInput(rfbScreen); } FD_CLR(rfbScreen->udpSock, &fds); if (--nfds == 0) return result; } i = rfbGetClientIterator(rfbScreen); while((cl = rfbClientIteratorNext(i))) { if (cl->onHold) continue; if (FD_ISSET(cl->sock, &(rfbScreen->allFds))) { if (FD_ISSET(cl->sock, &fds)) rfbProcessClientMessage(cl); else rfbSendFileTransferChunk(cl); } } rfbReleaseClientIterator(i); } while(rfbScreen->handleEventsEagerly); return result; }
int rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec) { int nfds; fd_set fds; struct timeval tv; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); char buf[6]; const int one = 1; int sock; rfbClientIteratorPtr i; rfbClientPtr cl; struct timeval tv_msg; fd_set fds_msg; int nfds_msg; int result = 0; if (!rfbScreen->inetdInitDone && rfbScreen->inetdSock != -1) { rfbNewClientConnection(rfbScreen,rfbScreen->inetdSock); rfbScreen->inetdInitDone = TRUE; } do { memcpy((char *)&fds, (char *)&(rfbScreen->allFds), sizeof(fd_set)); tv.tv_sec = 0; tv.tv_usec = usec; nfds = select(rfbScreen->maxFd + 1, &fds, NULL, NULL /* &fds */, &tv); if (nfds == 0) { /* timed out, check for async events */ i = rfbGetClientIterator(rfbScreen); while((cl = rfbClientIteratorNext(i))) { if (cl->onHold) continue; if (FD_ISSET(cl->sock, &(rfbScreen->allFds))) rfbSendFileTransferChunk(cl); } rfbReleaseClientIterator(i); return result; } if (nfds < 0) { #ifdef WIN32 errno = WSAGetLastError(); #endif if (errno != EINTR) rfbLogPerror("rfbCheckFds: select"); return -1; } result += nfds; if (rfbScreen->listenSock != -1 && FD_ISSET(rfbScreen->listenSock, &fds)) { if ((sock = accept(rfbScreen->listenSock, (struct sockaddr *)&addr, &addrlen)) < 0) { rfbLogPerror("rfbCheckFds: accept"); return -1; } #ifndef WIN32 if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { rfbLogPerror("rfbCheckFds: fcntl"); closesocket(sock); return -1; } #endif if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) { rfbLogPerror("rfbCheckFds: setsockopt"); closesocket(sock); return -1; } #ifdef USE_LIBWRAP if(!hosts_ctl("vnc",STRING_UNKNOWN,inet_ntoa(addr.sin_addr), STRING_UNKNOWN)) { rfbLog("Rejected connection from client %s\n", inet_ntoa(addr.sin_addr)); closesocket(sock); return -1; } #endif rfbLog("Got connection from client %s\n", inet_ntoa(addr.sin_addr)); rfbNewClient(rfbScreen,sock); FD_CLR(rfbScreen->listenSock, &fds); if (--nfds == 0) return result; } if ((rfbScreen->udpSock != -1) && FD_ISSET(rfbScreen->udpSock, &fds)) { if(!rfbScreen->udpClient) rfbNewUDPClient(rfbScreen); if (recvfrom(rfbScreen->udpSock, buf, 1, MSG_PEEK, (struct sockaddr *)&addr, &addrlen) < 0) { rfbLogPerror("rfbCheckFds: UDP: recvfrom"); rfbDisconnectUDPSock(rfbScreen); rfbScreen->udpSockConnected = FALSE; } else { if (!rfbScreen->udpSockConnected || (memcmp(&addr, &rfbScreen->udpRemoteAddr, addrlen) != 0)) { /* new remote end */ rfbLog("rfbCheckFds: UDP: got connection\n"); memcpy(&rfbScreen->udpRemoteAddr, &addr, addrlen); rfbScreen->udpSockConnected = TRUE; if (connect(rfbScreen->udpSock, (struct sockaddr *)&addr, addrlen) < 0) { rfbLogPerror("rfbCheckFds: UDP: connect"); rfbDisconnectUDPSock(rfbScreen); return -1; } rfbNewUDPConnection(rfbScreen,rfbScreen->udpSock); } rfbProcessUDPInput(rfbScreen); } FD_CLR(rfbScreen->udpSock, &fds); if (--nfds == 0) return result; } i = rfbGetClientIterator(rfbScreen); while((cl = rfbClientIteratorNext(i))) { if (cl->onHold) continue; if (FD_ISSET(cl->sock, &(rfbScreen->allFds))) { if (FD_ISSET(cl->sock, &fds)) { tv_msg.tv_sec = 0; tv_msg.tv_usec = 0; FD_ZERO(&fds_msg); FD_SET(cl->sock, &fds_msg); do { /* drain all messages, speed up mouse move processing */ rfbProcessClientMessage(cl); nfds_msg = select(cl->sock + 1, &fds_msg, NULL, NULL, &tv_msg); } while (nfds_msg > 0); } else rfbSendFileTransferChunk(cl); } } rfbReleaseClientIterator(i); } while(rfbScreen->handleEventsEagerly); return result; }
static int get_rate(int which) { rfbClientIteratorPtr iter; rfbClientPtr cl; int irate, irate_min = 1; /* 1 KB/sec */ int irate_max = 100000; /* 100 MB/sec */ int count = 0; double slowest = -1.0, rate; static double save_rate = 1000 * NETRATE0; if (!screen) { return 0; } iter = rfbGetClientIterator(screen); while( (cl = rfbClientIteratorNext(iter)) ) { ClientData *cd = (ClientData *) cl->clientData; if (! cd) { continue; } if (cl->state != RFB_NORMAL) { continue; } if (cd->send_cmp_rate == 0.0 || cd->send_raw_rate == 0.0) { continue; } count++; if (which == 0) { rate = cd->send_cmp_rate; } else { rate = cd->send_raw_rate; } if (slowest == -1.0 || rate < slowest) { slowest = rate; } } rfbReleaseClientIterator(iter); if (! count) { return NETRATE0; } if (slowest == -1.0) { slowest = save_rate; } else { save_rate = slowest; } irate = (int) (slowest/1000.0); if (irate < irate_min) { irate = irate_min; } if (irate > irate_max) { irate = irate_max; } if (0) fprintf(stderr, "get_rate(%d) %d %.3f/%.3f\n", which, irate, save_rate, slowest); return irate; }
rfbBool rfbProcessEvents(rfbScreenInfoPtr screen,long usec) { rfbClientIteratorPtr i; rfbClientPtr cl,clPrev; struct timeval tv; rfbBool result=FALSE; extern rfbClientIteratorPtr rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen); if(usec<0) usec=screen->deferUpdateTime*1000; rfbCheckFds(screen,usec); rfbHttpCheckFds(screen); i = rfbGetClientIteratorWithClosed(screen); cl=rfbClientIteratorHead(i); while(cl) { if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) && !sraRgnEmpty(cl->requestedRegion)) { result=TRUE; if(screen->deferUpdateTime == 0) { rfbSendFramebufferUpdate(cl,cl->modifiedRegion); } else if(cl->startDeferring.tv_usec == 0) { gettimeofday(&cl->startDeferring,NULL); if(cl->startDeferring.tv_usec == 0) cl->startDeferring.tv_usec++; } else { gettimeofday(&tv,NULL); if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */ || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000 +(tv.tv_usec-cl->startDeferring.tv_usec)/1000) > screen->deferUpdateTime) { cl->startDeferring.tv_usec = 0; rfbSendFramebufferUpdate(cl,cl->modifiedRegion); } } } if (!cl->viewOnly && cl->lastPtrX >= 0) { if(cl->startPtrDeferring.tv_usec == 0) { gettimeofday(&cl->startPtrDeferring,NULL); if(cl->startPtrDeferring.tv_usec == 0) cl->startPtrDeferring.tv_usec++; } else { struct timeval tv; gettimeofday(&tv,NULL); if(tv.tv_sec < cl->startPtrDeferring.tv_sec /* at midnight */ || ((tv.tv_sec-cl->startPtrDeferring.tv_sec)*1000 +(tv.tv_usec-cl->startPtrDeferring.tv_usec)/1000) > cl->screen->deferPtrUpdateTime) { cl->startPtrDeferring.tv_usec = 0; cl->screen->ptrAddEvent(cl->lastPtrButtons, cl->lastPtrX, cl->lastPtrY, cl); cl->lastPtrX = -1; } } } clPrev=cl; cl=rfbClientIteratorNext(i); if(clPrev->sock==-1) { rfbClientConnectionGone(clPrev); result=TRUE; } } rfbReleaseClientIterator(i); return result; }
void measure_send_rates(int init) { double cmp_rate, raw_rate; static double now, start = 0.0; static rfbDisplayHookPtr orig_display_hook = NULL; double cmp_max = 1.0e+08; /* 100 MB/sec */ double cmp_min = 1000.0; /* 9600baud */ double lat_max = 5.0; /* 5 sec */ double lat_min = .0005; /* 0.5 ms */ int min_cmp = 10000, nclients; rfbClientIteratorPtr iter; rfbClientPtr cl0, cl; int msg = 0, clcnt0 = 0, cc; int db = 0, ouch_db = 0, ouch = 0; if (! measure_speeds) { return; } if (speeds_net_rate && speeds_net_latency) { return; } if (!client_count) { return; } if (! orig_display_hook) { orig_display_hook = screen->displayHook; } if (start == 0.0) { dtime(&start); } dtime0(&now); if (now < last_client_gone+4.0) { return; } now = now - start; nclients = 0; if (!screen) { return; } cl0 = NULL; iter = rfbGetClientIterator(screen); while( (cl = rfbClientIteratorNext(iter)) ) { ClientData *cd = (ClientData *) cl->clientData; if (! cd) { continue; } if (cd->send_cmp_rate > 0.0) { continue; } if (cl->onHold) { continue; } nclients++; if (cl0 == NULL) { cl0 = cl; } } rfbReleaseClientIterator(iter); cl = cl0; cc = 0; while (cl != NULL && cc++ == 0) { int defer, i, cbs, rbs; char *httpdir; double dt, dt1 = 0.0, dt2, dt3; double tm, spin_max = 15.0, spin_lat_max = 1.5; int got_t2 = 0, got_t3 = 0; ClientData *cd = (ClientData *) cl->clientData; #if 0 for (i=0; i<MAX_ENCODINGS; i++) { cbs += cl->bytesSent[i]; } rbs = cl->rawBytesEquivalent; #else #if LIBVNCSERVER_HAS_STATS cbs = rfbStatGetSentBytes(cl); rbs = rfbStatGetSentBytesIfRaw(cl); #endif #endif if (init) { if (db) fprintf(stderr, "%d client num rects req: %d mod: %d cbs: %d " "rbs: %d dt1: %.3f t: %.3f\n", init, (int) sraRgnCountRects(cl->requestedRegion), (int) sraRgnCountRects(cl->modifiedRegion), cbs, rbs, dt1, now); cd->timer = dnow(); cd->cmp_bytes_sent = cbs; cd->raw_bytes_sent = rbs; continue; } /* first part of the bulk transfer of initial screen */ dt1 = dtime(&cd->timer); if (db) fprintf(stderr, "%d client num rects req: %d mod: %d cbs: %d " "rbs: %d dt1: %.3f t: %.3f\n", init, (int) sraRgnCountRects(cl->requestedRegion), (int) sraRgnCountRects(cl->modifiedRegion), cbs, rbs, dt1, now); if (dt1 <= 0.0) { continue; } cbs = cbs - cd->cmp_bytes_sent; rbs = rbs - cd->raw_bytes_sent; if (cbs < min_cmp) { continue; } if (ouch_db) fprintf(stderr, "START-OUCH: %d\n", client_count); clcnt0 = client_count; #define OUCH ( ouch || (ouch = (!client_count || client_count != clcnt0 || dnow() < last_client_gone+4.0)) ) rfbPE(1000); if (OUCH && ouch_db) fprintf(stderr, "***OUCH-A\n"); if (OUCH) continue; if (use_threads) LOCK(cl->updateMutex); if (sraRgnCountRects(cl->modifiedRegion)) { rfbPE(1000); if (OUCH && ouch_db) fprintf(stderr, "***OUCH-B\n"); if (use_threads) UNLOCK(cl->updateMutex); if (OUCH) continue; } if (use_threads) UNLOCK(cl->updateMutex); defer = screen->deferUpdateTime; httpdir = screen->httpDir; screen->deferUpdateTime = 0; screen->httpDir = NULL; /* mark a small rectangle: */ mark_rect_as_modified(0, 0, 16, 16, 1); dtime0(&tm); dt2 = 0.0; dt3 = 0.0; if (dt1 < 0.25) { /* try to cut it down to avoid long pauses. */ spin_max = 5.0; } /* when req1 = 1 mod1 == 0, end of 2nd part of bulk transfer */ while (1) { int req0, req1, mod0, mod1; if (OUCH && ouch_db) fprintf(stderr, "***OUCH-C1\n"); if (OUCH) break; if (use_threads) LOCK(cl->updateMutex); req0 = sraRgnCountRects(cl->requestedRegion); mod0 = sraRgnCountRects(cl->modifiedRegion); if (use_threads) UNLOCK(cl->updateMutex); if (use_threads) { usleep(1000); } else { if (mod0) { rfbPE(1000); } else { rfbCFD(1000); } } dt = dtime(&tm); dt2 += dt; if (dt2 > spin_max) { break; } if (OUCH && ouch_db) fprintf(stderr, "***OUCH-C2\n"); if (OUCH) break; if (use_threads) LOCK(cl->updateMutex); req1 = sraRgnCountRects(cl->requestedRegion); mod1 = sraRgnCountRects(cl->modifiedRegion); if (use_threads) UNLOCK(cl->updateMutex); if (db) fprintf(stderr, "dt2 calc: num rects req: %d/%d mod: %d/%d " "fbu-sent: %d dt: %.4f dt2: %.4f tm: %.4f\n", req0, req1, mod0, mod1, #if 0 cl->framebufferUpdateMessagesSent, #else #if LIBVNCSERVER_HAS_STATS rfbStatGetMessageCountSent(cl, rfbFramebufferUpdate), #endif #endif dt, dt2, tm); if (req1 != 0 && mod1 == 0) { got_t2 = 1; break; } } if (OUCH && ouch_db) fprintf(stderr, "***OUCH-D\n"); if (OUCH) goto ouch; if (! got_t2) { dt2 = 0.0; } else { int tr, trm = 3; double dts[10]; /* * Note: since often select(2) cannot sleep * less than 1/HZ (e.g. 10ms), the resolution * of the latency may be messed up by something * of this order. Effect may occur on both ends, * i.e. the viewer may not respond immediately. */ for (tr = 0; tr < trm; tr++) { usleep(5000); /* mark a 2nd small rectangle: */ mark_rect_as_modified(0, 0, 16, 16, 1); i = 0; dtime0(&tm); dt3 = 0.0; /* * when req1 > 0 and mod1 == 0, we say * that is the "ping" time. */ while (1) { int req0, req1, mod0, mod1; if (use_threads) LOCK(cl->updateMutex); req0 = sraRgnCountRects(cl->requestedRegion); mod0 = sraRgnCountRects(cl->modifiedRegion); if (use_threads) UNLOCK(cl->updateMutex); if (i == 0) { rfbPE(0); } else { if (use_threads) { usleep(1000); } else { /* try to get it all */ rfbCFD(1000*1000); } } if (OUCH && ouch_db) fprintf(stderr, "***OUCH-E\n"); if (OUCH) goto ouch; dt = dtime(&tm); i++; dt3 += dt; if (dt3 > spin_lat_max) { break; } if (use_threads) LOCK(cl->updateMutex); req1 = sraRgnCountRects(cl->requestedRegion); mod1 = sraRgnCountRects(cl->modifiedRegion); if (use_threads) UNLOCK(cl->updateMutex); if (db) fprintf(stderr, "dt3 calc: num rects req: %d/%d mod: %d/%d " "fbu-sent: %d dt: %.4f dt3: %.4f tm: %.4f\n", req0, req1, mod0, mod1, #if 0 cl->framebufferUpdateMessagesSent, #else #if LIBVNCSERVER_HAS_STATS rfbStatGetMessageCountSent(cl, rfbFramebufferUpdate), #endif #endif dt, dt3, tm); if (req1 != 0 && mod1 == 0) { dts[got_t3++] = dt3; break; } } } if (! got_t3) { dt3 = 0.0; } else { if (got_t3 == 1) { dt3 = dts[0]; } else if (got_t3 == 2) { dt3 = dts[1]; } else { if (dts[2] > 0.0) { double rat = dts[1]/dts[2]; if (rat > 0.5 && rat < 2.0) { dt3 = dts[1]+dts[2]; dt3 *= 0.5; } else { dt3 = dts[1]; } } else { dt3 = dts[1]; } } } } ouch: screen->deferUpdateTime = defer; screen->httpDir = httpdir; if (OUCH && ouch_db) fprintf(stderr, "***OUCH-F\n"); if (OUCH) break; dt = dt1 + dt2; if (dt3 <= dt2/2.0) { /* guess only 1/2 a ping for reply... */ dt = dt - dt3/2.0; } cmp_rate = cbs/dt; raw_rate = rbs/dt; if (cmp_rate > cmp_max) { cmp_rate = cmp_max; } if (cmp_rate <= cmp_min) { cmp_rate = cmp_min; } cd->send_cmp_rate = cmp_rate; cd->send_raw_rate = raw_rate; if (dt3 > lat_max) { dt3 = lat_max; } if (dt3 <= lat_min) { dt3 = lat_min; } cd->latency = dt3; rfbLog("client %d network rate %.1f KB/sec (%.1f eff KB/sec)\n", cd->uid, cmp_rate/1000.0, raw_rate/1000.0); rfbLog("client %d latency: %.1f ms\n", cd->uid, 1000.0*dt3); rfbLog("dt1: %.4f, dt2: %.4f dt3: %.4f bytes: %d\n", dt1, dt2, dt3, cbs); msg = 1; } if (msg) { int link, latency, netrate; char *str = "error"; link = link_rate(&latency, &netrate); if (link == LR_UNSET) { str = "LR_UNSET"; } else if (link == LR_UNKNOWN) { str = "LR_UNKNOWN"; } else if (link == LR_DIALUP) { str = "LR_DIALUP"; } else if (link == LR_BROADBAND) { str = "LR_BROADBAND"; } else if (link == LR_LAN) { str = "LR_LAN"; } rfbLog("link_rate: %s - %d ms, %d KB/s\n", str, latency, netrate); } if (init) { if (nclients) { screen->displayHook = measure_display_hook; } } else { screen->displayHook = orig_display_hook; } }
void GsSelect(GR_TIMEOUT timeout) { fd_set rfds; int e; int setsize = 0; struct timeval tout; struct timeval *to; #if NONETWORK int fd; #endif #if HAVE_VNCSERVER #if VNCSERVER_PTHREADED int dummy; #else rfbClientIteratorPtr i; rfbClientPtr cl; #endif #endif /* X11/SDL perform single update of aggregate screen update region*/ if (scrdev.PreSelect) { /* returns # pending events*/ if (scrdev.PreSelect(&scrdev)) { /* poll for mouse data and service if found*/ while (GsCheckMouseEvent()) continue; /* poll for keyboard data and service if found*/ while (GsCheckKeyboardEvent()) continue; /* events found, return with no sleep*/ return; } } /* Set up the FDs for use in the main select(): */ FD_ZERO(&rfds); if(mouse_fd >= 0) { FD_SET(mouse_fd, &rfds); if (mouse_fd > setsize) setsize = mouse_fd; } if(keyb_fd >= 0) { FD_SET(keyb_fd, &rfds); if (keyb_fd > setsize) setsize = keyb_fd; } #if MW_FEATURE_TWO_KEYBOARDS if(keyb2_fd >= 0) { FD_SET(keyb2_fd, &rfds); if (keyb2_fd > setsize) setsize = keyb2_fd; } #endif #if NONETWORK /* handle registered input file descriptors*/ for (fd = 0; fd < regfdmax; fd++) { if (!FD_ISSET(fd, ®fdset)) continue; FD_SET(fd, &rfds); if (fd > setsize) setsize = fd; } #else /* !NONETWORK */ /* handle client socket connections*/ FD_SET(un_sock, &rfds); if (un_sock > setsize) setsize = un_sock; curclient = root_client; while(curclient) { if(curclient->waiting_for_event && curclient->eventhead) { curclient->waiting_for_event = FALSE; GrGetNextEventWrapperFinish(curclient->id); return; } FD_SET(curclient->id, &rfds); if(curclient->id > setsize) setsize = curclient->id; curclient = curclient->next; } #endif /* NONETWORK */ #if HAVE_VNCSERVER #if VNCSERVER_PTHREADED /* Add file vnc thread fd. This is useful to force handling of events generated by the VNC thread*/ FD_SET( vnc_thread_fd, &(rfds) ); if ( vnc_thread_fd > setsize ) setsize = vnc_thread_fd; #else /* Add all VNC open sockets to nano-X select set */ FD_SET( rfbScreen->listenSock, &(rfds) ); if ( rfbScreen->listenSock > setsize ) setsize = rfbScreen->listenSock; FD_SET( rfbScreen->httpListenSock, &(rfds) ); if ( rfbScreen->httpListenSock > setsize ) setsize = rfbScreen->httpListenSock; i = rfbGetClientIterator(rfbScreen); cl = rfbClientIteratorNext(i); while ( cl ) { if ( cl->sock >= 0 ) { FD_SET( cl->sock, &(rfds) ); if ( cl->sock > setsize ) setsize = cl->sock; } cl = rfbClientIteratorNext(i); } rfbReleaseClientIterator(i); #endif #endif /* HAVE_VNCSERVER*/ /* setup timeval struct for block or poll in select()*/ tout.tv_sec = tout.tv_usec = 0; /* setup for assumed poll*/ to = &tout; int poll = (timeout == (GR_TIMEOUT) -1L); /* timeout = -1 means just poll*/ if (!poll) { #if MW_FEATURE_TIMERS /* get next timer or use passed timeout and convert to timeval struct*/ if (!GdGetNextTimeout(&tout, timeout)) /* no app timers or VTSWITCH?*/ #else if (timeout) /* setup mwin poll timer*/ { /* convert wait timeout to timeval struct*/ tout.tv_sec = timeout / 1000; tout.tv_usec = (timeout % 1000) * 1000; } else #endif { to = NULL; /* no timers, block*/ } } /* some drivers can't block in select as backend is poll based (SDL)*/ if (scrdev.flags & PSF_CANTBLOCK) { #define WAITTIME 100 /* check if would block permanently or timeout > WAITTIME*/ if (to == NULL || tout.tv_sec != 0 || tout.tv_usec > WAITTIME) { /* override timeouts and wait for max WAITTIME ms*/ to = &tout; tout.tv_sec = 0; tout.tv_usec = WAITTIME; } } /* Wait for some input on any of the fds in the set or a timeout*/ #if NONETWORK SERVER_UNLOCK(); /* allow other threads to run*/ #endif e = select(setsize+1, &rfds, NULL, NULL, to); #if NONETWORK SERVER_LOCK(); #endif if(e > 0) /* input ready*/ { /* service mouse file descriptor*/ if(mouse_fd >= 0 && FD_ISSET(mouse_fd, &rfds)) while(GsCheckMouseEvent()) continue; /* service keyboard file descriptor*/ if( (keyb_fd >= 0 && FD_ISSET(keyb_fd, &rfds)) #if MW_FEATURE_TWO_KEYBOARDS || (keyb2_fd >= 0 && FD_ISSET(keyb2_fd, &rfds)) #endif ) while(GsCheckKeyboardEvent()) continue; #if HAVE_VNCSERVER && VNCSERVER_PTHREADED if(vnc_thread_fd >= 0 && FD_ISSET(vnc_thread_fd, &rfds)) /* Read from vnc pipe */ read( vnc_thread_fd, &dummy, sizeof(int)); #endif #if NONETWORK /* check for input on registered file descriptors */ for (fd = 0; fd < regfdmax; fd++) { GR_EVENT_FDINPUT * gp; if (!FD_ISSET(fd, ®fdset) || !FD_ISSET(fd, &rfds)) continue; gp = (GR_EVENT_FDINPUT *)GsAllocEvent(curclient); if(gp) { gp->type = GR_EVENT_TYPE_FDINPUT; gp->fd = fd; } } #else /* !NONETWORK */ /* If a client is trying to connect, accept it: */ if(FD_ISSET(un_sock, &rfds)) GsAcceptClient(); /* If a client is sending us a command, handle it: */ curclient = root_client; while (curclient) { GR_CLIENT *curclient_next; /* curclient may be freed in GsDropClient*/ curclient_next = curclient->next; if(FD_ISSET(curclient->id, &rfds)) GsHandleClient(curclient->id); curclient = curclient_next; } #if HAVE_VNCSERVER && !VNCSERVER_PTHREADED rfbProcessEvents(rfbScreen, 0); #endif #endif /* NONETWORK */ } else if (e == 0) /* timeout*/ { #if NONETWORK /* * Timeout has occured. Currently return a timeout event * regardless of whether client has selected for it. * Note: this will be changed back to GR_EVENT_TYPE_NONE * for the GrCheckNextEvent/LINK_APP_TO_SERVER case */ #if MW_FEATURE_TIMERS if(GdTimeout()) #endif { GR_EVENT_GENERAL * gp; if ((gp = (GR_EVENT_GENERAL *)GsAllocEvent(curclient)) != NULL) gp->type = GR_EVENT_TYPE_TIMEOUT; } #else /* !NONETWORK */ #if MW_FEATURE_TIMERS /* check for timer timeouts and service if found*/ GdTimeout(); #endif #endif /* NONETWORK */ } else if(errno != EINTR) EPRINTF("Select() call in main failed\n"); }
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 0 /* TODO: is this needed? Or does it mess up deferring? */ /* while(!sraRgnEmpty(cl->copyRegion)) */ { { sraRegionPtr updateRegion = sraRgnCreateRgn(cl->modifiedRegion); sraRgnOr(updateRegion,cl->copyRegion); UNLOCK(cl->updateMutex); rfbSendFramebufferUpdate(cl,updateRegion); sraRgnDestroy(updateRegion); continue; } } #endif } else { sraRgnOr(cl->modifiedRegion,copyRegion); } UNLOCK(cl->updateMutex); } rfbReleaseClientIterator(iterator); }
void WINAPI VNCServerThread(HVNC hVNC) { HVNC_HANDLE *lpHandle=VNCGetHandleInformation(hVNC); if (!lpHandle) return; if (!SetThreadExecutionState(ES_CONTINUOUS+ES_SYSTEM_REQUIRED+ES_AWAYMODE_REQUIRED)) SetThreadExecutionState(ES_CONTINUOUS+ES_SYSTEM_REQUIRED); SetThreadDesktopEx(hDefaultDesktop); PHVNC lpServer=lpHandle->lpServer; rfbScreenInfoPtr rfbScreen=lpServer->rfbScreen=rfbGetScreen(NULL,NULL,lpServer->DeskInfo.dwWidth,lpServer->DeskInfo.dwHeight,8,3,lpServer->DeskInfo.bBytesPerPixel); if (!rfbScreen) { lpServer->bActive=false; SetEvent(lpHandle->hEvent); return; } rfbScreen->screenData=lpServer; rfbScreen->desktopName=lpServer->DeskInfo.szDeskName; rfbScreen->frameBuffer=(char*)lpServer->DIBInfo.lpOldBkgBits; rfbScreen->alwaysShared=lpHandle->ConnInfo.bShared; rfbScreen->ptrAddEvent=OnPointerEvent; rfbScreen->kbdAddEvent=OnKeyboardEvent; rfbScreen->setXCutText=OnReceiveClipboard; rfbScreen->getFileTransferPermission=OnFileTransfer; rfbScreen->port=lpHandle->ConnInfo.wVNCPort; if (!(lpServer->DeskInfo.dwFlags & HVNC_NO_VNC_CURSOR)) SetXCursor(rfbScreen,&cur_arrow); else rfbScreen->cursor=NULL; if ((lpHandle->ConnInfo.szBCHost[0]) && (lpHandle->ConnInfo.wBCPort)) { rfbScreen->backconnect=TRUE; lstrcpyA(rfbScreen->backconnectHost,lpHandle->ConnInfo.szBCHost); rfbScreen->bcPort=lpHandle->ConnInfo.wBCPort; } if (lpHandle->ConnInfo.Passwords.dwPasswordsCount) { DWORD dwPasswordsCount=lpHandle->ConnInfo.Passwords.dwPasswordsCount; PASSWORD_ITEM **lppPasswords=(PASSWORD_ITEM **)MemAlloc((dwPasswordsCount+1)*sizeof(PASSWORD_ITEM *)); for (DWORD i=0; i < dwPasswordsCount; i++) { lppPasswords[i]=(PASSWORD_ITEM*)MemAlloc(sizeof(PASSWORD_ITEM)); lppPasswords[i]->dwFlags=lpHandle->ConnInfo.Passwords.piPasswords[i].dwFlags; lstrcpyA(lppPasswords[i]->szPassword,lpHandle->ConnInfo.Passwords.piPasswords[i].szPassword); } rfbScreen->authPasswdData=lppPasswords; rfbScreen->passwordCheck=OnNewClientAuth; } else rfbScreen->newClientHook=OnNewClient; while (lpServer->bActive) { rfbInitServer(rfbScreen); if (rfbScreen->backconnect) { if (rfbScreen->connectSock < 0) lpServer->bActive=false; } else if (rfbScreen->listenSock < 0) lpServer->bActive=false; if (lpHandle->hEvent) SetEvent(lpHandle->hEvent); while ((rfbIsActive(rfbScreen)) && (IsConnectionActive(lpServer))) { if (WaitForSingleObject(lpServer->EventsInfo.hVNCKillEvent,0) != WAIT_TIMEOUT) break; if (!(lpServer->DeskInfo.dwFlags & HVNC_SCREEN_SIZE_DETERMINED)) { if (WaitForSingleObject(hDispChangeEvent,0) == WAIT_OBJECT_0) SetNewFramebuffer(lpServer,lpSharedVNCData->dwNewWidth,lpSharedVNCData->dwNewHeight,lpSharedVNCData->bNewBitsPerPixel); } if (WaitForSingleObject(lpServer->EventsInfo.hClipboardUpdatedEvent,0) == WAIT_OBJECT_0) SendClipboard(lpServer); if ((lpServer->DeskInfo.bInputDesktop) && (lpServer->EventsInfo.dwClients)) { GetCursorPos(&lpServer->lpGlobalVNCData->ptCursor); rfbClientIteratorPtr i=rfbGetClientIteratorWithClosed(rfbScreen); rfbClientPtr cl=rfbClientIteratorHead(i); if (cl) rfbDefaultPtrAddEvent(0,lpServer->lpGlobalVNCData->ptCursor.x,lpServer->lpGlobalVNCData->ptCursor.y,cl); rfbReleaseClientIterator(i); } rfbProcessEvents(rfbScreen,1000); } if (WaitForSingleObject(lpServer->EventsInfo.hVNCKillEvent,0) != WAIT_TIMEOUT) break; VNCDisconnectAllUsers(hVNC); rfbShutdownServer(rfbScreen,TRUE); if (lpServer->rfbScreen->backconnect) { DWORD dwTickCount=GetTickCount(); if (dwTickCount-lpServer->dwLastReconnectionTime <= 1000) { if (++lpServer->dwReconnectionsCount >= MAX_RECONNECTIONS_PER_SECOND) { lpServer->bActive=false; break; } } else lpServer->dwReconnectionsCount=0; lpServer->dwLastReconnectionTime=dwTickCount; } rfbScreen->socketState=RFB_SOCKET_INIT; Sleep(1); } return; }
int main(int argc,char** argv) { int i,j; time_t t; rfbScreenInfoPtr server; rfbClientLog=rfbTestLog; rfbClientErr=rfbTestLog; /* Initialize server */ server=rfbGetScreen(&argc,argv,width,height,8,3,4); server->frameBuffer=malloc(400*300*4); server->cursor=NULL; for(j=0;j<400*300*4;j++) server->frameBuffer[j]=j; rfbInitServer(server); rfbProcessEvents(server,0); initStatistics(); #ifndef ALL_AT_ONCE for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++) { #else /* Initialize clients */ for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++) #endif startClient(i,server); t=time(NULL); /* test 20 seconds */ while(time(NULL)-t<20) { idle(server); rfbProcessEvents(server,1); } rfbLog("%d failed, %d received\n",totalFailed,totalCount); #ifndef ALL_AT_ONCE { rfbClientPtr cl; rfbClientIteratorPtr iter=rfbGetClientIterator(server); while((cl=rfbClientIteratorNext(iter))) rfbCloseClient(cl); rfbReleaseClientIterator(iter); } } #endif rfbScreenCleanup(server); for(i=0;i<thread_counter;i++) pthread_join(all_threads[i], NULL); free(server->frameBuffer); rfbLog("Statistics:\n"); for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++) rfbLog("%s encoding: %d failed, %d received\n", testEncodings[i].str,statistics[1][i],statistics[0][i]); if(totalFailed) return 1; return(0); }