connection.c revision 8f34cbf9
1/* 2 * handles connections 3 */ 4/* 5 6Copyright 1990, 1991, 1998 The Open Group 7 8Permission to use, copy, modify, distribute, and sell this software and its 9documentation for any purpose is hereby granted without fee, provided that 10the above copyright notice appear in all copies and that both that 11copyright notice and this permission notice appear in supporting 12documentation. 13 14The above copyright notice and this permission notice shall be included in 15all copies or substantial portions of the Software. 16 17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24Except as contained in this notice, the name of The Open Group shall not be 25used in advertising or otherwise to promote the sale, use or other dealings 26in this Software without prior written authorization from The Open Group. 27 28 * Copyright 1990, 1991 Network Computing Devices; 29 * Portions Copyright 1987 by Digital Equipment Corporation 30 * 31 * Permission to use, copy, modify, distribute, and sell this software and 32 * its documentation for any purpose is hereby granted without fee, provided 33 * that the above copyright notice appear in all copies and that both that 34 * copyright notice and this permission notice appear in supporting 35 * documentation, and that the names of Network Computing Devices, or Digital 36 * not be used in advertising or publicity pertaining to distribution 37 * of the software without specific, written prior permission. 38 * 39 * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH 40 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF 41 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES, 42 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 43 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 44 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 45 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 46 * THIS SOFTWARE. 47 */ 48/* 49 * Copyright 1990, 1991 Network Computing Devices; 50 * Portions Copyright 1987 by Digital Equipment Corporation 51 * 52 * Permission to use, copy, modify, distribute, and sell this software and 53 * its documentation for any purpose is hereby granted without fee, provided 54 * that the above copyright notice appear in all copies and that both that 55 * copyright notice and this permission notice appear in supporting 56 * documentation, and that the names of Network Computing Devices, or Digital 57 * not be used in advertising or publicity pertaining to distribution 58 * of the software without specific, written prior permission. 59 * 60 * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH 61 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF 62 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES, 63 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 64 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 65 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 66 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 67 * THIS SOFTWARE. 68 */ 69 70#include "config.h" 71 72#include <stdlib.h> 73#include <X11/Xtrans/Xtrans.h> 74#include <stdlib.h> 75#include "misc.h" 76#include <stdio.h> 77#include <errno.h> 78#include <X11/Xos.h> 79#include <sys/param.h> 80#include <sys/socket.h> 81#include <sys/uio.h> 82#include <signal.h> 83 84#include <X11/fonts/FS.h> 85#include <X11/fonts/FSproto.h> 86#include "clientstr.h" 87#include "X11/Xpoll.h" 88#include "osdep.h" 89#include "globals.h" 90#include "osstruct.h" 91#include "servermd.h" 92#include "dispatch.h" 93#include "fsevents.h" 94 95 96 97int ListenPort = DEFAULT_FS_PORT; /* port to listen on */ 98int lastfdesc; 99 100fd_set WellKnownConnections; 101fd_set AllSockets; 102fd_set AllClients; 103fd_set LastSelectMask; 104fd_set ClientsWithInput; 105fd_set ClientsWriteBlocked; 106fd_set OutputPending; 107long OutputBufferSize = BUFSIZE; 108 109Bool NewOutputPending; 110Bool AnyClientsWriteBlocked; 111 112int ConnectionTranslation[MAXSOCKS]; 113 114XtransConnInfo *ListenTransConns = NULL; 115int *ListenTransFds = NULL; 116int ListenTransCount; 117 118 119extern int xfd_ffs (fd_mask); 120static void error_conn_max(XtransConnInfo trans_conn); 121static void close_fd(OsCommPtr oc); 122 123 124static XtransConnInfo 125lookup_trans_conn (int fd) 126{ 127 if (ListenTransFds) 128 { 129 int i; 130 for (i = 0; i < ListenTransCount; i++) 131 if (ListenTransFds[i] == fd) 132 return ListenTransConns[i]; 133 } 134 135 return (NULL); 136} 137 138void 139StopListening(void) 140{ 141 int i; 142 143 for (i = 0; i < ListenTransCount; i++) 144 { 145 FD_CLR (ListenTransFds[i], &AllSockets); 146 _FontTransCloseForCloning (ListenTransConns[i]); 147 } 148 149 free ((char *) ListenTransFds); 150 free ((char *) ListenTransConns); 151 152 ListenTransFds = NULL; 153 ListenTransConns = NULL; 154 ListenTransCount = 0; 155} 156 157/* 158 * creates the sockets for listening to clients 159 * 160 * only called when server first started 161 */ 162void 163CreateSockets(int old_listen_count, OldListenRec *old_listen) 164{ 165 int i; 166 struct sigaction act; 167 168 FD_ZERO(&AllSockets); 169 FD_ZERO(&AllClients); 170 FD_ZERO(&LastSelectMask); 171 FD_ZERO(&ClientsWithInput); 172 FD_ZERO(&WellKnownConnections); 173 174 for (i = 0; i < MAXSOCKS; i++) 175 ConnectionTranslation[i] = 0; 176 177 lastfdesc = sysconf(_SC_OPEN_MAX) - 1; 178 179 if ((lastfdesc < 0) || (lastfdesc > MAXSOCKS)) { 180 lastfdesc = MAXSOCKS; 181 } 182 183 if (old_listen_count > 0) { 184 185 /* 186 * The font server cloned itself. Re-use previously opened 187 * transports for listening. 188 */ 189 190 ListenTransConns = (XtransConnInfo *) malloc ( 191 old_listen_count * sizeof (XtransConnInfo)); 192 193 ListenTransFds = (int *) malloc (old_listen_count * sizeof (int)); 194 195 ListenTransCount = 0; 196 197 for (i = 0; i < old_listen_count; i++) 198 { 199 char portnum[10]; 200 201 if (old_listen[i].portnum != ListenPort) 202 continue; /* this should never happen */ 203 else 204 snprintf (portnum, sizeof(portnum), "%d", old_listen[i].portnum); 205 206 if ((ListenTransConns[ListenTransCount] = 207 _FontTransReopenCOTSServer (old_listen[i].trans_id, 208 old_listen[i].fd, portnum)) != NULL) 209 { 210 ListenTransFds[ListenTransCount] = old_listen[i].fd; 211 FD_SET (old_listen[i].fd, &WellKnownConnections); 212 213 NoticeF("reusing existing file descriptor %d\n", 214 old_listen[i].fd); 215 216 ListenTransCount++; 217 } 218 } 219 } else { 220 char port[20]; 221 int partial; 222 223 snprintf (port, sizeof(port), "%d", ListenPort); 224 225 if ((_FontTransMakeAllCOTSServerListeners (port, &partial, 226 &ListenTransCount, &ListenTransConns) >= 0) && 227 (ListenTransCount >= 1)) 228 { 229 ListenTransFds = (int *) malloc (ListenTransCount * sizeof (int)); 230 231 for (i = 0; i < ListenTransCount; i++) 232 { 233 int fd = _FontTransGetConnectionNumber (ListenTransConns[i]); 234 235 ListenTransFds[i] = fd; 236 FD_SET (fd, &WellKnownConnections); 237 } 238 } 239 } 240 241 if (! XFD_ANYSET(&WellKnownConnections)) 242 FatalError("cannot establish any listening sockets\n"); 243 244 /* set up all the signal handlers */ 245 sigemptyset(&act.sa_mask); 246 act.sa_flags = SA_RESTART; 247#define HANDLE_SIGNAL(s, h) act.sa_handler = h; sigaction(s, &act, NULL) 248 249 HANDLE_SIGNAL(SIGPIPE, SIG_IGN); 250 HANDLE_SIGNAL(SIGHUP, AutoResetServer); 251 HANDLE_SIGNAL(SIGINT, GiveUp); 252 HANDLE_SIGNAL(SIGTERM, GiveUp); 253 HANDLE_SIGNAL(SIGUSR1, ServerReconfig); 254 HANDLE_SIGNAL(SIGUSR2, ServerCacheFlush); 255 HANDLE_SIGNAL(SIGCHLD, CleanupChild); 256 257 XFD_COPYSET (&WellKnownConnections, &AllSockets); 258} 259 260/* 261 * called when server cycles 262 */ 263void 264ResetSockets(void) 265{ 266} 267 268void 269CloseSockets(void) 270{ 271 int i; 272 273 for (i = 0; i < ListenTransCount; i++) 274 _FontTransClose (ListenTransConns[i]); 275} 276 277/* 278 * accepts new connections 279 */ 280void 281MakeNewConnections(void) 282{ 283 fd_mask readyconnections; 284 int curconn; 285 int newconn; 286 long connect_time; 287 int i; 288 ClientPtr client; 289 OsCommPtr oc; 290 fd_set tmask; 291 292 XFD_ANDSET (&tmask, &LastSelectMask, &WellKnownConnections); 293 readyconnections = tmask.fds_bits[0]; 294 if (!readyconnections) 295 return; 296 connect_time = GetTimeInMillis(); 297 298 /* kill off stragglers */ 299 for (i = MINCLIENT; i < currentMaxClients; i++) { 300 if ((client = clients[i]) != NullClient) { 301 oc = (OsCommPtr) client->osPrivate; 302 if ((oc && (oc->conn_time != 0) && 303 (connect_time - oc->conn_time) >= TimeOutValue) || 304 ((client->noClientException != FSSuccess) && 305 (client->clientGone != CLIENT_GONE))) 306 CloseDownClient(client); 307 } 308 } 309 310 while (readyconnections) { 311 XtransConnInfo trans_conn, new_trans_conn; 312 int status; 313 314 curconn = xfd_ffs(readyconnections) - 1; 315 readyconnections &= ~(1 << curconn); 316 317 if ((trans_conn = lookup_trans_conn (curconn)) == NULL) 318 continue; 319 320 if ((new_trans_conn = _FontTransAccept (trans_conn, &status)) == NULL) 321 continue; 322 323 newconn = _FontTransGetConnectionNumber (new_trans_conn); 324 325 _FontTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1); 326 327 oc = (OsCommPtr) fsalloc(sizeof(OsCommRec)); 328 if (!oc) { 329 fsfree(oc); 330 error_conn_max(new_trans_conn); 331 _FontTransClose(new_trans_conn); 332 continue; 333 } 334 FD_SET(newconn, &AllClients); 335 FD_SET(newconn, &AllSockets); 336 oc->fd = newconn; 337 oc->trans_conn = new_trans_conn; 338 oc->input = (ConnectionInputPtr) NULL; 339 oc->output = (ConnectionOutputPtr) NULL; 340 oc->conn_time = connect_time; 341 342 if ((newconn < lastfdesc) && 343 (client = NextAvailableClient((pointer) oc))) { 344 ConnectionTranslation[newconn] = client->index; 345 } else { 346 error_conn_max(new_trans_conn); 347 close_fd(oc); 348 } 349 } 350} 351 352#define NOROOM "maximum number of clients reached" 353 354static void 355error_conn_max(XtransConnInfo trans_conn) 356{ 357 int fd = _FontTransGetConnectionNumber (trans_conn); 358 fsConnSetup conn; 359 char pad[3]; 360 char byteOrder = 0; 361 int whichbyte = 1; 362 struct timeval waittime; 363 fd_set mask; 364 365 366 waittime.tv_usec = BOTIMEOUT / MILLI_PER_SECOND; 367 waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) * 368 (1000000 / MILLI_PER_SECOND); 369 FD_ZERO(&mask); 370 FD_SET(fd, &mask); 371 (void) Select(fd + 1, &mask, NULL, NULL, &waittime); 372 /* try to read the byteorder of the connection */ 373 (void) _FontTransRead(trans_conn, &byteOrder, 1); 374 if ((byteOrder == 'l') || (byteOrder == 'B')) { 375 int num_alts; 376 AlternateServerPtr altservers, 377 as; 378 int i, 379 altlen = 0; 380 381 num_alts = ListAlternateServers(&altservers); 382 conn.status = AuthDenied; 383 conn.major_version = FS_PROTOCOL; 384 conn.minor_version = FS_PROTOCOL_MINOR; 385 conn.num_alternates = num_alts; 386 for (i = 0, as = altservers; i < num_alts; i++, as++) { 387 altlen += (2 + as->namelen + 3) >> 2; 388 } 389 conn.alternate_len = altlen; 390 /* blow off the auth info */ 391 conn.auth_index = 0; 392 conn.auth_len = 0; 393 394 if (((*(char *) &whichbyte) && (byteOrder == 'B')) || 395 (!(*(char *) &whichbyte) && (byteOrder == 'l'))) { 396 conn.status = lswaps(conn.status); 397 conn.major_version = lswaps(conn.major_version); 398 conn.minor_version = lswaps(conn.minor_version); 399 conn.alternate_len = lswaps(conn.alternate_len); 400 } 401 (void) _FontTransWrite(trans_conn, 402 (char *) &conn, SIZEOF(fsConnSetup)); 403 /* dump alternates */ 404 for (i = 0, as = altservers; i < num_alts; i++, as++) { 405 (void) _FontTransWrite(trans_conn, 406 (char *) as, 2); /* XXX */ 407 (void) _FontTransWrite(trans_conn, 408 (char *) as->name, as->namelen); 409 altlen = 2 + as->namelen; 410 /* pad it */ 411 if (altlen & 3) 412 (void) _FontTransWrite(trans_conn, 413 (char *) pad, ((4 - (altlen & 3)) & 3)); 414 } 415 } 416} 417 418static void 419close_fd(OsCommPtr oc) 420{ 421 int fd = oc->fd; 422 423 if (oc->trans_conn) 424 _FontTransClose(oc->trans_conn); 425 FreeOsBuffers(oc); 426 FD_CLR(fd, &AllSockets); 427 FD_CLR(fd, &AllClients); 428 FD_CLR(fd, &ClientsWithInput); 429 FD_CLR(fd, &ClientsWriteBlocked); 430 if (!XFD_ANYSET(&ClientsWriteBlocked)) 431 AnyClientsWriteBlocked = FALSE; 432 FD_CLR(fd, &OutputPending); 433 fsfree(oc); 434} 435 436void 437CheckConnections(void) 438{ 439 fd_set mask; 440 fd_set tmask; 441 int curclient; 442 int i; 443 struct timeval notime; 444 int r; 445 446 notime.tv_sec = 0; 447 notime.tv_usec = 0; 448 449 XFD_COPYSET(&AllClients, &mask); 450 for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) { 451 while (mask.fds_bits[i]) { 452 curclient = xfd_ffs(mask.fds_bits[i]) - 1 + (i * (sizeof(fd_mask) * 8)); 453 FD_ZERO(&tmask); 454 FD_SET(curclient, &tmask); 455 r = Select(curclient + 1, &tmask, NULL, NULL, ¬ime); 456 if (r < 0) 457 CloseDownClient(clients[ConnectionTranslation[curclient]]); 458 FD_CLR(curclient, &mask); 459 } 460 } 461} 462 463void 464CloseDownConnection(ClientPtr client) 465{ 466 OsCommPtr oc = (OsCommPtr) client->osPrivate; 467 468 if (oc == NULL) 469 return; 470 471 if (oc->output && oc->output->count) 472 FlushClient(client, oc, (char *) NULL, 0, 0); 473 ConnectionTranslation[oc->fd] = 0; 474 close_fd(oc); 475 client->osPrivate = (pointer) NULL; 476} 477 478 479/**************** 480 * IgnoreClient 481 * Removes one client from input masks. 482 * Must have cooresponding call to AttendClient. 483 ****************/ 484 485static fd_set IgnoredClientsWithInput; 486 487void 488IgnoreClient(ClientPtr client) 489{ 490 OsCommPtr oc = (OsCommPtr) client->osPrivate; 491 int connection = oc->fd; 492 493 if (FD_ISSET(connection, &ClientsWithInput)) 494 FD_SET(connection, &IgnoredClientsWithInput); 495 else 496 FD_CLR(connection, &IgnoredClientsWithInput); 497 FD_CLR(connection, &ClientsWithInput); 498 FD_CLR(connection, &AllSockets); 499 FD_CLR(connection, &AllClients); 500 FD_CLR(connection, &LastSelectMask); 501 isItTimeToYield = TRUE; 502} 503 504/**************** 505 * AttendClient 506 * Adds one client back into the input masks. 507 ****************/ 508 509void 510AttendClient(ClientPtr client) 511{ 512 OsCommPtr oc = (OsCommPtr) client->osPrivate; 513 int connection = oc->fd; 514 515 FD_SET(connection, &AllClients); 516 FD_SET(connection, &AllSockets); 517 FD_SET(connection, &LastSelectMask); 518 if (FD_ISSET(connection, &IgnoredClientsWithInput)) 519 FD_SET(connection, &ClientsWithInput); 520} 521 522/* 523 * figure out which clients need to be toasted 524 */ 525void 526ReapAnyOldClients(void) 527{ 528 int i; 529 long cur_time = GetTimeInMillis(); 530 ClientPtr client; 531 532#ifdef DEBUG 533 fprintf(stderr, "looking for clients to reap\n"); 534#endif 535 536 for (i = MINCLIENT; i < currentMaxClients; i++) { 537 client = clients[i]; 538 if (client) { 539 if ((cur_time - client->last_request_time) >= ReapClientTime) { 540 if (client->clientGone == CLIENT_AGED) { 541 client->clientGone = CLIENT_TIMED_OUT; 542 543#ifdef DEBUG 544 fprintf(stderr, "reaping client #%d\n", i); 545#endif 546 547 CloseDownClient(client); 548 } else { 549 client->clientGone = CLIENT_AGED; 550 SendKeepAliveEvent(client); 551 } 552 } 553 } 554 } 555} 556