diff --git a/ChangeLog b/ChangeLog index 827d780..f72130c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2005-05-07 Johannes E. Schindelin + * libvncserver/rfbserver.c: fix memory leak pointed out by Tim Jansen + * libvncserver/{httpd,main,rfbserver,sockets}.c, rfb/rfb.h: + replace "rfbBool socketInitDone" by "enum rfbSocketState + socketState" + 2005-05-03 Karl Runge * libvncserver/main.c: fix leak in rfbDoCopyRect/rfbScheduleCopyRect * configure.ac: guard against empty HAVE_X diff --git a/VisualNaCro/nacro.c b/VisualNaCro/nacro.c index eda2887..9d4e9ed 100644 --- a/VisualNaCro/nacro.c +++ b/VisualNaCro/nacro.c @@ -327,7 +327,11 @@ result_t private_process(resource_t resource,timeout_t timeout_in_seconds,result rfbBool loop; do { loop=rfbProcessEvents(res->server,res->server->deferUpdateTime); - } while(loop && (res->result&return_mask)==0); + } while(loop && (res->result&return_mask)==0 + && rfbIsActive(res->server)); + + if(!rfbIsActive(res->server)) + return RESULT_SHUTDOWN; if((res->result&return_mask)!=0) return res->result; diff --git a/VisualNaCro/nacro.h b/VisualNaCro/nacro.h index ec75630..c4a8581 100644 --- a/VisualNaCro/nacro.h +++ b/VisualNaCro/nacro.h @@ -29,11 +29,12 @@ typedef double timeout_t; /* the return values of process() and friends */ typedef int result_t; /* - * %constant int RESULT_TIMEOUT=1; +%constant int RESULT_TIMEOUT=1; %constant int RESULT_KEY=2; %constant int RESULT_MOUSE=4; %constant int RESULT_SCREEN=8; %constant int RESULT_FOUNDIMAGE=16; +%constant int RESULT_SHUTDOWN=32; */ %} @@ -52,6 +53,7 @@ typedef int result_t; #define RESULT_MOUSE 4 #define RESULT_SCREEN 8 #define RESULT_FOUNDIMAGE 16 +#define RESULT_SHUTDOWN 32 /* init/shutdown */ diff --git a/examples/example.c b/examples/example.c index da1385e..f4a1f08 100644 --- a/examples/example.c +++ b/examples/example.c @@ -168,6 +168,12 @@ void dokey(rfbBool down,rfbKeySym key,rfbClientPtr cl) if(down) { if(key==XK_Escape) rfbCloseClient(cl); + else if(key==XK_F12) + /* close down server, disconnecting clients */ + rfbShutdownServer(cl->screen,TRUE); + else if(key==XK_F11) + /* close down server, but wait for all clients to disconnect */ + rfbShutdownServer(cl->screen,FALSE); else if(key==XK_Page_Up) { initBuffer((unsigned char*)cl->screen->frameBuffer); rfbMarkRectAsModified(cl->screen,0,0,maxx,maxy); @@ -294,7 +300,7 @@ int main(int argc,char** argv) #ifdef USE_OWN_LOOP { int i; - for(i=0;;i++) { + for(i=0;rfbIsActive(rfbScreen);i++) { fprintf(stderr,"%d\r",i); rfbProcessEvents(rfbScreen,100000); } @@ -315,7 +321,6 @@ int main(int argc,char** argv) while(1) sleep(5); /* render(); */ #endif /* BACKGROUND_LOOP */ - rfbFreeCursor(rfbScreen->cursor); free(rfbScreen->frameBuffer); rfbScreenCleanup(rfbScreen); diff --git a/examples/fontsel.c b/examples/fontsel.c index 4aa702c..a2a2f82 100644 --- a/examples/fontsel.c +++ b/examples/fontsel.c @@ -58,13 +58,15 @@ int main(int argc,char** argv) exit(1); } - for(j=0;j<0;j++) + for(j=0;j<0 && rfbIsActive(s);j++) rfbProcessEvents(s,900000); i = rfbSelectBox(s,font,fontlist,10,20,200,300,0xffdfdf,0x602040,2,showFont); rfbLog("Selection: %d: %s\n",i,(i>=0)?fontlist[i]:"cancelled"); rfbFreeFont(font); + free(s->frameBuffer); + rfbScreenCleanup(s); return(0); } diff --git a/libvncserver/httpd.c b/libvncserver/httpd.c index b973bb6..f341d1a 100755 --- a/libvncserver/httpd.c +++ b/libvncserver/httpd.c @@ -111,6 +111,13 @@ rfbHttpInitSockets(rfbScreenInfoPtr rfbScreen) /*AddEnabledDevice(httpListenSock);*/ } +void rfbHttpShutdownSockets(rfbScreenInfoPtr rfbScreen) { + if(rfbScreen->httpSock>-1) { + close(rfbScreen->httpSock); + FD_CLR(rfbScreen->httpSock,&rfbScreen->allFds); + rfbScreen->httpSock=-1; + } +} /* * httpCheckFds is called from ProcessInputEvents to check for input on the diff --git a/libvncserver/main.c b/libvncserver/main.c index 529bf2a..d2dc69f 100644 --- a/libvncserver/main.c +++ b/libvncserver/main.c @@ -543,7 +543,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv, screen->clientHead=0; screen->pointerClient=0; screen->port=5900; - screen->socketInitDone=FALSE; + screen->socketState=RFB_SOCKET_INIT; screen->inetdInitDone = FALSE; screen->inetdSock=-1; @@ -729,7 +729,7 @@ void rfbScreenCleanup(rfbScreenInfoPtr screen) FREE_IF(colourMap.data.bytes); FREE_IF(underCursorBuffer); TINI_MUTEX(screen->cursorMutex); - if(screen->cursor) + if(screen->cursor && screen->cursor->cleanup) rfbFreeCursor(screen->cursor); free(screen); #ifdef LIBVNCSERVER_HAVE_LIBJPEG @@ -751,6 +751,20 @@ void rfbInitServer(rfbScreenInfoPtr screen) #endif } +void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) { + if(disconnectClients) { + rfbClientPtr cl; + rfbClientIteratorPtr iter = rfbGetClientIterator(screen); + while( (cl = rfbClientIteratorNext(iter)) ) + if (cl->sock > -1) + /* we don't care about maxfd here, because the server goes away */ + rfbCloseClient(cl); + } + + rfbShutdownSockets(screen); + rfbHttpShutdownSockets(screen); +} + #ifndef LIBVNCSERVER_HAVE_GETTIMEOFDAY #include #include @@ -820,6 +834,10 @@ rfbProcessEvents(rfbScreenInfoPtr screen,long usec) return result; } +rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo) { + return screenInfo->socketState!=RFB_SOCKET_SHUTDOWN || screenInfo->clientHead!=NULL; +} + void rfbRunEventLoop(rfbScreenInfoPtr screen, long usec, rfbBool runInBackground) { if(runInBackground) { @@ -839,6 +857,6 @@ void rfbRunEventLoop(rfbScreenInfoPtr screen, long usec, rfbBool runInBackground if(usec<0) usec=screen->deferUpdateTime*1000; - while(1) + while(rfbIsActive(screen)) rfbProcessEvents(screen,usec); } diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index e218fea..74f4fbd 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -354,10 +354,7 @@ rfbNewTCPOrUDPClient(rfbScreen,sock,isUDP) if (rfbWriteExact(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 - */ + rfbClientConnectionGone(cl); return NULL; } } diff --git a/libvncserver/sockets.c b/libvncserver/sockets.c index 0aba2dc..9025df8 100755 --- a/libvncserver/sockets.c +++ b/libvncserver/sockets.c @@ -104,10 +104,10 @@ rfbInitSockets(rfbScreenInfoPtr rfbScreen) { in_addr_t iface = rfbScreen->listenInterface; - if (rfbScreen->socketInitDone) + if (rfbScreen->socketState!=RFB_SOCKET_INIT) return; - rfbScreen->socketInitDone = TRUE; + rfbScreen->socketState = RFB_SOCKET_READY; if (rfbScreen->inetdSock != -1) { const int one = 1; @@ -176,6 +176,31 @@ rfbInitSockets(rfbScreenInfoPtr rfbScreen) } } +void rfbShutdownSockets(rfbScreenInfoPtr rfbScreen) +{ + if (rfbScreen->socketState!=RFB_SOCKET_READY) + return; + + rfbScreen->socketState = RFB_SOCKET_SHUTDOWN; + + if(rfbScreen->inetdSock>-1) { + close(rfbScreen->inetdSock); + FD_CLR(rfbScreen->inetdSock,&rfbScreen->allFds); + rfbScreen->inetdSock=-1; + } + + if(rfbScreen->listenSock>-1) { + close(rfbScreen->listenSock); + FD_CLR(rfbScreen->listenSock,&rfbScreen->allFds); + rfbScreen->listenSock=-1; + } + + if(rfbScreen->udpSock>-1) { + close(rfbScreen->udpSock); + FD_CLR(rfbScreen->udpSock,&rfbScreen->allFds); + rfbScreen->udpSock=-1; + } +} /* * rfbCheckFds is called from ProcessInputEvents to check for input on the RFB diff --git a/rfb/rfb.h b/rfb/rfb.h index 660baab..0c9ad21 100644 --- a/rfb/rfb.h +++ b/rfb/rfb.h @@ -116,6 +116,12 @@ enum rfbNewClientAction { RFB_CLIENT_REFUSE }; +enum rfbSocketState { + RFB_SOCKET_INIT, + RFB_SOCKET_READY, + RFB_SOCKET_SHUTDOWN +}; + typedef void (*rfbKbdAddEventProcPtr) (rfbBool down, rfbKeySym keySym, struct _rfbClientRec* cl); typedef void (*rfbKbdReleaseAllKeysProcPtr) (struct _rfbClientRec* cl); typedef void (*rfbPtrAddEventProcPtr) (int buttonMask, int x, int y, struct _rfbClientRec* cl); @@ -178,7 +184,7 @@ typedef struct _rfbScreenInfo fd_set allFds; #endif - rfbBool socketInitDone; + enum rfbSocketState socketState; SOCKET inetdSock; rfbBool inetdInitDone; @@ -500,6 +506,7 @@ extern char rfbEndianTest; extern int rfbMaxClientWait; extern void rfbInitSockets(rfbScreenInfoPtr rfbScreen); +extern void rfbShutdownSockets(rfbScreenInfoPtr rfbScreen); extern void rfbDisconnectUDPSock(rfbScreenInfoPtr rfbScreen); extern void rfbCloseClient(rfbClientPtr cl); extern int rfbReadExact(rfbClientPtr cl, char *buf, int len); @@ -563,6 +570,7 @@ extern void rfbSetClientColourMaps(rfbScreenInfoPtr rfbScreen, int firstColour, /* httpd.c */ extern void rfbHttpInitSockets(rfbScreenInfoPtr rfbScreen); +extern void rfbHttpShutdownSockets(rfbScreenInfoPtr rfbScreen); extern void rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen); @@ -741,6 +749,7 @@ extern rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv, int width,int height,int bitsPerSample,int samplesPerPixel, int bytesPerPixel); extern void rfbInitServer(rfbScreenInfoPtr rfbScreen); +extern void rfbShutdownServer(rfbScreenInfoPtr rfbScreen,rfbBool disconnectClients); extern void rfbNewFramebuffer(rfbScreenInfoPtr rfbScreen,char *framebuffer, int width,int height, int bitsPerSample,int samplesPerPixel, int bytesPerPixel); @@ -761,6 +770,7 @@ extern void rfbRefuseOnHoldClient(rfbClientPtr cl); extern void rfbRunEventLoop(rfbScreenInfoPtr screenInfo, long usec, rfbBool runInBackground); extern rfbBool rfbProcessEvents(rfbScreenInfoPtr screenInfo,long usec); +extern rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo); #endif diff --git a/test/cursortest.c b/test/cursortest.c index 8e98aed..4c75f23 100755 --- a/test/cursortest.c +++ b/test/cursortest.c @@ -343,7 +343,6 @@ int main(int argc,char** argv) /* 40000 are the microseconds to wait on select(), i.e. 0.04 seconds */ rfbRunEventLoop(rfbScreen,40000,FALSE); - rfbFreeCursor(rfbScreen->cursor); free(rfbScreen->frameBuffer); rfbScreenCleanup(rfbScreen); diff --git a/vncterm/LinuxVNC.c b/vncterm/LinuxVNC.c index 0905e74..bfff739 100644 --- a/vncterm/LinuxVNC.c +++ b/vncterm/LinuxVNC.c @@ -137,7 +137,7 @@ int main(int argc,char **argv) sprintf(tty_device,"/dev/vcsa%d",tty); #endif - while(1) { + while(rfbIsActive(console->screen)) { if(!console->currentlyMarking) { tty_file=fopen(tty_device,"rb"); if(!tty_file) { diff --git a/vncterm/VNConsole.c b/vncterm/VNConsole.c index 651546a..ec3002f 100644 --- a/vncterm/VNConsole.c +++ b/vncterm/VNConsole.c @@ -328,7 +328,7 @@ char vcGetCh(vncConsolePtr c) char vcGetChar(vncConsolePtr c) { - while(c->inputCount==0) + while(rfbIsActive(c->screen) && c->inputCount==0) vcProcessEvents(c); return(vcGetCh(c)); } @@ -352,7 +352,8 @@ char *vcGetString(vncConsolePtr c,char *buffer,int bufferSize) count=c->inputSize; c->inputSize=bufferSize; c->inputBuffer=buffer; - while(c->inputCountinputCount-1]!='\n') + while(rfbIsActive(c->screen) + && c->inputCountinputCount-1]!='\n') vcProcessEvents(c); buffer[c->inputCount]=0; c->inputBuffer=bufferBackup; diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c index 092c236..80eef99 100644 --- a/x11vnc/x11vnc.c +++ b/x11vnc/x11vnc.c @@ -9558,7 +9558,7 @@ void reset_rfbport(int old, int new) { screen->autoPort = FALSE; } screen->port = rp; - screen->socketInitDone = FALSE; + screen->socketState = RFB_SOCKET_INIT; if (screen->listenSock > -1) { close(screen->listenSock);