1 /* 2 * Copyright (C) 2011-2012 Christian Beier <dontmind (at) freeshell.org> 3 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 4 * 5 * This is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This software is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this software; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 18 * USA. 19 */ 20 21 /* 22 * listen.c - listen for incoming connections 23 */ 24 25 #ifdef __STRICT_ANSI__ 26 #define _BSD_SOURCE 27 #endif 28 #include <unistd.h> 29 #include <sys/types.h> 30 #ifdef WIN32 31 #define close closesocket 32 #include <winsock2.h> 33 #ifdef _MINGW32 34 #undef max 35 #endif // #ifdef _MINGW32 36 #else // #ifdef WIN32 37 #include <sys/wait.h> 38 #include <sys/utsname.h> 39 #endif 40 #include <sys/time.h> 41 #include <rfb/rfbclient.h> 42 43 /* 44 * listenForIncomingConnections() - listen for incoming connections from 45 * servers, and fork a new process to deal with each connection. 46 */ 47 48 void 49 listenForIncomingConnections(rfbClient* client) 50 { 51 #ifdef WIN32 52 /* FIXME */ 53 rfbClientErr("listenForIncomingConnections on MinGW32 NOT IMPLEMENTED\n"); 54 return; 55 #else 56 int listenSocket, listen6Socket = -1; 57 fd_set fds; 58 59 client->listenSpecified = TRUE; 60 61 listenSocket = ListenAtTcpPortAndAddress(client->listenPort, client->listenAddress); 62 63 if ((listenSocket < 0)) 64 return; 65 66 rfbClientLog("%s -listen: Listening on port %d\n", 67 client->programName,client->listenPort); 68 rfbClientLog("%s -listen: Command line errors are not reported until " 69 "a connection comes in.\n", client->programName); 70 71 #ifdef LIBVNCSERVER_IPv6 /* only try that if we're IPv6-capable, otherwise we may try to bind to the same port which would make all that listening fail */ 72 /* only do IPv6 listen of listen6Port is set */ 73 if (client->listen6Port > 0) 74 { 75 listen6Socket = ListenAtTcpPortAndAddress(client->listen6Port, client->listen6Address); 76 77 if (listen6Socket < 0) 78 return; 79 80 rfbClientLog("%s -listen: Listening on IPV6 port %d\n", 81 client->programName,client->listenPort); 82 rfbClientLog("%s -listen: Command line errors are not reported until " 83 "a connection comes in.\n", client->programName); 84 } 85 #endif 86 87 while (TRUE) { 88 int r; 89 /* reap any zombies */ 90 int status, pid; 91 while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0); 92 93 /* TODO: callback for discard any events (like X11 events) */ 94 95 FD_ZERO(&fds); 96 97 if(listenSocket >= 0) 98 FD_SET(listenSocket, &fds); 99 if(listen6Socket >= 0) 100 FD_SET(listen6Socket, &fds); 101 102 r = select(max(listenSocket, listen6Socket)+1, &fds, NULL, NULL, NULL); 103 104 if (r > 0) { 105 if (FD_ISSET(listenSocket, &fds)) 106 client->sock = AcceptTcpConnection(client->listenSock); 107 else if (FD_ISSET(listen6Socket, &fds)) 108 client->sock = AcceptTcpConnection(client->listen6Sock); 109 110 if (client->sock < 0) 111 return; 112 if (!SetNonBlocking(client->sock)) 113 return; 114 115 /* Now fork off a new process to deal with it... */ 116 117 switch (fork()) { 118 119 case -1: 120 rfbClientErr("fork\n"); 121 return; 122 123 case 0: 124 /* child - return to caller */ 125 close(listenSocket); 126 close(listen6Socket); 127 return; 128 129 default: 130 /* parent - go round and listen again */ 131 close(client->sock); 132 break; 133 } 134 } 135 } 136 #endif 137 } 138 139 140 141 /* 142 * listenForIncomingConnectionsNoFork() - listen for incoming connections 143 * from servers, but DON'T fork, instead just wait timeout microseconds. 144 * If timeout is negative, block indefinitly. 145 * Returns 1 on success (there was an incoming connection on the listen socket 146 * and we accepted it successfully), -1 on error, 0 on timeout. 147 */ 148 149 int 150 listenForIncomingConnectionsNoFork(rfbClient* client, int timeout) 151 { 152 fd_set fds; 153 struct timeval to; 154 int r; 155 156 to.tv_sec= timeout / 1000000; 157 to.tv_usec= timeout % 1000000; 158 159 client->listenSpecified = TRUE; 160 161 if (client->listenSock < 0) 162 { 163 client->listenSock = ListenAtTcpPortAndAddress(client->listenPort, client->listenAddress); 164 165 if (client->listenSock < 0) 166 return -1; 167 168 rfbClientLog("%s -listennofork: Listening on port %d\n", 169 client->programName,client->listenPort); 170 rfbClientLog("%s -listennofork: Command line errors are not reported until " 171 "a connection comes in.\n", client->programName); 172 } 173 174 #ifdef LIBVNCSERVER_IPv6 /* only try that if we're IPv6-capable, otherwise we may try to bind to the same port which would make all that listening fail */ 175 /* only do IPv6 listen of listen6Port is set */ 176 if (client->listen6Port > 0 && client->listen6Sock < 0) 177 { 178 client->listen6Sock = ListenAtTcpPortAndAddress(client->listen6Port, client->listen6Address); 179 180 if (client->listen6Sock < 0) 181 return -1; 182 183 rfbClientLog("%s -listennofork: Listening on IPV6 port %d\n", 184 client->programName,client->listenPort); 185 rfbClientLog("%s -listennofork: Command line errors are not reported until " 186 "a connection comes in.\n", client->programName); 187 } 188 #endif 189 190 FD_ZERO(&fds); 191 192 if(client->listenSock >= 0) 193 FD_SET(client->listenSock, &fds); 194 if(client->listen6Sock >= 0) 195 FD_SET(client->listen6Sock, &fds); 196 197 if (timeout < 0) 198 r = select(max(client->listenSock, client->listen6Sock) +1, &fds, NULL, NULL, NULL); 199 else 200 r = select(max(client->listenSock, client->listen6Sock) +1, &fds, NULL, NULL, &to); 201 202 if (r > 0) 203 { 204 if (FD_ISSET(client->listenSock, &fds)) 205 client->sock = AcceptTcpConnection(client->listenSock); 206 else if (FD_ISSET(client->listen6Sock, &fds)) 207 client->sock = AcceptTcpConnection(client->listen6Sock); 208 209 if (client->sock < 0) 210 return -1; 211 if (!SetNonBlocking(client->sock)) 212 return -1; 213 214 if(client->listenSock >= 0) { 215 close(client->listenSock); 216 client->listenSock = -1; 217 } 218 if(client->listen6Sock >= 0) { 219 close(client->listen6Sock); 220 client->listen6Sock = -1; 221 } 222 return r; 223 } 224 225 /* r is now either 0 (timeout) or -1 (error) */ 226 return r; 227 } 228 229 230