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