Commit 45a4b4a2 authored by dscho's avatar dscho

changes from Tim Jansen: threading issues, new client can be rejected, and more

parent fbf2c977
......@@ -83,7 +83,7 @@ Whenever you draw something, you have to call
This tells LibVNCServer to send updates to all connected clients.
Before you draw something, be sure to call
rfbUndrawCursor(cl).
rfbUndrawCursor(screen).
This tells LibVNCServer to hide the cursor.
Remark: There are vncviewers out there, which know a cursor encoding, so
that network traffic is low, and also the cursor doesn't need to be
......
......@@ -42,7 +42,7 @@ rfbSendCursorShape(cl)
CARD8 bitmapByte;
pCursor = cl->screen->getCursorPtr(cl);
//if(!pCursor) return TRUE;
/*if(!pCursor) return TRUE;*/
if (cl->useRichCursorEncoding) {
if(pCursor && !pCursor->richSource)
......@@ -227,7 +227,7 @@ rfbCursorPtr rfbMakeXCursor(int width,int height,char* cursorString,char* maskSt
cursor->width=width;
cursor->height=height;
//cursor->backRed=cursor->backGreen=cursor->backBlue=0xffff;
/*cursor->backRed=cursor->backGreen=cursor->backBlue=0xffff;*/
cursor->foreRed=cursor->foreGreen=cursor->foreBlue=0xffff;
cursor->source = (char*)calloc(w,height);
......
......@@ -67,10 +67,11 @@ void clientgone(rfbClientPtr cl)
free(cl->clientData);
}
void newclient(rfbClientPtr cl)
enum rfbNewClientAction newclient(rfbClientPtr cl)
{
cl->clientData = (void*)calloc(sizeof(ClientData),1);
cl->clientGoneHook = clientgone;
return RFB_CLIENT_ACCEPT;
}
/* aux function to draw a line */
......
......@@ -92,7 +92,7 @@ httpInitSockets(rfbScreenInfoPtr rfbScreen)
exit(1);
}
//AddEnabledDevice(httpListenSock);
/*AddEnabledDevice(httpListenSock);*/
}
......@@ -151,7 +151,7 @@ httpCheckFds(rfbScreenInfoPtr rfbScreen)
return;
}
//AddEnabledDevice(httpSock);
/*AddEnabledDevice(httpSock);*/
}
}
......@@ -161,7 +161,7 @@ httpCloseSock(rfbScreenInfoPtr rfbScreen)
{
fclose(rfbScreen->httpFP);
rfbScreen->httpFP = NULL;
//RemoveEnabledDevice(httpSock);
/*RemoveEnabledDevice(httpSock);*/
rfbScreen->httpSock = -1;
}
......
......@@ -41,7 +41,7 @@ char rfbEndianTest = (_BYTE_ORDER == _LITTLE_ENDIAN);
*/
void
rfbLog(char *format, ...)
rfbLog(const char *format, ...)
{
va_list args;
char buf[256];
......@@ -61,7 +61,7 @@ rfbLog(char *format, ...)
UNLOCK(logMutex);
}
void rfbLogPerror(char *str)
void rfbLogPerror(const char *str)
{
rfbLog("%s: %s\n", str, strerror(errno));
}
......@@ -128,7 +128,7 @@ void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,in
} else {
sraRgnOr(cl->modifiedRegion,copyRegion);
}
SIGNAL(cl->updateCond);
TSIGNAL(cl->updateCond);
UNLOCK(cl->updateMutex);
}
......@@ -186,7 +186,7 @@ void rfbMarkRegionAsModified(rfbScreenInfoPtr rfbScreen,sraRegionPtr modRegion)
while((cl=rfbClientIteratorNext(iterator))) {
LOCK(cl->updateMutex);
sraRgnOr(cl->modifiedRegion,modRegion);
SIGNAL(cl->updateCond);
TSIGNAL(cl->updateCond);
UNLOCK(cl->updateMutex);
}
......@@ -281,7 +281,7 @@ clientInput(void *data)
/* Get rid of the output thread. */
LOCK(cl->updateMutex);
SIGNAL(cl->updateCond);
TSIGNAL(cl->updateCond);
UNLOCK(cl->updateMutex);
IF_PTHREADS(pthread_join(output_thread, NULL));
......@@ -290,31 +290,52 @@ clientInput(void *data)
return NULL;
}
void*
static void*
listenerRun(void *data)
{
rfbScreenInfoPtr rfbScreen=(rfbScreenInfoPtr)data;
int client_fd;
struct sockaddr_in peer;
pthread_t client_thread;
rfbClientPtr cl;
int len;
len = sizeof(peer);
/* TODO: this thread wont die by restarting the server */
while ((client_fd = accept(rfbScreen->rfbListenSock,
(struct sockaddr *)&peer, &len)) >= 0) {
(struct sockaddr*)&peer, &len)) >= 0) {
cl = rfbNewClient(rfbScreen,client_fd);
pthread_create(&client_thread, NULL, clientInput, (void *)cl);
len = sizeof(peer);
if (cl && !cl->onHold )
rfbStartOnHoldClient(cl);
}
}
void
rfbStartOnHoldClient(rfbClientPtr cl)
{
pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
}
rfbLog("accept failed\n");
exit(1);
#else
void
rfbStartOnHoldClient(rfbClientPtr cl)
{
cl->onHold = FALSE;
}
#endif
void
void
rfbRefuseOnHoldClient(rfbClientPtr cl)
{
rfbCloseClient(cl);
rfbClientConnectionGone(cl);
}
static void
defaultKbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl)
{
}
......@@ -423,6 +444,11 @@ void doNothingWithClient(rfbClientPtr cl)
{
}
enum rfbNewClientAction defaultNewClientHook(rfbClientPtr cl)
{
return RFB_CLIENT_ACCEPT;
}
rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
int width,int height,int bitsPerSample,int samplesPerPixel,
int bytesPerPixel)
......@@ -435,6 +461,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
if(width&3)
fprintf(stderr,"WARNING: Width (%d) is not a multiple of 4. VncViewer has problems with that.\n",width);
rfbScreen->autoPort=FALSE;
rfbScreen->rfbClientHead=0;
rfbScreen->rfbPort=5900;
rfbScreen->socketInitDone=FALSE;
......@@ -536,7 +563,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
rfbScreen->setXCutText = defaultSetXCutText;
rfbScreen->getCursorPtr = defaultGetCursorPtr;
rfbScreen->setTranslateFunction = rfbSetTranslateFunction;
rfbScreen->newClientHook = doNothingWithClient;
rfbScreen->newClientHook = defaultNewClientHook;
rfbScreen->displayHook = 0;
/* initialize client list and iterator mutex */
......@@ -597,7 +624,7 @@ rfbProcessEvents(rfbScreenInfoPtr rfbScreen,long usec)
i = rfbGetClientIterator(rfbScreen);
cl=rfbClientIteratorNext(i);
while(cl) {
if(cl->sock>=0 && FB_UPDATE_PENDING(cl)) {
if(cl->sock>=0 && (!cl->onHold) && FB_UPDATE_PENDING(cl)) {
if(cl->screen->rfbDeferUpdateTime == 0) {
rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
} else if(cl->startDeferring.tv_usec == 0) {
......
......@@ -26,6 +26,11 @@
* USA.
*/
#if(defined __cplusplus)
extern "C"
{
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
......@@ -90,7 +95,7 @@ typedef unsigned long KeySym;
#undef SOCKET
#define SOCKET int
#else
int max(int,int);
#define max(a,b) (((a)>(b))?(a):(b))
#include <sys/time.h>
#include <netinet/in.h>
#define SOCKET int
......@@ -116,7 +121,7 @@ int max(int,int);
#define MUTEX(mutex) pthread_mutex_t (mutex)
#define INIT_MUTEX(mutex) pthread_mutex_init(&(mutex),NULL)
#define TINI_MUTEX(mutex) pthread_mutex_destroy(&(mutex))
#define SIGNAL(cond) pthread_cond_signal(&(cond))
#define TSIGNAL(cond) pthread_cond_signal(&(cond))
#define WAIT(cond,mutex) pthread_cond_wait(&(cond),&(mutex))
#define COND(cond) pthread_cond_t (cond)
#define INIT_COND(cond) pthread_cond_init(&(cond),NULL)
......@@ -129,7 +134,7 @@ int max(int,int);
#define MUTEX(mutex)
#define INIT_MUTEX(mutex)
#define TINI_MUTEX(mutex)
#define SIGNAL(cond)
#define TSIGNAL(cond)
#define WAIT(cond,mutex) this_is_unsupported
#define COND(cond)
#define INIT_COND(cond)
......@@ -151,19 +156,25 @@ int max(int,int);
#define MAX_ENCODINGS 10
struct rfbClientRec;
struct rfbScreenInfo;
struct _rfbClientRec;
struct _rfbScreenInfo;
struct rfbCursor;
typedef void (*KbdAddEventProcPtr) (Bool down, KeySym keySym, struct rfbClientRec* cl);
typedef void (*KbdReleaseAllKeysProcPtr) (struct rfbClientRec* cl);
typedef void (*PtrAddEventProcPtr) (int buttonMask, int x, int y, struct rfbClientRec* cl);
typedef void (*SetXCutTextProcPtr) (char* str,int len, struct rfbClientRec* cl);
typedef struct rfbCursor* (*GetCursorProcPtr) (struct rfbClientRec* pScreen);
typedef Bool (*SetTranslateFunctionProcPtr)(struct rfbClientRec* cl);
typedef Bool (*PasswordCheckProcPtr)(struct rfbClientRec* cl,char* encryptedPassWord,int len);
typedef void (*NewClientHookPtr)(struct rfbClientRec* cl);
typedef void (*DisplayHookPtr)(struct rfbClientRec* cl);
enum rfbNewClientAction {
RFB_CLIENT_ACCEPT,
RFB_CLIENT_ON_HOLD,
RFB_CLIENT_REFUSE
};
typedef void (*KbdAddEventProcPtr) (Bool down, KeySym keySym, struct _rfbClientRec* cl);
typedef void (*KbdReleaseAllKeysProcPtr) (struct _rfbClientRec* cl);
typedef void (*PtrAddEventProcPtr) (int buttonMask, int x, int y, struct _rfbClientRec* cl);
typedef void (*SetXCutTextProcPtr) (char* str,int len, struct _rfbClientRec* cl);
typedef struct rfbCursor* (*GetCursorProcPtr) (struct _rfbClientRec* pScreen);
typedef Bool (*SetTranslateFunctionProcPtr)(struct _rfbClientRec* cl);
typedef Bool (*PasswordCheckProcPtr)(struct _rfbClientRec* cl,char* encryptedPassWord,int len);
typedef enum rfbNewClientAction (*NewClientHookPtr)(struct _rfbClientRec* cl);
typedef void (*DisplayHookPtr)(struct _rfbClientRec* cl);
typedef struct {
CARD32 count;
......@@ -180,7 +191,7 @@ typedef struct {
* rfbProcessEvents for each of these.
*/
typedef struct
typedef struct _rfbScreenInfo
{
int width;
int paddedWidthInBytes;
......@@ -246,6 +257,7 @@ typedef struct
char* desktopName;
char rfbThisHost[255];
Bool autoPort;
int rfbPort;
SOCKET rfbListenSock;
int maxSock;
......@@ -258,7 +270,7 @@ typedef struct
int udpPort;
SOCKET udpSock;
struct rfbClientRec* udpClient;
struct _rfbClientRec* udpClient;
Bool udpSockConnected;
struct sockaddr_in udpRemoteAddr;
......@@ -282,7 +294,7 @@ typedef struct
Bool rfbAlwaysShared;
Bool rfbNeverShared;
Bool rfbDontDisconnect;
struct rfbClientRec* rfbClientHead;
struct _rfbClientRec* rfbClientHead;
/* cursor */
int cursorX, cursorY,underCursorBufferLen;
......@@ -346,9 +358,9 @@ typedef struct sraRegion* sraRegionPtr;
* Per-client structure.
*/
typedef void (*ClientGoneHookPtr)(struct rfbClientRec* cl);
typedef void (*ClientGoneHookPtr)(struct _rfbClientRec* cl);
typedef struct rfbClientRec {
typedef struct _rfbClientRec {
/* back pointer to the screen */
rfbScreenInfoPtr screen;
......@@ -364,6 +376,10 @@ typedef struct rfbClientRec {
SOCKET sock;
char *host;
#ifdef HAVE_PTHREADS
pthread_t client_thread;
#endif
/* Possible client states: */
enum {
RFB_PROTOCOL_VERSION, /* establishing protocol version */
......@@ -373,6 +389,7 @@ typedef struct rfbClientRec {
} state;
Bool reverseConnection;
Bool onHold;
Bool readyForSetColourMapEntries;
Bool useCopyRect;
int preferredEncoding;
......@@ -477,8 +494,8 @@ typedef struct rfbClientRec {
Bool enableBackChannel;
#endif
struct rfbClientRec *prev;
struct rfbClientRec *next;
struct _rfbClientRec *prev;
struct _rfbClientRec *next;
#ifdef HAVE_PTHREADS
/* whenever a client is referenced, the refCount has to be incremented
......@@ -741,8 +758,8 @@ extern void rfbProcessSizeArguments(int* width,int* height,int* bpp,int* argc, c
/* main.c */
extern void rfbLog(char *format, ...);
extern void rfbLogPerror(char *str);
extern void rfbLog(const char *format, ...);
extern void rfbLogPerror(const char *str);
void rfbScheduleCopyRect(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2,int dx,int dy);
void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy);
......@@ -753,6 +770,7 @@ void rfbDoCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,i
void rfbMarkRectAsModified(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2);
void rfbMarkRegionAsModified(rfbScreenInfoPtr rfbScreen,sraRegionPtr modRegion);
void doNothingWithClient(rfbClientPtr cl);
enum rfbNewClientAction defaultNewClientHook(rfbClientPtr cl);
/* to check against plain passwords */
Bool rfbCheckPasswordByList(rfbClientPtr cl,char* response,int len);
......@@ -764,6 +782,12 @@ extern rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
extern void rfbInitServer(rfbScreenInfoPtr rfbScreen);
extern void rfbScreenCleanup(rfbScreenInfoPtr screenInfo);
/* functions to accept/refuse a client that has been put on hold
by a NewClientHookPtr function. Must not be called in other
situations. */
extern void rfbStartOnHoldClient(rfbClientPtr cl);
extern void rfbRefuseOnHoldClient(rfbClientPtr cl);
/* call one of these two functions to service the vnc clients.
usec are the microseconds the select on the fds waits.
if you are using the event loop, set this to some value > 0, so the
......@@ -773,3 +797,7 @@ extern void rfbRunEventLoop(rfbScreenInfoPtr screenInfo, long usec, Bool runInBa
extern void rfbProcessEvents(rfbScreenInfoPtr screenInfo,long usec);
#endif
#if(defined __cplusplus)
}
#endif
......@@ -61,7 +61,7 @@ void rfbDecrClientRef(rfbClientPtr cl)
LOCK(cl->refCountMutex);
cl->refCount--;
if(cl->refCount<=0) /* just to be sure also < 0 */
SIGNAL(cl->deleteCond);
TSIGNAL(cl->deleteCond);
UNLOCK(cl->refCountMutex);
}
#endif
......@@ -271,14 +271,29 @@ rfbNewTCPOrUDPClient(rfbScreen,sock,isUDP)
if (WriteExact(cl, pv, sz_rfbProtocolVersionMsg) < 0) {
rfbLogPerror("rfbNewClient: write");
rfbCloseClient(cl);
/* TODO: memory leak here (cl is never freed)
* can rfbClientConnectionGone called at this time?
* tim@tjansen.de
*/
return NULL;
}
}
cl->clientData = NULL;
cl->clientGoneHook = doNothingWithClient;
cl->screen->newClientHook(cl);
switch (cl->screen->newClientHook(cl)) {
case RFB_CLIENT_ON_HOLD:
cl->onHold = TRUE;
break;
case RFB_CLIENT_ACCEPT:
cl->onHold = FALSE;
break;
case RFB_CLIENT_REFUSE:
rfbCloseClient(cl);
rfbClientConnectionGone(cl);
cl = NULL;
break;
}
return cl;
}
......@@ -781,7 +796,7 @@ rfbProcessClientNormalMessage(cl)
sraRgnOr(cl->modifiedRegion,tmpRegion);
sraRgnSubtract(cl->copyRegion,tmpRegion);
}
SIGNAL(cl->updateCond);
TSIGNAL(cl->updateCond);
UNLOCK(cl->updateMutex);
sraRgnDestroy(tmpRegion);
......@@ -1431,7 +1446,7 @@ rfbProcessUDPInput(rfbScreenInfoPtr rfbScreen)
rfbClientPtr cl=rfbScreen->udpClient;
rfbClientToServerMsg msg;
if(!cl)
if((!cl) || cl->onHold)
return;
if ((n = read(rfbScreen->udpSock, (char *)&msg, sizeof(msg))) <= 0) {
......
......@@ -69,9 +69,10 @@ struct timeval
#include "rfb.h"
//#ifndef WIN32
/*#ifndef WIN32
int max(int i,int j) { return(i<j?j:i); }
//#endif
#endif
*/
int rfbMaxClientWait = 20000; /* time (ms) after which we decide client has
gone away - needed to stop us hanging */
......@@ -111,7 +112,28 @@ rfbInitSockets(rfbScreenInfoPtr rfbScreen)
return;
}
if(rfbScreen->rfbPort>0) {
if(rfbScreen->autoPort) {
int i;
rfbLog("Autoprobing TCP port \n");
for (i = 5900; i < 6000; i++) {
if ((rfbScreen->rfbListenSock = ListenOnTCPPort(i)) >= 0) {
rfbScreen->rfbPort = i;
break;
}
}
if (i >= 6000) {
rfbLogPerror("Failure autoprobing");
exit(1);
}
rfbLog("Autoprobing selected port %d\n", rfbScreen->rfbPort);
FD_ZERO(&(rfbScreen->allFds));
FD_SET(rfbScreen->rfbListenSock, &(rfbScreen->allFds));
rfbScreen->maxFd = rfbScreen->rfbListenSock;
}
else if(rfbScreen->rfbPort>0) {
rfbLog("Listening for VNC connections on TCP port %d\n", rfbScreen->rfbPort);
if ((rfbScreen->rfbListenSock = ListenOnTCPPort(rfbScreen->rfbPort)) < 0) {
......@@ -204,7 +226,7 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
rfbLog("Got connection from client %s\n", inet_ntoa(addr.sin_addr));
rfbNewClient(rfbScreen,sock);
FD_CLR(rfbScreen->rfbListenSock, &fds);
if (--nfds == 0)
return;
......@@ -248,6 +270,8 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
i = rfbGetClientIterator(rfbScreen);
while((cl = rfbClientIteratorNext(i))) {
if (cl->onHold)
continue;
if (FD_ISSET(cl->sock, &fds) && FD_ISSET(cl->sock, &(rfbScreen->allFds)))
rfbProcessClientMessage(cl);
}
......@@ -268,10 +292,12 @@ rfbCloseClient(cl)
rfbClientPtr cl;
{
LOCK(cl->updateMutex);
FD_CLR(cl->sock,&(cl->screen->allFds));
close(cl->sock);
cl->sock = -1;
SIGNAL(cl->updateCond);
if (cl->sock != -1) {
FD_CLR(cl->sock,&(cl->screen->allFds));
close(cl->sock);
cl->sock = -1;
}
TSIGNAL(cl->updateCond);
UNLOCK(cl->updateMutex);
}
......@@ -360,7 +386,7 @@ ReadExact(cl, buf, len)
FD_SET(sock, &fds);
tv.tv_sec = rfbMaxClientWait / 1000;
tv.tv_usec = (rfbMaxClientWait % 1000) * 1000;
n = select(sock+1, &fds, NULL, NULL, &tv);
n = select(sock+1, &fds, NULL, &fds, &tv);
if (n < 0) {
rfbLogPerror("ReadExact: select");
return n;
......
......@@ -24,7 +24,7 @@
* USA.
*/
//#include <stdio.h>
/*#include <stdio.h>*/
#include "rfb.h"
#ifdef WIN32
......@@ -35,7 +35,6 @@
#include <jpeglib.h>
/* Note: The following constant should not be changed. */
#define TIGHT_MIN_TO_COMPRESS 12
......
......@@ -259,8 +259,9 @@ rfbSetTranslateFunction(cl)
#endif
(cl->screen->rfbServerFormat.bitsPerPixel != 32))
{
rfbLog("%s: server bits per pixel not 8, 16 or 32\n",
"rfbSetTranslateFunction");
rfbLog("%s: server bits per pixel not 8, 16 or 32 (is %d)\n",
"rfbSetTranslateFunction",
cl->screen->rfbServerFormat.bitsPerPixel);
rfbCloseClient(cl);
return FALSE;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment