connection.c revision ce6676db
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 "xfs-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#ifndef __UNIXOS2__ 82#include <sys/uio.h> 83#endif 84#include <signal.h> 85 86#include <X11/fonts/FS.h> 87#include <X11/fonts/FSproto.h> 88#include "clientstr.h" 89#include "X11/Xpoll.h" 90#include "osdep.h" 91#include "globals.h" 92#include "osstruct.h" 93#include "servermd.h" 94#include "dispatch.h" 95#include "fsevents.h" 96 97#ifdef __UNIXOS2__ 98#define _NFILE OPEN_MAX 99#define select(n,r,w,x,t) os2PseudoSelect(n,r,w,x,t) 100#endif 101 102 103int ListenPort = DEFAULT_FS_PORT; /* port to listen on */ 104int lastfdesc; 105 106fd_set WellKnownConnections; 107fd_set AllSockets; 108fd_set AllClients; 109fd_set LastSelectMask; 110fd_set ClientsWithInput; 111fd_set ClientsWriteBlocked; 112fd_set OutputPending; 113long OutputBufferSize = BUFSIZE; 114 115Bool NewOutputPending; 116Bool AnyClientsWriteBlocked; 117 118int ConnectionTranslation[MAXSOCKS]; 119 120XtransConnInfo *ListenTransConns = NULL; 121int *ListenTransFds = NULL; 122int ListenTransCount; 123 124 125static void error_conn_max(XtransConnInfo trans_conn); 126static void close_fd(OsCommPtr oc); 127 128 129static XtransConnInfo 130lookup_trans_conn (int fd) 131{ 132 if (ListenTransFds) 133 { 134 int i; 135 for (i = 0; i < ListenTransCount; i++) 136 if (ListenTransFds[i] == fd) 137 return ListenTransConns[i]; 138 } 139 140 return (NULL); 141} 142 143void 144StopListening(void) 145{ 146 int i; 147 148 for (i = 0; i < ListenTransCount; i++) 149 { 150 FD_CLR (ListenTransFds[i], &AllSockets); 151 _FontTransCloseForCloning (ListenTransConns[i]); 152 } 153 154 free ((char *) ListenTransFds); 155 free ((char *) ListenTransConns); 156 157 ListenTransFds = NULL; 158 ListenTransConns = NULL; 159 ListenTransCount = 0; 160} 161 162/* 163 * creates the sockets for listening to clients 164 * 165 * only called when server first started 166 */ 167void 168CreateSockets(int old_listen_count, OldListenRec *old_listen) 169{ 170 int i; 171 struct sigaction act; 172 173 FD_ZERO(&AllSockets); 174 FD_ZERO(&AllClients); 175 FD_ZERO(&LastSelectMask); 176 FD_ZERO(&ClientsWithInput); 177 FD_ZERO(&WellKnownConnections); 178 179 for (i = 0; i < MAXSOCKS; i++) 180 ConnectionTranslation[i] = 0; 181 182 lastfdesc = sysconf(_SC_OPEN_MAX) - 1; 183 184 if ((lastfdesc < 0) || (lastfdesc > MAXSOCKS)) { 185 lastfdesc = MAXSOCKS; 186 } 187 188 if (old_listen_count > 0) { 189 190 /* 191 * The font server cloned itself. Re-use previously opened 192 * transports for listening. 193 */ 194 195 ListenTransConns = (XtransConnInfo *) malloc ( 196 old_listen_count * sizeof (XtransConnInfo)); 197 198 ListenTransFds = (int *) malloc (old_listen_count * sizeof (int)); 199 200 ListenTransCount = 0; 201 202 for (i = 0; i < old_listen_count; i++) 203 { 204 char portnum[10]; 205 206 if (old_listen[i].portnum != ListenPort) 207 continue; /* this should never happen */ 208 else 209 sprintf (portnum, "%d", old_listen[i].portnum); 210 211 if ((ListenTransConns[ListenTransCount] = 212 _FontTransReopenCOTSServer (old_listen[i].trans_id, 213 old_listen[i].fd, portnum)) != NULL) 214 { 215 ListenTransFds[ListenTransCount] = old_listen[i].fd; 216 FD_SET (old_listen[i].fd, &WellKnownConnections); 217 218 NoticeF("reusing existing file descriptor %d\n", 219 old_listen[i].fd); 220 221 ListenTransCount++; 222 } 223 } 224 } else { 225 char port[20]; 226 int partial; 227 228 sprintf (port, "%d", ListenPort); 229 230 if ((_FontTransMakeAllCOTSServerListeners (port, &partial, 231 &ListenTransCount, &ListenTransConns) >= 0) && 232 (ListenTransCount >= 1)) 233 { 234 ListenTransFds = (int *) malloc (ListenTransCount * sizeof (int)); 235 236 for (i = 0; i < ListenTransCount; i++) 237 { 238 int fd = _FontTransGetConnectionNumber (ListenTransConns[i]); 239 240 ListenTransFds[i] = fd; 241 FD_SET (fd, &WellKnownConnections); 242 } 243 } 244 } 245 246 if (! XFD_ANYSET(&WellKnownConnections)) 247 FatalError("cannot establish any listening sockets\n"); 248 249 /* set up all the signal handlers */ 250 sigemptyset(&act.sa_mask); 251 act.sa_flags = SA_RESTART; 252#define HANDLE_SIGNAL(s, h) act.sa_handler = h; sigaction(s, &act, NULL) 253 254 HANDLE_SIGNAL(SIGPIPE, SIG_IGN); 255 HANDLE_SIGNAL(SIGHUP, AutoResetServer); 256 HANDLE_SIGNAL(SIGINT, GiveUp); 257 HANDLE_SIGNAL(SIGTERM, GiveUp); 258 HANDLE_SIGNAL(SIGUSR1, ServerReconfig); 259 HANDLE_SIGNAL(SIGUSR2, ServerCacheFlush); 260 HANDLE_SIGNAL(SIGCHLD, CleanupChild); 261 262 XFD_COPYSET (&WellKnownConnections, &AllSockets); 263} 264 265/* 266 * called when server cycles 267 */ 268void 269ResetSockets(void) 270{ 271} 272 273void 274CloseSockets(void) 275{ 276 int i; 277 278 for (i = 0; i < ListenTransCount; i++) 279 _FontTransClose (ListenTransConns[i]); 280} 281 282/* 283 * accepts new connections 284 */ 285void 286MakeNewConnections(void) 287{ 288 fd_mask readyconnections; 289 int curconn; 290 int newconn; 291 long connect_time; 292 int i; 293 ClientPtr client; 294 OsCommPtr oc; 295 fd_set tmask; 296 297 XFD_ANDSET (&tmask, &LastSelectMask, &WellKnownConnections); 298 readyconnections = tmask.fds_bits[0]; 299 if (!readyconnections) 300 return; 301 connect_time = GetTimeInMillis(); 302 303 /* kill off stragglers */ 304 for (i = MINCLIENT; i < currentMaxClients; i++) { 305 if ((client = clients[i]) != NullClient) { 306 oc = (OsCommPtr) client->osPrivate; 307 if ((oc && (oc->conn_time != 0) && 308 (connect_time - oc->conn_time) >= TimeOutValue) || 309 ((client->noClientException != FSSuccess) && 310 (client->clientGone != CLIENT_GONE))) 311 CloseDownClient(client); 312 } 313 } 314 315 while (readyconnections) { 316 XtransConnInfo trans_conn, new_trans_conn; 317 int status; 318 319 curconn = ffs(readyconnections) - 1; 320 readyconnections &= ~(1 << curconn); 321 322 if ((trans_conn = lookup_trans_conn (curconn)) == NULL) 323 continue; 324 325 if ((new_trans_conn = _FontTransAccept (trans_conn, &status)) == NULL) 326 continue; 327 328 newconn = _FontTransGetConnectionNumber (new_trans_conn); 329 330 _FontTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1); 331 332 oc = (OsCommPtr) fsalloc(sizeof(OsCommRec)); 333 if (!oc) { 334 fsfree(oc); 335 error_conn_max(new_trans_conn); 336 _FontTransClose(new_trans_conn); 337 continue; 338 } 339 FD_SET(newconn, &AllClients); 340 FD_SET(newconn, &AllSockets); 341 oc->fd = newconn; 342 oc->trans_conn = new_trans_conn; 343 oc->input = (ConnectionInputPtr) NULL; 344 oc->output = (ConnectionOutputPtr) NULL; 345 oc->conn_time = connect_time; 346 347 if ((newconn < lastfdesc) && 348 (client = NextAvailableClient((pointer) oc))) { 349 ConnectionTranslation[newconn] = client->index; 350 } else { 351 error_conn_max(new_trans_conn); 352 close_fd(oc); 353 } 354 } 355} 356 357#define NOROOM "maximum number of clients reached" 358 359static void 360error_conn_max(XtransConnInfo trans_conn) 361{ 362 int fd = _FontTransGetConnectionNumber (trans_conn); 363 fsConnSetup conn; 364 char pad[3]; 365 char byteOrder = 0; 366 int whichbyte = 1; 367 struct timeval waittime; 368 fd_set mask; 369 370 371 waittime.tv_usec = BOTIMEOUT / MILLI_PER_SECOND; 372 waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) * 373 (1000000 / MILLI_PER_SECOND); 374 FD_ZERO(&mask); 375 FD_SET(fd, &mask); 376 (void) Select(fd + 1, &mask, NULL, NULL, &waittime); 377 /* try to read the byteorder of the connection */ 378 (void) _FontTransRead(trans_conn, &byteOrder, 1); 379 if ((byteOrder == 'l') || (byteOrder == 'B')) { 380 int num_alts; 381 AlternateServerPtr altservers, 382 as; 383 int i, 384 altlen = 0; 385 386 num_alts = ListAlternateServers(&altservers); 387 conn.status = AuthDenied; 388 conn.major_version = FS_PROTOCOL; 389 conn.minor_version = FS_PROTOCOL_MINOR; 390 conn.num_alternates = num_alts; 391 for (i = 0, as = altservers; i < num_alts; i++, as++) { 392 altlen += (2 + as->namelen + 3) >> 2; 393 } 394 conn.alternate_len = altlen; 395 /* blow off the auth info */ 396 conn.auth_index = 0; 397 conn.auth_len = 0; 398 399 if (((*(char *) &whichbyte) && (byteOrder == 'B')) || 400 (!(*(char *) &whichbyte) && (byteOrder == 'l'))) { 401 conn.status = lswaps(conn.status); 402 conn.major_version = lswaps(conn.major_version); 403 conn.minor_version = lswaps(conn.minor_version); 404 conn.alternate_len = lswaps(conn.alternate_len); 405 } 406 (void) _FontTransWrite(trans_conn, 407 (char *) &conn, SIZEOF(fsConnSetup)); 408 /* dump alternates */ 409 for (i = 0, as = altservers; i < num_alts; i++, as++) { 410 (void) _FontTransWrite(trans_conn, 411 (char *) as, 2); /* XXX */ 412 (void) _FontTransWrite(trans_conn, 413 (char *) as->name, as->namelen); 414 altlen = 2 + as->namelen; 415 /* pad it */ 416 if (altlen & 3) 417 (void) _FontTransWrite(trans_conn, 418 (char *) pad, ((4 - (altlen & 3)) & 3)); 419 } 420 } 421} 422 423static void 424close_fd(OsCommPtr oc) 425{ 426 int fd = oc->fd; 427 428 if (oc->trans_conn) 429 _FontTransClose(oc->trans_conn); 430 FreeOsBuffers(oc); 431 FD_CLR(fd, &AllSockets); 432 FD_CLR(fd, &AllClients); 433 FD_CLR(fd, &ClientsWithInput); 434 FD_CLR(fd, &ClientsWriteBlocked); 435 if (!XFD_ANYSET(&ClientsWriteBlocked)) 436 AnyClientsWriteBlocked = FALSE; 437 FD_CLR(fd, &OutputPending); 438 fsfree(oc); 439} 440 441void 442CheckConnections(void) 443{ 444 fd_set mask; 445 fd_set tmask; 446 int curclient; 447 int i; 448 struct timeval notime; 449 int r; 450 451 notime.tv_sec = 0; 452 notime.tv_usec = 0; 453 454 XFD_COPYSET(&AllClients, &mask); 455 for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) { 456 while (mask.fds_bits[i]) { 457 curclient = ffs(mask.fds_bits[i]) - 1 + (i << 5); 458 FD_ZERO(&tmask); 459 FD_SET(curclient, &tmask); 460 r = Select(curclient + 1, &tmask, NULL, NULL, ¬ime); 461 if (r < 0) 462 CloseDownClient(clients[ConnectionTranslation[curclient]]); 463 FD_CLR(curclient, &mask); 464 } 465 } 466} 467 468void 469CloseDownConnection(ClientPtr client) 470{ 471 OsCommPtr oc = (OsCommPtr) client->osPrivate; 472 473 if (oc == NULL) 474 return; 475 476 if (oc->output && oc->output->count) 477 FlushClient(client, oc, (char *) NULL, 0, 0); 478 ConnectionTranslation[oc->fd] = 0; 479 close_fd(oc); 480 client->osPrivate = (pointer) NULL; 481} 482 483 484/**************** 485 * IgnoreClient 486 * Removes one client from input masks. 487 * Must have cooresponding call to AttendClient. 488 ****************/ 489 490static fd_set IgnoredClientsWithInput; 491 492void 493IgnoreClient(ClientPtr client) 494{ 495 OsCommPtr oc = (OsCommPtr) client->osPrivate; 496 int connection = oc->fd; 497 498 if (FD_ISSET(connection, &ClientsWithInput)) 499 FD_SET(connection, &IgnoredClientsWithInput); 500 else 501 FD_CLR(connection, &IgnoredClientsWithInput); 502 FD_CLR(connection, &ClientsWithInput); 503 FD_CLR(connection, &AllSockets); 504 FD_CLR(connection, &AllClients); 505 FD_CLR(connection, &LastSelectMask); 506 isItTimeToYield = TRUE; 507} 508 509/**************** 510 * AttendClient 511 * Adds one client back into the input masks. 512 ****************/ 513 514void 515AttendClient(ClientPtr client) 516{ 517 OsCommPtr oc = (OsCommPtr) client->osPrivate; 518 int connection = oc->fd; 519 520 FD_SET(connection, &AllClients); 521 FD_SET(connection, &AllSockets); 522 FD_SET(connection, &LastSelectMask); 523 if (FD_ISSET(connection, &IgnoredClientsWithInput)) 524 FD_SET(connection, &ClientsWithInput); 525} 526 527/* 528 * figure out which clients need to be toasted 529 */ 530void 531ReapAnyOldClients(void) 532{ 533 int i; 534 long cur_time = GetTimeInMillis(); 535 ClientPtr client; 536 537#ifdef DEBUG 538 fprintf(stderr, "looking for clients to reap\n"); 539#endif 540 541 for (i = MINCLIENT; i < currentMaxClients; i++) { 542 client = clients[i]; 543 if (client) { 544 if ((cur_time - client->last_request_time) >= ReapClientTime) { 545 if (client->clientGone == CLIENT_AGED) { 546 client->clientGone = CLIENT_TIMED_OUT; 547 548#ifdef DEBUG 549 fprintf(stderr, "reaping client #%d\n", i); 550#endif 551 552 CloseDownClient(client); 553 } else { 554 client->clientGone = CLIENT_AGED; 555 SendKeepAliveEvent(client); 556 } 557 } 558 } 559 } 560} 561