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); }
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); }
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; }
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; }
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 } } }