This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch master in repository x2gokdrive. commit 3c053c3e65d3da02546ab36d09fcd6f182fad842 Author: Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> Date: Fri Jun 11 12:18:03 2021 -0500 move calling of possibly thread-unsafe ospoll functions (SetNotifyFd, RemoveNotifyFd) to main thread. --- debian/changelog | 2 + x2gokdriveremote.c | 567 ++++++++++++++++++++++++++++------------------------- x2gokdriveremote.h | 2 + 3 files changed, 305 insertions(+), 266 deletions(-) diff --git a/debian/changelog b/debian/changelog index c15f816..88e0b7d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -20,6 +20,8 @@ x2gokdrive (0.0.0.1-0x2go1) UNRELEASED; urgency=medium - fix crashing if client is sending unrequested selection. - extended clipboard support for HTML client. - add name of the thread to the debug output. + - move calling of possibly thread-unsafe ospoll functions (SetNotifyFd, + RemoveNotifyFd) to main thread. [ Mihai Moldovan ] * Initial release: diff --git a/x2gokdriveremote.c b/x2gokdriveremote.c index 501ecfe..f317cb3 100644 --- a/x2gokdriveremote.c +++ b/x2gokdriveremote.c @@ -68,12 +68,10 @@ void restartTimerOnInit(void) static -void cancelThreadBeforeStart(void) +void cancelBeforeStart(void) { - shutdown(remoteVars.serversock, SHUT_RDWR); - close(remoteVars.serversock); - pthread_cancel(remoteVars.send_thread_id); - remoteVars.send_thread_id=0; + EPHYR_DBG("Closing server connection"); + close_server_socket(); setAgentState(SUSPENDED); } @@ -100,7 +98,7 @@ void remote_handle_signal(int signum) TimerFree(remoteVars.checkConnectionTimer); remoteVars.checkConnectionTimer=0; } - cancelThreadBeforeStart(); + cancelBeforeStart(); return; } case RUNNING: @@ -1440,315 +1438,212 @@ void *send_frame_thread (void *threadid) debug_sendThreadId=pthread_self(); - while (1) + while(1) { - EPHYR_DBG ("waiting for TCP connection\n"); - remoteVars.clientsock = accept ( remoteVars.serversock, (struct sockaddr *) &remoteVars.address, &remoteVars.addrlen ); - if (remoteVars.clientsock <= 0) + + pthread_mutex_lock(&remoteVars.sendqueue_mutex); + if(!remoteVars.client_connected) { - EPHYR_DBG( "ACCEPT ERROR OR CANCELD!\n"); + EPHYR_DBG ("TCP connection closed\n"); + shutdown(remoteVars.clientsock, SHUT_RDWR); + close(remoteVars.clientsock); + + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); break; } - EPHYR_DBG ("Connection from (%s)...\n", inet_ntoa (remoteVars.address.sin_addr)); + remoteVars.client_connected=TRUE; + + //check if we should send the server version to client + if(remoteVars.client_version && ! remoteVars.server_version_sent) + { + //the client supports versions and we didn't send our version yet + remote_sendVersion(); + } + - if(strlen(remoteVars.acceptAddr)) + + if(!remoteVars.first_sendqueue_element && !remoteVars.firstCursor && !remoteVars.selstruct.firstOutputChunk) { - struct addrinfo hints, *res; - int errcode; + /* sleep if frame queue is empty */ + pthread_cond_wait(&remoteVars.have_sendqueue_cond, &remoteVars.sendqueue_mutex); + } - memset (&hints, 0, sizeof (hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags |= AI_CANONNAME; + /* mutex is locked on this point */ - errcode = getaddrinfo (remoteVars.acceptAddr, NULL, &hints, &res); - if (errcode != 0 || !res) + //only send output selection chunks if there are no frames and cursors in the queue + //selections can take a lot of bandwidth and have less priority + if(remoteVars.selstruct.firstOutputChunk && !remoteVars.first_sendqueue_element && !remoteVars.firstCursor) + { + //get chunk from queue + struct OutputChunk* chunk=remoteVars.selstruct.firstOutputChunk; + remoteVars.selstruct.firstOutputChunk=chunk->next; + if(!remoteVars.selstruct.firstOutputChunk) { - EPHYR_DBG ("ERROR LOOKUP %s", remoteVars.acceptAddr); - terminateServer(-1); + remoteVars.selstruct.lastOutputChunk=NULL; } - if( ((struct sockaddr_in *) (res->ai_addr))->sin_addr.s_addr != remoteVars.address.sin_addr.s_addr) + + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + //send chunk + send_output_selection(chunk); + //free chunk and it's data + if(chunk->data) { - EPHYR_DBG("Connection only allowed from %s",inet_ntoa ( ((struct sockaddr_in *)(res->ai_addr))->sin_addr)); - shutdown(remoteVars.clientsock, SHUT_RDWR); - close(remoteVars.clientsock); - continue; + free(chunk->data); } - } - if(strlen(remoteVars.cookie)) - { - char msg[33]; - int length=32; - int ready=0; + // EPHYR_DBG(" REMOVE CHUNK %p %p %p", remoteVars.selstruct.firstOutputChunk, remoteVars.selstruct.lastOutputChunk, chunk); + free(chunk); -// EPHYR_DBG("Checking cookie: %s",remoteVars.cookie); + pthread_mutex_lock(&remoteVars.sendqueue_mutex); + } - while(ready<length) + //check if we need to request the selection from client + if(remoteVars.selstruct.requestSelection[PRIMARY] || remoteVars.selstruct.requestSelection[CLIPBOARD]) + { + for(r=PRIMARY; r<=CLIPBOARD; ++r) { - int chunk=read(remoteVars.clientsock, msg+ready, 32-ready); - - if(chunk<=0) + if(remoteVars.selstruct.requestSelection[r]) { - EPHYR_DBG("READ COOKIE ERROR"); - shutdown(remoteVars.clientsock, SHUT_RDWR); - close(remoteVars.clientsock); - continue; - } - ready+=chunk; + remoteVars.selstruct.requestSelection[r]=FALSE; - EPHYR_DBG("got %d COOKIE BYTES from client", ready); - } - if(strncmp(msg,remoteVars.cookie,32)) - { - EPHYR_DBG("Wrong cookie"); - shutdown(remoteVars.clientsock, SHUT_RDWR); - close(remoteVars.clientsock); - continue; + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + //send request for selection + request_selection_from_client(r); + + pthread_mutex_lock(&remoteVars.sendqueue_mutex); + } } - EPHYR_DBG("Cookie approved"); - } - else - { - EPHYR_DBG("Warning: not checking client's cookie"); } + if(remoteVars.firstCursor) + { + /* get cursor from queue, delete it from queue, unlock mutex and send cursor. After sending free cursor */ + struct cursorFrame* cframe=remoteVars.firstCursor; + if(remoteVars.firstCursor->next) + remoteVars.firstCursor=remoteVars.firstCursor->next; + else + remoteVars.firstCursor=remoteVars.lastCursor=0; + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + send_cursor(cframe); + if(cframe->data) + free(cframe->data); + free(cframe); - pthread_mutex_lock(&remoteVars.sendqueue_mutex); - //only accept one client, close server socket - shutdown(remoteVars.serversock, SHUT_RDWR); - close(remoteVars.serversock); -#if XORG_VERSION_CURRENT >= 11900000 - SetNotifyFd(remoteVars.clientsock, clientReadNotify, X_NOTIFY_READ, NULL); -#endif /* XORG_VERSION_CURRENT */ - remoteVars.client_connected=TRUE; - remoteVars.server_version_sent=FALSE; - set_client_version(0,0); - if(remoteVars.checkConnectionTimer) - { - TimerFree(remoteVars.checkConnectionTimer); - remoteVars.checkConnectionTimer=0; } - remoteVars.client_initialized=FALSE; - remoteVars.con_start_time=time(NULL); - remoteVars.data_sent=0; - remoteVars.data_copy=0; - remoteVars.evBufferOffset=0; - setAgentState(RUNNING); - - pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - - while(1) + else { - pthread_mutex_lock(&remoteVars.sendqueue_mutex); - if(!remoteVars.client_connected) - { - EPHYR_DBG ("TCP connection closed\n"); -#if XORG_VERSION_CURRENT >= 11900000 - RemoveNotifyFd(remoteVars.clientsock); -#endif /* XORG_VERSION_CURRENT */ - shutdown(remoteVars.clientsock, SHUT_RDWR); - close(remoteVars.clientsock); - - pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - break; - } - remoteVars.client_connected=TRUE; - - //check if we should send the server version to client - if(remoteVars.client_version && ! remoteVars.server_version_sent) - { - //the client supports versions and we didn't send our version yet - remote_sendVersion(); - } + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + } + pthread_mutex_lock(&remoteVars.sendqueue_mutex); + if(remoteVars.first_sendqueue_element) + { + int elems=queue_elements(); + struct cache_elem* frame = NULL; + struct sendqueue_element* current = NULL; + uint32_t x, y = 0; + int32_t width, height = 0; - if(!remoteVars.first_sendqueue_element && !remoteVars.firstCursor && !remoteVars.selstruct.firstOutputChunk) + if(remoteVars.maxfr<elems) { - /* sleep if frame queue is empty */ - pthread_cond_wait(&remoteVars.have_sendqueue_cond, &remoteVars.sendqueue_mutex); + remoteVars.maxfr=elems; } + // EPHYR_DBG("have %d max frames in queue, current %d", remoteVars.,elems); + frame=remoteVars.first_sendqueue_element->frame; - /* mutex is locked on this point */ - - //only send output selection chunks if there are no frames and cursors in the queue - //selections can take a lot of bandwidth and have less priority - if(remoteVars.selstruct.firstOutputChunk && !remoteVars.first_sendqueue_element && !remoteVars.firstCursor) + /* delete first element from frame queue */ + current=remoteVars.first_sendqueue_element; + if(remoteVars.first_sendqueue_element->next) { - //get chunk from queue - struct OutputChunk* chunk=remoteVars.selstruct.firstOutputChunk; - remoteVars.selstruct.firstOutputChunk=chunk->next; - if(!remoteVars.selstruct.firstOutputChunk) - { - remoteVars.selstruct.lastOutputChunk=NULL; - } - - pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - //send chunk - send_output_selection(chunk); - //free chunk and it's data - if(chunk->data) - { - free(chunk->data); - } -// EPHYR_DBG(" REMOVE CHUNK %p %p %p", remoteVars.selstruct.firstOutputChunk, remoteVars.selstruct.lastOutputChunk, chunk); - free(chunk); - - pthread_mutex_lock(&remoteVars.sendqueue_mutex); + remoteVars.first_sendqueue_element=remoteVars.first_sendqueue_element->next; } - - //check if we need to request the selection from client - if(remoteVars.selstruct.requestSelection[PRIMARY] || remoteVars.selstruct.requestSelection[CLIPBOARD]) + else { - for(r=PRIMARY; r<=CLIPBOARD; ++r) - { - if(remoteVars.selstruct.requestSelection[r]) - { - remoteVars.selstruct.requestSelection[r]=FALSE; - - pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - //send request for selection - request_selection_from_client(r); - - pthread_mutex_lock(&remoteVars.sendqueue_mutex); - } - } + remoteVars.first_sendqueue_element=remoteVars.last_sendqueue_element=NULL; } + x=current->x; + y=current->y; + width=current->width; + height=current->height; + free(current); - if(remoteVars.firstCursor) + if(frame) { - /* get cursor from queue, delete it from queue, unlock mutex and send cursor. After sending free cursor */ - struct cursorFrame* cframe=remoteVars.firstCursor; + uint32_t crc = frame->crc; + uint32_t frame_width=frame->width; + uint32_t frame_height=frame->height; - if(remoteVars.firstCursor->next) - remoteVars.firstCursor=remoteVars.firstCursor->next; - else - remoteVars.firstCursor=remoteVars.lastCursor=0; + /* unlock sendqueue for main thread */ pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - send_cursor(cframe); - if(cframe->data) - free(cframe->data); - free(cframe); - + send_frame(frame_width, frame_height, x, y, crc, frame->regions); } else { + EPHYR_DBG("Sending main image or screen update"); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + sendMainImageFromSendThread(width, height, x, y); } pthread_mutex_lock(&remoteVars.sendqueue_mutex); - if(remoteVars.first_sendqueue_element) + if(frame) { - int elems=queue_elements(); - struct cache_elem* frame = NULL; - struct sendqueue_element* current = NULL; - uint32_t x, y = 0; - int32_t width, height = 0; + frame->sent=TRUE; + frame->busy--; + if(frame->source) + frame->source->busy--; + frame->source=0; - if(remoteVars.maxfr<elems) + for(int i=0;i<9;++i) { - remoteVars.maxfr=elems; - } -// EPHYR_DBG("have %d max frames in queue, current %d", remoteVars.,elems); - frame=remoteVars.first_sendqueue_element->frame; - - /* delete first element from frame queue */ - current=remoteVars.first_sendqueue_element; - if(remoteVars.first_sendqueue_element->next) - { - remoteVars.first_sendqueue_element=remoteVars.first_sendqueue_element->next; - } - else - { - remoteVars.first_sendqueue_element=remoteVars.last_sendqueue_element=NULL; - } - x=current->x; - y=current->y; - width=current->width; - height=current->height; - free(current); - - if(frame) - { - uint32_t crc = frame->crc; - uint32_t frame_width=frame->width; - uint32_t frame_height=frame->height; - - /* unlock sendqueue for main thread */ - - pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - send_frame(frame_width, frame_height, x, y, crc, frame->regions); - } - else - { - EPHYR_DBG("Sending main image or screen update"); - - pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - sendMainImageFromSendThread(width, height, x, y); - } - - - pthread_mutex_lock(&remoteVars.sendqueue_mutex); - if(frame) - { - frame->sent=TRUE; - frame->busy--; - if(frame->source) - frame->source->busy--; - frame->source=0; - - for(int i=0;i<9;++i) + if(frame->regions[i].size) { - if(frame->regions[i].size) - { - free(frame->regions[i].compressed_data); - frame->regions[i].size=0; - } - frame->regions[i].source_crc=0; - frame->regions[i].rect.size.width=0; + free(frame->regions[i].compressed_data); + frame->regions[i].size=0; } + frame->regions[i].source_crc=0; + frame->regions[i].rect.size.width=0; } + } - if(remoteVars.cache_size>CACHEMAXSIZE) - { - clear_cache_data(CACHEMAXSIZE); - } - if(remoteVars.cache_size>CACHEMAXELEMENTS) - { - clear_frame_cache(CACHEMAXELEMENTS); - } + if(remoteVars.cache_size>CACHEMAXSIZE) + { + clear_cache_data(CACHEMAXSIZE); + } + if(remoteVars.cache_size>CACHEMAXELEMENTS) + { + clear_frame_cache(CACHEMAXELEMENTS); + } - if(remoteVars.first_deleted_elements) - { - send_deleted_elements(); - } + if(remoteVars.first_deleted_elements) + { + send_deleted_elements(); + } - if(remoteVars.first_deleted_cursor) - { - send_deleted_cursors(); - } + if(remoteVars.first_deleted_cursor) + { + send_deleted_cursors(); + } - pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - remoteVars.framenum++; - } - else - { + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + remoteVars.framenum++; + } + else + { - pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - } + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } - pthread_exit(0); } -// #warning add some conditions to exit thread properly + EPHYR_DBG("exit sending thread"); + remoteVars.send_thread_id=0; pthread_exit(0); } @@ -1933,6 +1828,11 @@ void disconnect_client(void) clear_frame_cache(0); freeCursors(); clear_output_selection(); +#if XORG_VERSION_CURRENT >= 11900000 + EPHYR_DBG("Remove notify FD for client sock %d",remoteVars.clientsock); + RemoveNotifyFd(remoteVars.clientsock); +#endif /* XORG_VERSION_CURRENT */ + pthread_cond_signal(&remoteVars.have_sendqueue_cond); @@ -2475,22 +2375,38 @@ void pollEvents(void) { //EPHYR_DBG("polling events"); struct pollfd fds[2]; - int nfds = 1; - BOOL con; + int nfds = 1; + BOOL client = FALSE; + + memset(fds, 0 , sizeof(fds)); pthread_mutex_lock(&remoteVars.sendqueue_mutex); - con=remoteVars.client_connected; - pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - if(!con) + //We are in connected state, poll client socket + if(remoteVars.client_connected) + { + client = TRUE; + fds[0].fd = remoteVars.clientsock; + } //we are in connecting state, poll server socket + else if(remoteVars.serversock != -1) + { + fds[0].fd = remoteVars.serversock; + } + else //not polling any sockets + { + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); return; + } + + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - memset(fds, 0 , sizeof(fds)); - fds[0].fd = remoteVars.clientsock; fds[0].events = POLLIN; if(poll(fds, nfds, 0)) { - clientReadNotify(remoteVars.clientsock, 0, NULL); + if(client) + clientReadNotify(fds[0].fd, 0, NULL); + else + serverAcceptNotify(fds[0].fd, 0, NULL); } } #endif /* XORG_VERSION_CURRENT */ @@ -2505,7 +2421,7 @@ unsigned int checkSocketConnection(OsTimerPtr timer, CARD32 time, void* args) if(!remoteVars.client_connected) { EPHYR_DBG("NO CLIENT CONNECTION SINCE %d seconds",ACCEPT_TIMEOUT); - cancelThreadBeforeStart(); + cancelBeforeStart(); } else { @@ -2516,10 +2432,128 @@ unsigned int checkSocketConnection(OsTimerPtr timer, CARD32 time, void* args) return 0; } +void serverAcceptNotify(int fd, int ready_sock, void *data) +{ + int ret; + remoteVars.clientsock = accept ( remoteVars.serversock, (struct sockaddr *) &remoteVars.address, &remoteVars.addrlen ); + if (remoteVars.clientsock <= 0) + { + EPHYR_DBG( "ACCEPT ERROR OR CANCELD!\n"); + return; + } + EPHYR_DBG ("Connection from (%s)...\n", inet_ntoa (remoteVars.address.sin_addr)); + + //only accept one client, close server socket + close_server_socket(); + + if(strlen(remoteVars.acceptAddr)) + { + struct addrinfo hints, *res; + int errcode; + + memset (&hints, 0, sizeof (hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags |= AI_CANONNAME; + + errcode = getaddrinfo (remoteVars.acceptAddr, NULL, &hints, &res); + if (errcode != 0 || !res) + { + EPHYR_DBG ("ERROR LOOKUP %s", remoteVars.acceptAddr); + terminateServer(-1); + } + if( ((struct sockaddr_in *) (res->ai_addr))->sin_addr.s_addr != remoteVars.address.sin_addr.s_addr) + { + EPHYR_DBG("Connection only allowed from %s",inet_ntoa ( ((struct sockaddr_in *)(res->ai_addr))->sin_addr)); + shutdown(remoteVars.clientsock, SHUT_RDWR); + close(remoteVars.clientsock); + return; + } + } + if(strlen(remoteVars.cookie)) + { + char msg[33]; + int length=32; + int ready=0; + + // EPHYR_DBG("Checking cookie: %s",remoteVars.cookie); + + while(ready<length) + { + int chunk=read(remoteVars.clientsock, msg+ready, 32-ready); + + if(chunk<=0) + { + EPHYR_DBG("READ COOKIE ERROR"); + shutdown(remoteVars.clientsock, SHUT_RDWR); + close(remoteVars.clientsock); + continue; + } + ready+=chunk; + + EPHYR_DBG("got %d COOKIE BYTES from client", ready); + } + if(strncmp(msg,remoteVars.cookie,32)) + { + EPHYR_DBG("Wrong cookie"); + shutdown(remoteVars.clientsock, SHUT_RDWR); + close(remoteVars.clientsock); + return; + } + EPHYR_DBG("Cookie approved"); + } + else + { + EPHYR_DBG("Warning: not checking client's cookie"); + } + + pthread_mutex_lock(&remoteVars.sendqueue_mutex); + #if XORG_VERSION_CURRENT >= 11900000 + EPHYR_DBG("Set notify FD for client sock: %d",remoteVars.clientsock); + SetNotifyFd(remoteVars.clientsock, clientReadNotify, X_NOTIFY_READ, NULL); + #endif /* XORG_VERSION_CURRENT */ + remoteVars.client_connected=TRUE; + remoteVars.server_version_sent=FALSE; + set_client_version(0,0); + if(remoteVars.checkConnectionTimer) + { + TimerFree(remoteVars.checkConnectionTimer); + remoteVars.checkConnectionTimer=0; + } + remoteVars.client_initialized=FALSE; + remoteVars.con_start_time=time(NULL); + remoteVars.data_sent=0; + remoteVars.data_copy=0; + remoteVars.evBufferOffset=0; + setAgentState(RUNNING); + + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + + //here start a send thread + ret = pthread_create(&remoteVars.send_thread_id, NULL, send_frame_thread, (void *)remoteVars.send_thread_id); + if (ret) + { + EPHYR_DBG("ERROR; return code from pthread_create() is %d\n", ret); + terminateServer(-1); + } +} + + +void close_server_socket(void) +{ +#if XORG_VERSION_CURRENT >= 11900000 + EPHYR_DBG("Remove notify FD for server sock %d",remoteVars.serversock); + RemoveNotifyFd(remoteVars.serversock); +#endif /* XORG_VERSION_CURRENT */ + shutdown(remoteVars.serversock, SHUT_RDWR); + close(remoteVars.serversock); + remoteVars.serversock=-1; +} + + void open_socket(void) { const int y = 1; - int ret = -1; remoteVars.serversock=socket (AF_INET, SOCK_STREAM, 0); setsockopt( remoteVars.serversock, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(int)); @@ -2553,14 +2587,13 @@ void open_socket(void) remoteVars.checkConnectionTimer=TimerSet(0,0,ACCEPT_TIMEOUT, checkSocketConnection, NULL); - ret = pthread_create(&remoteVars.send_thread_id, NULL, send_frame_thread, (void *)remoteVars.send_thread_id); - if (ret) - { - EPHYR_DBG("ERROR; return code from pthread_create() is %d\n", ret); - terminateServer(-1); - } +#if XORG_VERSION_CURRENT >= 11900000 + EPHYR_DBG("Set notify FD for server sock: %d",remoteVars.serversock); + EPHYR_DBG ("waiting for TCP connection\n"); + SetNotifyFd(remoteVars.serversock, serverAcceptNotify, X_NOTIFY_READ, NULL); +#endif /* XORG_VERSION_CURRENT */ - EPHYR_DBG("Socket is ready"); + EPHYR_DBG("Server socket is ready"); } @@ -2743,6 +2776,8 @@ remote_init(void) memset(&remoteVars,0,sizeof(RemoteHostVars)); + remoteVars.serversock=-1; + remoteVars.jpegQuality=JPG_QUALITY; remoteVars.compression=DEFAULT_COMPRESSION; remoteVars.selstruct.selectionMode = CLIP_BOTH; diff --git a/x2gokdriveremote.h b/x2gokdriveremote.h index dc8f4b0..d7d368b 100644 --- a/x2gokdriveremote.h +++ b/x2gokdriveremote.h @@ -476,6 +476,7 @@ unsigned int checkSocketConnection(OsTimerPtr timer, CARD32 time, void* args); void restartTimerOnInit(void); void open_socket(void); +void close_server_socket(void); void setAgentState(int state); @@ -496,6 +497,7 @@ unsigned char* png_compress(uint32_t image_width, uint32_t image_height, unsigned char* RGBA_buffer, uint32_t* png_size, BOOL compress_cursor); void clientReadNotify(int fd, int ready, void *data); +void serverAcceptNotify(int fd, int ready, void *data); void add_frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t crc, uint32_t size); -- Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/x2gokdrive.git