예제 #1
0
파일: sockets.c 프로젝트: DjCBS3/vino
void
rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
{
    int nfds;
    int n;
    fd_set fds;
    struct timeval tv;
    rfbClientIteratorPtr i;
    rfbClientPtr cl;

    if (!rfbScreen->inetdInitDone && rfbScreen->inetdSock != -1) {
	rfbNewClientConnection(rfbScreen,rfbScreen->inetdSock); 
	rfbScreen->inetdInitDone = TRUE;
    }

    memcpy(&fds, &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) {
	return;
    }
    if (nfds < 0) {
#ifdef WIN32
		errno = WSAGetLastError();
#endif
	if (errno != EINTR)
		rfbLogPerror("rfbCheckFds: select");
	return;
    }
    printf("DUMP: nfds = %d\n", nfds);
    for(n=0; n < rfbScreen->rfbListenSockTotal; n++) {
        if (rfbScreen->rfbListenSock[n] != -1 && FD_ISSET(rfbScreen->rfbListenSock[n], &fds)) {
          rfbProcessNewConnection(rfbScreen, rfbScreen->rfbListenSock[n]);
          FD_CLR(rfbScreen->rfbListenSock[n], &fds);
          if (--nfds == 0)
            return;
        }
    }

    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);
    }
    rfbReleaseClientIterator(i);
}
예제 #2
0
static void
httpProcessInput(rfbScreenInfoPtr rfbScreen)
{
#ifdef LIBVNCSERVER_IPv6
    struct sockaddr_storage addr;
    char host[1024];
#else
    struct sockaddr_in addr;
#endif
    socklen_t addrlen = sizeof(addr);
    char fullFname[512];
    char params[1024];
    char *ptr;
    char *fname;
    unsigned int maxFnameLen;
    FILE* fd;
    rfbBool performSubstitutions = FALSE;
    char str[256+32];
#ifndef WIN32
    char* user=getenv("USER");
#endif
   
    cl.sock=rfbScreen->httpSock;

    if (strlen(rfbScreen->httpDir) > 255) {
	rfbErr("-httpd directory too long\n");
	httpCloseSock(rfbScreen);
	return;
    }
    strcpy(fullFname, rfbScreen->httpDir);
    fname = &fullFname[strlen(fullFname)];
    maxFnameLen = 511 - strlen(fullFname);

    buf_filled=0;

    /* Read data from the HTTP client until we get a complete request. */
    while (1) {
	ssize_t got;

        if (buf_filled > sizeof (buf)) {
	    rfbErr("httpProcessInput: HTTP request is too long\n");
	    httpCloseSock(rfbScreen);
	    return;
	}

	got = read (rfbScreen->httpSock, buf + buf_filled,
			    sizeof (buf) - buf_filled - 1);

	if (got <= 0) {
	    if (got == 0) {
		rfbErr("httpd: premature connection close\n");
	    } else {
#ifdef WIN32
	        errno=WSAGetLastError();
#endif
		if (errno == EAGAIN) {
		    return;
		}
		rfbLogPerror("httpProcessInput: read");
	    }
	    httpCloseSock(rfbScreen);
	    return;
	}

	buf_filled += got;
	buf[buf_filled] = '\0';

	/* Is it complete yet (is there a blank line)? */
	if (strstr (buf, "\r\r") || strstr (buf, "\n\n") ||
	    strstr (buf, "\r\n\r\n") || strstr (buf, "\n\r\n\r"))
	    break;
    }


    /* Process the request. */
    if(rfbScreen->httpEnableProxyConnect) {
	const static char* PROXY_OK_STR = "HTTP/1.0 200 OK\r\nContent-Type: octet-stream\r\nPragma: no-cache\r\n\r\n";
	if(!strncmp(buf, "CONNECT ", 8)) {
	    if(atoi(strchr(buf, ':')+1)!=rfbScreen->port) {
		rfbErr("httpd: CONNECT format invalid.\n");
		rfbWriteExact(&cl,INVALID_REQUEST_STR, strlen(INVALID_REQUEST_STR));
		httpCloseSock(rfbScreen);
		return;
	    }
	    /* proxy connection */
	    rfbLog("httpd: client asked for CONNECT\n");
	    rfbWriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR));
	    rfbNewClientConnection(rfbScreen,rfbScreen->httpSock);
	    rfbScreen->httpSock = -1;
	    return;
	}
	if (!strncmp(buf, "GET ",4) && !strncmp(strchr(buf,'/'),"/proxied.connection HTTP/1.", 27)) {
	    /* proxy connection */
	    rfbLog("httpd: client asked for /proxied.connection\n");
	    rfbWriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR));
	    rfbNewClientConnection(rfbScreen,rfbScreen->httpSock);
	    rfbScreen->httpSock = -1;
	    return;
	}	   
    }

    if (strncmp(buf, "GET ", 4)) {
	rfbErr("httpd: no GET line\n");
	httpCloseSock(rfbScreen);
	return;
    } else {
	/* Only use the first line. */
	buf[strcspn(buf, "\n\r")] = '\0';
    }

    if (strlen(buf) > maxFnameLen) {
	rfbErr("httpd: GET line too long\n");
	httpCloseSock(rfbScreen);
	return;
    }

    if (sscanf(buf, "GET %s HTTP/1.", fname) != 1) {
	rfbErr("httpd: couldn't parse GET line\n");
	httpCloseSock(rfbScreen);
	return;
    }

    if (fname[0] != '/') {
	rfbErr("httpd: filename didn't begin with '/'\n");
	rfbWriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
	httpCloseSock(rfbScreen);
	return;
    }


    getpeername(rfbScreen->httpSock, (struct sockaddr *)&addr, &addrlen);
#ifdef LIBVNCSERVER_IPv6
    if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) {
      rfbLogPerror("httpProcessInput: error in getnameinfo");
    }
    rfbLog("httpd: get '%s' for %s\n", fname+1, host);
#else
    rfbLog("httpd: get '%s' for %s\n", fname+1,
	   inet_ntoa(addr.sin_addr));
#endif

    /* Extract parameters from the URL string if necessary */

    params[0] = '\0';
    ptr = strchr(fname, '?');
    if (ptr != NULL) {
       *ptr = '\0';
       if (!parseParams(&ptr[1], params, 1024)) {
           params[0] = '\0';
           rfbErr("httpd: bad parameters in the URL\n");
       }
    }


    /* If we were asked for '/', actually read the file index.vnc */

    if (strcmp(fname, "/") == 0) {
	strcpy(fname, "/index.vnc");
	rfbLog("httpd: defaulting to '%s'\n", fname+1);
    }

    /* Substitutions are performed on files ending .vnc */

    if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) {
	performSubstitutions = TRUE;
    }

    /* Open the file */

    if ((fd = fopen(fullFname, "r")) == 0) {
        rfbLogPerror("httpProcessInput: open");
        rfbWriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
        httpCloseSock(rfbScreen);
        return;
    }

    if(performSubstitutions) /* is the 'index.vnc' file */
      rfbWriteExact(&cl, OK_STR_HTML, strlen(OK_STR_HTML));
    else
      rfbWriteExact(&cl, OK_STR, strlen(OK_STR));

    while (1) {
	int n = fread(buf, 1, BUF_SIZE-1, fd);
	if (n < 0) {
	    rfbLogPerror("httpProcessInput: read");
	    fclose(fd);
	    httpCloseSock(rfbScreen);
	    return;
	}

	if (n == 0)
	    break;

	if (performSubstitutions) {

	    /* Substitute $WIDTH, $HEIGHT, etc with the appropriate values.
	       This won't quite work properly if the .vnc file is longer than
	       BUF_SIZE, but it's reasonable to assume that .vnc files will
	       always be short. */

	    char *ptr = buf;
	    char *dollar;
	    buf[n] = 0; /* make sure it's null-terminated */

	    while ((dollar = strchr(ptr, '$'))!=NULL) {
		rfbWriteExact(&cl, ptr, (dollar - ptr));

		ptr = dollar;

		if (compareAndSkip(&ptr, "$WIDTH")) {

		    sprintf(str, "%d", rfbScreen->width);
		    rfbWriteExact(&cl, str, strlen(str));

		} else if (compareAndSkip(&ptr, "$HEIGHT")) {

		    sprintf(str, "%d", rfbScreen->height);
		    rfbWriteExact(&cl, str, strlen(str));

		} else if (compareAndSkip(&ptr, "$APPLETWIDTH")) {

		    sprintf(str, "%d", rfbScreen->width);
		    rfbWriteExact(&cl, str, strlen(str));

		} else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) {

		    sprintf(str, "%d", rfbScreen->height + 32);
		    rfbWriteExact(&cl, str, strlen(str));

		} else if (compareAndSkip(&ptr, "$PORT")) {

		    sprintf(str, "%d", rfbScreen->port);
		    rfbWriteExact(&cl, str, strlen(str));

		} else if (compareAndSkip(&ptr, "$DESKTOP")) {

		    rfbWriteExact(&cl, rfbScreen->desktopName, strlen(rfbScreen->desktopName));

		} else if (compareAndSkip(&ptr, "$DISPLAY")) {

		    sprintf(str, "%s:%d", rfbScreen->thisHost, rfbScreen->port-5900);
		    rfbWriteExact(&cl, str, strlen(str));

		} else if (compareAndSkip(&ptr, "$USER")) {
#ifndef WIN32
		    if (user) {
			rfbWriteExact(&cl, user,
				   strlen(user));
		    } else
#endif
			rfbWriteExact(&cl, "?", 1);
		} else if (compareAndSkip(&ptr, "$PARAMS")) {
		    if (params[0] != '\0')
			rfbWriteExact(&cl, params, strlen(params));
		} else {
		    if (!compareAndSkip(&ptr, "$$"))
			ptr++;

		    if (rfbWriteExact(&cl, "$", 1) < 0) {
			fclose(fd);
			httpCloseSock(rfbScreen);
			return;
		    }
		}
	    }
	    if (rfbWriteExact(&cl, ptr, (&buf[n] - ptr)) < 0)
		break;

	} else {

	    /* For files not ending .vnc, just write out the buffer */

	    if (rfbWriteExact(&cl, buf, n) < 0)
		break;
	}
    }

    fclose(fd);
    httpCloseSock(rfbScreen);
}
예제 #3
0
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;
}
예제 #4
0
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;
}
예제 #5
0
파일: sockets.c 프로젝트: TurboVNC/turbovnc
void
rfbCheckFds()
{
    int nfds;
    fd_set fds;
    struct timeval tv;
    struct sockaddr_storage addr;
    socklen_t addrlen = sizeof(addr);
    char addrStr[INET6_ADDRSTRLEN];
    char buf[6];
    const int one = 1;
    int sock;
    rfbClientPtr cl;
    static Bool inetdInitDone = FALSE;

    if (!inetdInitDone && inetdSock != -1) {
        rfbNewClientConnection(inetdSock);
        inetdInitDone = TRUE;
    }

    memcpy((char *)&fds, (char *)&allFds, sizeof(fd_set));
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    nfds = select(maxFd + 1, &fds, NULL, NULL, &tv);
    if (nfds == 0) {
        return;
    }
    if (nfds < 0) {
        rfbLogPerror("rfbCheckFds: select");
        return;
    }

    if (rfbListenSock != -1 && FD_ISSET(rfbListenSock, &fds)) {

        if ((sock = accept(rfbListenSock,
                           (struct sockaddr *)&addr, &addrlen)) < 0) {
            rfbLogPerror("rfbCheckFds: accept");
            return;
        }

        if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
            rfbLogPerror("rfbCheckFds: fcntl");
            close(sock);
            return;
        }

        if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
                       (char *)&one, sizeof(one)) < 0) {
            rfbLogPerror("rfbCheckFds: setsockopt");
            close(sock);
            return;
        }

        fprintf(stderr, "\n");

#if USE_LIBWRAP
        if (!hosts_ctl("Xvnc", STRING_UNKNOWN,
                       sockaddr_string(&addr, addrStr, INET6_ADDRSTRLEN),
                       STRING_UNKNOWN)) {
          rfbLog("Rejected connection from client %s\n",
                 sockaddr_string(&addr, addrStr, INET6_ADDRSTRLEN))
          close(sock);
          return;
        }
#endif

        rfbLog("Got connection from client %s\n",
               sockaddr_string(&addr, addrStr, INET6_ADDRSTRLEN));

        AddEnabledDevice(sock);
        FD_SET(sock, &allFds);
        maxFd = max(sock, maxFd);

        rfbNewClientConnection(sock);

        FD_CLR(rfbListenSock, &fds);
        if (--nfds == 0)
            return;
    }

    if ((udpSock != -1) && FD_ISSET(udpSock, &fds)) {

        if (recvfrom(udpSock, buf, 1, MSG_PEEK,
                     (struct sockaddr *)&addr, &addrlen) < 0) {

            rfbLogPerror("rfbCheckFds: UDP: recvfrom");
            rfbDisconnectUDPSock();

        } else {

            if (!udpSockConnected ||
                (memcmp(&addr, &udpRemoteAddr, addrlen) != 0))
            {
                /* new remote end */
                rfbLog("rfbCheckFds: UDP: got connection\n");

                memcpy(&udpRemoteAddr, &addr, addrlen);
                udpSockConnected = TRUE;

                if (connect(udpSock,
                            (struct sockaddr *)&addr, addrlen) < 0) {
                    rfbLogPerror("rfbCheckFds: UDP: connect");
                    rfbDisconnectUDPSock();
                    return;
                }

                rfbNewUDPConnection(udpSock);
            }

            rfbProcessUDPInput(udpSock);
        }

        FD_CLR(udpSock, &fds);
        if (--nfds == 0)
            return;
    }

    for (cl = rfbClientHead; cl; cl = cl->next) {
        if (FD_ISSET(cl->sock, &fds) && FD_ISSET(cl->sock, &allFds)) {
            rfbClientPtr cl2;
#if USETLS
            do {
                rfbProcessClientMessage(cl);
                /* Make sure cl hasn't been freed */
                for (cl2 = rfbClientHead; cl2; cl2 = cl2->next) {
                    if (cl2 == cl)
                        break;
                }
                if (cl2 == NULL) return;
            } while (cl->sslctx && rfbssl_pending(cl) > 0);
#else
            rfbProcessClientMessage(cl);
            for (cl2 = rfbClientHead; cl2; cl2 = cl2->next) {
                if (cl2 == cl)
                    break;
            }
            if (cl2 == NULL) return;
#endif
        }
    }
}